6446197925
gates / gates (push) Successful in 2s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
117 lines
24 KiB
Markdown
117 lines
24 KiB
Markdown
# FIRST-ADMIN — how each app gets its first admin account (the audit behind `09` §3 decision 45)
|
||
|
||
**The rule (operator, 2026-09-28): an app is never published with a login a stranger knows.** The box publishes every
|
||
app on the household's domain (`*.domain` through the tunnel). Where the box can set the first admin password, it
|
||
generates one at install and shows it on the app page. Where it cannot, the app stays in the catalog, and the install
|
||
dialog and the app page say what the default login is and to change it at once.
|
||
|
||
**Mechanisms (controller ≥ 0.279.0; the gate ≥ 0.280.0):**
|
||
- `after_install:` in `.felhom.yml` — one command in the app's own container after a FRESH install, with generated
|
||
deploy values filled in; `success:` marker required. Never after a restore or a kept-data load. (`internal/stacks/after_install.go`)
|
||
- The page's default-login rule — `app_info.default_creds` is shown, with the sentence „Ez az alkalmazás egy ismert,
|
||
közös jelszóval indul: %s. Telepítés után azonnal változtasd meg." / "This app starts with a known, shared password:
|
||
%s. Change it right after the install.", while that login is in effect; hidden once `after_install` replaced it.
|
||
(`internal/web/known_login.go`)
|
||
- The setup gate (`09` §3 decision 46, controller ≥ 0.280.0) — `setup_gate: true` (+ optional `setup_done_probe:`): a
|
||
fresh install of an open-first-run app is closed to everyone but the household until the app's own status says an
|
||
admin exists, or the household presses „Kész, beállítottam". Spike and verdict:
|
||
`felhom.eu/documentation/audits/login-gate-2026-09-29/B/B-VERDICT.md` (14 of 34 class-4 apps have a probe — 2
|
||
measured, 12 upstream; 20 need the button). **It does not close OPEN SIGN-UP after the setup** (R-711).
|
||
- „Megváltoztattam" / "I changed it" (controller ≥ 0.280.0, R-710) — the household's word under a known default login.
|
||
|
||
**Classes:** 1 generated by us at install · 2 set by the household in our dialog · 3 a hard-coded default · 4 an open
|
||
first-run screen (the first visitor creates the admin) · 5 no login by design · 6 unknown.
|
||
**Sources:** **M** = measured on a box (named) · **R** = read in this catalog · **U** = upstream, read or remembered,
|
||
NOT measured. Every U must be measured before a fix is built on it.
|
||
|
||
**Status 2026-09-29 (afternoon):** every class-3 app fixed (5); **32 of 34 class-4 apps gated** (controller ≥ 0.281.0) —
|
||
9 open by the app's own status (probe measured before and after on 9202), the rest by the household's press, which
|
||
asks the probe first where there is one. Open sign-up is closed by the box after the setup on 11 apps (decision 47);
|
||
11 more refuse a stranger by themselves. **Not gated:** wanderer (R-714, needs a design); plant-it is not installable.
|
||
**Not provable on 9202:** the opening of seerr (media server), outline and rallly (e-mail).
|
||
|
||
| app | class | how the first admin exists | fix route | status | source |
|
||
|---|---|---|---|---|---|
|
||
| **actualbudget** | 4 | first visitor sets the server password | **setup gate**, opened by probe `/account/needs-bootstrap` → `data.bootstrapped`; the app itself refuses a stranger's second first-admin / sign-up call | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **adventurelog** | 4 | open sign-up | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); sign-up closed by the box after the setup: `/signup` + allauth signup | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **audiobookshelf** | 4 | first visitor creates root | **setup gate**, probe `GET /status` → `isInit` | **GATED** — catalog, 2026-09-29 | **M 9202**: as immich (the probe, read from upstream, measured: opened ~20 s after `POST /init`); its app's login 200 after |
|
||
| bentopdf | 5 | browser-only PDF tool, no accounts | – | fine | R |
|
||
| **bookstack** | 3 | `admin@admin.com / password` | (b) `artisan bookstack:create-admin --initial` | **FIXED** — catalog, decision 45 | **M 9202**: default fails, generated works; **M demo-hp**: default still works on the installed app (unchanged, page warns) |
|
||
| **calcom** | 4 | first visitor becomes admin (`/api/auth/setup`) | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); sign-up closed by the box after the setup: `/signup`, `/auth/signup`, `/api/auth/signup` | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **calibre-web** | 3 | `admin / admin123` | (b) `cps.py -p /config/app.db -s admin:<pw>` as `abc`; `generate: password:24:special` (controller ≥ 0.280.0) | **FIXED** — catalog, 2026-09-29 | **M 9202**: fresh install — default refused, generated signs in (302), wrong refused; **M demo-hp**: the installed app's password changed by the operator's ruling (Part A) |
|
||
| **claper** | 3 (+ open sign-up) | seeds `admin@claper.co / claper` | (b) `bin/claper rpc … update_user_password` | **FIXED** — catalog, decision 45 | **M 9202**: default fails, generated works, a restore keeps it |
|
||
| code-server | 1 | `PASSWORD` generated, applied every start | – | fine | R |
|
||
| crafty-controller | 1 | `CRAFTY_PASSWORD` → default.json | – | fine | R |
|
||
| **docmost** | 4 | first registered user is admin | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); the app itself refuses a stranger's second first-admin / sign-up call; no JSON status before/after → button | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **emby** | 4 | setup wizard | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); the app itself refuses a stranger's second first-admin / sign-up call | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **ghost** | 4 | `/ghost/` setup | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); the app itself refuses a stranger's second first-admin / sign-up call; its status exists but is a list (`setup[0].status`) — the box reads only objects → button | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **gitea** | 4 | web installer open (no `INSTALL_LOCK`) | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); sign-up closed by the box after the setup: `/user/sign_up`; `/api/v1/version` is not JSON before the install → button | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| glance | 5 | config-file dashboard, no users | – | fine | R |
|
||
| gokapi | 1 | `GOKAPI_PASSWORD` before first serve | – | fine | R |
|
||
| grafana | 1 | `GF_SECURITY_ADMIN_PASSWORD` — **falls back to `admin` if empty** (R-708) | – | fine while the field is set | R |
|
||
| **gramps-web** | 4 | first-run onboarding | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); sign-up closed by the box after the setup: `/api/users/<name>/register/`; its status answers HTTP 405 after the setup — the box reads only 200 answers (measured: the press was then refused, fail closed) → button; self-registration answered 500, blocked anyway | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **home-assistant** | 4 | onboarding | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); the app itself refuses a stranger's second first-admin / sign-up call; its status is a list (`/api/onboarding`) → button | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **homebox** | 4 | open registration | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); sign-up closed by the box after the setup: `/api/v1/users/register` | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| homepage | 5 | static start page | – | fine | R |
|
||
| **immich** | 4 | first visitor admin sign-up | **setup gate**, probe `GET /api/server/config` → `isInitialized` | **GATED** — catalog, 2026-09-29 (decision 46) | **M 9202**: stranger 302→gate page / 401 during and after the install; household in 0.2 s; probe opened it 0–20 s after the sign-up; phone-app API (Bearer) 200 after (`felhom.eu/documentation/audits/login-gate-2026-09-29/C/`) |
|
||
| **jellyfin** | 4 | startup wizard | **setup gate**, opened by probe `/System/Info/Public` → `StartupWizardCompleted`; the app itself refuses a stranger's second first-admin / sign-up call | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| kimai | 1 | `ADMIN_PASSWORD` → `ADMINPASS` | – | fine | R |
|
||
| **komga** | 4 | first visitor claims | **setup gate**, opened by probe `/api/v1/claim` → `isClaimed`; the app itself refuses a stranger's second first-admin / sign-up call | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **mealie** | 3 | `changeme@example.com / MyPassword` | (b) its own user repository (`update_password`), password as `sys.argv[1]` | **FIXED** — catalog, 2026-09-29 | **M 9202**: fresh install — default 401, generated 200, wrong 401 (`felhom.eu/documentation/audits/login-gate-2026-09-29/D/`) |
|
||
| **n8n** | 4 | owner setup | **setup gate**, probe `GET /rest/settings` → `data.userManagement.showSetupOnFirstLoad` = false | **GATED** — catalog, 2026-09-29 | **M 9202**: as immich; opened by the probe ~20 s after the owner setup |
|
||
| **navidrome** | 4 | first user is admin | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); the app itself refuses a stranger's second first-admin / sign-up call | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| nextcloud | 1 | `NEXTCLOUD_ADMIN_PASSWORD` → auto-install | – | fine | R; **M** demo-hp 2026-09-28 |
|
||
| onlyoffice | 5 | JWT-protected API, no login screen | – | fine | R |
|
||
| **opengist** | 4 | first registered user is admin | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); sign-up closed by the box after the setup: `/-/register` | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **outline** | 4 | e-mail / magic-link onboarding | **setup gate**, the household's press; needs e-mail or SSO to sign anyone in — not provable on 9202 | **GATED** — catalog, 2026-09-29; the opening NOT proven | **M 9202**: stranger → gate page / 401, household reached the first-setup screen (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| paperless-ngx | 1 | `PAPERLESS_ADMIN_PASSWORD` | – | fine | R |
|
||
| **papra** | 4 | open e-mail sign-up | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); sign-up closed by the box after the setup: `/api/auth/sign-up` | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| plant-it | 4 | open, `USERS_LIMIT=-1` | `setup_gate: true` in the template; the catalog marks it NOT installable (`lifecycle: abandoned`) — nothing to prove | not installable | R |
|
||
| plex | 2 | the household's plex.tv claim token | – | fine | R |
|
||
| privatebin | 5 | anonymous pastes by design | – | fine | R |
|
||
| **radarr** | 4 | first visitor sets auth | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); no sign-up to close (single user / no accounts); `/initialize.json` hands anyone the API key BEFORE the setup — the gate hides it; after, it needs a login | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **rallly** | 4 | magic link to any e-mail | **setup gate**, the household's press; magic link by e-mail — not provable on 9202 | **GATED** — catalog, 2026-09-29; the opening NOT proven | **M 9202**: stranger → gate page / 401, household reached the first-setup screen (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **recipe-importer** | 4 | our own image, open until set | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); no sign-up to close (single user / no accounts); our own app: open until a password is set in its settings — the confirm says so | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **romm** | 4 | first unauthenticated `POST /api/users` creates the user (harness); the stale `admin / admin` note is **removed** (2026-09-29) | **setup gate**, opened by probe `/api/heartbeat` → `SYSTEM.SHOW_SETUP_WIZARD` = false; the app itself refuses a stranger's second first-admin / sign-up call | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **seerr** | 4 | setup wizard (needs a media server) | **setup gate**, the household's press; needs a media server to finish its setup — not provable on 9202 (its `initialized` status measured false before) | **GATED** — catalog, 2026-09-29; the opening NOT proven | **M 9202**: stranger → gate page / 401, household reached the first-setup screen (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **sonarr** | 4 | as radarr | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); no sign-up to close (single user / no accounts); as radarr | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **sparkyfitness** | 4 | open registration | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); sign-up closed by the box after the setup: `/api/auth/sign-up` | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **tandoor** | 4 | setup page while no users | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); the app itself refuses a stranger's second first-admin / sign-up call | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **termix** | 4 | first registered user is admin | **setup gate**, opened by probe `/users/setup-required` → `setup_required` = false; sign-up closed by the box after the setup: `/users/create` | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **uptime-kuma** | 4 | first visitor creates admin (socket.io `setup`) | **setup gate**, no HTTP probe → the household's „Kész, beállítottam" | **GATED** — catalog, 2026-09-29 | **M 9202**: gate held across a controller restart; the press opened it (second press 409). The proof pressed WITHOUT doing the socket.io setup — the press trusts the household |
|
||
| vaultwarden | 1 | `ADMIN_TOKEN` generated; invite-only (R-512) | – | fine | R |
|
||
| **vikunja** | 4 | open registration | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); sign-up closed by the box after the setup: `/api/v1/register` | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **wanderer** | 4 | `PUBLIC_DISABLE_SIGNUP=false` | NOT gated (its web server calls its own database through the public name); no first-admin screen to take (PocketBase's superuser installer needs the one-time link from its log); sign-up closed by the household's „Close sign-up now” after its account (decision 48) | **LOCKED on the household's press** — catalog, 2026-09-29 evening | **M 9202**: before, a stranger made an account through PocketBase; after the press, every sign-up shape refused (`felhom.eu/documentation/audits/signup-lock-2026-09-29/D/`) |
|
||
| **wger** | 3 | `admin / adminadmin` | (b) Django `set_password`, password as `sys.argv[1]` | **FIXED** — catalog, 2026-09-29; + R-712 (a browser's https Origin was refused by CSRF) | **M 9202**: fresh install — default refused, generated signs in (302), wrong refused, with the browser's https Origin |
|
||
| **wishlist** | 4 | first sign-up is admin | **setup gate**, opened by the household's press („Kész, beállítottam", confirm first); sign-up closed by the box after the setup: `/signup` | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
| **zipline** | 4 | v4 sets up on first run; the stale `admin / zipline` note is **removed** (2026-09-29) | **setup gate**, opened by probe `/api/server/public` → `firstSetup` = false; the app itself refuses a stranger's second first-admin / sign-up call | **GATED** — catalog, 2026-09-29 (decisions 46–47) | **M 9202**: stranger → gate page / 401; household reached the first-setup screen; gate opened after the setup; the app answered after (`felhom.eu/documentation/audits/gate-rollout-2026-09-29/`) |
|
||
|
||
## Sign-up locks after the first admin (decision 47; controller ≥ 0.282.0) — measured on 9202, 2026-09-29 evening
|
||
|
||
Two locks per app where the app has its own switch: the app's own setting (set by `after_setup` when the gate opens) and
|
||
the address block (`signup_block`, case-insensitive). Tricks: each sign-up route tried in 8 shapes (as written, trailing
|
||
slash, UPPER, Mixed, last part UPPER, one letter percent-encoded, double slash, query string), through the public route.
|
||
Evidence: `felhom.eu/documentation/audits/signup-lock-2026-09-29/`.
|
||
|
||
| app | its own switch (env) | that switch also refuses the household's FIRST account? | address block (routes) | tricks (final run) |
|
||
|---|---|---|---|---|
|
||
| adventurelog | `DISABLE_REGISTRATION` | yes | `/signup`, allauth API, `/accounts/signup` | all refused (block) |
|
||
| calcom | `NEXT_PUBLIC_DISABLE_SIGNUP` (read at runtime; invites with a token still work) | no | `/signup`, `/auth/signup`, `/api/auth/signup` | all refused |
|
||
| gitea | `GITEA__service__DISABLE_REGISTRATION` (env-to-ini at every start) | no (the installer makes the admin) | `/user/sign_up` | all refused |
|
||
| gramps-web | `GRAMPSWEB_REGISTRATION_DISABLED` | no (create_owner) | `/api/users/<name>/register/` | all refused |
|
||
| homebox | `HBOX_OPTIONS_ALLOW_REGISTRATION` | yes | `/api/v1/users/register` | all refused |
|
||
| papra | `AUTH_IS_REGISTRATION_ENABLED` | yes | `/api/auth/sign-up/*` | all refused |
|
||
| sparkyfitness | `SPARKY_FITNESS_DISABLE_SIGNUP` | yes | `/api/auth/sign-up/*` | all refused |
|
||
| termix | `ALLOW_REGISTRATION` | yes | `/users/create` — **its router ignores case**: `/users/CREATE` reached the sign-up before the block was made case-insensitive (its own switch refused it) | all refused |
|
||
| vikunja | `VIKUNJA_SERVICE_ENABLEREGISTRATION` | yes (its register route answers 404) | `/api/v1/register` | all refused (its `/register` PAGE is only HTML; the API is blocked) |
|
||
| opengist | none reachable (an admin setting in its database) | — | `/-/register` | all refused (block only) |
|
||
| wishlist | none reachable (`system_config.enableSignup` in its database) | — | `/signup` | all refused (block only) |
|
||
| wanderer | `PUBLIC_DISABLE_SIGNUP` (web only — PocketBase's API ignores it) | — | `/register` + PocketBase `POST /api/collections/(users\|_pb_users_auth_)/records`, any case — **the collection id and a case change both got in before the fix** | all refused; the batch API is off by the app |
|
||
|
||
The household's 15-minute window lifts both locks (the app restarts once) and the loop puts both back (measured on
|
||
homebox). "Close sign-up now" (decision 49) is offered on an app installed before the rule — and on wanderer, which is
|
||
not gated: the household makes its account, then presses it (measured on 9202).
|
||
|
||
**Counts (computed from the table, 2026-09-29 afternoon):** class 1: 8 · class 2: 1 · class 3: 5 · class 4: 34 · class 5: 5.
|
||
**Fixed: 5.** **Gated: 32** (3 of them without a proven opening). **Not gated: 2** (wanderer — its sign-up is locked by the household's press instead, decision 48; plant-it — not installable). Fine: 14.
|