storage identity build A: 16 accepted + §13 build status; D14; close R-1072/R-1074/R-1075; open R-1083/R-1084; live evidence
gates / gates (push) Successful in 6m44s

The operator ruled D1-D6 as recommended. Build A shipped (agent v0.157.0, controller v0.317.0 MinAgent 0.157.0,
hub v0.154.0): live on Tester 1 (unknown/vm, the "cannot check" notice, copies made not counted), demo-hp and
the N100 (proven, different, unchanged). NAS notice and the no-drive sentence are unit-proven only.
STATUS: D10 removed; vouch agent 0.157.0 and rule on R-1082 added. Poster: the Tier-2 line, text only.

Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
This commit is contained in:
admin committed 2026-10-15 21:49:38 +02:00
1 parent bf99798c96
commit 314308b4aa
32 files changed
+2280 -13

No files matched your search

@@ -179,6 +179,7 @@
| <a id="d11"></a>[D11](capability-map-detail/D.md#d11) | Decommission (migrate-first and anyway-paths), eject | agent, controller | **PROVEN-LIVE** | — | `audits/storage-lifecycle-acceptance-2026-06-15.md` (2026-06-15) |
| <a id="d12"></a>[D12](capability-map-detail/D.md#d12) | Boot ordering: automount + networking survive reboot; appliance self-heal watchdog | agent v0.85 | **PROVEN-LIVE** | — | `audits/CAMPAIGN-4-2026-07-13.md` (2026-07-13); `audits/CAMPAIGN-6A-2026-07-14.md` (2026-07-14) |
| <a id="d13"></a>[D13](capability-map-detail/D.md#d13) | Media apps see EVERY drive; a drive added, pulled, back or safely removed is handled per app (notice, real restart, wiring, torrents paused/resumed) | controller v0.313.0, catalog `0188430`, hub v0.151.0 | **PROVEN-LIVE** | Tier-0 boxes (Tester 1, demo-hp 9201); the fleet with golden 0.313.0 + the floor | `audits/media-build-2026-10-15/G/` (2026-10-15); `audits/media-drive-events-2026-10-14/` (2026-10-14) |
| <a id="d14"></a>[D14](capability-map-detail/D.md#d14) | A second local copy COUNTS only on a proven different physical disk: the agent knows each place's disks; a VM box makes the copy but says it cannot check; a same-disk copy is not made; a NAS never hides the one-copy notice; a box with no drive refuses a data-folder app in words | agent v0.157.0, controller v0.317.0, hub v0.154.0 | **PARTIAL** | live: VM `unknown` (Tester 1) and two real-disk boxes `proven` (demo-hp, N100); unit only: the same-disk skip, the NAS notice, the no-drive sentence; `usb_bridge` never seen on a device | `audits/storage-identity-buildA-2026-10-15/README.md` (2026-10-15); `architecture/16-storage-physical-identity.md` §13 |
## E. Access, networking & household use
@@ -5,7 +5,9 @@
> Operator ruling 2026-10-15: „Felhom must support drives split into parts; the agent and the controller must know
> whether two storage places sit on the same physical disk." Triggered by the OMV test (`audits/omv-vm-2026-10-15/`,
> R-1068). Spike: `audits/storage-identity-2026-10-15/` (Part B there). Marks as in `01`: **[FACT]** read in a named
> file or measured; **[DESIGN]** a proposal. **Status: DRAFT — waits on the operator's rulings in §11. Nothing is built.**
> file or measured; **[DESIGN]** a proposal. **Status: ACCEPTED 2026-10-15** — the operator ruled D1–D6 as recommended (§12). **Build A shipped 2026-10-15**
> (§3, §4, §5's D4 sentence, §8, §10); **§5's internal place, §6 and §7 wait for build B** — what is built, and where the
> build differs from this text, is §13.
> Paths: A = `felhom-agent/`, C = `felhom-controller/controller/`, E = `felhom.eu/`.
## 1. Today, in one table (Part A)
@@ -171,7 +173,7 @@ data-bearing. The agent never trusts a guest path it cannot map to a host mount
- **Ask the hypervisor (OMV/libvirt) which host disk backs a virtual disk** — Felhom has no access there, and it would trust a party it does not control.
- **Let the dashboard create partitions** — a new destructive power for the household with no recovery; not needed for the cases in hand.
## 12. Decisions for the operator (D1–D6) — STOP here
## 12. Decisions for the operator (D1–D6) — RULED 2026-10-15: all six as recommended
| # | Question | Options | Recommendation | If you do nothing |
|---|---|---|---|---|
@@ -186,3 +188,27 @@ data-bearing. The agent never trusts a guest path it cannot map to a host mount
partition candidates, the loop step) · controller (Tier-2 and the notice ask the agent; i18n sentences; the install
refusal in words; register the internal place) · installer (`step_grows` + the internal LV) · hub (store and show the two
fields) · website and guides (the OMV guide's second-disk line; the backup explanation page).
## 13. Build status
**Build A — honest backup copies (D1, D2, D4), shipped 2026-10-15** (agent v0.157.0, controller v0.317.0 with MinAgent
0.157.0, hub v0.154.0; evidence `audits/storage-identity-buildA-2026-10-15/`):
| Section | Built | Proven |
|---|---|---|
| §3 model | the agent computes `kind`, `physical_disks`, `identity` + reason for every PVE storage and every own mount; `GET /disks` and the hub report carry them | live: N100 and demo-hp `proven`, Tester 1 `unknown/vm`, the PBS store `network`; the hub stores and shows them |
| §4 tiers | `POST /disks/same-disk`; Tier-2 choice, the pre-run guard and the one-copy notice ask it (D1: same disk → no copy; D2: unknown → copy made, not counted); a NAS never counts and never hides the notice (R-1075) | live: Tester 1 shows the „cannot check" notice and its copies are made, not counted; demo-hp and N100 count theirs, no notice. **Unit only:** the same-disk skip (no box has two places on one disk), the NAS notice (no box with a NAS can reach the agent, R-1083) |
| §5 D4 | the install of a data-folder app on a box with no drive answers „Ehhez az alkalmazáshoz egy adattároló kell. A Meghajtók oldalon adhatsz hozzá egyet." with a link to the Meghajtók page; never the field name | **unit only** — no one-disk box was at hand |
| §8 VMs | every place on a VM box is `unknown/vm` | live, Tester 1 |
| §10 | the agent maps only paths to mounts it made; an absent drive (its folder on the root disk) is `unmapped`, never „the system disk" | unit, and live (`unmapped` for an absent drive on demo-hp) |
**Where the build differs from the text above:**
- §3 „When": the identity is computed **on every read** (each `GET /disks`, each report, each same-disk call), not cached
at start and on hot-plug. The rule's purpose — a swapped disk never inherits an old verdict — holds with no cache.
- `usb_bridge`: built from the spike's rule, **never seen on a real device** (the N100's USB enclosure passes the real serial).
- §4 said the notice closes „R-1072's half": it closed all of R-1072 — the other sentence was already informal.
- An older agent (no same-disk call): the controller keeps the pre-build `st_dev` rule and logs it once.
- §11 rejects `sys_drive` for household data, but the drives page still offers `/mnt/sys_drive` to attach (R-280) — R-1082.
**Build B — waits:** §5's internal place, §6 partitions, §7 the installer (and the D3 space check the operator asked for).
@@ -237,3 +237,34 @@ the unmount, the drive returns by itself and the torrents resume; G6 13 hardlink
---
<a id="d14"></a>
## D14 — A second local copy counts only on a proven different physical disk
*Map row: [D14](../00-capability-map.md#d14) · added 2026-10-15.*
**Scenario:** a household's Tier-2 copy is worth something against a disk failure only when it sits on another physical
disk. The agent reads, for every storage place, the physical disk(s) under it and whether it can prove them; the
controller asks it before it makes or counts a copy.
**Components:** agent v0.157.0 (place identity in `GET /disks` and the hub report, `POST /disks/same-disk`), controller
v0.317.0 (Tier-2 choice and guard, the one-copy notice, the no-drive install sentence; MinAgent 0.157.0), hub v0.154.0
(the host page shows the disks and the verdict). Design: `architecture/16-storage-physical-identity.md` §3–§4, §13.
**Status:** **PARTIAL** (2026-10-15).
**Proven live:** Tester 1 (a box inside a VM): every place `unknown/vm`; `/backups` shows „A Felhom nem tudja
ellenőrizni…”; a Tier-2 run copied the apps and marked them not counted. demo-hp and the N100 (real disks): every place
`proven`; drive vs system data „different, proven”; Tier-2 copies counted; no notice. An absent drive is `unmapped`,
never „the system disk”. The hub stores and shows the fields for all three.
**Unit only (red-proved):** the same-disk skip (no box has two places on one disk), the NAS notice (the scratch box cannot
reach its agent, R-1083), the no-drive install sentence (no one-disk box at hand, R-1068). `usb_bridge` is built from the
spike's rule and was never seen on a device.
**Gaps:** the whole-box backup offer still trusts any second drive (R-1084); build B — the internal place, partitions,
the installer (R-1079).
**Evidence:** `audits/storage-identity-buildA-2026-10-15/README.md`.
---
@@ -82,7 +82,7 @@ Title: **"Where a household's data is copied"**
| Tier | What it copies | Where | When | Kept | Locked by |
|---|---|---|---|---|---|
| **Tier 1 — recovery unit** | each app: its settings, database dump, volumes | data drive 1, on the box | nightly at **02:30** (W) | 1 point per app | not encrypted (it never leaves the home) |
| **Tier 2 — cross-drive** | a mirror of Tier 1, plus the app's files | data drive 2, on the box (only if the household has 2 drives) | nightly **03:30** | mirror | not encrypted |
| **Tier 2 — cross-drive** | a mirror of Tier 1, plus the app's files | data drive 2, on the box (counted only on a different physical disk; in a VM made, not counted) | nightly **03:30** | mirror | not encrypted |
| **Tier 3 — off-site, per app** | Tier 1 + the app's must-keep files | **Hetzner Storage Box** (Germany), one folder per household | nightly **04:15** | 7 daily, 4 weekly, 6 monthly | the household's own restic password |
| **Whole guest — local** | the guest's system (not the data drives) | the box's own system disk | daily, in the window **04:30–08:30** | up to 3 copies (fewer on a small disk) | not encrypted |
| **Whole guest — off-site** | the same | **ep0** (Hetzner, Germany), one namespace per household | weekly, same window | last 2 | the household's own key, escrowed with a recovery code |
@@ -385,7 +385,7 @@ document.addEventListener('DOMContentLoaded', async function() {
</script>
<script type="__bundler/template">
"<!DOCTYPE html>\n<html lang=\"en\"><head>\n<meta charset=\"utf-8\">\n<title>Felhom system poster<\u002Ftitle>\n<script src=\"7425d086-bbee-40a4-a354-fbfba43c8a3d\"><\u002Fscript>\n<meta name=\"hz:slide-selector\" content=\"[data-canvas-width]\"><meta name=\"hz:canvas-width\" content=\"3200\"><meta name=\"hz:canvas-height\" content=\"2262\"><\u002Fhead>\n<body>\n<x-dc>\n<helmet>\n<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n<style>/* cyrillic-ext */\n@font-face {\n font-family: 'Plus Jakarta Sans';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(https://fonts.gstatic.com/s/plusjakartasans/v12/LDIoaomQNQcsA88c7O9yZ4KMCoOg4Ko70yyygA.woff2) format('woff2');\n unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n/* vietnamese */\n@font-face {\n font-family: 'Plus Jakarta Sans';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(https://fonts.gstatic.com/s/plusjakartasans/v12/LDIoaomQNQcsA88c7O9yZ4KMCoOg4Ko50yyygA.woff2) format('woff2');\n unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;\n}\n/* latin-ext */\n@font-face {\n font-family: 'Plus Jakarta Sans';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(https://fonts.gstatic.com/s/plusjakartasans/v12/LDIoaomQNQcsA88c7O9yZ4KMCoOg4Ko40yyygA.woff2) format('woff2');\n unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n/* latin */\n@font-face {\n font-family: 'Plus Jakarta Sans';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(\"e228819f-c09e-4d10-9162-36e030c24619\") format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n/* cyrillic-ext */\n@font-face {\n font-family: 'Plus Jakarta Sans';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(https://fonts.gstatic.com/s/plusjakartasans/v12/LDIoaomQNQcsA88c7O9yZ4KMCoOg4Ko70yyygA.woff2) format('woff2');\n unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n/* vietnamese */\n@font-face {\n font-family: 'Plus Jakarta Sans';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(https://fonts.gstatic.com/s/plusjakartasans/v12/LDIoaomQNQcsA88c7O9yZ4KMCoOg4Ko50yyygA.woff2) format('woff2');\n unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;\n}\n/* latin-ext */\n@font-face {\n font-family: 'Plus Jakarta Sans';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(https://fonts.gstatic.com/s/plusjakartasans/v12/LDIoaomQNQcsA88c7O9yZ4KMCoOg4Ko40yyygA.woff2) format('woff2');\n unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n/* latin */\n@font-face {\n font-family: 'Plus Jakarta Sans';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(\"e228819f-c09e-4d10-9162-36e030c24619\") format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n/* cyrillic-ext */\n@font-face {\n font-family: 'Plus Jakarta Sans';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(https://fonts.gstatic.com/s/plusjakartasans/v12/LDIoaomQNQcsA88c7O9yZ4KMCoOg4Ko70yyygA.woff2) format('woff2');\n unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n/* vietnamese */\n@font-face {\n font-family: 'Plus Jakarta Sans';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(https://fonts.gstatic.com/s/plusjakartasans/v12/LDIoaomQNQcsA88c7O9yZ4KMCoOg4Ko50yyygA.woff2) format('woff2');\n unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;\n}\n/* latin-ext */\n@font-face {\n font-family: 'Plus Jakarta Sans';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(https://fonts.gstatic.com/s/plusjakartasans/v12/LDIoaomQNQcsA88c7O9yZ4KMCoOg4Ko40yyygA.woff2) format('woff2');\n unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, Line truncated
"<!DOCTYPE html>\n<html lang=\"en\"><head>\n<meta charset=\"utf-8\">\n<title>Felhom system poster<\u002Ftitle>\n<script src=\"7425d086-bbee-40a4-a354-fbfba43c8a3d\"><\u002Fscript>\n<meta name=\"hz:slide-selector\" content=\"[data-canvas-width]\"><meta name=\"hz:canvas-width\" content=\"3200\"><meta name=\"hz:canvas-height\" content=\"2262\"><\u002Fhead>\n<body>\n<x-dc>\n<helmet>\n<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n<style>/* cyrillic-ext */\n@font-face {\n font-family: 'Plus Jakarta Sans';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(https://fonts.gstatic.com/s/plusjakartasans/v12/LDIoaomQNQcsA88c7O9yZ4KMCoOg4Ko70yyygA.woff2) format('woff2');\n unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n/* vietnamese */\n@font-face {\n font-family: 'Plus Jakarta Sans';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(https://fonts.gstatic.com/s/plusjakartasans/v12/LDIoaomQNQcsA88c7O9yZ4KMCoOg4Ko50yyygA.woff2) format('woff2');\n unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;\n}\n/* latin-ext */\n@font-face {\n font-family: 'Plus Jakarta Sans';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(https://fonts.gstatic.com/s/plusjakartasans/v12/LDIoaomQNQcsA88c7O9yZ4KMCoOg4Ko40yyygA.woff2) format('woff2');\n unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n/* latin */\n@font-face {\n font-family: 'Plus Jakarta Sans';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(\"e228819f-c09e-4d10-9162-36e030c24619\") format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n/* cyrillic-ext */\n@font-face {\n font-family: 'Plus Jakarta Sans';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(https://fonts.gstatic.com/s/plusjakartasans/v12/LDIoaomQNQcsA88c7O9yZ4KMCoOg4Ko70yyygA.woff2) format('woff2');\n unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n/* vietnamese */\n@font-face {\n font-family: 'Plus Jakarta Sans';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(https://fonts.gstatic.com/s/plusjakartasans/v12/LDIoaomQNQcsA88c7O9yZ4KMCoOg4Ko50yyygA.woff2) format('woff2');\n unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;\n}\n/* latin-ext */\n@font-face {\n font-family: 'Plus Jakarta Sans';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(https://fonts.gstatic.com/s/plusjakartasans/v12/LDIoaomQNQcsA88c7O9yZ4KMCoOg4Ko40yyygA.woff2) format('woff2');\n unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n/* latin */\n@font-face {\n font-family: 'Plus Jakarta Sans';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(\"e228819f-c09e-4d10-9162-36e030c24619\") format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n/* cyrillic-ext */\n@font-face {\n font-family: 'Plus Jakarta Sans';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(https://fonts.gstatic.com/s/plusjakartasans/v12/LDIoaomQNQcsA88c7O9yZ4KMCoOg4Ko70yyygA.woff2) format('woff2');\n unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n/* vietnamese */\n@font-face {\n font-family: 'Plus Jakarta Sans';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(https://fonts.gstatic.com/s/plusjakartasans/v12/LDIoaomQNQcsA88c7O9yZ4KMCoOg4Ko50yyygA.woff2) format('woff2');\n unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;\n}\n/* latin-ext */\n@font-face {\n font-family: 'Plus Jakarta Sans';\n font-style: normal;\n font-weight: 600;\n font-display: swap;\n src: url(https://fonts.gstatic.com/s/plusjakartasans/v12/LDIoaomQNQcsA88c7O9yZ4KMCoOg4Ko40yyygA.woff2) format('woff2');\n unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, Line truncated
</script>
</body>
</html>