@nolit/dsh-notify 0.0.0-stage → 0.0.1-rc.4

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +445 -0
  2. package/LICENSE +21 -0
  3. package/PROVENANCE.md +96 -0
  4. package/README.md +331 -2
  5. package/cordis.patch.yml +19 -0
  6. package/docs/2026-10-20-dsh-notify-design.md +335 -0
  7. package/docs/2026-10-20-final-status.md +125 -0
  8. package/docs/2026-10-23-asset-policy.md +170 -0
  9. package/docs/2026-10-23-deployment-strategy-review.md +530 -0
  10. package/docs/2026-10-23-headless-nonintrusive-ui-architecture.md +579 -0
  11. package/docs/2026-10-23-hybrid-dual-mode-design.md +955 -0
  12. package/docs/2026-10-23-timezone-global-report.md +204 -0
  13. package/docs/2026-10-23-web-notify-plugin-spec.md +454 -0
  14. package/docs/2026-10-23-web-plugin-mount.md +111 -0
  15. package/docs/2026-10-23-windows-widget-poc-report.md +312 -0
  16. package/docs/2026-10-24-linux-desktop-verification.md +134 -0
  17. package/docs/BOOT-CARD.md +176 -0
  18. package/docs/RECOVERY-NOTES.md +111 -0
  19. package/docs/WORK-PROTOCOL.md +155 -0
  20. package/docs/deepseek-peak-spec.md +370 -0
  21. package/docs/dsh-harness-notify-spec.md +149 -0
  22. package/icon.svg +6 -0
  23. package/lib/client.js +2175 -0
  24. package/lib/client.src.js +1966 -0
  25. package/lib/index.js +13 -0
  26. package/lib/locale-table.js +215 -0
  27. package/locale/en.json +104 -0
  28. package/locale/ko.json +104 -0
  29. package/market/icons/dsh-notify.svg +6 -0
  30. package/market/index.json +77 -0
  31. package/package.json +80 -4
  32. package/scripts/build-client.mjs +41 -0
  33. package/scripts/gen-locale.mjs +36 -0
  34. package/test/client.test.mjs +601 -0
  35. package/test/locale.test.mjs +114 -0
  36. package/test/manifest.test.mjs +115 -0
  37. package/test/peak.test.mjs +370 -0
  38. package/test/typography.test.mjs +85 -0
package/README.md CHANGED
@@ -1,3 +1,332 @@
1
- # Temporary Holding Version
1
+ # Notify for Chrome
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ <!-- skeleton:
4
+ version: 2.0
5
+ kind: readme
6
+ status: active
7
+ updated: 2026-11-05
8
+ summary: Operator manual and behavior contract for Notify for Chrome (Korean: 알림 for 크롬) — Chrome/Web Notification only, silent in-app toast fallback, native DSH settings rows and typography, Windows/install-mode notification branches.
9
+ -->
10
+
11
+ > Status: active · Updated: 2026-11-07 · Package: `@nolit/dsh-notify` v`0.0.1-rc.4` · Korean display name: **알림 for 크롬** · Parent: `README.md` in the `dsh-plugins` workspace
12
+
13
+ **Notify for Chrome** turns DeepSeek Harness events into **Chrome notifications** (the Web
14
+ Notification API, `new Notification(...)`). It has no native app, no ports, no IPC, no file queue
15
+ and no system notifier. When Chrome cannot show a notification, the plugin falls back to a
16
+ **silent in-app toast**.
17
+
18
+ ## 0. Version numbering — why `0.0.1-rc.4` is not lower than `0.2.1`
19
+
20
+ The version number went **down** against this project's own history, on purpose. Two separate
21
+ facts explain it, and until 2026-11-06 neither was written down anywhere.
22
+
23
+ **`0.2.x` was never this plugin's version.** The `v0.2.0` and `v0.2.1` releases belonged to the
24
+ **Windows PowerShell/WPF prototype** (a tray widget polling the DeepSeek billing window). The
25
+ browser plugin lived inside that repository under `plugin/` and happened to carry the same
26
+ number — by accident, not by design.
27
+
28
+ **The `@nolit` ladder was reset by owner decision on 2026-11-05.** Every `@nolit` package moved
29
+ to one scheme, `0.0.1-rc.N`, in which only the `rc#` moves. `0.1.8` and `0.2.1` are not
30
+ milestones under that scheme; the scheme replaced them.
31
+
32
+ | Surface | Before | After |
33
+ | :--- | :--- | :--- |
34
+ | Version scheme | per-track, drifting (`0.1.6 → 0.1.7 → 0.1.8 → 0.2.1`) | **`0.0.1-rc.N`** |
35
+ | Package | `@nolit/dsh-notify-web` @ `0.2.1`, nested in `plugin/` | **`@nolit/dsh-notify`** @ `0.0.1-rc.4`, repository root |
36
+ | Repository | Windows prototype at root | plugin at root, prototype preserved in `prototype-windows/` |
37
+
38
+ The `-web` suffix came from the 2026-10-24 recovery and was never the owner's choice;
39
+ `PROVENANCE.md` documented the package as `@nolit/dsh-notify` the entire time while the files
40
+ said `-web`. The rename landed in `0.0.1-rc.3`; `0.0.1-rc.4` is the corrected build.
41
+
42
+ Version numbers are the owner's decision. An agent must not choose, bump or "stabilise" one.
43
+
44
+ ## 1. Behavior
45
+
46
+ | DSH event | Channel |
47
+ |---|---|
48
+ | `api-session/status` (`running=false`) | Chrome notification "Turn complete", root sessions only, 5 s cooldown |
49
+ | `api-session/error` | Chrome notification "Turn failed", message truncated to 160 chars |
50
+ | `approval/request` | Chrome notification "Approval needed"; `next()` passes through immediately |
51
+ | `user-questions/request` | Chrome notification "Question waiting"; `next()` passes through immediately |
52
+
53
+ - **Chrome first.** The plugin calls the Notification API. A granted permission and a secure
54
+ context are the only prerequisites.
55
+ - **Silent toast fallback.** If the permission is denied/pending, the origin is not a secure
56
+ context, the Notification API is unavailable, or the constructor/`onerror` fails, the event is
57
+ shown as the **native DSH toast** and nothing else. There is no sound, no second notification
58
+ channel, and no title-bar marker.
59
+ - **One tab delivers.** Multiple tabs elect a leader (Web Locks, localStorage lease fallback) so an
60
+ event is not announced once per tab. A focused tab always delivers.
61
+ - **No sound engine.** The plugin never synthesizes audio, never ships or stores audio, and never
62
+ uses `<audio>`/Web Audio/IndexedDB. When the OS notification has a sound, it is the **operating
63
+ system's own** notification sound.
64
+
65
+ ## 2. Windows and install-environment behavior
66
+
67
+ **Which OS does the environment card report?** The **browser's** OS — the machine running the tab
68
+ that shows the notification — not the OS running the `dsh` host process. The two are independent:
69
+ a Windows Chrome can be pointed at a DSH server on Linux (the default remote setup), and the
70
+ notification rules that matter (Action Center persistence, `requireInteraction` support, the
71
+ installed-app branch) are properties of the browser's OS.
72
+
73
+ The sensitivity is per-platform, measured:
74
+
75
+ | Browser OS | Installed app | Behaviour |
76
+ |---|---|---|
77
+ | Windows | yes | `requireInteraction: true` for every kind; the app window and Action Center keep them |
78
+ | Windows | no | `requireInteraction` follows the setting, approval/question only |
79
+ | Linux | either | same as the Windows browser tab |
80
+ | macOS | either | `requireInteraction` is not honoured by Chrome, so it stays `false` |
81
+ | Android / other | either | `silent: false`, unique `tag`; no persistence |
82
+
83
+ Because a value like "Windows" next to a Linux host looks wrong, the row is labelled
84
+ **Browser OS** (브라우저 OS) and carries that explanation inline.
85
+
86
+ The Chrome notification parameters branch on the **runtime platform** and the **install mode**.
87
+ Platform detection order: DSH's `document.documentElement.dataset.platform` (the native shell sets
88
+ it; native code also tests it for `darwin`), then `navigator.userAgentData.platform`, then
89
+ `navigator.platform`, then `navigator.userAgent`. Install mode is `installed` when the page runs in
90
+ a standalone/minimal-ui/fullscreen display mode (or `navigator.standalone`), otherwise `browser`.
91
+
92
+ | Environment | `requireInteraction` | `silent` | `tag` |
93
+ |---|---|---|---|
94
+ | **Windows, installed app** | `true` for every kind — the Action Center keeps the alert while the app window is minimized, so a completion cannot be auto-dismissed | `false` (the OS plays the sound) | unique per event |
95
+ | **Windows, browser tab** | follows the "Keep approval alerts open" setting; approval/question only | `false` | unique per event |
96
+ | **macOS** | `false` — Chrome does not honour `requireInteraction`, so claiming it would misrepresent the behavior | `false` | unique per event |
97
+ | **Linux / other** | follows the setting; approval/question only | `false` | unique per event |
98
+
99
+ - **Why a unique tag on Windows:** Windows replaces an existing notification that reuses a `tag`,
100
+ which silently drops repeated events. Every event gets a fresh tag so completions accumulate in
101
+ the Action Center instead of being replaced.
102
+ - **Permission guidance is platform-specific:** a Windows profile points at Chrome's site settings
103
+ and **Windows Settings → System → Notifications**; other platforms point at the browser's site
104
+ settings. The guidance is shown next to the status row and is the only place a blocked
105
+ permission is explained.
106
+ - Nothing else is Windows-specific: event filtering, cooldowns, tab leadership, locale and the
107
+ toast fallback are generic.
108
+
109
+ ## 3. Install
110
+
111
+ The package name stays `@nolit/dsh-notify`; only the **display identity** changed to
112
+ "Notify for Chrome" / "알림 for 크롬". Renaming the npm package would break the live profile's
113
+ `link:` dependency.
114
+
115
+ Local checkout (the live profile already links it):
116
+
117
+ ```bash
118
+ dsh plugin --profile web add "link:/path/to/dsh-plugins/dsh-notify"
119
+ ```
120
+
121
+ From npm after publishing:
122
+
123
+ ```bash
124
+ dsh plugin --profile web add @nolit/dsh-notify
125
+ ```
126
+
127
+ The package must be listed in the profile's `dsh.profile.bundles`. Reload the DSH page after
128
+ installing. If `lib/client.js` has a syntax error only this plugin is disabled; the DSH core keeps
129
+ working.
130
+
131
+ ## 4. Settings
132
+
133
+ **Settings → Notify for Chrome** (English; the label is **알림 for 크롬** when the host locale is
134
+ Korean) renders native DSH settings surfaces only:
135
+
136
+ - a native `Tag` for the Chrome-notification status, native `Button` actions, native `Switch`
137
+ toggles and a native `Input` for the cooldown;
138
+ - the section navigation icon is a **DSH icon** (`IconAlarmClockOutlineRegular`), registered through
139
+ `settings.section.icon`; the plugin ships no icon set of its own;
140
+ - typography comes from the live DSH tokens `--dsh-content-font-size` /
141
+ `--dsh-content-font-size-secondary` and their `--dsh-content-font-delta*` line-height deltas;
142
+ colours and surfaces come from `--dsw-*` tokens. The plugin **injects no stylesheet**, sets **no
143
+ font-family** and hardcodes **no pixel font size**.
144
+
145
+ The page is grouped into four cards. The two owner-requested categories (2026-11-06) are the
146
+ **DeepSeek peak timer** and **notifications**, in that order.
147
+
148
+ **알림 조건 (notification rows)**
149
+
150
+ | Row | Default | Meaning |
151
+ |---|---|---|
152
+ | Turn complete / Approval needed / Question waiting / Turn error | on | which events notify |
153
+ | Include subagents | off | also notify for subagent complete/error |
154
+ | Hide completion alerts while focused | off | suppress completion while the DSH tab is focused |
155
+ | Keep approval alerts open | on | `requireInteraction` for approval/question where supported (Windows/Linux) |
156
+ | Completion cooldown | 5 s | per-session grouping window |
157
+
158
+ **딥시크 피크 타이머 (peak timer rows)**
159
+
160
+ | Row | Default | Meaning |
161
+ |---|---|---|
162
+ | Show peak countdown chip | on | 7-segment `HH:MM:SS` chip in the Session header: green off-peak, red at peak |
163
+ | Announce peak changes | on | Chrome notification + `setAppBadge` when the billing window flips |
164
+ | Show timer on other providers | **off** | also render the chip when the active route is *not* an official DeepSeek route |
165
+
166
+ ### The peak timer only trusts official DeepSeek routes by default
167
+
168
+ The peak/off-peak clock is a property of **DeepSeek's own API billing**
169
+ ([pricing footnote](https://api-docs.deepseek.com/quick_start/pricing)). DeepSeek publishes the
170
+ off-peak discount for its own API; **a different service serving the same model may bill
171
+ differently**, so the timer is a *reference*, not a fact, on any other route.
172
+
173
+ The plugin therefore gates on the **provider id**, never on a model name:
174
+
175
+ | Route | Chip by default |
176
+ |---|---|
177
+ | `deepseek-official` (official API-key route) | shown |
178
+ | `deepseek-account` (official account route) | shown |
179
+ | everything else (OpenCode, DeepInfra, Antigravity, any proxy/gateway) | **hidden** |
180
+
181
+ Those two ids are the ones the official DSH packages register. **Provider ids differ between
182
+ installations** — if your setup exposes the official DeepSeek route under a different id, turn on
183
+ **Show timer on other providers** and the chip appears on every route. The default stays
184
+ conservative because a wrong "50% off" claim is worse than a hidden widget.
185
+
186
+ The live selection is read from `[data-provider-id][data-model-id]` on the model selector trigger,
187
+ which is the same path DeepInfra's cost chip uses. Nothing is guessed from the model name.
188
+
189
+ The settings card carries the caveat inline, in the owner's wording (2026-11-06):
190
+
191
+ > 딥시크는 공식 모델 API에 대해서만 할인을 명시합니다. 같은 모델이라도 다른 제공자는 서비스 요금이
192
+ > 다를 수 있으며 보장하지 않습니다. 그 경우 이 타이머는 참고 사항일 뿐입니다.
193
+ >
194
+ > *DeepSeek states this discount only for its official model API. A different provider may charge
195
+ > differently for the same model, and that is not guaranteed. In that case this timer is a reference
196
+ > only.*
197
+
198
+ Preferences persist in the browser's `localStorage` under `dsh-notify-web:settings` (version 2).
199
+ They are browser preferences, not Host configuration: the plugin's Host half is intentionally a
200
+ no-op and exposes no settings namespace. No audio file is read, stored or referenced.
201
+
202
+ Guidance rules:
203
+
204
+ - **Permission pending** → the Enable button is shown.
205
+ - **Denied / insecure / unsupported** → the Enable button is **hidden** (a capability that is gone
206
+ is not shown as a broken control); the row explains what to change, and the test action still
207
+ exercises the toast fallback.
208
+
209
+ ## 5. Localization
210
+
211
+ English is the default. Korean is used **only** while the host locale (`ctx.locale.active`) is
212
+ Korean; a locale change switches the next notification and the settings strings live.
213
+
214
+ - Source of truth: [`locale/en.json`](locale/en.json) and [`locale/ko.json`](locale/ko.json).
215
+ - `scripts/gen-locale.mjs` bakes them into `lib/locale-table.js`; `scripts/build-client.mjs` inlines
216
+ that table into `lib/client.js` (the browser loader cannot import JSON).
217
+ - No hardcoded Korean exists outside the baked dictionary (a test enforces this).
218
+ - Display identity: English **Notify for Chrome**, Korean **알림 for 크롬**.
219
+
220
+ ## 6. Limitations
221
+
222
+ ### Browser support — Chrome / Chromium required
223
+
224
+ The plugin is built for **Chrome and Chromium-based browsers** (Edge, Brave, Opera, Vivaldi, Arc).
225
+ Those are the engines where the whole surface below exists at once. **On any other browser, correct
226
+ operation is not guaranteed and is not tested.**
227
+
228
+ | Capability | Chrome / Chromium | Firefox | Safari |
229
+ |---|---|---|---|
230
+ | `new Notification()` | yes | yes | 16+ only |
231
+ | `badge` / `setAppBadge` | 81+ | no (falls back silently) | no |
232
+ | `navigator.locks` (tab leader) | 69+ | yes | no (localStorage lease fallback) |
233
+ | `requireInteraction` | Windows/Linux | **ignored** | **ignored** |
234
+ | Installed-app notification branch | yes | n/a | n/a |
235
+
236
+ **The plugin does not detect the browser.** It feature-detects (`Notification`, `isSecureContext`,
237
+ `navigator.locks`, `setAppBadge`) and degrades, but it never claims a browser is supported just
238
+ because it is not Chrome. A non-Chromium browser may look functional while behaving differently —
239
+ for example Firefox accepts `requireInteraction` and ignores it, so an approval alert auto-dismisses
240
+ even though the setting is on.
241
+
242
+ Recommended minimum: **Chrome 81+** (when `setAppBadge` landed; everything else the plugin uses is
243
+ older). Older Chrome still works, minus the badge channel.
244
+
245
+ ### Security constraints that can stop a notification appearing
246
+
247
+ These are browser/OS security rules, not plugin bugs. Each one degrades to the **silent in-app
248
+ toast** rather than failing loudly, which is why the toast fallback exists.
249
+
250
+ | Constraint | What the user sees | Measured behaviour |
251
+ |---|---|---|
252
+ | **Permission not granted** (`default`) | nothing from the OS | `new Notification(...)` **does not throw** — it looks successful and shows nothing. The plugin checks `Notification.permission === 'granted'` *before* constructing, so it routes to the toast instead. |
253
+ | **Permission blocked** (`denied`) | nothing, and no prompt returns | `requestPermission()` resolves `'denied'` immediately; Chrome will not prompt again for the origin. Only the user can undo it in site settings. The plugin hides the Enable button, because a control that cannot work is not shown as a broken one. |
254
+ | **Insecure origin** | nothing | `http://<LAN-IP>:3080` is not a secure context; Chrome refuses OS notifications. Use `https://` or `localhost`. Reported as `insecure`. A self-signed certificate needs to be trusted once in the browser; do **not** browse with certificate errors bypassed — notifications and the peak timer need a genuinely secure context. |
255
+ | **No user gesture** | prompt never appears | `requestPermission()` needs a click. A call on page load is auto-denied; the plugin drives it from the Enable button only. |
256
+ | **OS Do Not Disturb** / Focus Assist | nothing, or a silent banner | The OS owns this; the page cannot override it and cannot detect it. |
257
+ | **Browser-level site mute** | nothing | Silent skip at the Chrome layer; indistinguishable from a delivered notification. |
258
+ | **Tab closed** | nothing | No service-worker backend, so no delivery once the DSH tab is gone. |
259
+
260
+ - Notifications work **only while the DSH tab is open**. There is no service-worker push backend.
261
+ - Background-tab throttling, browser notification policy and OS Focus Assist / Do Not Disturb can
262
+ change what is shown.
263
+ - Approval/question notifications do not replace the DSH approval UI; the event handler passes
264
+ `next()` through immediately.
265
+
266
+ ## 7. Privacy
267
+
268
+ - No `XMLHttpRequest`, `WebSocket`, `EventSource` or local port; no filesystem access.
269
+ - **One network request**: the peak timer fetches the Chinese public-holiday list from
270
+ `raw.githubusercontent.com/NateScarlet/holiday-cn`. Nothing is sent but the request itself — no
271
+ prompt, code, session title, token or identifier. The response is cached in `localStorage` for 10
272
+ days. Disable **Show peak countdown chip** and the request never happens.
273
+ - The only storage is the settings object, the tab-leader lease key and that holiday cache, all in
274
+ `localStorage`.
275
+ - Notification bodies are fixed copy plus the session title (80 chars max); prompts, code and tool
276
+ arguments are never included.
277
+ - Notification clicks only focus the DSH tab; no external link is opened.
278
+
279
+ ## 8. Development
280
+
281
+ ```bash
282
+ cd dsh-notify
283
+ npm test # pretest runs gen-locale + build-client, then node --test
284
+ npm run build # regenerate lib/locale-table.js and lib/client.js
285
+ node --check lib/client.js
286
+ node --check lib/index.js
287
+ ```
288
+
289
+ Tests use mocked browser APIs (Notification, localStorage, Web Locks) and assert event filtering,
290
+ cooldowns, approval/question pass-through, the Chrome-vs-toast channel decision, Windows/macOS/Linux
291
+ parameter branches, locale switching, settings persistence, native-primitive rendering, the
292
+ typography token contract, and the absence of every removed legacy path.
293
+
294
+ ## 9. Structure
295
+
296
+ - `lib/client.src.js` — editable browser-half source (baked by `scripts/build-client.mjs`).
297
+ - `lib/client.js` — shipped browser entry (generated; do not edit by hand).
298
+ - `lib/locale-table.js` — generated locale dictionary (from `locale/*.json`).
299
+ - `lib/index.js` — no-op Host half; registers the package only. No services, no I/O.
300
+ - `cordis.patch.yml` — bundle row and default settings.
301
+ - `market/index.json` — market/index entry (renamed titles, version, no audio keyword).
302
+
303
+ ## 10. License and assets
304
+
305
+ - Code: MIT. See [LICENSE](LICENSE).
306
+ - The package bundles **no fonts, logos or audio**. The manifest icon is the neutral clock SVG at
307
+ [`icon.svg`](icon.svg)/[`market/icons/dsh-notify.svg`](market/icons/dsh-notify.svg).
308
+ - The historical `docs/` and `prototype-windows/` trees are kept as history; neither is shipped in
309
+ the package (`package.json` `files`) nor referenced by the notification code path.
310
+
311
+ ---
312
+
313
+
314
+ ## 한국어 요약
315
+
316
+ **버전이 내려간 이유부터**: `0.0.1-rc.4`는 `0.2.1`보다 낮은 것이 아닙니다. `0.2.x`는 이
317
+ 플러그인의 버전이 아니라 같은 저장소에 있던 **Windows 프로토타입**의 버전이었고, 2026-11-05
318
+ 소유자 결정으로 모든 `@nolit` 패키지가 **`0.0.1-rc.N`** 단일 사다리로 재설정됐습니다.
319
+ `rc#`만 올라갑니다. 패키지명도 `@nolit/dsh-notify-web` → **`@nolit/dsh-notify`** 로
320
+ 바뀌었습니다. `-web`은 2026-10-24 복구 당시 붙은 것으로 소유자가 고른 이름이 아니었습니다.
321
+
322
+ **알림 for 크롬**은 DeepSeek Harness의 턴 완료·도구 승인·질문·오류를 **크롬 알림**(Web
323
+ Notification API)으로 알립니다. 크롬이 알림을 막거나 표시할 수 없으면 **소리 없이 DSH 인앱
324
+ 토스트**로 대신 알립니다. 자체 오디오 엔진·BYO 오디오·자체 CSS·네이티브 앱/포트/파일 경로는
325
+ 모두 제거되었습니다.
326
+
327
+ - 설정은 **설정 → 알림 for 크롬**에서 하며, DSH 네이티브 컴포넌트(Switch/Button/Tag/Input/
328
+ Toast)와 DSH 디자인·타이포그래피 토큰만 사용합니다.
329
+ - 영어가 기본이고, 호스트 로케일이 한국어일 때만 한국어로 표시됩니다.
330
+ - Windows에서는 플랫폼과 설치 환경(설치된 앱/브라우저 탭)에 따라 알림 파라미터가 달라집니다:
331
+ 설치된 앱은 모든 알림을 닫을 때까지 유지하고, 브라우저 탭은 승인·질문만 유지합니다.
332
+ macOS에서는 `requireInteraction`을 사용하지 않습니다.
@@ -0,0 +1,19 @@
1
+ # Notify for Chrome bundle layer.
2
+ # The package is the bundle; this row activates its no-op Host half. Every
3
+ # notification runs through the browser's Chrome / Web Notification API. No
4
+ # local IPC, HTTP, ports, filesystem access, native notifier or audio engine.
5
+ - insert:
6
+ - id: notify
7
+ name: '@nolit/dsh-notify'
8
+ config:
9
+ notifyOnComplete: true
10
+ notifyOnApproval: true
11
+ notifyOnQuestion: true
12
+ notifyOnError: true
13
+ completeCooldownMs: 5000
14
+ suppressWhenFocused: false
15
+ requireInteractionForApproval: true
16
+ notifyOnSubagents: false
17
+ showPeakChip: true
18
+ notifyOnPeakChange: true
19
+ peakOnAnyProvider: false