dsh-paoding 0.3.0 → 0.3.1
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 +7 -16
- package/README_en.md +7 -16
- package/bin/dsh-paoding.mjs +2 -2
- package/docs/architecture.md +7 -5
- package/docs/architecture_en.md +14 -7
- package/docs/configuration.md +13 -13
- package/docs/configuration_en.md +11 -11
- package/docs/images/1.png +0 -0
- package/docs/installation.md +24 -23
- package/docs/installation_en.md +24 -23
- package/docs/orchestration.md +20 -24
- package/docs/orchestration_en.md +20 -24
- package/package.json +1 -1
- package/plugins/paoding-config-ui/index.mjs +4 -3
- package/plugins/paoding-config-ui/lib/client.js +1 -1
- package/plugins/paoding-config-ui/package.json +1 -1
- package/tools/lib/alloc.mjs +2 -2
- package/tools/lib/cli.mjs +7 -6
- package/tools/lib/config.mjs +1 -1
- package/docs/images/2.png +0 -0
- package/docs/images/3.png +0 -0
- package/docs/images/4.png +0 -0
- package/docs/images/5.png +0 -0
- package/docs/images/6.png +0 -0
package/docs/orchestration_en.md
CHANGED
|
@@ -22,19 +22,19 @@ The main agent's model-facing surface is narrowed by `restrict.mjs` on the `syst
|
|
|
22
22
|
| Child management | `send_message` / `list_agents` / `interrupt_agent` |
|
|
23
23
|
| Internal search (hot path) | `glob` / `grep` / `read` / `read_image` / `bash` |
|
|
24
24
|
| Coordination | `todo_write` / `ask_user_question` / `get_goal` / `create_goal` / `update_goal` / `exit_plan_mode` / `job_output` / `job_list` / `job_kill` |
|
|
25
|
-
| Deliberately hidden from the main agent | `web_search`, `mcp__tavily__*`, `write` / `edit`, `skill`, `workflow`, `ralph`, bare `subagent` / `subagent_fork` |
|
|
25
|
+
| Deliberately hidden from the main agent (excerpt; full list in the `restrict.mjs` header comment) | `web_search`, `mcp__tavily__*`, `write` / `edit` / `str_replace_editor`, `skill`, `workflow`, `ralph`, `ssh_*`, `mcp__tablepro__*`, `describe_image`, bare `subagent` / `subagent_fork` |
|
|
26
26
|
|
|
27
27
|
Per-request tool tax (estimates; they float with the registered surface): full monolithic main agent ~16.2k tokens → ~5.5k after the allow list; `search_external` ~3.0k / `design` ~3.3k / `implement` ~3.8k, incurred only when actually delegated (figures from the header comment of `agent.cordis.yml`).
|
|
28
28
|
|
|
29
29
|
### Main-agent persona (excerpt, verbatim)
|
|
30
30
|
|
|
31
|
-
Taken from the `- id: persona` row of `presets/orchestrator/agent.cordis.yml` (a YAML `
|
|
31
|
+
Taken from the `- id: persona` row of `presets/orchestrator/agent.cordis.yml` (a YAML `prefix: |-` block scalar whose content lines are indented 6 spaces; as of v0.3.0 the persona config key is `prefix`, with `text` kept as a legacy alias the generator still accepts). The overall orchestration-and-delegation guidance:
|
|
32
32
|
|
|
33
33
|
```text
|
|
34
34
|
You are the orchestrator agent powered by the {{model}} model. Your working directory is {{cwd}}.
|
|
35
35
|
|
|
36
36
|
Decompose the task, delegate to role agents, integrate results.
|
|
37
|
-
- Internal file questions (finding code, references, reading files): solve yourself with glob/grep/read
|
|
37
|
+
- Internal file questions (finding code, references, reading files): solve yourself with glob/grep/read (and codegraph if enabled) — never delegate them.
|
|
38
38
|
- External research: delegate to search_external.
|
|
39
39
|
- UI/design work: delegate to design.
|
|
40
40
|
- Code implementation: delegate to implement.
|
|
@@ -44,7 +44,7 @@ Keep your own context lean; integrate only summaries. Use todo_write to plan, an
|
|
|
44
44
|
Reading notes:
|
|
45
45
|
|
|
46
46
|
- The main agent is an orchestrator running the **decompose → delegate → integrate** loop rather than doing everything itself.
|
|
47
|
-
- "Internal file questions (finding code, references, reading files): solve yourself with glob/grep/read
|
|
47
|
+
- "Internal file questions (finding code, references, reading files): solve yourself with glob/grep/read (and codegraph if enabled) — **never delegate them**": internal search is the hot path — delegation costs round-trips and cold starts, and the main agent already carries a full read-only set, so it goes direct. (Note: `codegraph` is a host MCP tool and only becomes usable when install-time detection finds it and it is explicitly injected via `main_agent_extra`, see above.)
|
|
48
48
|
- Task texture decides the destination: networked research → `search_external`; UI/design → `design`; code → `implement` (whole-repo exploration → `search_internal_deep`).
|
|
49
49
|
- **Keep your own context lean**: integrate only summaries; plan with `todo_write`; use `ask_user_question` only for user-owned choices — questions that inspection can answer must not bother the user.
|
|
50
50
|
- The failure-handling SOP lives inline in the persona, so it is active in every session with zero extra configuration — see the next section.
|
|
@@ -61,9 +61,9 @@ A delegated run reports failure in two runtime shapes (verbatim from the persona
|
|
|
61
61
|
|
|
62
62
|
At child creation, DSH validates `toolFilter.allow` through `tools.restrict()`: every allow name must exist in the child's visible registry (= this composition's full registration plus host-layer MCP/plugin tools), otherwise creation is rejected (`tools.restrict() ... unknown tools`).
|
|
63
63
|
|
|
64
|
-
The preset eliminates this class of failure at generation time: the generator (the same pipeline behind the panel's Save & Apply and the fallback CLI) reads the host patch layers (home / profile / `--patch`), detects which MCP servers and local tool plugins are actually enabled, resolves exact tool names (a
|
|
64
|
+
The preset eliminates this class of failure at generation time: the generator (the same pipeline behind the panel's Save & Apply and the fallback CLI) reads the host patch layers (home / profile / `--patch`), detects which MCP servers and local tool plugins are actually enabled, resolves exact tool names (a live JSON-RPC handshake first for every server; known servers fall back to the static known-tools table only when the handshake fails), and rewrites the allow lists of the three configurable roles (search_external / design / implement) as "static intent ∩ actually detected tools" — composition-guaranteed base tools stay untouched, host tools that are disabled or unresolvable are removed. Only unknown servers that fail the handshake or use an unsupported transport are skipped entirely (known servers keep their table tools on handshake failure): the role simply lacks those tools and applying does not error. After enabling/disabling MCPs or plugins on the host, hit Save & Apply once in 庖丁配置 to sync the allow lists (Preview shows the list first). Details in [Installation](installation_en.md).
|
|
65
65
|
|
|
66
|
-
Note that the generator's allow rewriting covers only the three built-in roles (`search_external` / `design` / `implement` — the `ROLES` constant in tools/install.mjs). Hand-written extra `delegation-*` blocks (e.g. the hand-written `implement_cont` in section 4) ship **as-is and are never auto-cleaned**: host-dependent names inside them must be kept in sync with the plugins actually enabled on the host, or child creation is rejected. That is exactly why role allow lists dropped `memory_search` / `mcp__codegraph__codegraph_explore` as of 2026-09-02 (those names are not in the registry while the plugins are off; add them back when you re-enable the plugin — see the comment on `delegation-search-internal-deep` in `agent.cordis.yml`).
|
|
66
|
+
Note that the generator's allow rewriting covers only the three built-in roles (`search_external` / `design` / `implement` — the `ROLES` constant in `tools/lib/util.mjs`, re-exported by `tools/install.mjs`). Hand-written extra `delegation-*` blocks (e.g. the hand-written `implement_cont` in section 4) ship **as-is and are never auto-cleaned**: host-dependent names inside them must be kept in sync with the plugins actually enabled on the host, or child creation is rejected. That is exactly why role allow lists dropped `memory_search` / `mcp__codegraph__codegraph_explore` as of 2026-09-02 (those names are not in the registry while the plugins are off; add them back when you re-enable the plugin — see the comment on `delegation-search-internal-deep` in `agent.cordis.yml`).
|
|
67
67
|
|
|
68
68
|
### Layer 2: detection
|
|
69
69
|
|
|
@@ -94,6 +94,11 @@ Delegation failure handling (SOP):
|
|
|
94
94
|
· aborted → only re-delegate when the cancellation was accidental.
|
|
95
95
|
· completed but poor output → re-delegate with concrete missing points, or send_message
|
|
96
96
|
to ask a continuable child to finish the gaps.
|
|
97
|
+
- Continuable roles (background_mode: continuable): when a delegated run fails or
|
|
98
|
+
the output falls short, first send_message in the SAME child session to continue
|
|
99
|
+
and fix in place — resuming keeps the child's accumulated context, while
|
|
100
|
+
re-delegating starts a cold task and repeats finished work. Only re-delegate
|
|
101
|
+
when the child session is gone or the task needs a different role.
|
|
97
102
|
- If the same task fails twice, stop retrying: report to the user what failed, why,
|
|
98
103
|
and what you already tried. Never loop a failing delegation.
|
|
99
104
|
- When re-delegating (fresh task or continuation), always include your integration
|
|
@@ -113,9 +118,9 @@ Behavior by stop reason (complete coverage, one-to-one with the persona):
|
|
|
113
118
|
| Same task fails **twice** | Stop retrying; report to the user what failed, why, and what you already tried; never loop a failing delegation |
|
|
114
119
|
| Any re-delegation | **Always carry the previous integration summary** — what was done, what failed, what to pick up from — so the child never re-derives it from a cold context |
|
|
115
120
|
|
|
116
|
-
The continuable branch
|
|
121
|
+
The continuable branch: when a run fails or the output disappoints **and the role is configured continuable**, first resume the same child conversation with `send_message` — the child remembers where it left off and finishes in place; re-delegate only when the child session is gone or the task needs a different role (the same wording as the Continuable roles entry in the persona SOP); otherwise fall back to the table above (re-delegation drops from first choice to fallback).
|
|
117
122
|
|
|
118
|
-
Design note: the SOP is persona text, not code, so it is tunable: edit the persona block in `presets/orchestrator/agent.cordis.yml` (YAML block scalar; content lines are indented
|
|
123
|
+
Design note: the SOP is persona text, not code, so it is tunable: edit the persona block in `presets/orchestrator/agent.cordis.yml` (YAML block scalar; content lines are indented 6 spaces — keep the indentation), then hit Save & Apply in 庖丁配置 to regenerate. For example, you can make failures bounce back to the main agent more often, or give a specific role a different retry ceiling.
|
|
119
124
|
|
|
120
125
|
## One-shot vs continuable
|
|
121
126
|
|
|
@@ -153,7 +158,7 @@ Quick comparison:
|
|
|
153
158
|
|
|
154
159
|
## Advanced: hand-editing implement_cont (no panel)
|
|
155
160
|
|
|
156
|
-
The main path for Path B is the panel or the config key — one toggle on the role card's「会话模式」("session mode") control (see [Configuration](configuration_en.md) 2.6). This section is the equivalent panel-free route, in 5 steps — read it when you want to see exactly what the generation layer writes, or when working without the panel. The default preset does **not** ship `implement_cont`; enable it when you need it and remove it entirely when you no longer do. All YAML below is verbatim configuration (
|
|
161
|
+
The main path for Path B is the panel or the config key — one toggle on the role card's「会话模式」("session mode") control (see [Configuration](configuration_en.md) 2.6). This section is the equivalent panel-free route, in 5 steps — read it when you want to see exactly what the generation layer writes, or when working without the panel. The default preset does **not** ship `implement_cont`; enable it when you need it and remove it entirely when you no longer do. All YAML below is verbatim configuration (structured like the preset's delegation blocks and checked against the source).
|
|
157
162
|
|
|
158
163
|
### Step 1 — mount the persistence backend at the host layer (machine-level, global)
|
|
159
164
|
|
|
@@ -215,28 +220,19 @@ Two caveats:
|
|
|
215
220
|
- `memory_search` depends on the host magic-memory plugin: **if the plugin is not enabled, remove that line from the allow list** or child creation is rejected by `tools.restrict()` with unknown tools. This is consistent with the 2026-09-02 decision to strip `memory_search` / `mcp__codegraph__codegraph_explore` from role allow lists (see the in-file comment in `agent.cordis.yml`); and since the installer's allow rewriting covers only the three built-in roles, the hand-written `implement_cont` block is **never auto-cleaned** — keep its allow list in sync with the plugins actually enabled on the host by hand.
|
|
216
221
|
- The persona in the block above is a YAML `|-` block scalar whose content lines are indented 10 spaces; preserve the indentation when editing the text.
|
|
217
222
|
|
|
218
|
-
### Step 3 — let the main agent call `implement_cont` (
|
|
223
|
+
### Step 3 — let the main agent call `implement_cont` (edit the restrict constant)
|
|
219
224
|
|
|
220
|
-
The main agent can only call tools on its allow list
|
|
225
|
+
The main agent can only call tools on its allow list. The preferred way is to edit the `MAIN_AGENT_ALLOW` constant directly — add a line `'implement_cont'` to `MAIN_AGENT_ALLOW` (the 21-entry allow constant, `new Set([...])`) in `presets/orchestrator/restrict.mjs` (this edits the SRC, so you must re-apply afterwards, see step 4).
|
|
221
226
|
|
|
222
|
-
|
|
227
|
+
Why the config file is not an option here: `main_agent_extra` injections go through the whitelist reconciliation — a name is kept only if it belongs to the **presetUniverse** (the `restrict.mjs` main-agent allow ∪ the source preset's role allows) or to the **detection inventory**; names in neither are always dropped. A custom delegation name like `implement_cont` falls in neither bucket: written under `main_agent_extra` it is silently dropped by the generator (the fallback CLI output only totals the count, with no per-name detail), and the panel's main-agent card cannot tick it either. For the config-layer path to work, a hand-written name must first exist in the presetUniverse / inventory.
|
|
223
228
|
|
|
224
|
-
|
|
225
|
-
main_agent_extra:
|
|
226
|
-
- implement_cont
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
At apply time `implement_cont` — not a host-dependent name — is merged into the generated `config.allow`. You can equally tick it in the panel (Settings → 庖丁配置 → the main-agent card); see [Configuration](configuration_en.md).
|
|
230
|
-
|
|
231
|
-
**Alternative: edit the `restrict.mjs` constant.** Add a line `'implement_cont'` to `MAIN_AGENT_ALLOW` (the 21-entry allow constant, `new Set([...])`) in `presets/orchestrator/restrict.mjs`. Mind the **override semantics**: at runtime `allow = config.allow ?? MAIN_AGENT_ALLOW` (an empty allow refuses to load). The generator re-extracts this constant from `restrict.mjs` source as its base and generates `config.allow = base + main_agent_extra (only detected host names kept) − main_agent_remove`, injecting the `config.allow` row **only when the result differs from the base**. So after editing the constant you must re-apply (the base is re-extracted and the installed copy refreshed); and when the running `agent.cordis.yml` already has an injected `config.allow`, that generated list wins at runtime and the constant only serves as fallback.
|
|
232
|
-
|
|
233
|
-
Either way, re-apply to take effect (next step).
|
|
229
|
+
Mind the **override semantics**: at runtime `allow = config.allow ?? MAIN_AGENT_ALLOW` (an empty allow refuses to load). The generator re-extracts this constant from `restrict.mjs` source as its base and generates `config.allow = (base + main_agent_extra − main_agent_remove) ∩ (presetUniverse ∪ inventory)`, injecting the `config.allow` row **only when the result differs from the base**. So after editing the constant you must re-apply (the base is re-extracted and the installed copy refreshed); and when the running `agent.cordis.yml` already has an injected `config.allow`, that generated list wins at runtime and the constant only serves as fallback.
|
|
234
230
|
|
|
235
231
|
### Step 4 — apply
|
|
236
232
|
|
|
237
|
-
Open Settings
|
|
233
|
+
Open the「**庖丁配置**」entry in the action bar at the bottom of the left sidebar (just above the Settings row) and hit「**保存并应用**」(Save & Apply) — the preset regenerates (new delegation block + allow-list changes), and your hand edits go live with it.
|
|
238
234
|
|
|
239
|
-
Then **restart the host or open a new session** for it to take effect.
|
|
235
|
+
Then **restart the host or open a new session** for it to take effect. Later config changes re-apply idempotently the same way — hit Save & Apply again (developers who cloned the repo can also use the fallback CLI, `node tools/install.mjs --auto`).
|
|
240
236
|
|
|
241
237
|
### Step 5 — clean up after use
|
|
242
238
|
|
package/package.json
CHANGED
|
@@ -10,8 +10,9 @@
|
|
|
10
10
|
* 兜底);upgrade 经 tools/lib/upgrade.mjs spawn `dsh plugin update` 完成
|
|
11
11
|
* 一键升级。首装 / 升级后 preset 自动重生成(ensurePresetInstalled,等价
|
|
12
12
|
* install --auto 语义)在路由注册完成后异步触发,不阻塞启动。
|
|
13
|
-
* - Client 侧:lib/client.js
|
|
14
|
-
*
|
|
13
|
+
* - Client 侧:lib/client.js 经宿主 sidebar.footer.action 键控槽在左侧栏
|
|
14
|
+
* 底部(设置行上方)注册「庖丁配置」入口,点击后在会话中栏打开全页配置
|
|
15
|
+
* overlay(data-dsh-paoding-active)。
|
|
15
16
|
*
|
|
16
17
|
* 挂载(~/.dsh/cordis.patch.yml):
|
|
17
18
|
* - id: paoding-config-ui
|
|
@@ -177,7 +178,7 @@ function triggerPresetEnsure(ctx, isDisposed) {
|
|
|
177
178
|
} else if (r.error) {
|
|
178
179
|
// 失败复位防抖闩:下次 activate(热重载 / 重注册)可重试
|
|
179
180
|
presetEnsureStarted = false
|
|
180
|
-
ctx.logger?.warn?.(`paoding-config-ui: preset
|
|
181
|
+
ctx.logger?.warn?.(`paoding-config-ui: preset 自动生成失败(可在侧栏底部「庖丁配置」入口手动应用): ${r.error}`)
|
|
181
182
|
}
|
|
182
183
|
// 版本一致的常规跳过不打日志:每次启动都刷一行纯噪音。
|
|
183
184
|
})
|
|
@@ -2526,7 +2526,7 @@ window.__ModuleLoader__.load({
|
|
|
2526
2526
|
}
|
|
2527
2527
|
|
|
2528
2528
|
// ── 侧栏底部入口(sidebar.footer.action 键控槽)────────────────────────
|
|
2529
|
-
//
|
|
2529
|
+
// 入口挂在左下角底部动作条:注册 sidebar.footer.action
|
|
2530
2530
|
// 列表槽(与插件广场 cordis 徽章同一槽位,渲染在设置行上方的动作条里)。
|
|
2531
2531
|
// 观感复刻 cordis 徽章 / 设置触发钮:宽栏 = 42px 圆角行(图标 + 文案),
|
|
2532
2532
|
// 窄栏(56px rail)= 36px 圆形图标钮。点击开 / 关全页 overlay(mountPanel
|
package/tools/lib/alloc.mjs
CHANGED
|
@@ -74,8 +74,8 @@ export function keywords(names, pattern) {
|
|
|
74
74
|
/**
|
|
75
75
|
* 基础模板 assignments(fresh 非交互安装的默认起点):每个内置角色保留静态
|
|
76
76
|
* preset 的 dsh 基础工具,host/MCP 工具一概不纳入 —— 首装(插件通道启动自愈
|
|
77
|
-
* 或 --auto)先装完可用基础版,host
|
|
78
|
-
*
|
|
77
|
+
* 或 --auto)先装完可用基础版,host 工具留给用户在侧栏底部「庖丁配置」入口
|
|
78
|
+
* 里显式开启,避免智能默认把检测到的 host 工具静默塞进委派链。形状与 smartDefaults
|
|
79
79
|
* 返回值完全一致,生成层 / 序列化层无需区分来源;staticBase 复制而非别名,
|
|
80
80
|
* 防调用方原地改写。每个内置角色条目显式带 background_mode: 'one-shot',随
|
|
81
81
|
* serializeConfig 恒写出 —— fresh 落盘的配置文件里旋钮可见。
|
package/tools/lib/cli.mjs
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* 官方安装通道是 DSH 插件通道(dsh plugin --profile web add dsh-paoding),
|
|
6
6
|
* npm 包不再携带 CLI 入口;本 CLI 仅作仓库内不宣传的开发兜底(--auto /
|
|
7
7
|
* --dry-run / --config / --help)。交互模式已整块移除:可视化配置走插件通道
|
|
8
|
-
* 自带的 Web
|
|
8
|
+
* 自带的 Web 配置器(侧栏底部「庖丁配置」入口)。
|
|
9
9
|
*
|
|
10
10
|
* 依赖 util(ROLES / SRC_DIR / PROFILE_NAME_RE)、config(normalizeRoleName)、
|
|
11
11
|
* host(removedReason)、state(collectState /
|
|
@@ -31,7 +31,7 @@ export function printHelp() {
|
|
|
31
31
|
|
|
32
32
|
dsh plugin --profile web add dsh-paoding
|
|
33
33
|
|
|
34
|
-
可视化配置随插件通道自带:DSH Web
|
|
34
|
+
可视化配置随插件通道自带:DSH Web 侧栏底部「庖丁配置」入口。
|
|
35
35
|
|
|
36
36
|
Usage:
|
|
37
37
|
node tools/install.mjs [options]
|
|
@@ -58,9 +58,10 @@ Environment:
|
|
|
58
58
|
DSH_HOME Directory holding cordis.patch.yml etc. (default: $HOME/.dsh)
|
|
59
59
|
|
|
60
60
|
With --auto and no config file, a base template is written: only the dsh
|
|
61
|
-
built-in tools stay enabled — add host/MCP tools afterwards
|
|
62
|
-
(visual config UI from the plugin channel).
|
|
63
|
-
the smart defaults that fold detected host
|
|
61
|
+
built-in tools stay enabled — add host/MCP tools afterwards via the 庖丁配置
|
|
62
|
+
entry at the sidebar bottom (visual config UI from the plugin channel).
|
|
63
|
+
Pass --suggest to fall back to the smart defaults that fold detected host
|
|
64
|
+
tools in automatically.`)
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
// --profile 值白名单:与 bin/dsh-paoding.mjs 共用同一份 PROFILE_NAME_RE(抽在
|
|
@@ -311,7 +312,7 @@ export async function main({ argv = process.argv.slice(2) } = {}) {
|
|
|
311
312
|
// fresh 非交互安装:提示基础模板已落盘、host/MCP 工具去哪补(--suggest 可
|
|
312
313
|
// 恢复智能默认自动纳入)。
|
|
313
314
|
console.log(
|
|
314
|
-
`\n基础模板已写入 ${configFile}:默认仅 dsh
|
|
315
|
+
`\n基础模板已写入 ${configFile}:默认仅 dsh 基础工具,重启后在侧栏底部「庖丁配置」入口` +
|
|
315
316
|
`里自定义 host/MCP 工具。`,
|
|
316
317
|
)
|
|
317
318
|
}
|
package/tools/lib/config.mjs
CHANGED
|
@@ -457,7 +457,7 @@ function writeWorkspaces(lines, workspaces) {
|
|
|
457
457
|
|
|
458
458
|
/** Serialize the config back to YAML (fixed structure, hand-rolled writer). */
|
|
459
459
|
export function serializeConfig(config) {
|
|
460
|
-
const lines = ['# dsh-paoding(庖丁)安装配置 ——
|
|
460
|
+
const lines = ['# dsh-paoding(庖丁)安装配置 —— 可手编;改后在侧栏底部「庖丁配置」入口应用,或重跑 node tools/install.mjs --auto']
|
|
461
461
|
lines.push(`profile: ${config.profile ?? 'web'}`)
|
|
462
462
|
writeTargetFields(lines, '', config)
|
|
463
463
|
// workspaces 段可选:键缺失 / 空对象整段省略(不含 workspaces 的配置输出与
|
package/docs/images/2.png
DELETED
|
Binary file
|
package/docs/images/3.png
DELETED
|
Binary file
|
package/docs/images/4.png
DELETED
|
Binary file
|
package/docs/images/5.png
DELETED
|
Binary file
|
package/docs/images/6.png
DELETED
|
Binary file
|