@agentrq/codex-gateway 0.1.2 → 0.2.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/README.md +45 -0
- package/dist/__tests__/approvals.test.js +152 -0
- package/dist/__tests__/approvals.test.js.map +1 -0
- package/dist/__tests__/elicitation.test.js +136 -0
- package/dist/__tests__/elicitation.test.js.map +1 -0
- package/dist/__tests__/index.test.js +277 -14
- package/dist/__tests__/index.test.js.map +1 -1
- package/dist/__tests__/taskIdentity.test.js +1 -1
- package/dist/__tests__/taskIdentity.test.js.map +1 -1
- package/dist/approvals.js +168 -0
- package/dist/approvals.js.map +1 -0
- package/dist/codexClient.js.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/elicitation.js +108 -0
- package/dist/elicitation.js.map +1 -0
- package/dist/index.js +161 -35
- package/dist/index.js.map +1 -1
- package/dist/mcpClient.js.map +1 -1
- package/dist/taskIdentity.js +1 -1
- package/dist/taskIdentity.js.map +1 -1
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -79,6 +79,51 @@ codex-gateway -- codex app-server
|
|
|
79
79
|
| Variable | Description | Default |
|
|
80
80
|
|---|---|---|
|
|
81
81
|
| `CODEX_MODEL` | Override the model used for all threads/turns | _(codex default)_ |
|
|
82
|
+
| `CODEX_APPROVAL_POLICY` | When Codex asks before acting: `untrusted`, `on-failure`, `on-request`, `never` | `on-request` |
|
|
83
|
+
| `CODEX_SANDBOX` | Sandbox for command execution: `read-only`, `workspace-write`, `danger-full-access` | `read-only` |
|
|
84
|
+
|
|
85
|
+
Unrecognized values fall back to the default and log a warning rather than
|
|
86
|
+
being passed through to Codex.
|
|
87
|
+
|
|
88
|
+
> [!WARNING]
|
|
89
|
+
> `CODEX_APPROVAL_POLICY=never` means Codex never sends an approval request, so
|
|
90
|
+
> tool calls run without reaching agentrq for human review.
|
|
91
|
+
> `CODEX_SANDBOX=danger-full-access` removes the sandbox boundary entirely.
|
|
92
|
+
> The gateway logs a prominent warning when either is set.
|
|
93
|
+
|
|
94
|
+
### Approvals
|
|
95
|
+
|
|
96
|
+
Codex sends approval requests to the gateway as JSON-RPC requests. The gateway
|
|
97
|
+
forwards each one to agentrq as a `permission_request` and blocks the turn until
|
|
98
|
+
the human answers in the dashboard:
|
|
99
|
+
|
|
100
|
+
| Codex request | Approved | Denied |
|
|
101
|
+
|---|---|---|
|
|
102
|
+
| `item/commandExecution/requestApproval` | `accept` | `decline` |
|
|
103
|
+
| `item/fileChange/requestApproval` | `accept` | `decline` |
|
|
104
|
+
| `item/permissions/requestApproval` | grants the requested profile for the turn | grants nothing |
|
|
105
|
+
|
|
106
|
+
Approval requests identify their subject only by `itemId`, so the gateway
|
|
107
|
+
remembers each item announced via `item/started` and uses it to show the human
|
|
108
|
+
the real command, tool, or file list. Entries are dropped as items complete.
|
|
109
|
+
|
|
110
|
+
agentrq's own MCP tool calls are auto-allowed, matched on the MCP server name
|
|
111
|
+
(`agentrq-<workspaceId>`) rather than on free text, so a shell command that
|
|
112
|
+
merely mentions a workspace id cannot approve itself.
|
|
113
|
+
|
|
114
|
+
### Elicitations
|
|
115
|
+
|
|
116
|
+
When an MCP server configured in `.codex/config.toml` asks a question
|
|
117
|
+
(`mcpServer/elicitation/request`), the gateway forwards it to agentrq's `elicit`
|
|
118
|
+
tool and returns the human's answer to Codex. Both `form` and `url` modes are
|
|
119
|
+
supported, and the three-action result (`accept` / `decline` / `cancel`) maps
|
|
120
|
+
one-to-one.
|
|
121
|
+
|
|
122
|
+
If the elicitation belongs to a thread with no associated task — it arrived
|
|
123
|
+
outside any task the gateway is running — a task is created and marked ongoing
|
|
124
|
+
so the question still reaches the human. Anything that goes wrong (unsupported
|
|
125
|
+
mode, tool error, unreachable human) resolves to `cancel`, since Codex is
|
|
126
|
+
blocked on a response either way.
|
|
82
127
|
|
|
83
128
|
### Configuration
|
|
84
129
|
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { resolveThreadPolicy, describeItem, ThreadItemRegistry, DEFAULT_APPROVAL_POLICY, DEFAULT_SANDBOX, } from "../approvals.js";
|
|
3
|
+
describe("resolveThreadPolicy", () => {
|
|
4
|
+
it("should default to the conservative policy/sandbox pair", () => {
|
|
5
|
+
const policy = resolveThreadPolicy({});
|
|
6
|
+
expect(policy.approvalPolicy).toBe(DEFAULT_APPROVAL_POLICY);
|
|
7
|
+
expect(policy.sandbox).toBe(DEFAULT_SANDBOX);
|
|
8
|
+
expect(policy.warnings).toEqual([]);
|
|
9
|
+
});
|
|
10
|
+
it("should honor CODEX_APPROVAL_POLICY", () => {
|
|
11
|
+
const policy = resolveThreadPolicy({ CODEX_APPROVAL_POLICY: "untrusted" });
|
|
12
|
+
expect(policy.approvalPolicy).toBe("untrusted");
|
|
13
|
+
expect(policy.warnings).toEqual([]);
|
|
14
|
+
});
|
|
15
|
+
it("should honor CODEX_SANDBOX", () => {
|
|
16
|
+
const policy = resolveThreadPolicy({ CODEX_SANDBOX: "workspace-write" });
|
|
17
|
+
expect(policy.sandbox).toBe("workspace-write");
|
|
18
|
+
expect(policy.warnings).toEqual([]);
|
|
19
|
+
});
|
|
20
|
+
it("should treat an empty value as unset", () => {
|
|
21
|
+
const policy = resolveThreadPolicy({ CODEX_APPROVAL_POLICY: "", CODEX_SANDBOX: "" });
|
|
22
|
+
expect(policy.approvalPolicy).toBe(DEFAULT_APPROVAL_POLICY);
|
|
23
|
+
expect(policy.sandbox).toBe(DEFAULT_SANDBOX);
|
|
24
|
+
expect(policy.warnings).toEqual([]);
|
|
25
|
+
});
|
|
26
|
+
it("should fall back to the default and warn on an unrecognized policy", () => {
|
|
27
|
+
const policy = resolveThreadPolicy({ CODEX_APPROVAL_POLICY: "yolo" });
|
|
28
|
+
expect(policy.approvalPolicy).toBe(DEFAULT_APPROVAL_POLICY);
|
|
29
|
+
expect(policy.warnings.join(" ")).toContain("CODEX_APPROVAL_POLICY");
|
|
30
|
+
});
|
|
31
|
+
it("should fall back to the default and warn on an unrecognized sandbox", () => {
|
|
32
|
+
const policy = resolveThreadPolicy({ CODEX_SANDBOX: "wide-open" });
|
|
33
|
+
expect(policy.sandbox).toBe(DEFAULT_SANDBOX);
|
|
34
|
+
expect(policy.warnings.join(" ")).toContain("CODEX_SANDBOX");
|
|
35
|
+
});
|
|
36
|
+
it("should warn that a 'never' policy keeps approvals away from the human", () => {
|
|
37
|
+
const policy = resolveThreadPolicy({ CODEX_APPROVAL_POLICY: "never" });
|
|
38
|
+
expect(policy.approvalPolicy).toBe("never");
|
|
39
|
+
expect(policy.warnings.join(" ")).toContain("never request approval");
|
|
40
|
+
});
|
|
41
|
+
it("should warn about a full-access sandbox", () => {
|
|
42
|
+
const policy = resolveThreadPolicy({ CODEX_SANDBOX: "danger-full-access" });
|
|
43
|
+
expect(policy.sandbox).toBe("danger-full-access");
|
|
44
|
+
expect(policy.warnings.join(" ")).toContain("removes the sandbox boundary");
|
|
45
|
+
});
|
|
46
|
+
it("should report both warnings when the pair fully bypasses review", () => {
|
|
47
|
+
const policy = resolveThreadPolicy({
|
|
48
|
+
CODEX_APPROVAL_POLICY: "never",
|
|
49
|
+
CODEX_SANDBOX: "danger-full-access",
|
|
50
|
+
});
|
|
51
|
+
expect(policy.warnings).toHaveLength(2);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
describe("describeItem", () => {
|
|
55
|
+
it("should describe a command execution with its cwd", () => {
|
|
56
|
+
const d = describeItem({
|
|
57
|
+
id: "i1",
|
|
58
|
+
type: "commandExecution",
|
|
59
|
+
command: "npm test",
|
|
60
|
+
cwd: "/repo",
|
|
61
|
+
});
|
|
62
|
+
expect(d).toEqual({
|
|
63
|
+
title: "npm test",
|
|
64
|
+
inputPreview: "npm test\n(cwd: /repo)",
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
it("should describe a command execution without a cwd", () => {
|
|
68
|
+
const d = describeItem({ id: "i1", type: "commandExecution", command: "ls" });
|
|
69
|
+
expect(d?.inputPreview).toBe("ls");
|
|
70
|
+
});
|
|
71
|
+
it("should describe an MCP tool call as server.tool and expose the server", () => {
|
|
72
|
+
const d = describeItem({
|
|
73
|
+
id: "i2",
|
|
74
|
+
type: "mcpToolCall",
|
|
75
|
+
server: "agentrq-0cHdAEOUJvN",
|
|
76
|
+
tool: "reply",
|
|
77
|
+
arguments: { chatId: "c1" },
|
|
78
|
+
});
|
|
79
|
+
expect(d?.title).toBe("agentrq-0cHdAEOUJvN.reply");
|
|
80
|
+
expect(d?.server).toBe("agentrq-0cHdAEOUJvN");
|
|
81
|
+
expect(d?.inputPreview).toBe('{"chatId":"c1"}');
|
|
82
|
+
});
|
|
83
|
+
it("should describe a file change by path count and list the paths", () => {
|
|
84
|
+
const d = describeItem({
|
|
85
|
+
id: "i3",
|
|
86
|
+
type: "fileChange",
|
|
87
|
+
changes: [{ path: "/a.ts" }, { path: "/b.ts" }],
|
|
88
|
+
});
|
|
89
|
+
expect(d?.title).toBe("Edit 2 files");
|
|
90
|
+
expect(d?.inputPreview).toBe("/a.ts\n/b.ts");
|
|
91
|
+
});
|
|
92
|
+
it("should singularize a one-file change", () => {
|
|
93
|
+
const d = describeItem({ id: "i4", type: "fileChange", changes: [{ path: "/a.ts" }] });
|
|
94
|
+
expect(d?.title).toBe("Edit 1 file");
|
|
95
|
+
});
|
|
96
|
+
it("should still describe a file change with no readable paths", () => {
|
|
97
|
+
const d = describeItem({ id: "i5", type: "fileChange", changes: [] });
|
|
98
|
+
expect(d?.title).toBe("File change");
|
|
99
|
+
});
|
|
100
|
+
it("should ignore item types that are never approved", () => {
|
|
101
|
+
expect(describeItem({ id: "i6", type: "agentMessage", text: "hi" })).toBeUndefined();
|
|
102
|
+
expect(describeItem({ id: "i7", type: "reasoning" })).toBeUndefined();
|
|
103
|
+
});
|
|
104
|
+
it("should ignore a command execution with no command", () => {
|
|
105
|
+
expect(describeItem({ id: "i8", type: "commandExecution" })).toBeUndefined();
|
|
106
|
+
});
|
|
107
|
+
it("should handle malformed input", () => {
|
|
108
|
+
expect(describeItem(undefined)).toBeUndefined();
|
|
109
|
+
expect(describeItem(null)).toBeUndefined();
|
|
110
|
+
expect(describeItem("nope")).toBeUndefined();
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
describe("ThreadItemRegistry", () => {
|
|
114
|
+
it("should record and return a describable item", () => {
|
|
115
|
+
const r = new ThreadItemRegistry();
|
|
116
|
+
r.record({ id: "a", type: "commandExecution", command: "ls" });
|
|
117
|
+
expect(r.get("a")?.title).toBe("ls");
|
|
118
|
+
expect(r.size).toBe(1);
|
|
119
|
+
});
|
|
120
|
+
it("should not record items that cannot be described", () => {
|
|
121
|
+
const r = new ThreadItemRegistry();
|
|
122
|
+
r.record({ id: "a", type: "agentMessage", text: "hi" });
|
|
123
|
+
expect(r.size).toBe(0);
|
|
124
|
+
});
|
|
125
|
+
it("should ignore items without a usable id", () => {
|
|
126
|
+
const r = new ThreadItemRegistry();
|
|
127
|
+
r.record({ type: "commandExecution", command: "ls" });
|
|
128
|
+
r.record({ id: 42, type: "commandExecution", command: "ls" });
|
|
129
|
+
expect(r.size).toBe(0);
|
|
130
|
+
});
|
|
131
|
+
it("should return undefined for an unknown or non-string id", () => {
|
|
132
|
+
const r = new ThreadItemRegistry();
|
|
133
|
+
expect(r.get("missing")).toBeUndefined();
|
|
134
|
+
expect(r.get(undefined)).toBeUndefined();
|
|
135
|
+
expect(r.get(7)).toBeUndefined();
|
|
136
|
+
});
|
|
137
|
+
it("should forget an item so the map stays bounded", () => {
|
|
138
|
+
const r = new ThreadItemRegistry();
|
|
139
|
+
r.record({ id: "a", type: "commandExecution", command: "ls" });
|
|
140
|
+
r.forget("a");
|
|
141
|
+
expect(r.get("a")).toBeUndefined();
|
|
142
|
+
expect(r.size).toBe(0);
|
|
143
|
+
});
|
|
144
|
+
it("should clear every entry", () => {
|
|
145
|
+
const r = new ThreadItemRegistry();
|
|
146
|
+
r.record({ id: "a", type: "commandExecution", command: "ls" });
|
|
147
|
+
r.record({ id: "b", type: "commandExecution", command: "pwd" });
|
|
148
|
+
r.clear();
|
|
149
|
+
expect(r.size).toBe(0);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
//# sourceMappingURL=approvals.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approvals.test.js","sourceRoot":"","sources":["../../src/__tests__/approvals.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { resolveElicitation } from "../elicitation.js";
|
|
3
|
+
function textResult(text, isError = false) {
|
|
4
|
+
return { isError, content: [{ type: "text", text }] };
|
|
5
|
+
}
|
|
6
|
+
describe("resolveElicitation", () => {
|
|
7
|
+
let callTool;
|
|
8
|
+
let deps;
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
vi.spyOn(console, "error").mockImplementation(() => { });
|
|
11
|
+
callTool = vi.fn();
|
|
12
|
+
deps = { mcpBridge: { callTool }, resolveTaskId: () => "task-1" };
|
|
13
|
+
});
|
|
14
|
+
it("should delegate a form elicitation to the elicit tool with the thread's task", async () => {
|
|
15
|
+
callTool.mockResolvedValue(textResult(JSON.stringify({ action: "accept", content: { name: "mt" } })));
|
|
16
|
+
const result = await resolveElicitation({
|
|
17
|
+
serverName: "some-server",
|
|
18
|
+
threadId: "thr_1",
|
|
19
|
+
mode: "form",
|
|
20
|
+
message: "What is your name?",
|
|
21
|
+
requestedSchema: { type: "object", properties: {} },
|
|
22
|
+
}, deps);
|
|
23
|
+
expect(callTool).toHaveBeenCalledWith("elicit", {
|
|
24
|
+
taskId: "task-1",
|
|
25
|
+
message: "What is your name?",
|
|
26
|
+
mode: "form",
|
|
27
|
+
requestedSchema: { type: "object", properties: {} },
|
|
28
|
+
});
|
|
29
|
+
expect(result).toEqual({ action: "accept", content: { name: "mt" } });
|
|
30
|
+
});
|
|
31
|
+
it("should pass the url through for url-mode elicitations", async () => {
|
|
32
|
+
callTool.mockResolvedValue(textResult(JSON.stringify({ action: "accept" })));
|
|
33
|
+
await resolveElicitation({
|
|
34
|
+
serverName: "s",
|
|
35
|
+
threadId: "thr_1",
|
|
36
|
+
mode: "url",
|
|
37
|
+
message: "Authorize access",
|
|
38
|
+
url: "https://example.test/auth",
|
|
39
|
+
elicitationId: "e1",
|
|
40
|
+
}, deps);
|
|
41
|
+
expect(callTool).toHaveBeenCalledWith("elicit", {
|
|
42
|
+
taskId: "task-1",
|
|
43
|
+
message: "Authorize access",
|
|
44
|
+
mode: "url",
|
|
45
|
+
url: "https://example.test/auth",
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
it("should map a declined answer", async () => {
|
|
49
|
+
callTool.mockResolvedValue(textResult(JSON.stringify({ action: "decline" })));
|
|
50
|
+
const r = await resolveElicitation({ threadId: "t", mode: "form", message: "m" }, deps);
|
|
51
|
+
expect(r).toEqual({ action: "decline" });
|
|
52
|
+
});
|
|
53
|
+
it("should map an unrecognized action to cancel", async () => {
|
|
54
|
+
callTool.mockResolvedValue(textResult(JSON.stringify({ action: "whatever" })));
|
|
55
|
+
const r = await resolveElicitation({ threadId: "t", mode: "form", message: "m" }, deps);
|
|
56
|
+
expect(r).toEqual({ action: "cancel" });
|
|
57
|
+
});
|
|
58
|
+
it("should cancel an unsupported mode without calling the tool", async () => {
|
|
59
|
+
const r = await resolveElicitation({ threadId: "t", mode: "telepathy", message: "m" }, deps);
|
|
60
|
+
expect(r).toEqual({ action: "cancel" });
|
|
61
|
+
expect(callTool).not.toHaveBeenCalled();
|
|
62
|
+
});
|
|
63
|
+
it("should cancel when the elicit tool reports an error", async () => {
|
|
64
|
+
callTool.mockResolvedValue(textResult("boom", true));
|
|
65
|
+
const r = await resolveElicitation({ threadId: "t", mode: "form", message: "m" }, deps);
|
|
66
|
+
expect(r).toEqual({ action: "cancel" });
|
|
67
|
+
});
|
|
68
|
+
it("should cancel when the elicit tool returns no content", async () => {
|
|
69
|
+
callTool.mockResolvedValue({ isError: false, content: [] });
|
|
70
|
+
const r = await resolveElicitation({ threadId: "t", mode: "form", message: "m" }, deps);
|
|
71
|
+
expect(r).toEqual({ action: "cancel" });
|
|
72
|
+
});
|
|
73
|
+
it("should cancel when the elicit tool returns unparseable content", async () => {
|
|
74
|
+
callTool.mockResolvedValue(textResult("not json"));
|
|
75
|
+
const r = await resolveElicitation({ threadId: "t", mode: "form", message: "m" }, deps);
|
|
76
|
+
expect(r).toEqual({ action: "cancel" });
|
|
77
|
+
});
|
|
78
|
+
it("should cancel when the tool call throws", async () => {
|
|
79
|
+
callTool.mockRejectedValue(new Error("offline"));
|
|
80
|
+
const r = await resolveElicitation({ threadId: "t", mode: "form", message: "m" }, deps);
|
|
81
|
+
expect(r).toEqual({ action: "cancel" });
|
|
82
|
+
});
|
|
83
|
+
describe("when the thread has no task", () => {
|
|
84
|
+
beforeEach(() => {
|
|
85
|
+
deps.resolveTaskId = () => undefined;
|
|
86
|
+
});
|
|
87
|
+
it("should create an ongoing task and use it", async () => {
|
|
88
|
+
callTool.mockImplementation(async (name) => {
|
|
89
|
+
if (name === "createTask")
|
|
90
|
+
return textResult("Created task id=task-new");
|
|
91
|
+
if (name === "updateTaskStatus")
|
|
92
|
+
return textResult("ok");
|
|
93
|
+
return textResult(JSON.stringify({ action: "accept", content: { a: 1 } }));
|
|
94
|
+
});
|
|
95
|
+
const r = await resolveElicitation({ threadId: "unknown", mode: "form", message: "Pick one", requestedSchema: {} }, deps);
|
|
96
|
+
expect(callTool).toHaveBeenCalledWith("createTask", {
|
|
97
|
+
title: "Pick one",
|
|
98
|
+
body: "Pick one",
|
|
99
|
+
assignee: "human",
|
|
100
|
+
});
|
|
101
|
+
expect(callTool).toHaveBeenCalledWith("updateTaskStatus", {
|
|
102
|
+
taskId: "task-new",
|
|
103
|
+
status: "ongoing",
|
|
104
|
+
});
|
|
105
|
+
expect(callTool).toHaveBeenCalledWith("elicit", expect.objectContaining({ taskId: "task-new" }));
|
|
106
|
+
expect(r).toEqual({ action: "accept", content: { a: 1 } });
|
|
107
|
+
});
|
|
108
|
+
it("should truncate a long message into the task title", async () => {
|
|
109
|
+
const long = "x".repeat(200);
|
|
110
|
+
callTool.mockImplementation(async (name) => {
|
|
111
|
+
if (name === "createTask")
|
|
112
|
+
return textResult("id=t2");
|
|
113
|
+
if (name === "updateTaskStatus")
|
|
114
|
+
return textResult("ok");
|
|
115
|
+
return textResult(JSON.stringify({ action: "decline" }));
|
|
116
|
+
});
|
|
117
|
+
await resolveElicitation({ threadId: "u", mode: "form", message: long }, deps);
|
|
118
|
+
const call = callTool.mock.calls.find((c) => c[0] === "createTask");
|
|
119
|
+
expect(call?.[1].title).toHaveLength(80);
|
|
120
|
+
expect(call?.[1].title.endsWith("...")).toBe(true);
|
|
121
|
+
expect(call?.[1].body).toBe(long);
|
|
122
|
+
});
|
|
123
|
+
it("should cancel when the created task id cannot be parsed", async () => {
|
|
124
|
+
callTool.mockResolvedValue(textResult("something unexpected"));
|
|
125
|
+
const r = await resolveElicitation({ threadId: "u", mode: "form", message: "m" }, deps);
|
|
126
|
+
expect(r).toEqual({ action: "cancel" });
|
|
127
|
+
expect(callTool).not.toHaveBeenCalledWith("elicit", expect.anything());
|
|
128
|
+
});
|
|
129
|
+
it("should cancel when task creation throws", async () => {
|
|
130
|
+
callTool.mockRejectedValue(new Error("nope"));
|
|
131
|
+
const r = await resolveElicitation({ threadId: "u", mode: "form", message: "m" }, deps);
|
|
132
|
+
expect(r).toEqual({ action: "cancel" });
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
//# sourceMappingURL=elicitation.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elicitation.test.js","sourceRoot":"","sources":["../../src/__tests__/elicitation.test.ts"],"names":[],"mappings":"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"}
|