@kadj-amoah/showrunner 1.1.6 → 1.1.8
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/CHANGELOG.md +187 -186
- package/README.md +213 -191
- package/dist/cli.js +149 -19
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +11 -0
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/package.json +85 -85
package/README.md
CHANGED
|
@@ -1,191 +1,213 @@
|
|
|
1
|
-
# Showrunner
|
|
2
|
-
|
|
3
|
-
Automated product demo recording & production tool.
|
|
4
|
-
|
|
5
|
-
Showrunner collapses the demo-video pipeline into a single, repeatable, automatable command. Point it at a running web product, give it a one-page brief, and it produces a finished, captioned MP4 — comprehension, script, recording, voiceover, and mux in one pass.
|
|
6
|
-
|
|
7
|
-
## Status
|
|
8
|
-
|
|
9
|
-
v1.1 — usable end-to-end for short demos. The LLM and TTS layers are provider-agnostic so you can bring your own keys or wire in an in-house pipeline. See `prd_showrunner.md` for the full product spec.
|
|
10
|
-
|
|
11
|
-
## What you need on your machine
|
|
12
|
-
|
|
13
|
-
- **Node ≥ 20.6** (`process.loadEnvFile` is required)
|
|
14
|
-
- **ffmpeg + ffprobe on PATH** (`apt install ffmpeg` on Debian/Ubuntu, `brew install ffmpeg` on macOS, gyan.dev build on Windows)
|
|
15
|
-
- **A Chromium binary** — Playwright installs one for you (`npx playwright install chromium`)
|
|
16
|
-
- **API keys for the providers you pick**, OR a headless CLI agent like `claude -p` (see _Provider choices_ below)
|
|
17
|
-
|
|
18
|
-
Showrunner is built to deploy on Linux but develops fine on WSL2 or macOS.
|
|
19
|
-
|
|
20
|
-
## Install
|
|
21
|
-
|
|
22
|
-
Published to both npmjs.org (zero-friction install) and GitHub Packages (mirrors the GitHub Releases timeline). Pick whichever matches your workflow.
|
|
23
|
-
|
|
24
|
-
Showrunner ships with `playwright-core`, which means **no browsers are downloaded during `npm install`**. You must run the browser-bootstrap step (`npx playwright install chromium`) after install — otherwise the first recording attempt will fail with a "browser binary missing" error from `doctor`.
|
|
25
|
-
|
|
26
|
-
### npx (no install, recommended for first-time use)
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
npx @kadj-amoah/showrunner --version # → 1.1.1
|
|
30
|
-
npx playwright install chromium # required: bootstraps the browser
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Running `showrunner` with no arguments prints a context-aware welcome with the next command to run — from outside a project it suggests `showrunner init`; inside a project root it suggests `showrunner doctor -c demo.yaml`.
|
|
34
|
-
|
|
35
|
-
### Global install (`npm i -g`)
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
npm install -g @kadj-amoah/showrunner
|
|
39
|
-
npx playwright install chromium # required: bootstraps the browser
|
|
40
|
-
showrunner --version # → 1.1.1
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
> **Linux note:** if `npm i -g` needs `sudo`, **do not** run `sudo npx playwright install` afterwards — the browser will land in `/root/.cache/ms-playwright` where your user-mode `showrunner` process can't find it. Run `npx playwright install chromium` as your normal user. (`showrunner doctor` will detect and warn about this case.)
|
|
44
|
-
|
|
45
|
-
### GitHub Packages
|
|
46
|
-
|
|
47
|
-
Requires a one-time `~/.npmrc` setup since GitHub Packages requires auth even for public packages:
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
# Generate a Personal Access Token at github.com/settings/tokens
|
|
51
|
-
# Scope needed: read:packages
|
|
52
|
-
echo "@kadj-amoah:registry=https://npm.pkg.github.com" >> ~/.npmrc
|
|
53
|
-
echo "//npm.pkg.github.com/:_authToken=YOUR_TOKEN_HERE" >> ~/.npmrc
|
|
54
|
-
|
|
55
|
-
npm install -g @kadj-amoah/showrunner
|
|
56
|
-
npx playwright install chromium
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
### Directly from a git tag (no registry at all)
|
|
60
|
-
|
|
61
|
-
```bash
|
|
62
|
-
npm install -g github:kadj-amoah/showrunner#v1.1.1
|
|
63
|
-
npx playwright install chromium
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
### From source
|
|
67
|
-
|
|
68
|
-
```bash
|
|
69
|
-
git clone https://github.com/kadj-amoah/showrunner.git
|
|
70
|
-
cd showrunner
|
|
71
|
-
npm install
|
|
72
|
-
npm run build
|
|
73
|
-
npm link # makes `showrunner` available globally
|
|
74
|
-
npx playwright install chromium
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
Verify any of the above with `showrunner --help`.
|
|
78
|
-
|
|
79
|
-
##
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
|
125
|
-
|
|
126
|
-
| `
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
1
|
+
# Showrunner
|
|
2
|
+
|
|
3
|
+
Automated product demo recording & production tool.
|
|
4
|
+
|
|
5
|
+
Showrunner collapses the demo-video pipeline into a single, repeatable, automatable command. Point it at a running web product, give it a one-page brief, and it produces a finished, captioned MP4 — comprehension, script, recording, voiceover, and mux in one pass.
|
|
6
|
+
|
|
7
|
+
## Status
|
|
8
|
+
|
|
9
|
+
v1.1 — usable end-to-end for short demos. The LLM and TTS layers are provider-agnostic so you can bring your own keys or wire in an in-house pipeline. See `prd_showrunner.md` for the full product spec.
|
|
10
|
+
|
|
11
|
+
## What you need on your machine
|
|
12
|
+
|
|
13
|
+
- **Node ≥ 20.6** (`process.loadEnvFile` is required)
|
|
14
|
+
- **ffmpeg + ffprobe on PATH** (`apt install ffmpeg` on Debian/Ubuntu, `brew install ffmpeg` on macOS, gyan.dev build on Windows)
|
|
15
|
+
- **A Chromium binary** — Playwright installs one for you (`npx playwright install chromium`)
|
|
16
|
+
- **API keys for the providers you pick**, OR a headless CLI agent like `claude -p` (see _Provider choices_ below)
|
|
17
|
+
|
|
18
|
+
Showrunner is built to deploy on Linux but develops fine on WSL2 or macOS.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
Published to both npmjs.org (zero-friction install) and GitHub Packages (mirrors the GitHub Releases timeline). Pick whichever matches your workflow.
|
|
23
|
+
|
|
24
|
+
Showrunner ships with `playwright-core`, which means **no browsers are downloaded during `npm install`**. You must run the browser-bootstrap step (`npx playwright install chromium`) after install — otherwise the first recording attempt will fail with a "browser binary missing" error from `doctor`.
|
|
25
|
+
|
|
26
|
+
### npx (no install, recommended for first-time use)
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx @kadj-amoah/showrunner --version # → 1.1.1
|
|
30
|
+
npx playwright install chromium # required: bootstraps the browser
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Running `showrunner` with no arguments prints a context-aware welcome with the next command to run — from outside a project it suggests `showrunner init`; inside a project root it suggests `showrunner doctor -c demo.yaml`.
|
|
34
|
+
|
|
35
|
+
### Global install (`npm i -g`)
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm install -g @kadj-amoah/showrunner
|
|
39
|
+
npx playwright install chromium # required: bootstraps the browser
|
|
40
|
+
showrunner --version # → 1.1.1
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
> **Linux note:** if `npm i -g` needs `sudo`, **do not** run `sudo npx playwright install` afterwards — the browser will land in `/root/.cache/ms-playwright` where your user-mode `showrunner` process can't find it. Run `npx playwright install chromium` as your normal user. (`showrunner doctor` will detect and warn about this case.)
|
|
44
|
+
|
|
45
|
+
### GitHub Packages
|
|
46
|
+
|
|
47
|
+
Requires a one-time `~/.npmrc` setup since GitHub Packages requires auth even for public packages:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Generate a Personal Access Token at github.com/settings/tokens
|
|
51
|
+
# Scope needed: read:packages
|
|
52
|
+
echo "@kadj-amoah:registry=https://npm.pkg.github.com" >> ~/.npmrc
|
|
53
|
+
echo "//npm.pkg.github.com/:_authToken=YOUR_TOKEN_HERE" >> ~/.npmrc
|
|
54
|
+
|
|
55
|
+
npm install -g @kadj-amoah/showrunner
|
|
56
|
+
npx playwright install chromium
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Directly from a git tag (no registry at all)
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm install -g github:kadj-amoah/showrunner#v1.1.1
|
|
63
|
+
npx playwright install chromium
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### From source
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
git clone https://github.com/kadj-amoah/showrunner.git
|
|
70
|
+
cd showrunner
|
|
71
|
+
npm install
|
|
72
|
+
npm run build
|
|
73
|
+
npm link # makes `showrunner` available globally
|
|
74
|
+
npx playwright install chromium
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Verify any of the above with `showrunner --help`.
|
|
78
|
+
|
|
79
|
+
## After installing: run the doctor first
|
|
80
|
+
|
|
81
|
+
Before doing anything else, run a system check. This catches missing prerequisites (ffmpeg, ffprobe, the recording browser) before they bite you mid-pipeline:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
showrunner doctor # no -c flag yet — this is the system-only pass
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
If it flags anything missing, fix it now. The most common gaps are `ffmpeg` (install via your OS package manager: `apt`, `pacman`, `dnf`, `brew`, or `winget`) and the recording browser (`showrunner install-browser`).
|
|
88
|
+
|
|
89
|
+
## First demo in six commands
|
|
90
|
+
|
|
91
|
+
**Step 1 is the one most people get wrong: `cd` into the root of the product you want to demo *before* running `init`.** The scaffold creates a `showrunner-demo/` directory inside your current location, and several things in `demo.yaml` (`recording.target_url`, `project.codebase_root`, lifecycle scripts) are wired up assuming the parent directory is your product's root. If you run `init` from a random location (your home directory, `~/Downloads`, etc.), the resulting project will target nothing and you'll get a reel about an empty directory.
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# 1. Navigate to your product's root directory — the same place your package.json / pyproject.toml / etc. lives.
|
|
95
|
+
cd ~/my-product
|
|
96
|
+
|
|
97
|
+
# 2. Scaffold the demo project (creates ./showrunner-demo/ inside your product).
|
|
98
|
+
# `init` is interactive by default — it'll prompt for provider keys, target URL, etc.
|
|
99
|
+
showrunner init
|
|
100
|
+
|
|
101
|
+
# 3. Move into the scaffold and finish setup. The wizard already wrote .env if you pasted keys.
|
|
102
|
+
cd showrunner-demo
|
|
103
|
+
$EDITOR docs/PRD.md # replace the stub with your product brief
|
|
104
|
+
|
|
105
|
+
# 4. Full preflight (now with project context — ~11–12 PASS/FAIL rows).
|
|
106
|
+
showrunner doctor -c demo.yaml
|
|
107
|
+
|
|
108
|
+
# 5. Run the pipeline.
|
|
109
|
+
showrunner run -c demo.yaml
|
|
110
|
+
open output/demo_final.mp4
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
If you'd rather not write a PRD upfront, swap the `$EDITOR` step for `showrunner understand -c demo.yaml --interactive` — it asks five questions and produces the product model on the spot.
|
|
114
|
+
|
|
115
|
+
## Provider choices
|
|
116
|
+
|
|
117
|
+
The two generative stages (LLM for comprehension + script, TTS for voiceover) are pluggable. Pick them at scaffold time with `--llm-provider` and `--tts-provider`, or edit the `llm` and `voiceover.provider` blocks in `demo.yaml` later.
|
|
118
|
+
|
|
119
|
+
### LLM (`llm.default.provider`)
|
|
120
|
+
|
|
121
|
+
| Provider | Needs | Notes |
|
|
122
|
+
|----------------|--------------------------------------------|-----------------------------------------------------------------------------|
|
|
123
|
+
| `anthropic` | `ANTHROPIC_API_KEY` | Default. Uses Claude with structured outputs. |
|
|
124
|
+
| `openai` | `OPENAI_API_KEY` | Uses `response_format: json_schema`, falls back to `json_object` if needed. |
|
|
125
|
+
| `agent_bridge` | A headless CLI agent on PATH (default `claude -p --output-format json`) | No API key on file — Showrunner spawns the agent per request. |
|
|
126
|
+
| `custom` | A dynamic-importable module | Implement the `LLMProvider` interface. |
|
|
127
|
+
|
|
128
|
+
Per-stage overrides are supported under `llm.overrides.{comprehension,script,instrument}` so you can, e.g., use `agent_bridge` for the heavy script generation and `anthropic` for the small `instrument` calls.
|
|
129
|
+
|
|
130
|
+
### TTS (`voiceover.provider.name`)
|
|
131
|
+
|
|
132
|
+
| Provider | Needs | Alignment? | Default `alignment_strategy` |
|
|
133
|
+
|--------------|------------------------|------------|------------------------------|
|
|
134
|
+
| `elevenlabs` | `ELEVENLABS_API_KEY` | ✅ | `required` |
|
|
135
|
+
| `openai` | `OPENAI_API_KEY` | ❌ | `best_effort` |
|
|
136
|
+
| `custom` | A dynamic-import module| Your call | `best_effort` |
|
|
137
|
+
|
|
138
|
+
Only ElevenLabs returns per-character alignment. With other providers, Showrunner takes the **best-effort path**: one synthesis call per segment (no slicing), captions collapse to whole-segment cues, and `at_word` action timing degrades to `at`. Set `voiceover.alignment_strategy: required` if you want it to fail loudly instead.
|
|
139
|
+
|
|
140
|
+
## Pipeline
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
comprehension → script → record + voiceover → mux → demo_final.mp4
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
| Stage | What it does | Inputs | Outputs |
|
|
147
|
+
|-----------------|----------------------------------------------------------------------------------------------------|-----------------------------------------|---------------------------------------------------------|
|
|
148
|
+
| `comprehension` | Reads `docs/`, an optional codebase, or runs the interactive Q&A. Emits `product_model.json`. | `docs/PRD.md` (or `--interactive`) | `product_model.json` |
|
|
149
|
+
| `script` | Scrapes the live target's actionable DOM, then asks the LLM for a manifest using only those selectors. | `product_model.json` + live target URL | `scripts/manifest.json`, `vo_script.txt`, Playwright spec |
|
|
150
|
+
| `record` | Drives Playwright through the manifest, captures `master.webm` + a slice plan. | manifest, dev server | `segments/video/master.webm`, `slice_plan.json` |
|
|
151
|
+
| `voiceover` | TTS for the whole script, slices per segment, writes alignment files (when supported). | manifest | `segments/audio/*.mp3`, `segments/alignment/*.json` |
|
|
152
|
+
| `mux` | Normalizes, slices, branding cards, background music, captions. Outputs the MP4. | video + audio + alignment | `output/demo_final.mp4` (+ `.srt`/`.vtt` if enabled) |
|
|
153
|
+
|
|
154
|
+
Stages are independently runnable, checkpointed, and idempotent. Existing artifacts are never silently overwritten — use `--force <stage>[,<stage>]` to regenerate.
|
|
155
|
+
|
|
156
|
+
## Daily commands
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# preflight — catches missing keys, ffmpeg, dev server down, free disk, RAM cap
|
|
160
|
+
showrunner doctor -c demo.yaml
|
|
161
|
+
|
|
162
|
+
# generate (or refresh) product_model.json from docs/PRD.md
|
|
163
|
+
showrunner understand -c demo.yaml
|
|
164
|
+
showrunner understand -c demo.yaml --interactive # 5-question fallback
|
|
165
|
+
|
|
166
|
+
# full pipeline (`--skip-doctor` to bypass the implicit preflight)
|
|
167
|
+
showrunner run -c demo.yaml
|
|
168
|
+
|
|
169
|
+
# re-run just one stage
|
|
170
|
+
showrunner run -c demo.yaml --stages script
|
|
171
|
+
showrunner run -c demo.yaml --force voiceover,mux # regen, don't reuse
|
|
172
|
+
|
|
173
|
+
# the LLM's selectors are wrong for one segment — demo it yourself
|
|
174
|
+
showrunner record-actions -c demo.yaml --segment fill-form
|
|
175
|
+
|
|
176
|
+
# preview the manifest in Playwright UI Mode (no recording)
|
|
177
|
+
showrunner preview -c demo.yaml
|
|
178
|
+
|
|
179
|
+
# inspect a failed take
|
|
180
|
+
showrunner trace -c demo.yaml --segment <id>
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## When things go wrong
|
|
184
|
+
|
|
185
|
+
- **`x264 malloc failed` during mux** — out of RAM. The `doctor` row "free memory: … (ffmpeg thread cap: N)" shows what was budgeted. Drop resolution to 1280x720 (or 854x480 for draft), set `SHOWRUNNER_FFMPEG_THREADS=1`, or close Docker / browsers.
|
|
186
|
+
- **Recording fails because a selector doesn't resolve** — usually the LLM picked something fragile. The `script` stage's DOM preflight is supposed to prevent this; if it does happen, run `showrunner record-actions -c demo.yaml --segment <id>` and demonstrate the interaction yourself.
|
|
187
|
+
- **`vo_review_gate` halted the pipeline** — by design. Edit `scripts/vo_script.txt`, then `showrunner approve-vo -c demo.yaml`. (The init scaffold ships with this off — you have to opt in via `script.vo_review_gate: true`.)
|
|
188
|
+
- **Output file is locked by a media player** — close VLC/QuickTime/your-browser-tab. Showrunner falls back to writing a timestamped sibling MP4 with a warning, but the canonical path needs the lock released.
|
|
189
|
+
- **DOM preflight failed** — your dev server isn't on the URL in `demo.yaml`, or it's behind auth. Bring the server up, configure `recording.auth` for session/form/setup-script flows.
|
|
190
|
+
- **Playwright warns "your OS is not officially supported"** — on Arch / CachyOS / Fedora during `npx playwright install`. Safe to ignore; Playwright falls back to the Ubuntu 24.04 build, which works fine.
|
|
191
|
+
- **`browser binary missing` even though I ran `npx playwright install`** — you likely ran the install under `sudo`, so the browser is in the root cache. Re-run as your normal user: `npx playwright install chromium`. `showrunner doctor` detects this and prints the specific cache it found the browser in.
|
|
192
|
+
|
|
193
|
+
## Configuration reference
|
|
194
|
+
|
|
195
|
+
`demo.yaml` is the single source of truth. Sections:
|
|
196
|
+
|
|
197
|
+
- `project` — name and optional `product_model` path
|
|
198
|
+
- `comprehension` — `mode` + `sources` (PRD, README, codebase, OpenAPI, etc.)
|
|
199
|
+
- `script` — `style`, `duration_target_seconds`, `highlight_features`, `vo_review_gate`
|
|
200
|
+
- `recording` — `target_url`, viewport, browser, cursor + segment timing knobs, auth, lifecycle scripts
|
|
201
|
+
- `voiceover` — `provider` (discriminated by `name`), `alignment_strategy`, output dirs, drift behavior, pause placement
|
|
202
|
+
- `llm` — `default` provider + per-stage `overrides` (comprehension, script, instrument)
|
|
203
|
+
- `output` — resolution, fps, branding cards, background music, captions, output path
|
|
204
|
+
|
|
205
|
+
Legacy v1.0 configs (flat `voiceover.voice_id`, no `llm` block) are auto-migrated by the loader — your existing demos keep working without edits.
|
|
206
|
+
|
|
207
|
+
## Deployment target
|
|
208
|
+
|
|
209
|
+
Linux. Local dev runs on WSL2/Docker on Windows or macOS hosts. A Docker image bundling Node 20, Playwright (Chromium), FFmpeg, and `xvfb` is on the roadmap.
|
|
210
|
+
|
|
211
|
+
## License
|
|
212
|
+
|
|
213
|
+
MIT
|