osdy-pi 1.11.0 → 1.11.2
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 +32 -11
- package/extensions/osdy-pi/assets/PROVENANCE.md +27 -0
- package/extensions/osdy-pi/assets/assistant-mascot-export.mjs +43 -0
- package/extensions/osdy-pi/assets/assistant-mascot.png +0 -0
- package/extensions/osdy-pi/assets/assistant-mascot.svg +37 -0
- package/extensions/osdy-pi/message-role-marker-image.test.ts +117 -0
- package/extensions/osdy-pi/message-role-marker-image.ts +97 -0
- package/extensions/osdy-pi/message-role-markers.test.ts +31 -2
- package/extensions/osdy-pi/message-role-markers.ts +3 -7
- package/extensions/osdy-pi/profile-label.ts +40 -0
- package/extensions/osdy-pi/runtime.test.ts +276 -1
- package/extensions/osdy-pi/runtime.ts +93 -9
- package/extensions/osdy-pi/todo-provider-settings.test.ts +150 -0
- package/extensions/osdy-pi/todo-provider-settings.ts +192 -0
- package/extensions/osdy-pi.ts +2 -2
- package/package.json +6 -1
- package/scripts/osdy-pi-gentle-coexistence.mjs +115 -43
- package/scripts/osdy-pi-profile-setup.mjs +21 -22
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Osdy Pi gives [Pi](https://github.com/earendil-works/pi) a themed, responsive te
|
|
|
6
6
|
|
|
7
7
|
## Release highlights
|
|
8
8
|
|
|
9
|
-
**1.11.0 adds three Spider-Man-inspired dark palettes**, bringing the bundle to **23 themes**. It retains the four-page local usage analytics introduced in 1.10.0, with shared period and profile/provider/model filters, keyboard navigation, and metadata-only history. These
|
|
9
|
+
**1.11.0 adds three Spider-Man-inspired dark palettes**, bringing the bundle to **23 themes**. It retains the four-page local usage analytics introduced in 1.10.0, with shared period and profile/provider/model filters, keyboard navigation, and metadata-only history. These version introductions are historical, not a fixed latest-version claim. After npm Trusted Publishing is configured, pushes to main (including direct pushes) run checks and attempt to publish an automatically allocated patch to npm. Failed checks publish nothing; authentication or registry failures can also stop publication. Verify the resolved npm version before installing. Maintainers: [automatic npm publishing setup](https://github.com/OsdyOrtiz/Osdy-Pi/blob/main/docs/npm-publishing.md).
|
|
10
10
|
|
|
11
11
|
| Area | What ships |
|
|
12
12
|
| --- | --- |
|
|
@@ -18,7 +18,7 @@ Osdy Pi gives [Pi](https://github.com/earendil-works/pi) a themed, responsive te
|
|
|
18
18
|
| Header and mascot | A theme-aware `neon` header and selectable `bts` mascot, both responsive and persisted independently. |
|
|
19
19
|
| Accounts | `/osdy-account` switches Codex profiles in place with atomic activation, rollback, bounded auth files, and process-safe locks. |
|
|
20
20
|
| Quota | `/usage` and compact bars emphasize remaining Codex quota at warning (40% or less) and error (15% or less) thresholds. |
|
|
21
|
-
| TODO (starting in 1.5.0) |
|
|
21
|
+
| TODO (starting in 1.5.0, opt-in) | Default-off first-party `todo` snapshots track the Pi session branch; `/todos` reads them without editing. ODD Markdown remains separate. |
|
|
22
22
|
|
|
23
23
|
## Prerequisites
|
|
24
24
|
|
|
@@ -40,7 +40,7 @@ Osdy Pi gives [Pi](https://github.com/earendil-works/pi) a themed, responsive te
|
|
|
40
40
|
pi install git:github.com/OsdyOrtiz/Osdy-Pi
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
Check the resolved npm version: the Spider-Man-inspired themes require 1.11.0 or later; local analytics requires 1.10.0 or later. To
|
|
43
|
+
Check the resolved npm version: the Spider-Man-inspired themes require 1.11.0 or later; local analytics requires 1.10.0 or later. To pin the historical feature release explicitly, use `pi install npm:osdy-pi@1.11.0` if that version is available on npm; automatic patches may already be newer. For an unpinned installation, use `pi update`; it does not move a pinned version, so replace an older pin explicitly. First-party TODO is included starting in 1.5.0; `/osdy-pi uninstall` and explicit agent provider modes start in 1.6.0. Installing Osdy does not automatically install Joker; see [explicit agent provider modes](#explicit-agent-provider-modes-in-normal-pi).
|
|
44
44
|
|
|
45
45
|
2. Start Pi:
|
|
46
46
|
|
|
@@ -48,7 +48,9 @@ Osdy Pi gives [Pi](https://github.com/earendil-works/pi) a themed, responsive te
|
|
|
48
48
|
pi
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
Osdy
|
|
51
|
+
**Osdy TODO is off by default**, so installing Osdy alongside Gentle Shell does not register a competing `todo`, `/todos`, or TODO widget. To select Osdy explicitly, run `/osdy-pi todo on`, confirm the active profile target, then check `/osdy-pi todo status`. See [TODO selection](#explicit-todo-selection).
|
|
52
|
+
|
|
53
|
+
Osdy Pi's own extension and themes are bundled—do not install them separately. Starting with **1.11.0**, the package bundles **23 themes**, including Spider-Man Classic, Miles Morales, and Spider-Verse: Gruvbox Dark, Nord, Rosé Pine base dark, and Daniela Cute were introduced in 1.8.0; Halloween and Halloween Killer were added in 1.9.0. Check your installed npm version to see which themes are available. Launch through `osdy-pi` (or `npm run pi:dev`) to activate a valid Osdy default account into Pi's shared agent directory before Pi starts. With no default, Pi remains unmanaged; run `/osdy-account` to create a profile and establish a default. On session start, Osdy Pi restores its persisted enabled state when a UI is available and preserves your selected Pi theme. When disabled, it leaves Gentle Shell (or Pi's native UI) untouched.
|
|
52
54
|
|
|
53
55
|
### Optional: isolated `osdy` command
|
|
54
56
|
|
|
@@ -128,14 +130,30 @@ To load a local `gentle-pi` checkout while keeping Osdy Pi's UI authoritative, r
|
|
|
128
130
|
osdy-pi gentle setup /absolute/path/to/gentle-pi
|
|
129
131
|
```
|
|
130
132
|
|
|
131
|
-
The command validates that the absolute source is a readable `gentle-pi` package with Gentle's todo and agents extensions before atomically updating `$PI_CODING_AGENT_DIR/settings.json` (or `~/.pi/agent/settings.json`).
|
|
133
|
+
The command validates that the absolute source is a readable `gentle-pi` package with Gentle's todo and agents extensions before atomically updating `$PI_CODING_AGENT_DIR/settings.json` (or `~/.pi/agent/settings.json`). For a new registration, it places the local package before the first configured Osdy Pi entry, with exclusions for `ask-user-question.ts` and `gentle-agents.ts`, plus `themes: []`. Existing Gentle entries, deliberate filters and resource selections are preserved. Gentle TODO remains eligible by default; an existing explicit Osdy TODO opt-in retains its TODO exclusion and ownership. Restart Pi or run `/reload` after setup.
|
|
132
134
|
|
|
133
135
|
Gentle Shell intentionally remains fully active underneath Osdy, including its footer and widgets. While Osdy is enabled, Osdy claims the footer and editor; disabling Osdy restores the editor Gentle Shell provided at session startup. Gentle's changes widget may coexist with Osdy's visual widgets.
|
|
134
136
|
|
|
135
|
-
The exclusions prevent Gentle's
|
|
137
|
+
The default exclusions prevent Gentle's questionnaire and agents extensions from competing with the suite, without selecting Osdy TODO. Pre-existing Gentle TODO exclusions remain unowned and are not erased or treated as opt-in. When explicitly selected, Osdy's session-branch snapshots are authoritative for its `todo` tool and read-only `/todos` command; `pi-subagents-j0k3r` is the subagent system in Joker mode (Gentle agents in Gentle mode) and `@juicesharp/rpiv-ask-user-question` remains the structured-question plugin. This setup does **not** remove an independently installed `@juicesharp/rpiv-todo` package or edit its package entry. Remove that package yourself as described below to avoid duplicate `todo` and `/todos` registrations.
|
|
138
|
+
|
|
139
|
+
## Explicit TODO selection
|
|
140
|
+
|
|
141
|
+
```text
|
|
142
|
+
/osdy-pi todo on
|
|
143
|
+
/osdy-pi todo status
|
|
144
|
+
/osdy-pi todo off
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
`on` requires confirmation showing the active `$PI_CODING_AGENT_DIR/settings.json` (otherwise `~/.pi/agent/settings.json`). It atomically saves opt-in and only the necessary `-extensions/gentle-todo.ts` exclusions in the `osdyPiTodoProvider` namespace (`version: 1`, `enabled`, `ownedExclusions`). `off` opts out and removes only exclusions actually added by this selector; pre-existing user/legacy exclusions stay intact. Both preserve unrelated settings and task history. Successful switches notify before reloading; restart Pi if reload fails. Manual settings changes require `/reload` or restart. `status` distinguishes configured selection, actual registration in this runtime and current settings eligibility; legacy filters can leave no provider and are reported rather than repaired silently. `/osdy-pi off` remains visual-only.
|
|
148
|
+
|
|
149
|
+
Supported scope: active personal, custom or isolated profiles with npm Gentle or validated local packages (absolute, settings-relative, `~/`, `file:`); duplicate entries are checked individually. Project Gentle overrides, malformed/symlink settings, direct-extension settings, unsupported identities and uncertain allowlists refuse activation without writes. Disabled `extensions: []` is never broadened by a negative filter. Startup fails closed if an opted-on profile later gains an unfiltered Gentle source. Startup never writes defaults or infers opt-in from old filters. Only an explicit opt-in runs a bounded read-only Node cwd probe through `pi.exec`; the awaited factory checks the SDK working directory before registering TODO surfaces and fails closed if it cannot obtain a valid cwd. Reordering selector-owned package entries requires resolving ownership before switching; the selector refuses ambiguous restoration.
|
|
150
|
+
|
|
151
|
+
This is a supported-settings guarantee, not detection of arbitrary CLI/SDK-injected competing tools. SDK-only `agentDir` overrides must also set `PI_CODING_AGENT_DIR`. No project settings, installed packages, task snapshots, credentials or upstream Gentle code are changed. A new isolated setup defaults off and removes only proven selector-owned inherited TODO exclusions before remapping package sources; malformed or ambiguous ownership refuses setup before writes. User/legacy exclusions remain intact. Repeat setup preserves its existing explicit selection and resource filters.
|
|
136
152
|
|
|
137
153
|
## First-party TODO included starting in 1.5.0
|
|
138
154
|
|
|
155
|
+
The surfaces below register only after explicit TODO opt-in.
|
|
156
|
+
|
|
139
157
|
The model-facing `todo` tool supports `create`, `update`, `list`, `get`, `delete`, and `clear`. Tool results carry full task snapshots; Pi's current session branch is the TODO authority. Session switches and compaction replay the latest valid branch snapshot, rather than sharing one project-wide list. `/todos` opens a read-only, grouped modal (pending, in progress, completed) in interactive Pi; scroll with arrow or Page Up/Down keys and close with Esc or q. The refreshed modal adds a completed-task progress meter, theme-aware status groups and a scroll-position footer while keeping every task reachable. It is not an interactive Markdown editor. In non-terminal modes with UI support, it retains notification output. ODD's `odd/tasks/*.md` ledger and Engram are separate orchestration records: there is no automatic sync with these Pi TODOs.
|
|
140
158
|
|
|
141
159
|
In interactive Pi, the persistent widget appears above the editor while visible tasks exist. Its compact preview shows up to three task rows (excluding heading, overflow hint, and spacer), prioritizes unfinished tasks on overflow, and crosses out completed subjects. In fullscreen Pi, left-click the heading to expand or return to preview; wheel over the expanded widget to move one task at a time beneath the fixed heading. The final task can reach the first task row even in a short dock. A heading-only or hidden dock cannot display tasks; use `/todos` for the full keyboard-accessible list. Regular mode stays compact; Pi's tool-output expansion does not change this widget. `ctrl+shift+t` retains the separate fully collapsed view.
|
|
@@ -144,7 +162,7 @@ Expansion and scroll position survive same-session refresh, tree navigation, and
|
|
|
144
162
|
|
|
145
163
|
### Try session TODO
|
|
146
164
|
|
|
147
|
-
|
|
165
|
+
Run `/osdy-pi todo on` in this checkout (or a package containing the three-task preview), confirm and let Pi reload, then ask the agent to track a task with `todo`, then run `/todos`. The modal shows the entire grouped list with arrow/Page Up/Down scrolling. `maxWidgetLines: 7` permits five task rows in the expanded fullscreen widget; the preview remains capped at three. Smaller budgets also constrain the preview. Fullscreen widget mouse handling uses Pi's public 0.99.1 component APIs.
|
|
148
166
|
|
|
149
167
|
**Verification to date (not complete):** The user confirmed fullscreen appearance and behavior via `pi:dev`. Automated PTY interaction passed 27 assertions, but fixture cleanup failed and the final task snapshot remains unverified; this was not a full end-to-end pass. Prior feature checks passed 187 extension tests, 60 script tests, typecheck, and lint. A disposable Pi TUI with seeded tasks showed the modal's progress meter, grouped rows, scroll footer, and close behavior. Authenticated RPC turns exercised all six `todo` actions, and an authenticated TUI smoke observed widget and `/todos` updates. An RPC lifecycle check observed an empty new session and the completed task on switching back. Compaction replay remains unverified because Pi returned “Nothing to compact (session too small).” Language switching in the authenticated TODO flow remains unverified (an isolated TUI with both extensions did switch English to Spanish). Visual strikethrough of completed rows in the authenticated TUI remains unverified. Launch under an installed Osdy account profile remains unverified. These checks do not establish full feature parity or validate a published npm artifact.
|
|
150
168
|
|
|
@@ -222,12 +240,14 @@ Profile names accept ASCII letters, numbers, and hyphens, up to 63 characters, p
|
|
|
222
240
|
|
|
223
241
|
### See and switch the active account
|
|
224
242
|
|
|
225
|
-
|
|
243
|
+
Direct `pi` startup restores the last activated profile label from valid active-account metadata. A valid explicit launcher profile (`OSDY_PI_PROFILE_NAME`) takes precedence. Osdy Pi shows the profile name in the editor:
|
|
226
244
|
|
|
227
245
|
- **Simple/native editor:** beside the model, for example `gpt-5.6-sol · personal · think high`.
|
|
228
246
|
- **Extended/framed editor:** `personal` replaces the `Osdy-Pi` title.
|
|
229
247
|
- **No managed profile:** the existing model line and `Osdy-Pi` title remain unchanged.
|
|
230
248
|
|
|
249
|
+
Label recovery is visual only: it does not switch credentials or change the configured default. Missing, invalid, unreadable, or stale active-account metadata keeps the existing fallback.
|
|
250
|
+
|
|
231
251
|
`account use <name>` activates the profile in Pi's shared agent directory, saves it as active/default, then starts Pi. Inside Pi, `/osdy-account` waits for active work to finish and swaps the canonical `auth.json` in place; the next request resolves the new account without a spawn, shutdown, session handoff, or restart.
|
|
232
252
|
|
|
233
253
|
To resume a specific session directly from the terminal:
|
|
@@ -267,9 +287,9 @@ Before rename or removal, close this Pi process when it uses the target and **ma
|
|
|
267
287
|
|
|
268
288
|
### Themes
|
|
269
289
|
|
|
270
|
-
|
|
290
|
+
The **1.11.0** release introduced a **23-theme** bundle, including Spider-Man Classic, Miles Morales, and Spider-Verse. Gruvbox Dark, Nord, Rosé Pine base dark, and Daniela Cute were introduced in **1.8.0**; Halloween and Halloween Killer were added in **1.9.0**. To try the themes from a checkout:
|
|
271
291
|
|
|
272
|
-
1. Run `npm run pi:dev` from
|
|
292
|
+
1. Run `npm run pi:dev` from a checkout containing these themes, or `/reload` if that checkout is already loaded in Pi.
|
|
273
293
|
2. Open `/settings` → **Theme** and select `osdy-pi-spider-man-classic`, `osdy-pi-miles-morales`, `osdy-pi-spider-verse`, or another name below.
|
|
274
294
|
|
|
275
295
|
| Theme | Use |
|
|
@@ -354,7 +374,8 @@ The enabled state, editor mode, working-tree visibility preference, header, and
|
|
|
354
374
|
| Main | `/osdy-pi` |
|
|
355
375
|
| Main | `/osdy-pi enable\|disable\|on\|off\|status` |
|
|
356
376
|
| Accounts | `/osdy-account` |
|
|
357
|
-
|
|
|
377
|
+
| TODO selection | `/osdy-pi todo on\|off\|status` |
|
|
378
|
+
| Session TODO (opt-in, starting in 1.5.0) | `/todos` (read-only) |
|
|
358
379
|
| Header | `/osdy-pi header osdy-theme\|neon\|status` |
|
|
359
380
|
| Mascot | `/osdy-pi mascot current\|bts\|status` |
|
|
360
381
|
| Editor | `/osdy-pi editor auto\|extended\|simple\|on\|off\|toggle\|status` |
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Assistant marker artwork
|
|
2
|
+
|
|
3
|
+
`assistant-mascot.png` is the landing's raccoon, exported as a transparent 360 × 350 RGBA PNG. It is not the unrelated package cover image.
|
|
4
|
+
|
|
5
|
+
## Reproduce
|
|
6
|
+
|
|
7
|
+
With the existing landing dependencies and Chromium installed, run from Osdy-Pi:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
node extensions/osdy-pi/assets/assistant-mascot-export.mjs /path/to/osdy-pi-landing
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The exporter reads the landing without modifying it and writes only the adjacent SVG and PNG. No runtime browser or font dependency is added.
|
|
14
|
+
|
|
15
|
+
## Fidelity and origin
|
|
16
|
+
|
|
17
|
+
- Source: `osdy-pi-landing/src/components/Mascot.tsx` and `src/data/mascot.ts`, adapted from Osdy-Pi's `HTML_MASCOT`, map, and tones. Artwork: MIT, Copyright (c) 2026 Osdy.
|
|
18
|
+
- Geometry: original 360 × 350 viewBox, 6px character pitch, 10px row pitch, 9px first baseline, and last-three-occupied-character edge selection.
|
|
19
|
+
- Font: landing's `@fontsource/jetbrains-mono` Latin normal 400 WOFF2, loaded into the export page only; Chromium waits for the font before capture. The retained SVG references the font family but does not redistribute font bytes. JetBrains Mono is licensed under SIL OFL 1.1 (see the installed font package's LICENSE).
|
|
20
|
+
- Palette: body `#F9F7F2`, `#F0E5D7`, `#C7B4A1`, `#7D6F67`, `#2A2321`; edge p/c/v `#22d3ee`/`#a78bfa`/`#67e8f9`. These resolve the default landing theme (`themes[0]`, Osdy Pi New). Alternate landing themes can have pink edges; this fixed asset intentionally preserves the default, not all theme variants.
|
|
21
|
+
- Generated artifacts: SVG source and PNG, captured headlessly with Playwright Chromium at device scale 1 and no background.
|
|
22
|
+
|
|
23
|
+
## Terminal boundary
|
|
24
|
+
|
|
25
|
+
The assistant marker uses Pi's real `Image`, at most 3 columns × 2 rows. At default 9 × 18 pixel cells it reserves 3 × 1 on Kitty and 3 × 2 on iTerm2. iTerm2 sends `height=auto`, so width is additionally bounded using current cell geometry. Narrow widths down to 2 columns remain safe; invalid widths render an empty row.
|
|
26
|
+
|
|
27
|
+
PNG preview was inspected. Automated protocol tests are not a live Kitty/iTerm2 visual check; legibility at tiny terminal size still requires the user's trial. Emoji fallback and stored marker lifecycle are unchanged.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/* global document */
|
|
2
|
+
import process from 'node:process';
|
|
3
|
+
import { Buffer } from 'node:buffer';
|
|
4
|
+
import { URL } from 'node:url';
|
|
5
|
+
import console from 'node:console';
|
|
6
|
+
// Run: node extensions/osdy-pi/assets/assistant-mascot-export.mjs /path/to/osdy-pi-landing
|
|
7
|
+
// Uses existing landing dependencies only; writes only the adjacent SVG and PNG.
|
|
8
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
9
|
+
import { createRequire } from 'node:module';
|
|
10
|
+
import { resolve } from 'node:path';
|
|
11
|
+
import ts from 'typescript';
|
|
12
|
+
|
|
13
|
+
const landing = resolve(process.argv[2]);
|
|
14
|
+
const require = createRequire(`${landing}/package.json`);
|
|
15
|
+
const { chromium } = require('@playwright/test');
|
|
16
|
+
const source = readFileSync(`${landing}/src/data/mascot.ts`, 'utf8');
|
|
17
|
+
const compiled = ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.ESNext } }).outputText;
|
|
18
|
+
const { mascot, toneMap, mascotColors } = await import(`data:text/javascript;base64,${Buffer.from(compiled).toString('base64')}`);
|
|
19
|
+
// Default landing theme: themes[0], Osdy Pi New. Resolve CSS variables explicitly.
|
|
20
|
+
const colors = { ...mascotColors, p: '#22d3ee', c: '#a78bfa', v: '#67e8f9' };
|
|
21
|
+
const font = readFileSync(`${landing}/node_modules/@fontsource/jetbrains-mono/files/jetbrains-mono-latin-400-normal.woff2`).toString('base64');
|
|
22
|
+
const rows = mascot.map((row, y) => {
|
|
23
|
+
const edges = [...row].map((ch, x) => ch === ' ' ? -1 : x).filter(x => x >= 0).reverse().slice(0, 3);
|
|
24
|
+
const spans = [...row].map((ch, x) => {
|
|
25
|
+
const edge = edges.indexOf(x);
|
|
26
|
+
const tone = edge >= 0 ? ['p', 'c', 'v'][edge] : toneMap[y]?.[x];
|
|
27
|
+
return `<tspan x="${x * 6}" fill="${colors[tone] ?? colors.m}">${ch}</tspan>`;
|
|
28
|
+
}).join('');
|
|
29
|
+
return `<text y="${y * 10 + 9}" font-family="JetBrains Mono, monospace" font-size="10" xml:space="preserve">${spans}</text>`;
|
|
30
|
+
});
|
|
31
|
+
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="360" height="350" viewBox="0 0 360 350">\n${rows.join('\n')}\n</svg>\n`;
|
|
32
|
+
const browser = await chromium.launch({ headless: true });
|
|
33
|
+
try {
|
|
34
|
+
const page = await browser.newPage({ viewport: { width: 360, height: 350 }, deviceScaleFactor: 1 });
|
|
35
|
+
await page.setContent(`<style>html,body{margin:0;background:transparent}@font-face{font-family:'JetBrains Mono';src:url(data:font/woff2;base64,${font}) format('woff2');font-weight:400}</style>${svg}`);
|
|
36
|
+
await page.evaluate(async () => { await document.fonts.load('10px "JetBrains Mono"'); await document.fonts.ready; });
|
|
37
|
+
if (!await page.evaluate(() => document.fonts.check('10px "JetBrains Mono"'))) throw new Error('Font failed to load');
|
|
38
|
+
writeFileSync(new URL('./assistant-mascot.svg', import.meta.url), svg);
|
|
39
|
+
await page.locator('svg').screenshot({ path: new URL('./assistant-mascot.png', import.meta.url).pathname, omitBackground: true });
|
|
40
|
+
console.log('Exported transparent 360×350 PNG with loaded JetBrains Mono 400 and default landing edge colors.');
|
|
41
|
+
} finally {
|
|
42
|
+
await browser.close();
|
|
43
|
+
}
|
|
Binary file
|