@njuptlzf/dsh-ponytail 1.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/LICENSE +26 -0
- package/README.md +129 -0
- package/cordis.patch.yml +5 -0
- package/index.js +141 -0
- package/package.json +39 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kasakaze (njuptlzf)
|
|
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.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
The bundled `SKILL.md` originates from https://github.com/DietrichGebert/ponytail
|
|
26
|
+
and is licensed under MIT by its respective author(s).
|
package/README.md
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# dsh-ponytail
|
|
2
|
+
|
|
3
|
+
<details open>
|
|
4
|
+
<summary><b>English</b> · <i>点击下方「中文」切换中文</i></summary>
|
|
5
|
+
|
|
6
|
+
A [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) plugin that installs the [Ponytail](https://github.com/DietrichGebert/ponytail) "lazy senior developer" ruleset. It mirrors upstream's two-layer split:
|
|
7
|
+
|
|
8
|
+
- an **always-on, mode-switchable** system-prompt section built from the *compact* ruleset (~2.5 KB), and
|
|
9
|
+
- the **full** ruleset + 5 companion skills as on-demand `/` skills.
|
|
10
|
+
|
|
11
|
+
**This repo vendors no skill content.** On first boot it fetches once from upstream `DietrichGebert/ponytail`, caches to disk, and never re-fetches or hand-syncs afterwards.
|
|
12
|
+
|
|
13
|
+
### What it does
|
|
14
|
+
|
|
15
|
+
1. **Always-on section (lean)** — the compact ruleset (`.agents/rules/ponytail.md`, ~2.5 KB) as a system-prompt section, cached at `~/.dsh/ponytail-cache/compact.md`. Switch the level per session with `/ponytail lite|full|ultra|off`; `off` empties the section so the tokens are actually saved. Default `full`.
|
|
16
|
+
2. **On-demand skills** — the full ruleset (`ponytail`) and the 5 companions (`ponytail-help` / `ponytail-audit` / `ponytail-debt` / `ponytail-gain` / `ponytail-review`) written once to `~/.dsh/skills/<name>/SKILL.md`, invocable from the `/` palette.
|
|
17
|
+
|
|
18
|
+
### Install
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
dsh plugin --profile web add @njuptlzf/dsh-ponytail
|
|
22
|
+
# without a global dsh:
|
|
23
|
+
npx @deepseek-ai/dsh plugin --profile web add @njuptlzf/dsh-ponytail
|
|
24
|
+
# from git instead: dsh plugin --profile web add github:njuptlzf/dsh-ponytail
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Restart `dsh web` after install. The first boot fetches once and caches, so later boots — online or offline — never touch the network. To update the skills, delete the corresponding cache/skill files and restart.
|
|
28
|
+
|
|
29
|
+
### Usage
|
|
30
|
+
|
|
31
|
+
- `/ponytail` — report the current level; `/ponytail lite|full|ultra|off` — switch it. Mode is per-session (`agent.id`), so one conversation's `off` does not affect another.
|
|
32
|
+
- The 6 skills stay in the `/` palette; name them (e.g. "audit for over-engineering") and the model loads them on its own.
|
|
33
|
+
|
|
34
|
+
### dsh-ponytail vs codex-ponytail
|
|
35
|
+
|
|
36
|
+
| | codex-ponytail (upstream Codex plugin) | dsh-ponytail (this plugin) |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| Mechanism | Codex plugin: `SessionStart` + `SubagentStart` + `UserPromptSubmit` lifecycle hooks | DSH bundle: `systemPrompt` section + `commands` service |
|
|
39
|
+
| Always-on content | full ruleset, mode-filtered, at `SessionStart` | **compact ruleset (~2.5 KB)** every step |
|
|
40
|
+
| Per-turn cost | full rules only at session start / compact / subagent; one mode line per turn | ~2.5 KB re-rendered per step (DSH `systemPrompt` per-step semantics) |
|
|
41
|
+
| `off` | `UserPromptSubmit` stops injecting, tokens saved | section renders empty, tokens saved (parity) |
|
|
42
|
+
| Levels | `lite`/`full`/`ultra` filter the full ruleset's per-mode rows | level carried as header + behavior; per-mode detail lives in the on-demand full skill |
|
|
43
|
+
| Session isolation | single-session process → process-level flag file | multi-session process → per `agent.id` (== `session.id`) |
|
|
44
|
+
| Compaction | `SessionStart` re-fires on the `compact` matcher | compaction only shatters history, never the system prompt (inherent) |
|
|
45
|
+
| Subagents | `SubagentStart` + `PONYTAIL_SUBAGENT_MATCHER` | global section inherits into subagents via composition (no patch expected) |
|
|
46
|
+
| On-demand detail | `ponytail` skill | `ponytail` skill (parity) |
|
|
47
|
+
| Fallback | inline `getFallbackInstructions` | TODO (see `OPTIMIZATION_PLAN.md`) |
|
|
48
|
+
|
|
49
|
+
### Structure
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
dsh-ponytail/
|
|
53
|
+
├── index.js # host plugin: fetch once → compact always-on + mirror full/companions
|
|
54
|
+
├── package.json # dsh.bundle.patch declaration
|
|
55
|
+
├── cordis.patch.yml # mount row
|
|
56
|
+
├── OPTIMIZATION_PLAN.md # full design rationale + comparison
|
|
57
|
+
├── README.md
|
|
58
|
+
└── LICENSE # MIT
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Attribution
|
|
62
|
+
|
|
63
|
+
Skill content comes from [DietrichGebert/ponytail](https://github.com/DietrichGebert/ponytail) (MIT), fetched at runtime. The plugin wrapper is MIT © 2026 Kasakaze (njuptlzf).
|
|
64
|
+
|
|
65
|
+
</details>
|
|
66
|
+
|
|
67
|
+
<details>
|
|
68
|
+
<summary><b>中文</b> · <i>点击上方「English」切换英文</i></summary>
|
|
69
|
+
|
|
70
|
+
一个 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 插件:把 [Ponytail](https://github.com/DietrichGebert/ponytail)「懒高级工程师」规范接入进来,对标上游的两层结构:
|
|
71
|
+
|
|
72
|
+
- **常驻、可按档切换**的 system-prompt section,用 **精简规则**(~2.5 KB)构建;
|
|
73
|
+
- **全文规则** + 5 个同伴技能作为按需 `/` skill。
|
|
74
|
+
|
|
75
|
+
**本仓库不存技能内容**——首次启动从上游 `DietrichGebert/ponytail` 抓取一次并落盘缓存,之后不再联网、永不手工同步。
|
|
76
|
+
|
|
77
|
+
### 它做什么
|
|
78
|
+
|
|
79
|
+
1. **常驻 section(精简)** — 精简规则(`.agents/rules/ponytail.md`,~2.5 KB)作为 system-prompt section,缓存于 `~/.dsh/ponytail-cache/compact.md`。用 `/ponytail lite|full|ultra|off` 按会话切档;`off` 会让 section 渲染为空、真的省回 token。默认 `full`。
|
|
80
|
+
2. **按需 skills** — 全文规则(`ponytail`)和 5 个同伴(`ponytail-help` / `ponytail-audit` / `ponytail-debt` / `ponytail-gain` / `ponytail-review`)写入 `~/.dsh/skills/<name>/SKILL.md`,`/` 面板可调。
|
|
81
|
+
|
|
82
|
+
### 安装
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
dsh plugin --profile web add @njuptlzf/dsh-ponytail
|
|
86
|
+
# 无全局 dsh:
|
|
87
|
+
npx @deepseek-ai/dsh plugin --profile web add @njuptlzf/dsh-ponytail
|
|
88
|
+
# 或者从 git 安装:dsh plugin --profile web add github:njuptlzf/dsh-ponytail
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
安装后**重启 `dsh web`**:首次启动联网抓取一次并缓存,之后无论在线离线都不再联网。要更新技能,删对应缓存/技能文件再重启即可触发重抓。
|
|
92
|
+
|
|
93
|
+
### 使用
|
|
94
|
+
|
|
95
|
+
- `/ponytail` — 报告当前档;`/ponytail lite|full|ultra|off` — 切档。档位按会话(`agent.id`)隔离,一个会话的 `off` 不影响其它会话。
|
|
96
|
+
- 6 个技能常驻 `/` 面板;直接说「audit for over-engineering」等关键词,模型会按描述自行加载。
|
|
97
|
+
|
|
98
|
+
### dsh-ponytail vs codex-ponytail
|
|
99
|
+
|
|
100
|
+
| | codex-ponytail(上游官方 Codex 插件) | dsh-ponytail(本插件) |
|
|
101
|
+
|---|---|---|
|
|
102
|
+
| 接入机制 | Codex 插件:`SessionStart` + `SubagentStart` + `UserPromptSubmit` 三个 lifecycle hook | DSH bundle:`systemPrompt` section + `commands` 服务 |
|
|
103
|
+
| 常驻内容 | `SessionStart` 时注入**全文**(按 mode 过滤) | 每步注入**精简规则(~2.5 KB)** |
|
|
104
|
+
| 每轮成本 | 全文只在会话开始/压缩/子代理时;每轮只一行 mode 标记 | 每步重渲 ~2.5 KB(DSH `systemPrompt` 的 per-step 语义) |
|
|
105
|
+
| off | `UserPromptSubmit` 停止注入、省回 token | section 渲染为空、省回 token(对齐) |
|
|
106
|
+
| 强度档 | `lite`/`full`/`ultra` 过滤全文对应档的内容 | 档位以 header + 行为承载;分档细节落在按需全文 skill |
|
|
107
|
+
| 会话隔离 | 单会话进程 → 进程级 flag 文件 | 多会话单进程 → 按 `agent.id`(== `session.id`)隔离 |
|
|
108
|
+
| 压缩/遗忘 | `SessionStart` 的 `compact` matcher 在压缩时重注入 | 压缩只 shadow 历史、不动 system prompt(天然免疫) |
|
|
109
|
+
| 子代理 | `SubagentStart` + `PONYTAIL_SUBAGENT_MATCHER` | 全局 section 随 composition 继承子代理(预期无需补丁) |
|
|
110
|
+
| 按需详情 | `ponytail` skill | `ponytail` skill(对齐) |
|
|
111
|
+
| 兜底 | 内置 `getFallbackInstructions` | 待补(见 `OPTIMIZATION_PLAN.md`) |
|
|
112
|
+
|
|
113
|
+
### 结构
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
dsh-ponytail/
|
|
117
|
+
├── index.js # host 插件:只抓一次 → 精简常驻 + 镜像全文/同伴
|
|
118
|
+
├── package.json # dsh.bundle.patch 声明
|
|
119
|
+
├── cordis.patch.yml # 挂载行
|
|
120
|
+
├── OPTIMIZATION_PLAN.md # 完整设计说明与对比
|
|
121
|
+
├── README.md
|
|
122
|
+
└── LICENSE # MIT
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 归属
|
|
126
|
+
|
|
127
|
+
技能内容来自 [DietrichGebert/ponytail](https://github.com/DietrichGebert/ponytail)(MIT),运行时抓取。插件包装层 MIT © 2026 Kasakaze (njuptlzf)。
|
|
128
|
+
|
|
129
|
+
</details>
|
package/cordis.patch.yml
ADDED
package/index.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-ponytail — Ponytail (lazy senior dev) as a mode-switchable, always-on
|
|
3
|
+
* DSH host plugin.
|
|
4
|
+
*
|
|
5
|
+
* Vendors NO skill content — everything is fetched once from the canonical
|
|
6
|
+
* upstream (https://github.com/DietrichGebert/ponytail, MIT) and cached to
|
|
7
|
+
* disk, never re-fetched:
|
|
8
|
+
*
|
|
9
|
+
* Layer 1 — always-on (lean): the COMPACT ruleset
|
|
10
|
+
* (.agents/rules/ponytail.md, ~2.5 KB) as a per-step systemPrompt section.
|
|
11
|
+
* Mode-switchable per session via /ponytail lite|full|ultra|off; "off"
|
|
12
|
+
* renders the section empty, so the tokens are really saved (no restart).
|
|
13
|
+
*
|
|
14
|
+
* Layer 2 — on-demand skills: the FULL ruleset
|
|
15
|
+
* (skills/ponytail/SKILL.md) and the five companions, fetched once directly
|
|
16
|
+
* into ~/.dsh/skills/<name>/SKILL.md, invocable from the "/" palette.
|
|
17
|
+
*
|
|
18
|
+
* "只抓一次": fetch only when a disk copy is missing; a present copy is reused
|
|
19
|
+
* forever. Delete a copy to force a refetch.
|
|
20
|
+
*
|
|
21
|
+
* DSH-specific: one process hosts many sessions, so mode is stored per agent id
|
|
22
|
+
* (agent.id === session.id), NOT process-global as in single-session CLI hosts.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
26
|
+
import { dirname, join } from 'node:path';
|
|
27
|
+
import { homedir } from 'node:os';
|
|
28
|
+
|
|
29
|
+
export var name = 'dsh-ponytail';
|
|
30
|
+
export var inject = ['systemPrompt', 'commands'];
|
|
31
|
+
|
|
32
|
+
var RAW_BASE = 'https://raw.githubusercontent.com/DietrichGebert/ponytail/main/';
|
|
33
|
+
var MAIN = 'ponytail';
|
|
34
|
+
var COMPACT_REL = '.agents/rules/ponytail.md';
|
|
35
|
+
var COMPANIONS = ['ponytail-help', 'ponytail-audit', 'ponytail-debt', 'ponytail-gain', 'ponytail-review'];
|
|
36
|
+
var MODES = ['off', 'lite', 'full', 'ultra'];
|
|
37
|
+
var DEFAULT_MODE = 'full';
|
|
38
|
+
|
|
39
|
+
var compactSpec = '';
|
|
40
|
+
|
|
41
|
+
// sessionId (agent.id) -> mode. DSH is multi-session single-process, so state
|
|
42
|
+
// must be per-session; the Map's growth is bounded by live session count.
|
|
43
|
+
var modeById = new Map();
|
|
44
|
+
|
|
45
|
+
function modeFor(agent) {
|
|
46
|
+
var m = agent && agent.id !== undefined ? modeById.get(agent.id) : undefined;
|
|
47
|
+
return MODES.includes(m) ? m : DEFAULT_MODE;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function skillFile(name) {
|
|
51
|
+
return join(homedir(), '.dsh', 'skills', name, 'SKILL.md');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function compactCacheFile() {
|
|
55
|
+
return join(homedir(), '.dsh', 'ponytail-cache', 'compact.md');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function readFileOrNull(path) {
|
|
59
|
+
try {
|
|
60
|
+
return readFileSync(path, 'utf8');
|
|
61
|
+
} catch (e) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function saveFile(target, content) {
|
|
67
|
+
try {
|
|
68
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
69
|
+
writeFileSync(target, content);
|
|
70
|
+
} catch (e) {
|
|
71
|
+
console.error('[dsh-ponytail] write failed:', e && e.message ? e.message : String(e));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function fetchUrl(rel) {
|
|
76
|
+
try {
|
|
77
|
+
var res = await fetch(RAW_BASE + rel);
|
|
78
|
+
if (!res.ok) throw new Error('HTTP ' + res.status);
|
|
79
|
+
return await res.text();
|
|
80
|
+
} catch (e) {
|
|
81
|
+
console.error('[dsh-ponytail] fetch failed for ' + rel + ':', e && e.message ? e.message : String(e));
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function apply(ctx) {
|
|
87
|
+
// Cache-first: the always-on section has content offline, from turn one.
|
|
88
|
+
compactSpec = readFileOrNull(compactCacheFile()) || '';
|
|
89
|
+
|
|
90
|
+
ctx.effect(function () {
|
|
91
|
+
return ctx.systemPrompt.section({
|
|
92
|
+
name: 'ponytail',
|
|
93
|
+
order: 900,
|
|
94
|
+
text: function (context) {
|
|
95
|
+
var mode = modeFor(context && context.agent);
|
|
96
|
+
if (mode === 'off' || compactSpec === '') return ''; // empty → dropped by renderPrompt
|
|
97
|
+
return 'PONYTAIL MODE ACTIVE — level: ' + mode + '\n\n' + compactSpec;
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}, 'ponytail always-on section');
|
|
101
|
+
|
|
102
|
+
ctx.effect(function () {
|
|
103
|
+
return ctx.commands.register({
|
|
104
|
+
name: 'ponytail',
|
|
105
|
+
description: 'Set ponytail intensity (lite|full|ultra|off), or report the current level',
|
|
106
|
+
handler: function (invocation) {
|
|
107
|
+
var id = invocation.agent && invocation.agent.id;
|
|
108
|
+
var arg = (invocation.rawInput || '').trim().toLowerCase();
|
|
109
|
+
if (arg !== '') {
|
|
110
|
+
if (!MODES.includes(arg)) return { kind: 'error', text: 'Usage: /ponytail [lite|full|ultra|off]' };
|
|
111
|
+
if (id !== undefined) modeById.set(id, arg);
|
|
112
|
+
}
|
|
113
|
+
var current = id !== undefined && modeById.has(id) ? modeById.get(id) : DEFAULT_MODE;
|
|
114
|
+
return { kind: 'success', text: 'PONYTAIL MODE ' + current.toUpperCase() };
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}, 'ponytail mode command');
|
|
118
|
+
|
|
119
|
+
// 只抓一次: fetch only missing skill files; reuse present ones forever.
|
|
120
|
+
(async function bootstrap() {
|
|
121
|
+
if (compactSpec === '') {
|
|
122
|
+
var compact = await fetchUrl(COMPACT_REL);
|
|
123
|
+
if (compact !== null) { compactSpec = compact; saveFile(compactCacheFile(), compact); }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Full ruleset + 5 companions: each is a skill fetched once directly into
|
|
127
|
+
// ~/.dsh/skills/<name>/SKILL.md — the skill file IS the cache anchor.
|
|
128
|
+
var fetched = 0;
|
|
129
|
+
var skills = [MAIN].concat(COMPANIONS);
|
|
130
|
+
for (var i = 0; i < skills.length; i++) {
|
|
131
|
+
var name = skills[i];
|
|
132
|
+
if (existsSync(skillFile(name))) continue;
|
|
133
|
+
var content = await fetchUrl('skills/' + name + '/SKILL.md');
|
|
134
|
+
if (content !== null) { saveFile(skillFile(name), content); fetched += 1; }
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
console.log('[dsh-ponytail] ready: compact=' + (compactSpec !== '' ? 'ok' : 'MISSING') + ', skills fetched=' + fetched + ' (rest cached)');
|
|
138
|
+
})();
|
|
139
|
+
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@njuptlzf/dsh-ponytail",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Ponytail (lazy-senior-dev) as a mode-switchable, always-on DSH plugin: injects the COMPACT ruleset every step (off empties it) and mirrors the full ruleset + five companions into ~/.dsh/skills. Attribution: github.com/DietrichGebert/ponytail (MIT).",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./index.js",
|
|
9
|
+
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
10
|
+
"./package.json": "./package.json"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"index.js",
|
|
14
|
+
"cordis.patch.yml"
|
|
15
|
+
],
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=22"
|
|
19
|
+
},
|
|
20
|
+
"dsh": {
|
|
21
|
+
"bundle": {
|
|
22
|
+
"patch": "./cordis.patch.yml"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"dsh",
|
|
27
|
+
"dsh-plugin",
|
|
28
|
+
"deepseek-harness",
|
|
29
|
+
"cordis",
|
|
30
|
+
"plugin",
|
|
31
|
+
"ponytail",
|
|
32
|
+
"lazy-senior-dev",
|
|
33
|
+
"skill"
|
|
34
|
+
],
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://github.com/njuptlzf/dsh-ponytail.git"
|
|
38
|
+
}
|
|
39
|
+
}
|