evolcore 0.0.28 → 0.0.29-test.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/CHANGELOG.md +12 -0
- package/bin/ec-safe-output.js +270 -54
- package/dist/agents/baseagent-availability.js +37 -1
- package/dist/agents/baseagent.js +19 -9
- package/dist/agents/claude-runner.js +171 -13
- package/dist/agents/codex/app-server-client.js +6 -2
- package/dist/agents/codex/diagnostics.js +4 -3
- package/dist/agents/codex-runner.js +396 -95
- package/dist/agents/gemini-runner.js +35 -17
- package/dist/aun/group/history.js +130 -90
- package/dist/aun/group/operations.js +1 -3
- package/dist/aun/menu/transport.js +5 -3
- package/dist/aun/msg/managed-operation.js +70 -0
- package/dist/aun/msg/p2p.js +1 -3
- package/dist/aun/msg/upload.js +2 -2
- package/dist/aun/outbox.js +1 -37
- package/dist/channels/aun.js +249 -89
- package/dist/channels/daemon.js +18 -1
- package/dist/channels/feishu.js +1 -2
- package/dist/cli/agent-command.js +23 -3
- package/dist/cli/agent-create.js +68 -2
- package/dist/cli/agent.js +12 -2
- package/dist/cli/aun-commands.js +87 -13
- package/dist/cli/cli-argv.js +26 -0
- package/dist/cli/daemon-commands.js +40 -10
- package/dist/cli/data-command.js +4 -4
- package/dist/cli/handoff-command.js +2 -0
- package/dist/cli/index.js +18 -1
- package/dist/cli/managed-command-guard.js +10 -0
- package/dist/cli/memory-command.js +441 -0
- package/dist/cli/restart-monitor.js +62 -6
- package/dist/cli/skill-command.js +41 -0
- package/dist/cli/task-context.js +2 -23
- package/dist/cli/trigger-command.js +9 -1
- package/dist/cli/watch-msg-diag.js +209 -0
- package/dist/config/config-field-policy.js +52 -3
- package/dist/config/config-manager.js +17 -4
- package/dist/config/contact-book-store.js +2 -2
- package/dist/config/mention-mode.js +7 -2
- package/dist/config/merge.js +28 -9
- package/dist/config/resolved-config-op.js +1 -1
- package/dist/config/runtime-env.js +137 -0
- package/dist/config/schema-registry.js +11 -1
- package/dist/config-store.js +10 -10
- package/dist/core/audit/event-key.js +3 -1
- package/dist/core/audit/log-integrity.js +4 -0
- package/dist/core/auth/agent-delegation.js +2 -1
- package/dist/core/auth/auth-gateway.js +13 -6
- package/dist/core/auth/authorization-audit.js +54 -19
- package/dist/core/auth/operation-authorizer.js +17 -0
- package/dist/core/auth/operation-catalog.js +9 -0
- package/dist/core/causation/context.js +5 -1
- package/dist/core/command/agent-control.js +1 -2
- package/dist/core/command/command-handler.js +51 -23
- package/dist/core/command/memory-slash.js +270 -0
- package/dist/core/command/menu-catalog.js +1 -0
- package/dist/core/command/menu-handler.js +315 -60
- package/dist/core/command/menu-protocol.js +42 -4
- package/dist/core/command/slash-gate.js +10 -10
- package/dist/core/command/slash-handler.js +206 -64
- package/dist/core/data-migration.js +282 -505
- package/dist/core/event-catalog.js +26 -0
- package/dist/core/evolagent-registry.js +6 -0
- package/dist/core/evolagent.js +0 -10
- package/dist/core/handoff/store.js +1 -20
- package/dist/core/inference/text-inference.js +57 -1
- package/dist/core/memory/consolidation-context.js +505 -0
- package/dist/core/memory/consolidation-ops-records.js +124 -0
- package/dist/core/memory/consolidation-trigger.js +394 -0
- package/dist/core/memory/index-manager.js +308 -0
- package/dist/core/memory/launch-consolidation.js +395 -0
- package/dist/core/memory/memory-admin.js +234 -0
- package/dist/core/memory/memory-document.js +100 -0
- package/dist/core/memory/memory-session-policy.js +41 -0
- package/dist/core/memory/memory-signature.js +257 -0
- package/dist/core/memory/memory-writer.js +432 -0
- package/dist/core/memory/staleness.js +117 -0
- package/dist/core/message/auto-mention-gate.js +454 -0
- package/dist/core/message/im-renderer.js +69 -16
- package/dist/core/message/message-bridge.js +287 -21
- package/dist/core/message/message-log.js +1 -0
- package/dist/core/message/message-queue.js +114 -27
- package/dist/core/message/pending-hints.js +329 -161
- package/dist/core/message/response-engine.js +567 -80
- package/dist/core/permission/ec-command-parser.js +1029 -80
- package/dist/core/permission/protected-paths.js +376 -126
- package/dist/core/permission/sandbox-runtime.js +40 -12
- package/dist/core/permission/tool-error-code.js +96 -13
- package/dist/core/permission/tool-policy.js +276 -23
- package/dist/core/role/runtime-policy.js +3 -7
- package/dist/core/session/{runner-task-history.js → runner-event-summary.js} +1 -1
- package/dist/core/session/session-fs-store.js +0 -76
- package/dist/core/session/session-idle-monitor.js +355 -0
- package/dist/core/session/session-manager.js +478 -17
- package/dist/core/session/session-mapper.js +33 -16
- package/dist/core/session/session-renew.js +217 -155
- package/dist/core/session/{session-turns.js → session-transcript.js} +35 -6
- package/dist/core/skill/global-watcher.js +282 -0
- package/dist/core/skill/index-generator.js +84 -0
- package/dist/core/skill/startup.js +73 -0
- package/dist/core/skill/switch-resolver.js +115 -0
- package/dist/core/task/task-activity-store.js +219 -0
- package/dist/eck/kit-renderer.js +30 -3
- package/dist/eck/manifest-engine.js +26 -4
- package/dist/index.js +708 -18
- package/dist/ipc.js +564 -2
- package/dist/paths.js +30 -9
- package/dist/response-system/engines/v1/proactive-flow.js +116 -15
- package/dist/response-system/modes/single-session/index.js +3 -0
- package/dist/trigger/feedback.js +1 -0
- package/dist/trigger/manager.js +0 -10
- package/dist/trigger/scheduler.js +11 -0
- package/dist/trigger/validation.js +22 -0
- package/dist/utils/avatar-upload.js +59 -18
- package/dist/utils/error-dict.json +6 -3
- package/dist/utils/error-utils.js +27 -0
- package/dist/utils/logger.js +32 -10
- package/dist/utils/media-cache.js +84 -0
- package/dist/utils/msg-diag.js +97 -0
- package/dist/utils/welcome.js +37 -8
- package/kits/docs/AUTHORING.md +314 -0
- package/kits/docs/GUIDE.md +2 -0
- package/kits/docs/INDEX.md +2 -0
- package/kits/docs/aun/CHEATSHEET.md +4 -0
- package/kits/docs/aun/SDK.md +60 -0
- package/kits/docs/context-assembly.md +10 -6
- package/kits/docs/evolcore/INDEX.md +17 -3
- package/kits/docs/evolcore/agent-create.md +24 -0
- package/kits/docs/evolcore/agent.md +5 -2
- package/kits/docs/evolcore/config.md +1 -1
- package/kits/docs/evolcore/ec-capabilities.md +364 -0
- package/kits/docs/evolcore/group.md +34 -18
- package/kits/docs/evolcore/memory-architecture.md +78 -0
- package/kits/docs/evolcore/memory-consolidation-batches.md +133 -0
- package/kits/docs/evolcore/memory-consolidation.md +263 -0
- package/kits/docs/evolcore/memory-tags.md +63 -0
- package/kits/docs/evolcore/memory.md +110 -0
- package/kits/docs/evolcore/menu-client.md +27 -11
- package/kits/{schemas → docs/evolcore}/menu-exec-schema-commands.md +12 -6
- package/kits/docs/evolcore/menu-protocol.md +213 -0
- package/kits/docs/evolcore/msg.md +2 -0
- package/kits/docs/evolcore/trigger.md +7 -5
- package/kits/docs/path-registry.md +6 -8
- package/kits/docs/prompt-loading-architecture.md +5 -3
- package/kits/docs/venues/group.md +5 -4
- package/kits/eck_manifest.json +294 -88
- package/kits/eck_manifest.memory.json +257 -0
- package/kits/rules/03-identity.md +8 -8
- package/kits/rules/05-venue.md +4 -2
- package/kits/rules/06-channel.md +1 -1
- package/kits/schemas/_meta.json +276 -47
- package/kits/schemas/agent-config.schema.12.json +38 -2
- package/kits/schemas/agent-config.schema.13.json +591 -0
- package/kits/schemas/daemon.schema.6.json +9 -9
- package/kits/schemas/defaults.schema.5.json +29 -0
- package/kits/schemas/relation-config.schema.8.json +14 -1
- package/kits/schemas/relation-config.schema.9.json +129 -0
- package/kits/schemas/role-config.schema.1.json +3 -3
- package/kits/skills/.switches.json +3 -0
- package/kits/skills/ec-skill/SKILL.md +217 -0
- package/kits/skills/ec-skill/scripts/cli.mjs +128 -0
- package/kits/skills/ec-skill/scripts/deps.mjs +107 -0
- package/kits/skills/ec-skill/scripts/frontmatter.mjs +104 -0
- package/kits/skills/ec-skill/scripts/skill.mjs +629 -0
- package/kits/skills/ec-skill/scripts/template/SKILL.md.tmpl +30 -0
- package/kits/templates/decision/auto-mention.md +25 -0
- package/kits/templates/decision/session-renew.md +22 -0
- package/kits/templates/memory-consolidation/forget.md +104 -0
- package/kits/templates/memory-consolidation/generalize.md +76 -0
- package/kits/templates/memory-consolidation/notes.md +133 -0
- package/kits/templates/memory-consolidation/profile.md +58 -0
- package/kits/templates/memory-consolidation/promote.md +72 -0
- package/kits/templates/memory-consolidation/workflow.md +75 -0
- package/kits/templates/system-fragments/bootstrap.md +14 -5
- package/kits/templates/system-fragments/commands.md +1 -0
- package/kits/templates/system-fragments/group-history.md +6 -0
- package/kits/templates/system-fragments/identity.md +0 -3
- package/kits/templates/system-fragments/memory.md +79 -0
- package/kits/templates/system-fragments/reply.md +1 -0
- package/kits/templates/system-fragments/venue.md +1 -1
- package/package.json +4 -6
- package/dist/trigger/legacy-session-history.js +0 -19
- package/kits/templates/system-fragments/group-unread-history.md +0 -7
|
@@ -118,6 +118,7 @@ const CATALOG = [
|
|
|
118
118
|
{ path: 'baseagent', type: 'string', optional: true },
|
|
119
119
|
{ path: 'model', type: 'string', optional: true },
|
|
120
120
|
{ path: 'effort', type: 'string', optional: true },
|
|
121
|
+
{ path: 'newProbability', type: 'number', optional: true },
|
|
121
122
|
{ path: 'fallbackReason', type: 'string', optional: true },
|
|
122
123
|
{ path: 'durationMs', type: 'number' },
|
|
123
124
|
{ path: 'timestamp', type: 'number' },
|
|
@@ -141,6 +142,26 @@ const CATALOG = [
|
|
|
141
142
|
description: '会话删除',
|
|
142
143
|
fields: [{ path: 'sessionId', type: 'string' }],
|
|
143
144
|
},
|
|
145
|
+
{
|
|
146
|
+
type: 'session:idle',
|
|
147
|
+
namespace: 'session',
|
|
148
|
+
name: 'idle',
|
|
149
|
+
description: '会话达到闲置阈值',
|
|
150
|
+
fields: [
|
|
151
|
+
{ path: 'sessionId', type: 'string' },
|
|
152
|
+
{ path: 'agentAid', type: 'string' },
|
|
153
|
+
{ path: 'channel', type: 'string' },
|
|
154
|
+
{ path: 'channelName', type: 'string', optional: true },
|
|
155
|
+
{ path: 'channelId', type: 'string' },
|
|
156
|
+
{ path: 'chatType', type: 'string', optional: true },
|
|
157
|
+
{ path: 'threadId', type: 'string', optional: true },
|
|
158
|
+
{ path: 'peerId', type: 'string', optional: true },
|
|
159
|
+
{ path: 'encrypted', type: 'boolean', optional: true },
|
|
160
|
+
{ path: 'idleMs', type: 'number' },
|
|
161
|
+
{ path: 'lastEndedAt', type: 'number' },
|
|
162
|
+
{ path: 'timestamp', type: 'number' },
|
|
163
|
+
],
|
|
164
|
+
},
|
|
144
165
|
{
|
|
145
166
|
type: 'session:renamed',
|
|
146
167
|
namespace: 'session',
|
|
@@ -284,6 +305,7 @@ const CATALOG = [
|
|
|
284
305
|
{ path: 'terminalReason', type: 'string', optional: true },
|
|
285
306
|
{ path: 'agentName', type: 'string', optional: true },
|
|
286
307
|
{ path: 'numTurns', type: 'number', optional: true },
|
|
308
|
+
{ path: 'encrypted', type: 'boolean', optional: true },
|
|
287
309
|
{ path: 'timestamp', type: 'number', optional: true },
|
|
288
310
|
],
|
|
289
311
|
},
|
|
@@ -317,6 +339,7 @@ const CATALOG = [
|
|
|
317
339
|
{ path: 'generation', type: 'number', optional: true },
|
|
318
340
|
{ path: 'reason', type: 'string', optional: true },
|
|
319
341
|
{ path: 'agentName', type: 'string', optional: true },
|
|
342
|
+
{ path: 'encrypted', type: 'boolean', optional: true },
|
|
320
343
|
],
|
|
321
344
|
},
|
|
322
345
|
{
|
|
@@ -354,7 +377,10 @@ const CATALOG = [
|
|
|
354
377
|
{ path: 'eventPhase', type: 'string' },
|
|
355
378
|
{ path: 'isError', type: 'boolean', optional: true },
|
|
356
379
|
{ path: 'errorCode', type: 'string', optional: true },
|
|
380
|
+
{ path: 'errorDetailCode', type: 'string', optional: true },
|
|
357
381
|
{ path: 'classificationMissing', type: 'boolean', optional: true },
|
|
382
|
+
{ path: 'classificationConflict', type: 'boolean', optional: true },
|
|
383
|
+
{ path: 'exitCode', type: 'number', optional: true },
|
|
358
384
|
{ path: 'agentName', type: 'string', optional: true },
|
|
359
385
|
{ path: 'callId', type: 'string', optional: true },
|
|
360
386
|
{ path: 'correlationId', type: 'string', optional: true },
|
|
@@ -516,6 +516,9 @@ export class EvolAgentRegistry {
|
|
|
516
516
|
this.manuallyStopped.add(agent.aid);
|
|
517
517
|
this.channelIndex.clear();
|
|
518
518
|
this.buildChannelIndex();
|
|
519
|
+
// 注销该 Agent 的技能目录监控
|
|
520
|
+
const { globalSkillWatcher } = await import('./skill/global-watcher.js');
|
|
521
|
+
await globalSkillWatcher.unwatchAgent(agent.aid);
|
|
519
522
|
logger.info(`[Registry] Stopped agent ${aidOrName}`);
|
|
520
523
|
}
|
|
521
524
|
async startAgent(aidOrName, hooks) {
|
|
@@ -535,6 +538,9 @@ export class EvolAgentRegistry {
|
|
|
535
538
|
this.manuallyStopped.delete(agent.aid);
|
|
536
539
|
this.channelIndex.clear();
|
|
537
540
|
this.buildChannelIndex();
|
|
541
|
+
// 注册该 Agent 的技能目录监控
|
|
542
|
+
const { watchAgentSkills } = await import('./skill/startup.js');
|
|
543
|
+
watchAgentSkills(agent.aid);
|
|
538
544
|
logger.info(`[Registry] Started agent ${aidOrName}`);
|
|
539
545
|
}
|
|
540
546
|
checkConflictForReload(newRaw, excludeAid) {
|
package/dist/core/evolagent.js
CHANGED
|
@@ -284,16 +284,6 @@ export class EvolAgent {
|
|
|
284
284
|
const raw = fileCache.getText(personaPath, { policy: 'mtime', group: this.agentFilesGroup() });
|
|
285
285
|
return raw === null ? null : (raw.trim() || null);
|
|
286
286
|
}
|
|
287
|
-
/**
|
|
288
|
-
* 读取 personal/memory/working.md 内容。走 fileCache(mtime 门控):
|
|
289
|
-
* agent 在对话中改写 working memory、不触发 reload,故每次读 stat 比对、
|
|
290
|
-
* 变了自动重读,既即时反映又避免无谓重读。
|
|
291
|
-
*/
|
|
292
|
-
getWorkingMemory() {
|
|
293
|
-
const workingPath = path.join(agentPersonalDir(this.aid), 'memory', 'working.md');
|
|
294
|
-
const raw = fileCache.getText(workingPath, { policy: 'mtime', group: this.agentFilesGroup() });
|
|
295
|
-
return raw === null ? null : (raw.trim() || null);
|
|
296
|
-
}
|
|
297
287
|
/** 清除本 agent 身份层缓存(reload 后重新读取)。只失效自己的文件组,不波及他人。 */
|
|
298
288
|
invalidatePersonaCache() {
|
|
299
289
|
fileCache.invalidateGroup(this.agentFilesGroup());
|
|
@@ -64,12 +64,6 @@ export class HandoffStore {
|
|
|
64
64
|
throw new Error('invalid handoff_id');
|
|
65
65
|
return path.join(this.agentDir(selfAid), `${safeSegment(handoffId, 'handoff_id')}.json`);
|
|
66
66
|
}
|
|
67
|
-
/** Read the pre-flat layout during the transition to the flat store. */
|
|
68
|
-
legacyInstancePath(selfAid, handoffId) {
|
|
69
|
-
if (!HANDOFF_ID_RE.test(handoffId))
|
|
70
|
-
throw new Error('invalid handoff_id');
|
|
71
|
-
return path.join(this.agentDir(selfAid), 'handoffs', safeSegment(handoffId, 'handoff_id'), 'handoff.json');
|
|
72
|
-
}
|
|
73
67
|
historyPath(selfAid) {
|
|
74
68
|
return path.join(this.agentDir(selfAid), 'history.jsonl');
|
|
75
69
|
}
|
|
@@ -165,8 +159,7 @@ export class HandoffStore {
|
|
|
165
159
|
get(selfAid, handoffId) {
|
|
166
160
|
if (!HANDOFF_ID_RE.test(handoffId))
|
|
167
161
|
return null;
|
|
168
|
-
const parsed = atomicReadJson(this.instancePath(selfAid, handoffId))
|
|
169
|
-
?? atomicReadJson(this.legacyInstancePath(selfAid, handoffId));
|
|
162
|
+
const parsed = atomicReadJson(this.instancePath(selfAid, handoffId));
|
|
170
163
|
if (!parsed)
|
|
171
164
|
return null;
|
|
172
165
|
if (parsed.schema_version !== HANDOFF_SCHEMA_VERSION || parsed.handoff_id !== handoffId) {
|
|
@@ -186,18 +179,6 @@ export class HandoffStore {
|
|
|
186
179
|
if (match && HANDOFF_ID_RE.test(match[1]))
|
|
187
180
|
handoffIds.add(match[1]);
|
|
188
181
|
}
|
|
189
|
-
// Keep nested snapshots visible; a later flat snapshot takes precedence.
|
|
190
|
-
const legacyDir = path.join(dir, 'handoffs');
|
|
191
|
-
try {
|
|
192
|
-
for (const entry of fs.readdirSync(legacyDir, { withFileTypes: true })) {
|
|
193
|
-
if (entry.isDirectory() && HANDOFF_ID_RE.test(entry.name))
|
|
194
|
-
handoffIds.add(entry.name);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
catch (error) {
|
|
198
|
-
if (error.code !== 'ENOENT')
|
|
199
|
-
throw error;
|
|
200
|
-
}
|
|
201
182
|
const result = [];
|
|
202
183
|
for (const handoffId of handoffIds) {
|
|
203
184
|
const instance = this.get(selfAid, handoffId);
|
|
@@ -12,6 +12,25 @@ function apiEndpoint(baseUrl, resource) {
|
|
|
12
12
|
: `${pathname}/v1/${resource}`;
|
|
13
13
|
return parsed.toString();
|
|
14
14
|
}
|
|
15
|
+
async function completeDecisionRequest(config, request) {
|
|
16
|
+
const response = await fetch(appendRequestQueryParams(config.baseUrl, config.queryParams), {
|
|
17
|
+
method: 'POST',
|
|
18
|
+
signal: request.signal,
|
|
19
|
+
headers: {
|
|
20
|
+
'Content-Type': 'application/json',
|
|
21
|
+
Authorization: `Bearer ${config.apiKey}`,
|
|
22
|
+
...config.headers,
|
|
23
|
+
},
|
|
24
|
+
body: JSON.stringify({
|
|
25
|
+
model: request.model,
|
|
26
|
+
state: request.state,
|
|
27
|
+
questions: request.questions,
|
|
28
|
+
}),
|
|
29
|
+
});
|
|
30
|
+
if (!response.ok)
|
|
31
|
+
throw await parseError(response);
|
|
32
|
+
return JSON.stringify(await response.json());
|
|
33
|
+
}
|
|
15
34
|
async function parseError(response) {
|
|
16
35
|
let raw = '';
|
|
17
36
|
try {
|
|
@@ -27,6 +46,40 @@ async function parseError(response) {
|
|
|
27
46
|
const suffix = detail ? `: ${String(detail).slice(0, 500)}` : '';
|
|
28
47
|
return new Error(`Text inference request failed with HTTP ${response.status}${suffix}`);
|
|
29
48
|
}
|
|
49
|
+
export class AlibabaDecisionInferenceProvider {
|
|
50
|
+
config;
|
|
51
|
+
constructor(config) {
|
|
52
|
+
this.config = config;
|
|
53
|
+
}
|
|
54
|
+
async completeDecision(request) {
|
|
55
|
+
return completeDecisionRequest(this.config, request);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export function createAlibabaDecisionInferenceProvider(baseUrl) {
|
|
59
|
+
const apiKey = process.env.DASHSCOPE_API_KEY?.trim();
|
|
60
|
+
const configuredBaseUrl = baseUrl?.trim();
|
|
61
|
+
if (!apiKey || !configuredBaseUrl)
|
|
62
|
+
return undefined;
|
|
63
|
+
return new AlibabaDecisionInferenceProvider({ apiKey, baseUrl: apiEndpoint(configuredBaseUrl, 'systemone') });
|
|
64
|
+
}
|
|
65
|
+
export function createDecisionInferenceProvider(config) {
|
|
66
|
+
const apiKey = config?.apikey?.trim();
|
|
67
|
+
const baseUrl = config?.base_url?.trim();
|
|
68
|
+
if (!apiKey || !baseUrl)
|
|
69
|
+
return undefined;
|
|
70
|
+
try {
|
|
71
|
+
new URL(baseUrl);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
return new AlibabaDecisionInferenceProvider({
|
|
77
|
+
apiKey,
|
|
78
|
+
baseUrl,
|
|
79
|
+
headers: config?.headers,
|
|
80
|
+
queryParams: config?.queryParams,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
30
83
|
export class AnthropicTextInferenceProvider {
|
|
31
84
|
config;
|
|
32
85
|
baseagent = 'claude';
|
|
@@ -156,7 +209,10 @@ export class EcagentTextInferenceProvider {
|
|
|
156
209
|
export function createTextInferenceProvider(baseagent, config) {
|
|
157
210
|
const canonical = normalizeBaseagent(baseagent).canonical;
|
|
158
211
|
if (canonical === 'claude') {
|
|
159
|
-
const resolved = resolveAnthropicDirectConfig(config.baseagents?.claude
|
|
212
|
+
const resolved = resolveAnthropicDirectConfig(config.baseagents?.claude, {
|
|
213
|
+
agentAid: config.aid,
|
|
214
|
+
projectPath: config.projects?.defaultPath,
|
|
215
|
+
});
|
|
160
216
|
return resolved ? new AnthropicTextInferenceProvider({
|
|
161
217
|
...resolved,
|
|
162
218
|
headers: buildModelRequestHeaders({
|