#!/usr/bin/env python3 """Build the NOC site into ./public. Brand, domain and facts come from site.json; prose from content/*.txt.""" import json, html, shutil, pathlib root = pathlib.Path(__file__).parent S = json.load(open(root / "site.json")) out = root / "public" shutil.rmtree(out, ignore_errors=True) shutil.copytree(root / "static", out) e = html.escape CSS = """:root{--bg:#fff;--fg:#1c1f24;--mut:#5b6470;--ac:#0b5cad;--bd:#d9dee4} @media (prefers-color-scheme:dark){:root{--bg:#14171b;--fg:#e6e9ed;--mut:#9aa4b0;--ac:#6cb2ff;--bd:#2d333b}} body{margin:0;background:var(--bg);color:var(--fg);font:16px/1.6 system-ui,sans-serif} .w{max-width:46rem;margin:0 auto;padding:0 16px}header{border-bottom:1px solid var(--bd);padding:1rem 0} header a.b{font-weight:700;color:var(--fg);text-decoration:none}nav{margin-top:.4rem}nav a{margin-right:1rem} a{color:var(--ac)}h1{margin-top:2rem}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid var(--bd);padding:.4rem .5rem;text-align:left;vertical-align:top} th{color:var(--mut);font-weight:600;width:35%}code{word-break:break-all}footer{color:var(--mut);border-top:1px solid var(--bd);margin:3rem 0 2rem;padding-top:1rem;font-size:.9rem}""" NAV = [("/", "Home"), ("/peering/", "Peering"), ("/pgp/", "PGP keys"), ("/contact/", "Contact")] def paras(name): return "".join(f"
{e(l)}
" for l in (root / "content" / f"{name}.txt").read_text().splitlines() if l.strip()) def page(path, title, body): nav = "".join(f'{t}' for u, t in NAV) doc = f"""| ASN | {e(S['asn'])} |
|---|---|
| Prefix | {e(S['prefix'])} (IPv6 only) |
| Upstreams |
|
| AS-SET | {e(S['as_set'])} (RIPE) |
| RPKI | ROA {e(S['prefix'])}, origin {e(S['asn'])}, maxLength 48; ASPA providers AS41051, AS6517 |
| PeeringDB | {S['peeringdb']} |
| Policy | Open, IPv6 preferred |
{e(S['tagline'])}
{paras('home')}{e(f)}| NOC for {e(S['asn'])} | {c['noc']} |
|---|---|
| Abuse | {c['abuse']} |
| Emergency | {e(c['phone'])} |
| Threema | {e(c['threema'])}![]() |