@ruvector/ruqu 0.1.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/.claude/commands/doctor.md +12 -0
- package/.claude/settings.json +44 -0
- package/.claude/skills/evolve/SKILL.md +14 -0
- package/.claude/skills/memory-inspect/SKILL.md +14 -0
- package/CLAUDE.md +31 -0
- package/LICENSE +21 -0
- package/README.md +40 -0
- package/bin/cli.js +100 -0
- package/package.json +62 -0
- package/src/agents/experimenter.ts +7 -0
- package/src/agents/federator.ts +7 -0
- package/src/agents/hypothesizer.ts +7 -0
- package/src/init.ts +21 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Health-check the harness: kernel load, MCP wiring, memory backend, host adapter."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Run a full health check and print a PASS/FAIL table.
|
|
6
|
+
|
|
7
|
+
1. Kernel loads and `kernelInfo().version` matches package.json.
|
|
8
|
+
2. The MCP server starts and lists its tools.
|
|
9
|
+
3. The memory backend is reachable.
|
|
10
|
+
4. The configured host adapter is present.
|
|
11
|
+
|
|
12
|
+
Exit non-zero if any check fails.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(npx ruqu*)",
|
|
5
|
+
"mcp__ruqu__*",
|
|
6
|
+
"mcp__evolution_log__*",
|
|
7
|
+
"mcp__federation__*"
|
|
8
|
+
],
|
|
9
|
+
"deny": [
|
|
10
|
+
"Read(./.env)",
|
|
11
|
+
"Read(./.env.*)",
|
|
12
|
+
"Bash(rm -rf*)"
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
"mcpServers": {
|
|
16
|
+
"ruqu": {
|
|
17
|
+
"command": "npx",
|
|
18
|
+
"args": [
|
|
19
|
+
"-y",
|
|
20
|
+
"ruqu@latest",
|
|
21
|
+
"mcp",
|
|
22
|
+
"start"
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
"evolution_log": {
|
|
26
|
+
"command": "npx",
|
|
27
|
+
"args": [
|
|
28
|
+
"-y",
|
|
29
|
+
"ruqu@latest",
|
|
30
|
+
"mcp",
|
|
31
|
+
"evolution"
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
"federation": {
|
|
35
|
+
"command": "npx",
|
|
36
|
+
"args": [
|
|
37
|
+
"-y",
|
|
38
|
+
"ruqu@latest",
|
|
39
|
+
"mcp",
|
|
40
|
+
"federate"
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: evolve
|
|
3
|
+
description: "Run one safe self-improvement cycle: hypothesize → experiment → record → (maybe) federate."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# evolve
|
|
7
|
+
|
|
8
|
+
Run one evolution cycle.
|
|
9
|
+
|
|
10
|
+
1. Hypothesizer reads the evolution log and proposes a falsifiable change with a metric.
|
|
11
|
+
2. Experimenter tests it in a sandbox and records a signed kept/killed result.
|
|
12
|
+
3. Federator shares it to peers only if witness-signed and reproduced.
|
|
13
|
+
|
|
14
|
+
Guard against Goodharting the metric. See ADR-014 (self-evolution + federation).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: memory-inspect
|
|
3
|
+
description: Search and inspect the harness memory namespace (HNSW + emergent-time decay).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# memory-inspect
|
|
7
|
+
|
|
8
|
+
Inspect what the harness has learned.
|
|
9
|
+
|
|
10
|
+
- `search <query>` — semantic nearest-neighbour over the namespace
|
|
11
|
+
- `list` — recent patterns with decay weight
|
|
12
|
+
- `forget <id>` — evict a pattern
|
|
13
|
+
|
|
14
|
+
Use this before planning so the harness reuses prior trajectories instead of starting cold.
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# ruqu
|
|
2
|
+
|
|
3
|
+
ruqu quantum CLI — agent harness over the quantum-sim + coherence crates
|
|
4
|
+
|
|
5
|
+
> Exotic / Self-Evolving harness · domain: `exotic/self-evolution`. Generated with [create-agent-harness](https://github.com/ruvnet/agent-harness-generator).
|
|
6
|
+
|
|
7
|
+
## Behavioral rules
|
|
8
|
+
|
|
9
|
+
- Use the harness's MCP tools (`mcp__ruqu__*`) for orchestration
|
|
10
|
+
- Memory and routing are handled by the kernel — you don't need to learn them
|
|
11
|
+
- Defer destructive operations to the user
|
|
12
|
+
|
|
13
|
+
## Agents
|
|
14
|
+
|
|
15
|
+
| Agent | Tier | Role |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| `hypothesizer` | opus | Proposes a falsifiable self-improvement. |
|
|
18
|
+
| `experimenter` | opus | Tests the hypothesis safely and records it. |
|
|
19
|
+
| `federator` | sonnet | Shares vetted improvements across instances. |
|
|
20
|
+
## Skills
|
|
21
|
+
|
|
22
|
+
- `/memory-inspect` — Search and inspect the harness memory namespace (HNSW + emergent-time decay).
|
|
23
|
+
- `/evolve` — Run one safe self-improvement cycle: hypothesize → experiment → record → (maybe) federate.
|
|
24
|
+
|
|
25
|
+
## Commands
|
|
26
|
+
|
|
27
|
+
- `doctor` — Health-check the harness: kernel load, MCP wiring, memory backend, host adapter.
|
|
28
|
+
|
|
29
|
+
## Architecture
|
|
30
|
+
|
|
31
|
+
This harness uses [@metaharness/kernel](https://www.npmjs.com/package/@metaharness/kernel) — a Rust-compiled WASM module with a NAPI-RS native fallback — so the same code runs identically on every platform.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ruvector Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# ruqu
|
|
2
|
+
|
|
3
|
+
**Agent-harness CLI for the [ruqu](https://github.com/ruvnet/ruqu) quantum project.** Boots the
|
|
4
|
+
[metaharness](https://github.com/ruvnet/agent-harness-generator) kernel + a Claude Code host
|
|
5
|
+
adapter, with a self-evolving agent loop (hypothesizer → experimenter → federator) over a
|
|
6
|
+
witness-signed evolution log.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npx @ruvector/ruqu init # boot the kernel + host adapter
|
|
10
|
+
npx @ruvector/ruqu doctor # verify the install end-to-end
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or install globally:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g @ruvector/ruqu
|
|
17
|
+
ruqu doctor
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Agents
|
|
21
|
+
|
|
22
|
+
| Agent | Role |
|
|
23
|
+
|---|---|
|
|
24
|
+
| `hypothesizer` | Proposes a falsifiable self-improvement. |
|
|
25
|
+
| `experimenter` | Tests the hypothesis safely and records it. |
|
|
26
|
+
| `federator` | Shares vetted improvements across instances. |
|
|
27
|
+
|
|
28
|
+
Ships with the **claude-code** host adapter.
|
|
29
|
+
|
|
30
|
+
## Kernel backend
|
|
31
|
+
|
|
32
|
+
The harness loads `@metaharness/kernel`, which resolves a backend in order **native → wasm → js**.
|
|
33
|
+
The published `@metaharness/kernel@0.1.0` beta ships only the **pure-JS** floor backend; the native
|
|
34
|
+
(NAPI) and WASM artifacts are produced by separate upstream build jobs and are not in the npm
|
|
35
|
+
package yet, so `ruqu doctor` currently reports the **`js`** backend. It will pick up native/WASM
|
|
36
|
+
automatically once those kernel artifacts are published — no change needed here.
|
|
37
|
+
|
|
38
|
+
## License
|
|
39
|
+
|
|
40
|
+
MIT © Ruvector Team
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Generated by metaharness — the `ruqu` CLI entry point.
|
|
4
|
+
//
|
|
5
|
+
// This is plain ESM JavaScript on purpose: it runs as-is via `npx ruqu`
|
|
6
|
+
// with NO build step. `npm run build` (tsc) is only needed if you extend the
|
|
7
|
+
// TypeScript in src/. The published package ships this file directly (see the
|
|
8
|
+
// "bin" + "files" fields in package.json), so `npx ruqu` works the moment
|
|
9
|
+
// `npm install` has resolved @metaharness/kernel + @metaharness/host-claude-code.
|
|
10
|
+
|
|
11
|
+
import { loadKernel } from '@metaharness/kernel';
|
|
12
|
+
import adapter from '@metaharness/host-claude-code';
|
|
13
|
+
|
|
14
|
+
const HARNESS_NAME = 'ruqu';
|
|
15
|
+
|
|
16
|
+
/** `ruqu init` — boot the kernel + host adapter and report status. */
|
|
17
|
+
async function init() {
|
|
18
|
+
const kernel = await loadKernel();
|
|
19
|
+
const info = kernel.kernelInfo();
|
|
20
|
+
console.log(`${HARNESS_NAME} — kernel ${info.version} (${kernel.backend})`);
|
|
21
|
+
console.log(`Host adapter: ${adapter.name}`);
|
|
22
|
+
console.log(`Run \`${HARNESS_NAME} doctor\` to verify the install.`);
|
|
23
|
+
return 0;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** `ruqu doctor` — verify the install end-to-end (kernel + host resolve). */
|
|
27
|
+
async function doctor() {
|
|
28
|
+
const kernel = await loadKernel();
|
|
29
|
+
const info = kernel.kernelInfo();
|
|
30
|
+
const checks = [
|
|
31
|
+
['kernel loads', !!kernel],
|
|
32
|
+
['kernel reports a version', typeof info.version === 'string' && info.version.length > 0],
|
|
33
|
+
['kernel backend is native|wasm|js', ['native', 'wasm', 'js'].includes(kernel.backend)],
|
|
34
|
+
['host adapter has a name', typeof adapter?.name === 'string' && adapter.name.length > 0],
|
|
35
|
+
];
|
|
36
|
+
let ok = true;
|
|
37
|
+
for (const [label, pass] of checks) {
|
|
38
|
+
console.log(`${pass ? 'PASS' : 'FAIL'} ${label}`);
|
|
39
|
+
if (!pass) ok = false;
|
|
40
|
+
}
|
|
41
|
+
console.log(
|
|
42
|
+
ok
|
|
43
|
+
? `\n${HARNESS_NAME}: all checks passed (kernel ${info.version}, ${kernel.backend} backend, host ${adapter.name})`
|
|
44
|
+
: `\n${HARNESS_NAME}: doctor found problems`,
|
|
45
|
+
);
|
|
46
|
+
return ok ? 0 : 1;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Dispatch one CLI invocation. Exported (not just run on import) so a test can
|
|
51
|
+
* drive it without spawning a subprocess. Returns the intended exit code.
|
|
52
|
+
*/
|
|
53
|
+
export async function run(argv) {
|
|
54
|
+
const cmd = argv[0] ?? 'init';
|
|
55
|
+
switch (cmd) {
|
|
56
|
+
case 'init':
|
|
57
|
+
return init();
|
|
58
|
+
case 'doctor':
|
|
59
|
+
return doctor();
|
|
60
|
+
case '--version':
|
|
61
|
+
case '-v': {
|
|
62
|
+
const kernel = await loadKernel();
|
|
63
|
+
console.log(kernel.version());
|
|
64
|
+
return 0;
|
|
65
|
+
}
|
|
66
|
+
case '--help':
|
|
67
|
+
case '-h':
|
|
68
|
+
console.log(`Usage: ${HARNESS_NAME} <command>\n\n init boot the kernel + host adapter (default)\n doctor verify the install end-to-end\n --version print the kernel version`);
|
|
69
|
+
return 0;
|
|
70
|
+
default:
|
|
71
|
+
console.error(`Unknown command: ${cmd}. Try \`${HARNESS_NAME} --help\`.`);
|
|
72
|
+
return 2;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// CLI guard: execute only when invoked directly (not when imported by a test).
|
|
77
|
+
// npm's bin shims pass a NON-normalized argv[1] (e.g. ".../.bin/../<pkg>/bin/cli.js"
|
|
78
|
+
// on Windows) and may differ in case, so realpath BOTH sides before comparing —
|
|
79
|
+
// a naive string === misses the npx/shim path and the CLI silently no-ops.
|
|
80
|
+
import { fileURLToPath } from 'node:url';
|
|
81
|
+
import { realpathSync } from 'node:fs';
|
|
82
|
+
import { argv } from 'node:process';
|
|
83
|
+
const invokedDirectly = (() => {
|
|
84
|
+
if (!argv[1]) return false;
|
|
85
|
+
try {
|
|
86
|
+
const a = realpathSync(argv[1]);
|
|
87
|
+
const b = realpathSync(fileURLToPath(import.meta.url));
|
|
88
|
+
return process.platform === 'win32' ? a.toLowerCase() === b.toLowerCase() : a === b;
|
|
89
|
+
} catch {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
})();
|
|
93
|
+
if (invokedDirectly) {
|
|
94
|
+
run(argv.slice(2))
|
|
95
|
+
.then((code) => process.exit(code))
|
|
96
|
+
.catch((err) => {
|
|
97
|
+
console.error(err);
|
|
98
|
+
process.exit(1);
|
|
99
|
+
});
|
|
100
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ruvector/ruqu",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Agent-harness CLI for the ruqu quantum project — boots the metaharness kernel + Claude Code host adapter. Run: npx @ruvector/ruqu",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ruqu": "bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/**",
|
|
11
|
+
"src/**",
|
|
12
|
+
"tsconfig.json",
|
|
13
|
+
".claude/**",
|
|
14
|
+
"CLAUDE.md",
|
|
15
|
+
"README.md",
|
|
16
|
+
"LICENSE"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"init": "node ./bin/cli.js init",
|
|
22
|
+
"doctor": "node ./bin/cli.js doctor"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@metaharness/kernel": "^0.1.0",
|
|
26
|
+
"@metaharness/host-claude-code": "^0.1.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/node": "^20.0.0",
|
|
30
|
+
"typescript": "^5.4.0",
|
|
31
|
+
"vitest": "^3.0.0"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=20.0.0"
|
|
35
|
+
},
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"author": "Ruvector Team <info@ruv.io> (https://ruv.io)",
|
|
41
|
+
"homepage": "https://github.com/ruvnet/ruqu#readme",
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "git+https://github.com/ruvnet/ruqu.git",
|
|
45
|
+
"directory": "cli"
|
|
46
|
+
},
|
|
47
|
+
"bugs": {
|
|
48
|
+
"url": "https://github.com/ruvnet/ruqu/issues"
|
|
49
|
+
},
|
|
50
|
+
"keywords": [
|
|
51
|
+
"ruqu",
|
|
52
|
+
"cli",
|
|
53
|
+
"agent",
|
|
54
|
+
"agent-harness",
|
|
55
|
+
"metaharness",
|
|
56
|
+
"ai-agent",
|
|
57
|
+
"claude-code",
|
|
58
|
+
"quantum",
|
|
59
|
+
"harness",
|
|
60
|
+
"npx"
|
|
61
|
+
]
|
|
62
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Experimenter agent — Tests the hypothesis safely and records it.
|
|
3
|
+
|
|
4
|
+
export const SYSTEM_PROMPT = `You test a hypothesis in a sandbox, measure against its declared metric, and write the signed result to the evolution log — kept or killed, with the number. You guard against the harness optimising its own metric into nonsense (Goodhart). A negative result recorded is real progress. You operate inside the ruqu harness; defer destructive actions to the user.`;
|
|
5
|
+
|
|
6
|
+
export const NAME = 'experimenter';
|
|
7
|
+
export const TIER = 'opus' as const;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Federator agent — Shares vetted improvements across instances.
|
|
3
|
+
|
|
4
|
+
export const SYSTEM_PROMPT = `You federate kept improvements to peer harness instances over the federation MCP, and pull theirs in — but only changes whose evolution-log entry is witness-signed and reproduced locally. You are the immune system: an unsigned or unreproduced "improvement" from a peer is rejected, not trusted. You operate inside the ruqu harness; defer destructive actions to the user.`;
|
|
5
|
+
|
|
6
|
+
export const NAME = 'federator';
|
|
7
|
+
export const TIER = 'sonnet' as const;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Hypothesizer agent — Proposes a falsifiable self-improvement.
|
|
3
|
+
|
|
4
|
+
export const SYSTEM_PROMPT = `You propose changes to the harness itself: a routing tweak, a new pattern, a prompt refinement. Each proposal is a falsifiable hypothesis with a metric that would confirm or kill it. You read the evolution log first so you never re-test a settled question. Bold proposals, honest metrics. You operate inside the ruqu harness; defer destructive actions to the user.`;
|
|
5
|
+
|
|
6
|
+
export const NAME = 'hypothesizer';
|
|
7
|
+
export const TIER = 'opus' as const;
|
package/src/init.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Generated by create-agent-harness — your harness's `ruqu init` entry.
|
|
3
|
+
|
|
4
|
+
import { loadKernel } from '@metaharness/kernel';
|
|
5
|
+
import adapter from '@metaharness/host-claude-code';
|
|
6
|
+
|
|
7
|
+
const HARNESS_NAME = 'ruqu';
|
|
8
|
+
|
|
9
|
+
async function main(): Promise<number> {
|
|
10
|
+
const kernel = await loadKernel();
|
|
11
|
+
const info = kernel.kernelInfo();
|
|
12
|
+
console.log(`${HARNESS_NAME} — kernel ${info.version} (${kernel.backend})`);
|
|
13
|
+
console.log(`Host adapter: ${adapter.name}`);
|
|
14
|
+
console.log(`Run \`${HARNESS_NAME} doctor\` to verify the install.`);
|
|
15
|
+
return 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
main().then(c => process.exit(c)).catch(err => {
|
|
19
|
+
console.error(err);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"declarationMap": true,
|
|
11
|
+
"sourceMap": true,
|
|
12
|
+
"strict": true,
|
|
13
|
+
"esModuleInterop": true,
|
|
14
|
+
"skipLibCheck": true,
|
|
15
|
+
"forceConsistentCasingInFileNames": true
|
|
16
|
+
},
|
|
17
|
+
"include": ["src/**/*.ts"],
|
|
18
|
+
"exclude": ["node_modules", "dist", "__tests__"]
|
|
19
|
+
}
|