diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json
index ed0c44a..b2bd921 100644
--- a/.claude-plugin/marketplace.json
+++ b/.claude-plugin/marketplace.json
@@ -1,7 +1,7 @@
{
"name": "diagram-design",
"metadata": {
- "description": "Editorial-quality technical and product diagrams — 13 types rendered as standalone HTML with inline SVG, skinnable to match your brand"
+ "description": "Editorial-quality technical and product diagrams — 26 types rendered as standalone HTML with inline SVG, skinnable to match your brand"
},
"owner": {
"name": "Cathryn Lavery"
diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json
index 45c2308..71e67b2 100644
--- a/.claude-plugin/plugin.json
+++ b/.claude-plugin/plugin.json
@@ -1,7 +1,7 @@
{
"name": "diagram-design",
- "description": "Editorial-quality technical and product diagrams — 13 types rendered as standalone HTML with inline SVG, skinnable to match your brand",
- "version": "1.0.0",
+ "description": "Editorial-quality technical and product diagrams — 26 types rendered as standalone HTML with inline SVG, skinnable to match your brand",
+ "version": "2.0.0",
"homepage": "https://github.com/cathrynlavery/diagram-design",
"repository": "https://github.com/cathrynlavery/diagram-design",
"license": "MIT",
diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json
index e52c881..74ca72f 100644
--- a/.codex-plugin/plugin.json
+++ b/.codex-plugin/plugin.json
@@ -1,7 +1,7 @@
{
"name": "diagram-design",
- "description": "Editorial-quality technical and product diagrams - 13 types rendered as standalone HTML with inline SVG, skinnable to match your brand",
- "version": "1.0.0",
+ "description": "Editorial-quality technical and product diagrams - 26 types rendered as standalone HTML with inline SVG, skinnable to match your brand",
+ "version": "2.0.0",
"author": {
"name": "Cathryn Lavery",
"url": "https://github.com/cathrynlavery"
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4c4cc40
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.claude/
+.mcp.json
diff --git a/README.md b/README.md
index 39b07fc..504114a 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@

-14 types. One Claude Code skill. Your brand in 60 seconds — the skill reads your website and maps colors + fonts to every diagram.
+26 types. One Claude Code skill. Your brand in 60 seconds — the skill reads your website and maps colors + fonts to every diagram.
No Figma. No generic rounded boxes. No 30-minute color-picking sessions.
@@ -14,7 +14,7 @@ No Figma. No generic rounded boxes. No 30-minute color-picking sessions.
I write at [littlemight.com](https://littlemight.com?utm_source=diagram-design&utm_medium=readme&utm_campaign=github&utm_content=intro) (and run [BestSelf.co](https://bestself.co?utm_source=diagram-design&utm_medium=readme&utm_campaign=github&utm_content=intro) on the side). Every time I needed a diagram — an architecture sketch, a flowchart, a pyramid of what matters most — I'd ask Claude and get back a generic rounded-box thing that looked nothing like the rest of the site. I'd either fight with Figma for 30 minutes or just skip the diagram.
-So I built a Claude Code skill for it. Fourteen types, editorial quality, matches your brand in 60 seconds by reading your website.
+So I built a Claude Code skill for it. Twenty-six types, editorial quality, matches your brand in 60 seconds by reading your website.
> *The highest-quality move is usually deletion.* Every node earns its place. The accent color is reserved for the 1–2 things the reader should look at first. Target density: 4/10.
@@ -22,7 +22,7 @@ So I built a Claude Code skill for it. Fourteen types, editorial quality, matche
## What it makes
-All 14 diagrams ship in three variants: minimal light, minimal dark, and full-editorial. Open any of them directly in a browser — no build step, no JS, no external images.
+All 26 diagrams ship in three variants: minimal light, minimal dark, and full-editorial. Open any of them directly in a browser — no build step, no JS, no external images.
@@ -32,7 +32,7 @@ All 14 diagrams ship in three variants: minimal light, minimal dark, and full-ed
State machine States + transitions
- ER / data model Entities + fields
+ ER / data model Entities + fields
Timeline Events on an axis
@@ -48,16 +48,31 @@ All 14 diagrams ship in three variants: minimal light, minimal dark, and full-ed
Layer stack Stacked abstractions
Pyramid / funnel Ranked hierarchy or drop-off
-
+ Consultant 2×2 Scenario matrix · named cells
- Consultant 2×2 Scenario matrix · named cells
-
-
+ Radar / Spider Multi-axis comparison
+ IT current-state Legacy landscape · modernization
+ High-Level End-to-end stack on a cluster
+
+
+ Bar chart Categorical comparison
+ Line chart Trends over time
+ Gantt Tasks and phases on a timeline
+
+
+ Scatter plot Distribution and correlation
+ Process Multi-actor sequential workflow
+ Medallion Multi-tier data storage
+
+
+ Data flow Role-scoped pipeline steps
+ DP integration Sources → core → consumers
+ DP security matrix Per-role access permissions
-**Browse the live gallery:** open [`skills/diagram-design/assets/index.html`](skills/diagram-design/assets/index.html) in your browser to flip through all 14 diagrams with light / dark / full-editorial tabs.
+**Browse the live gallery:** open [`skills/diagram-design/assets/index.html`](skills/diagram-design/assets/index.html) in your browser to flip through all 26 diagrams with light / dark / full-editorial tabs.
---
@@ -78,6 +93,7 @@ Restart Claude Code. The skill registers as `diagram-design` and activates whene
Quicker to install — but the skill lives in the plugin cache, so edits to `references/style-guide.md` don't survive plugin updates. Pick this if you just want to try it out; use the clone route above if you plan to customize the style guide by hand.
**Claude Code:**
+
```
/plugin marketplace add cathrynlavery/diagram-design
/plugin install diagram-design@diagram-design
@@ -86,6 +102,7 @@ Quicker to install — but the skill lives in the plugin cache, so edits to `ref
**Claude Cowork:** Customize → Directory → Plugins → **+** → paste `cathrynlavery/diagram-design` → Sync, then install from the Personal list.
**Codex:**
+
```
npx skills add https://github.com/cathrynlavery/diagram-design --skill diagram-design
```
@@ -132,7 +149,7 @@ Before writing tokens, the skill verifies WCAG AA contrast on `ink` over `paper`
### Manual override
-Prefer to set tokens by hand? Open [`skills/diagram-design/references/style-guide.md`](skills/diagram-design/references/style-guide.md) and edit the table. Everything downstream reads from there — all 14 diagrams, the annotation primitive, and the gallery all inherit semantic role names (`accent`, not `#eb6c36`).
+Prefer to set tokens by hand? Open [`skills/diagram-design/references/style-guide.md`](skills/diagram-design/references/style-guide.md) and edit the table. Everything downstream reads from there — all 26 diagrams, the annotation primitive, and the gallery all inherit semantic role names (`accent`, not `#eb6c36`).
### First-run gate
@@ -147,7 +164,7 @@ See [`skills/diagram-design/references/onboarding.md`](skills/diagram-design/ref
## Quickstart
```bash
-# Open the gallery to see all 14 diagrams
+# Open the gallery to see all 26 diagrams
open ~/.claude/skills/diagram-design/assets/index.html
# In Claude Code, just ask:
@@ -165,6 +182,30 @@ cp assets/template-full.html my-diagram.html # editorial with summary cards
---
+## Export to PNG / SVG
+
+Diagrams ship as self-contained HTML, but you can export the diagram itself for Figma, slides, or social cards. Use the slash command:
+
+```
+/diagram-design:export path/to/diagram.html
+/diagram-design:export path/to/diagram.html --svg-only
+/diagram-design:export path/to/diagram.html --png-only --scale=3
+```
+
+Or just ask in natural language:
+
+```
+"Export this diagram as SVG and PNG."
+"Save my-diagram.html as PNG."
+```
+
+- **SVG** — extracts the `` node and injects Google Fonts so it renders standalone in browsers, Figma, and Illustrator.
+- **PNG** — rasterizes the diagram via Playwright at 2× by default. One-time setup: `pip install playwright && playwright install chromium`.
+
+Both formats are diagram-only — editorial cards and headers from `-full` variants aren't included. For a screenshot of the full editorial layout, use your browser's print-to-PDF or full-page screenshot. See [`skills/diagram-design/references/export.md`](skills/diagram-design/references/export.md) for the full procedure.
+
+---
+
## Architecture
Progressive disclosure. `SKILL.md` is a lean index — it tells Claude how to pick a type and where to look for detail. Every type lives in its own reference file, loaded only when relevant.
@@ -194,16 +235,16 @@ diagram-design/
├── assets/
│ ├── index.html — live gallery, tabbed
│ ├── template*.html — scaffolds for new diagrams
-│ ├── example-.html — 3 variants × 14 types
+│ ├── example-.html — 3 variants × 26 types
│ └── example-quadrant-consultant.html — consultant-special 2×2 scenario matrix
└── docs/screenshots/ — the images in this README
```
-This keeps Claude's working context tight (only load what you need) and makes the skill easy to extend — drop a new `type-.md` and wire it into the selection guide.
+This keeps Claude's working context tight (only load what you need) and makes the skill easy to extend — drop a new `type-.md` and wire it into the selection guide. The skill ships with 32 reference files covering every diagram type, primitive, and utility.
### What loads when
-The top-level `SKILL.md` is always in context. Everything else is pulled in only when relevant — this is what keeps the skill fast even with 15 reference files.
+The top-level `SKILL.md` is always in context. Everything else is pulled in only when relevant — this is what keeps the skill fast even with 32 reference files.
| You ask for… | Claude loads |
|---|---|
@@ -212,7 +253,7 @@ The top-level `SKILL.md` is always in context. Everything else is pulled in only
| "Onboard this skill to my site" | `SKILL.md` + `references/onboarding.md` + `references/style-guide.md` |
| "Add an editorial callout to this diagram" | `SKILL.md` + `references/primitive-annotation.md` |
| "Give me a hand-drawn version" | `SKILL.md` + `references/primitive-sketchy.md` |
-| Routine diagram-making (any of the 14 diagrams) | Only `SKILL.md` + that one type's reference |
+| Routine diagram-making (any of the 26 diagrams) | Only `SKILL.md` + that one type's reference |
No matter how many types exist, Claude only reads the one you need. Add a new type tomorrow and nothing else changes.
@@ -228,6 +269,7 @@ One accent color, 1–2 focal elements per diagram. Three font families: Instrum
- **Annotation callout** — italic Instrument Serif + dashed Bézier leader, for editorial asides that sit in the margins. See [`skills/diagram-design/references/primitive-annotation.md`](skills/diagram-design/references/primitive-annotation.md).
- **Sketchy filter** — SVG turbulence + displacement map for a hand-drawn variant. Good for essays, not for technical docs. See [`skills/diagram-design/references/primitive-sketchy.md`](skills/diagram-design/references/primitive-sketchy.md).
+- **Icon set** — 55 monochrome IT/cloud icons (laptop, phone, user, server, database, Docker, Kubernetes, AWS, Azure, GitHub, Postgres…) for richer architecture and sequence diagrams. Stroked icons from [Tabler Icons](https://tabler.io/icons) (MIT); brand silhouettes from [Simple Icons](https://simpleicons.org) (CC0). Each icon uses `currentColor` so it inherits the editorial skin or your onboarded brand. See [`skills/diagram-design/references/primitive-icons.md`](skills/diagram-design/references/primitive-icons.md); browse the [gallery](skills/diagram-design/assets/icons.html). Regenerate with `python scripts/build-icons.py`.
---
diff --git a/THIRD_PARTY_LICENSES.md b/THIRD_PARTY_LICENSES.md
new file mode 100644
index 0000000..df36f4a
--- /dev/null
+++ b/THIRD_PARTY_LICENSES.md
@@ -0,0 +1,43 @@
+# Third-party licenses
+
+The diagram-design skill itself is MIT-licensed (see [`LICENSE`](LICENSE)). It bundles content from the following third-party sources, redistributed under their respective licenses.
+
+## Tabler Icons
+
+- **License:** MIT
+- **Upstream:** https://github.com/tabler/tabler-icons
+- **Used in:** stroked icons in `skills/diagram-design/references/primitive-icons.md` and `skills/diagram-design/assets/icons.html` (categories: Compute, People, Network, Data, Kubernetes, Action, DevOps, plus the stroked Brand outlines for Docker, Terraform, AWS, Azure, GitHub).
+
+The MIT license is reproduced in full at https://github.com/tabler/tabler-icons/blob/main/LICENSE.
+
+## Simple Icons
+
+- **License:** CC0 1.0 Universal (Public Domain Dedication)
+- **Upstream:** https://github.com/simple-icons/simple-icons
+- **Used in:** filled brand silhouettes in `skills/diagram-design/references/primitive-icons.md` and `skills/diagram-design/assets/icons.html` (Kubernetes, Google Cloud, PostgreSQL, Nginx, Gitea, Keycloak, MinIO, Apache NiFi, Apache Airflow, Trino, Apache Superset, Jupyter, Python, R).
+
+The CC0 dedication is reproduced in full at https://github.com/simple-icons/simple-icons/blob/develop/LICENSE.md.
+
+## log-z/logos
+
+- **License:** MIT
+- **Upstream:** https://github.com/log-z/logos/tree/main/website-logos
+- **Used in:** filled brand silhouettes that aren't carried by Simple Icons or Tabler — currently MySQL, Redis, and StarRocks. Source SVGs are 100×100 with embedded `", "", body, flags=re.DOTALL | re.IGNORECASE)
+ body = re.sub(r"]*>.*? ", "", body, flags=re.DOTALL | re.IGNORECASE)
+ body = re.sub(r"]*>.*? ", "", body, flags=re.DOTALL | re.IGNORECASE)
+ # Strip Inkscape canvas-offset translate transforms from group wrappers
+ body = re.sub(r'\btransform="translate\([^"]+\)"', '', body)
+
+ def _rewrite_fill(m: re.Match) -> str:
+ """Keep white; turn everything else into currentColor."""
+ hex_val = m.group(1).lower().strip()
+ if hex_val in ("#fff", "#ffffff", "white", "#fefefe", "#fdfdfd"):
+ return 'fill="#fff"'
+ return 'fill="currentColor"'
+
+ # Rewrite inline style="fill:#rrggbb" → standalone fill= attribute
+ body = re.sub(
+ r'style="[^"]*fill:\s*(#[0-9a-fA-F]{3,8}|white)[^"]*"',
+ lambda m: _rewrite_fill(re.search(r'(#[0-9a-fA-F]{3,8}|white)', m.group(0))),
+ body,
+ )
+ # Rewrite standalone fill="#rrggbb" attributes
+ body = re.sub(
+ r'\bfill="(#[0-9a-fA-F]{3,8}|white)"',
+ _rewrite_fill,
+ body,
+ )
+ body = re.sub(r'\bstroke="#[0-9a-fA-F]{3,8}"', 'stroke="currentColor"', body)
+ body = re.sub(r'\bfill="none"', '', body)
+ body = re.sub(r"\s+", " ", body).strip()
+ return (
+ f'{body} '
+ )
+
+
+def normalize_devicon(raw: str) -> str:
+ """Devicon SVGs have colored fills and a 128x128 or 32x32 viewBox.
+ Strip fills/classes and rewrite to 24x24 currentColor."""
+ inner = re.search(r"]*>(.*?) ", raw, flags=re.DOTALL | re.IGNORECASE)
+ if not inner:
+ raise ValueError("no in Devicon payload")
+ body = inner.group(1)
+ body = re.sub(r"", "", body, flags=re.DOTALL | re.IGNORECASE)
+ body = re.sub(r"]*>.*? ", "", body, flags=re.DOTALL | re.IGNORECASE)
+ body = re.sub(r'\bfill="#[0-9a-fA-F]{3,8}"', 'fill="currentColor"', body)
+ body = re.sub(r'\bstroke="#[0-9a-fA-F]{3,8}"', 'stroke="currentColor"', body)
+ body = re.sub(r'\bclass="[^"]*"', 'fill="currentColor"', body)
+ body = re.sub(r"\s+", " ", body).strip()
+ return (
+ '{body} '
+ )
+
+
+def normalize_logz(raw: str) -> str:
+ """log-z/logos SVGs are 100x100 with embedded ", "", body, flags=re.DOTALL | re.IGNORECASE)
+ body = re.sub(r'\bclass="st\d+"', 'fill="currentColor"', body)
+ body = re.sub(r'\bfill="#[0-9a-fA-F]{3,8}"', 'fill="currentColor"', body)
+ body = re.sub(r"\s+", " ", body).strip()
+ return (
+ '{body} '
+ )
+
+
+def build() -> tuple[list[str], list[str]]:
+ md_chunks: list[str] = []
+ gallery_chunks: list[str] = []
+ misses: list[str] = []
+
+ md_chunks.append(
+ "# Icons (primitive)\n\n"
+ "A monochrome 24×24 icon library for IT/cloud diagrams. Each icon "
+ "uses `currentColor` so it inherits ink from its parent SVG and "
+ "adapts to the editorial skin or any user-onboarded brand palette.\n\n"
+ "## Usage\n\n"
+ "Find the icon by name (the `### name` headings below). Copy the "
+ "fenced `` snippet into your diagram. Default size is 24×24; "
+ "wrap in `` to position and "
+ "resize. Set `color`, `fill`, or `stroke` on the parent group/SVG to "
+ "control color.\n\n"
+ "Generic icons are stroked (1.5px, hairline, like the rest of the "
+ "skill); brand silhouettes are filled. Don't mix the two styles in "
+ "the same diagram unnecessarily.\n\n"
+ )
+
+ for category, items in ICONS.items():
+ md_chunks.append(f"## {category}\n\n")
+ gallery_chunks.append(f'{category} ')
+
+ for slot, source, source_id, blurb in items:
+ vpath = vendor_path(slot, source, source_id)
+
+ if source == "tabler":
+ normalize = normalize_tabler
+ attribution = f"Tabler Icons / `{source_id}` (MIT)"
+ elif source == "simple":
+ normalize = normalize_simple
+ attribution = f"Simple Icons / `{source_id}` (CC0)"
+ elif source == "logz":
+ normalize = normalize_logz
+ attribution = f"log-z/logos / `{source_id}` (MIT)"
+ elif source.startswith("devicon"):
+ variant = source.split(":")[1] if ":" in source else "plain"
+ normalize = normalize_devicon
+ attribution = f"Devicon / `{source_id}-{variant}` (MIT)"
+ elif source == "url":
+ normalize = normalize_url
+ domain = re.sub(r"https?://([^/]+)/.*", r"\1", source_id)
+ attribution = f"Direct fetch / `{domain}` — verify license before use"
+ else:
+ raise ValueError(f"unknown source: {source}")
+
+ if vpath.exists():
+ print(f" local {source}/{source_id} -> {slot}", file=sys.stderr)
+ raw = vpath.read_text(encoding="utf-8")
+ else:
+ print(f" fetching {source}/{source_id} -> {slot}", file=sys.stderr)
+ if source == "tabler":
+ raw = fetch_tabler(source_id)
+ elif source == "simple":
+ raw = fetch_simple(source_id)
+ elif source == "logz":
+ raw = fetch_logz(source_id)
+ elif source.startswith("devicon"):
+ variant = source.split(":")[1] if ":" in source else "plain"
+ raw = fetch_devicon(source_id, variant)
+ elif source == "url":
+ raw = fetch_url(source_id)
+ if raw is not None:
+ vpath.parent.mkdir(parents=True, exist_ok=True)
+ vpath.write_text(raw, encoding="utf-8")
+
+ if raw is None:
+ misses.append(f"{slot} <- {source}/{source_id}")
+ md_chunks.append(
+ f"### {slot}\n_NOT FOUND — please pick a fallback_\n\n"
+ )
+ gallery_chunks.append(
+ f'
'
+ )
+ continue
+
+ try:
+ snippet = normalize(raw)
+ except ValueError as e:
+ misses.append(f"{slot} <- {source}/{source_id} (parse: {e})")
+ continue
+
+ md_chunks.append(
+ f"### {slot}\n{blurb}\n\n"
+ f"```svg\n{snippet}\n```\n\n"
+ f"Source: {attribution}\n\n"
+ )
+ gallery_chunks.append(
+ f'
'
+ )
+
+ gallery_chunks.append("
")
+
+ md_chunks.append(
+ "---\n\n"
+ "## License attribution\n\n"
+ "- **Tabler Icons** — MIT — https://github.com/tabler/tabler-icons\n"
+ "- **Simple Icons** — CC0 — https://github.com/simple-icons/simple-icons\n"
+ "- **Devicon** — MIT — https://github.com/devicons/devicon\n"
+ "- **log-z/logos** — MIT — https://github.com/log-z/logos\n\n"
+ "All libraries' licenses permit redistribution, including in this "
+ "repository's MIT-licensed source. Brand logos retain their "
+ "respective trademarks; this set is for documentation and "
+ "illustrative use only.\n"
+ )
+
+ return md_chunks, gallery_chunks, misses
+
+
+GALLERY_TEMPLATE = """
+
+
+
+
+ Icon library · Diagram Design
+
+
+
+
+
+
+ {SECTIONS}
+
+ Tabler Icons · MIT · github.com/tabler/tabler-icons · Simple Icons · CC0 · github.com/simple-icons/simple-icons · Devicon · MIT · github.com/devicons/devicon
+
+
+
+
+"""
+
+
+def main() -> int:
+ print("Building icon library…", file=sys.stderr)
+ md_chunks, gallery_chunks, misses = build()
+
+ MD_OUT.parent.mkdir(parents=True, exist_ok=True)
+ MD_OUT.write_text("".join(md_chunks), encoding="utf-8")
+
+ HTML_OUT.parent.mkdir(parents=True, exist_ok=True)
+ html = GALLERY_TEMPLATE.replace("{SECTIONS}", "\n".join(gallery_chunks))
+ HTML_OUT.write_text(html, encoding="utf-8")
+
+ total = sum(len(items) for items in ICONS.values())
+ print(f"\nDone. {total - len(misses)}/{total} fetched.", file=sys.stderr)
+ print(f" primitive-icons.md: {MD_OUT}", file=sys.stderr)
+ print(f" icons.html: {HTML_OUT}", file=sys.stderr)
+ if misses:
+ print(f"\n {len(misses)} miss(es) — review and pick fallbacks:", file=sys.stderr)
+ for m in misses:
+ print(f" - {m}", file=sys.stderr)
+ return 1
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/scripts/fix-mojibake.py b/scripts/fix-mojibake.py
new file mode 100644
index 0000000..856cf17
--- /dev/null
+++ b/scripts/fix-mojibake.py
@@ -0,0 +1,61 @@
+"""Replace mojibake sequences in UTF-8 files with their original characters.
+
+The repo had a few files saved by a tool that interpreted UTF-8 as cp1252 and
+re-saved as UTF-8, producing classic mojibake (em-dash --> 'â€"', section sign
+--> '§', right arrow --> 'â†'', etc.). This script rewrites those sequences
+in-place without touching legitimately-encoded UTF-8 elsewhere in the file.
+"""
+import sys
+
+PAIRS = [
+ ('—', '—'), # em-dash
+ ('–', '–'), # en-dash
+ ('’', '’'), # right single quote
+ ('‘', '‘'), # left single quote
+ ('“', '“'), # left double quote
+ ('â€', '”'), # right double quote
+ ('…', '…'), # horizontal ellipsis
+ ('•', '•'), # bullet
+ ('→', '→'), # right arrow
+ ('↑', '←'), # left arrow
+ ('↑', '↑'), # up arrow (same prefix collision - rare)
+ ('↓', '↓'), # down arrow
+ ('≤', '≤'), # less-than-or-equal
+ ('≥', '≥'), # greater-than-or-equal
+ ('×', '×'), # multiplication sign
+ ('÷', '÷'), # division sign
+ ('§', '§'), # section sign
+ ('°', '°'), # degree
+ ('½', '½'), # one-half
+ ('«', '«'), # «
+ ('»', '»'), # »
+ ('©', '©'), # ©
+ ('®', '®'), # ®
+]
+
+
+def fix(path: str) -> int:
+ with open(path, 'rb') as f:
+ raw = f.read()
+ had_bom = raw.startswith(b'\xef\xbb\xbf')
+ if had_bom:
+ raw = raw[3:]
+ text = raw.decode('utf-8')
+ n = 0
+ for bad, good in PAIRS:
+ if bad in text:
+ n += text.count(bad)
+ text = text.replace(bad, good)
+ if n == 0 and not had_bom:
+ print(f'{path}: no mojibake found')
+ return 0
+ with open(path, 'w', encoding='utf-8', newline='\n') as f:
+ f.write(text)
+ note = f' (also stripped BOM)' if had_bom else ''
+ print(f'{path}: replaced {n} sequence(s){note}')
+ return n
+
+
+if __name__ == '__main__':
+ for p in sys.argv[1:]:
+ fix(p)
diff --git a/scripts/vendor/icons/devicon/rstudio-plain.svg b/scripts/vendor/icons/devicon/rstudio-plain.svg
new file mode 100644
index 0000000..28c580a
--- /dev/null
+++ b/scripts/vendor/icons/devicon/rstudio-plain.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/scripts/vendor/icons/devicon/spss-plain.svg b/scripts/vendor/icons/devicon/spss-plain.svg
new file mode 100644
index 0000000..e4e43fa
--- /dev/null
+++ b/scripts/vendor/icons/devicon/spss-plain.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/scripts/vendor/icons/logz/mysql.svg b/scripts/vendor/icons/logz/mysql.svg
new file mode 100644
index 0000000..debc50f
--- /dev/null
+++ b/scripts/vendor/icons/logz/mysql.svg
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/logz/redis.svg b/scripts/vendor/icons/logz/redis.svg
new file mode 100644
index 0000000..60a3f06
--- /dev/null
+++ b/scripts/vendor/icons/logz/redis.svg
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/logz/starrocks.svg b/scripts/vendor/icons/logz/starrocks.svg
new file mode 100644
index 0000000..0029dda
--- /dev/null
+++ b/scripts/vendor/icons/logz/starrocks.svg
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/simple/apacheairflow.svg b/scripts/vendor/icons/simple/apacheairflow.svg
new file mode 100644
index 0000000..8cc4ad0
--- /dev/null
+++ b/scripts/vendor/icons/simple/apacheairflow.svg
@@ -0,0 +1 @@
+Apache Airflow
\ No newline at end of file
diff --git a/scripts/vendor/icons/simple/apachehive.svg b/scripts/vendor/icons/simple/apachehive.svg
new file mode 100644
index 0000000..ae828a2
--- /dev/null
+++ b/scripts/vendor/icons/simple/apachehive.svg
@@ -0,0 +1 @@
+Apache Hive
\ No newline at end of file
diff --git a/scripts/vendor/icons/simple/apachenifi.svg b/scripts/vendor/icons/simple/apachenifi.svg
new file mode 100644
index 0000000..a0b413b
--- /dev/null
+++ b/scripts/vendor/icons/simple/apachenifi.svg
@@ -0,0 +1 @@
+Apache NiFi
\ No newline at end of file
diff --git a/scripts/vendor/icons/simple/apachesuperset.svg b/scripts/vendor/icons/simple/apachesuperset.svg
new file mode 100644
index 0000000..7421ca0
--- /dev/null
+++ b/scripts/vendor/icons/simple/apachesuperset.svg
@@ -0,0 +1 @@
+Apache Superset
\ No newline at end of file
diff --git a/scripts/vendor/icons/simple/gitea.svg b/scripts/vendor/icons/simple/gitea.svg
new file mode 100644
index 0000000..d870f71
--- /dev/null
+++ b/scripts/vendor/icons/simple/gitea.svg
@@ -0,0 +1 @@
+Gitea
\ No newline at end of file
diff --git a/scripts/vendor/icons/simple/googlecloud.svg b/scripts/vendor/icons/simple/googlecloud.svg
new file mode 100644
index 0000000..b7b4dcc
--- /dev/null
+++ b/scripts/vendor/icons/simple/googlecloud.svg
@@ -0,0 +1 @@
+Google Cloud
\ No newline at end of file
diff --git a/scripts/vendor/icons/simple/jupyter.svg b/scripts/vendor/icons/simple/jupyter.svg
new file mode 100644
index 0000000..9353854
--- /dev/null
+++ b/scripts/vendor/icons/simple/jupyter.svg
@@ -0,0 +1 @@
+Jupyter
\ No newline at end of file
diff --git a/scripts/vendor/icons/simple/keycloak.svg b/scripts/vendor/icons/simple/keycloak.svg
new file mode 100644
index 0000000..9a6d6f0
--- /dev/null
+++ b/scripts/vendor/icons/simple/keycloak.svg
@@ -0,0 +1 @@
+Keycloak
\ No newline at end of file
diff --git a/scripts/vendor/icons/simple/kubernetes.svg b/scripts/vendor/icons/simple/kubernetes.svg
new file mode 100644
index 0000000..667f2d4
--- /dev/null
+++ b/scripts/vendor/icons/simple/kubernetes.svg
@@ -0,0 +1 @@
+Kubernetes
\ No newline at end of file
diff --git a/scripts/vendor/icons/simple/microsoftsqlserver.svg b/scripts/vendor/icons/simple/microsoftsqlserver.svg
new file mode 100644
index 0000000..3b3da3f
--- /dev/null
+++ b/scripts/vendor/icons/simple/microsoftsqlserver.svg
@@ -0,0 +1 @@
+Microsoft SQL Server
\ No newline at end of file
diff --git a/scripts/vendor/icons/simple/minio.svg b/scripts/vendor/icons/simple/minio.svg
new file mode 100644
index 0000000..baf5f88
--- /dev/null
+++ b/scripts/vendor/icons/simple/minio.svg
@@ -0,0 +1 @@
+MinIO
\ No newline at end of file
diff --git a/scripts/vendor/icons/simple/nginx.svg b/scripts/vendor/icons/simple/nginx.svg
new file mode 100644
index 0000000..5875410
--- /dev/null
+++ b/scripts/vendor/icons/simple/nginx.svg
@@ -0,0 +1 @@
+NGINX
\ No newline at end of file
diff --git a/scripts/vendor/icons/simple/oracle.svg b/scripts/vendor/icons/simple/oracle.svg
new file mode 100644
index 0000000..a7b5a8d
--- /dev/null
+++ b/scripts/vendor/icons/simple/oracle.svg
@@ -0,0 +1 @@
+Oracle
\ No newline at end of file
diff --git a/scripts/vendor/icons/simple/postgresql.svg b/scripts/vendor/icons/simple/postgresql.svg
new file mode 100644
index 0000000..dcf75b7
--- /dev/null
+++ b/scripts/vendor/icons/simple/postgresql.svg
@@ -0,0 +1 @@
+PostgreSQL
\ No newline at end of file
diff --git a/scripts/vendor/icons/simple/powerbi.svg b/scripts/vendor/icons/simple/powerbi.svg
new file mode 100644
index 0000000..1448662
--- /dev/null
+++ b/scripts/vendor/icons/simple/powerbi.svg
@@ -0,0 +1 @@
+Power BI
\ No newline at end of file
diff --git a/scripts/vendor/icons/simple/python.svg b/scripts/vendor/icons/simple/python.svg
new file mode 100644
index 0000000..30587d8
--- /dev/null
+++ b/scripts/vendor/icons/simple/python.svg
@@ -0,0 +1 @@
+Python
\ No newline at end of file
diff --git a/scripts/vendor/icons/simple/qgis.svg b/scripts/vendor/icons/simple/qgis.svg
new file mode 100644
index 0000000..a0d2e8d
--- /dev/null
+++ b/scripts/vendor/icons/simple/qgis.svg
@@ -0,0 +1 @@
+QGIS
\ No newline at end of file
diff --git a/scripts/vendor/icons/simple/r.svg b/scripts/vendor/icons/simple/r.svg
new file mode 100644
index 0000000..39c03e1
--- /dev/null
+++ b/scripts/vendor/icons/simple/r.svg
@@ -0,0 +1 @@
+R
\ No newline at end of file
diff --git a/scripts/vendor/icons/simple/redash.svg b/scripts/vendor/icons/simple/redash.svg
new file mode 100644
index 0000000..32e7638
--- /dev/null
+++ b/scripts/vendor/icons/simple/redash.svg
@@ -0,0 +1 @@
+Redash
\ No newline at end of file
diff --git a/scripts/vendor/icons/simple/sqlite.svg b/scripts/vendor/icons/simple/sqlite.svg
new file mode 100644
index 0000000..a776ea1
--- /dev/null
+++ b/scripts/vendor/icons/simple/sqlite.svg
@@ -0,0 +1 @@
+SQLite
\ No newline at end of file
diff --git a/scripts/vendor/icons/simple/tableau.svg b/scripts/vendor/icons/simple/tableau.svg
new file mode 100644
index 0000000..0c24b37
--- /dev/null
+++ b/scripts/vendor/icons/simple/tableau.svg
@@ -0,0 +1 @@
+Tableau
\ No newline at end of file
diff --git a/scripts/vendor/icons/simple/trino.svg b/scripts/vendor/icons/simple/trino.svg
new file mode 100644
index 0000000..e960ed2
--- /dev/null
+++ b/scripts/vendor/icons/simple/trino.svg
@@ -0,0 +1 @@
+Trino
\ No newline at end of file
diff --git a/scripts/vendor/icons/tabler/address-book.svg b/scripts/vendor/icons/tabler/address-book.svg
new file mode 100644
index 0000000..4af540d
--- /dev/null
+++ b/scripts/vendor/icons/tabler/address-book.svg
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/alert-triangle.svg b/scripts/vendor/icons/tabler/alert-triangle.svg
new file mode 100644
index 0000000..03f550c
--- /dev/null
+++ b/scripts/vendor/icons/tabler/alert-triangle.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/arrow-left.svg b/scripts/vendor/icons/tabler/arrow-left.svg
new file mode 100644
index 0000000..a134e8a
--- /dev/null
+++ b/scripts/vendor/icons/tabler/arrow-left.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/arrow-right-rhombus.svg b/scripts/vendor/icons/tabler/arrow-right-rhombus.svg
new file mode 100644
index 0000000..56d4f7d
--- /dev/null
+++ b/scripts/vendor/icons/tabler/arrow-right-rhombus.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/arrow-right.svg b/scripts/vendor/icons/tabler/arrow-right.svg
new file mode 100644
index 0000000..b97ebd2
--- /dev/null
+++ b/scripts/vendor/icons/tabler/arrow-right.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/arrows-split.svg b/scripts/vendor/icons/tabler/arrows-split.svg
new file mode 100644
index 0000000..b225146
--- /dev/null
+++ b/scripts/vendor/icons/tabler/arrows-split.svg
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/bolt.svg b/scripts/vendor/icons/tabler/bolt.svg
new file mode 100644
index 0000000..3d8e365
--- /dev/null
+++ b/scripts/vendor/icons/tabler/bolt.svg
@@ -0,0 +1,19 @@
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/braces.svg b/scripts/vendor/icons/tabler/braces.svg
new file mode 100644
index 0000000..0fbd023
--- /dev/null
+++ b/scripts/vendor/icons/tabler/braces.svg
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/brand-aws.svg b/scripts/vendor/icons/tabler/brand-aws.svg
new file mode 100644
index 0000000..c05828d
--- /dev/null
+++ b/scripts/vendor/icons/tabler/brand-aws.svg
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/brand-azure.svg b/scripts/vendor/icons/tabler/brand-azure.svg
new file mode 100644
index 0000000..e3bb468
--- /dev/null
+++ b/scripts/vendor/icons/tabler/brand-azure.svg
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/brand-docker.svg b/scripts/vendor/icons/tabler/brand-docker.svg
new file mode 100644
index 0000000..175a804
--- /dev/null
+++ b/scripts/vendor/icons/tabler/brand-docker.svg
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/brand-github.svg b/scripts/vendor/icons/tabler/brand-github.svg
new file mode 100644
index 0000000..977f5a3
--- /dev/null
+++ b/scripts/vendor/icons/tabler/brand-github.svg
@@ -0,0 +1,19 @@
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/brand-terraform.svg b/scripts/vendor/icons/tabler/brand-terraform.svg
new file mode 100644
index 0000000..42e2e6d
--- /dev/null
+++ b/scripts/vendor/icons/tabler/brand-terraform.svg
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/bucket.svg b/scripts/vendor/icons/tabler/bucket.svg
new file mode 100644
index 0000000..a7fface
--- /dev/null
+++ b/scripts/vendor/icons/tabler/bucket.svg
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/bug.svg b/scripts/vendor/icons/tabler/bug.svg
new file mode 100644
index 0000000..791be9b
--- /dev/null
+++ b/scripts/vendor/icons/tabler/bug.svg
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/chart-line.svg b/scripts/vendor/icons/tabler/chart-line.svg
new file mode 100644
index 0000000..6747e86
--- /dev/null
+++ b/scripts/vendor/icons/tabler/chart-line.svg
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/cloud.svg b/scripts/vendor/icons/tabler/cloud.svg
new file mode 100644
index 0000000..dc277b6
--- /dev/null
+++ b/scripts/vendor/icons/tabler/cloud.svg
@@ -0,0 +1,19 @@
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/cube.svg b/scripts/vendor/icons/tabler/cube.svg
new file mode 100644
index 0000000..fe57d91
--- /dev/null
+++ b/scripts/vendor/icons/tabler/cube.svg
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/database.svg b/scripts/vendor/icons/tabler/database.svg
new file mode 100644
index 0000000..2f6a00f
--- /dev/null
+++ b/scripts/vendor/icons/tabler/database.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/device-desktop.svg b/scripts/vendor/icons/tabler/device-desktop.svg
new file mode 100644
index 0000000..342f886
--- /dev/null
+++ b/scripts/vendor/icons/tabler/device-desktop.svg
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/device-floppy.svg b/scripts/vendor/icons/tabler/device-floppy.svg
new file mode 100644
index 0000000..598874e
--- /dev/null
+++ b/scripts/vendor/icons/tabler/device-floppy.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/device-laptop.svg b/scripts/vendor/icons/tabler/device-laptop.svg
new file mode 100644
index 0000000..b757ebd
--- /dev/null
+++ b/scripts/vendor/icons/tabler/device-laptop.svg
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/device-mobile.svg b/scripts/vendor/icons/tabler/device-mobile.svg
new file mode 100644
index 0000000..6cbe33b
--- /dev/null
+++ b/scripts/vendor/icons/tabler/device-mobile.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/device-sd-card.svg b/scripts/vendor/icons/tabler/device-sd-card.svg
new file mode 100644
index 0000000..3d9b165
--- /dev/null
+++ b/scripts/vendor/icons/tabler/device-sd-card.svg
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/door-enter.svg b/scripts/vendor/icons/tabler/door-enter.svg
new file mode 100644
index 0000000..ca300a1
--- /dev/null
+++ b/scripts/vendor/icons/tabler/door-enter.svg
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/file-text.svg b/scripts/vendor/icons/tabler/file-text.svg
new file mode 100644
index 0000000..10f097c
--- /dev/null
+++ b/scripts/vendor/icons/tabler/file-text.svg
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/file-type-csv.svg b/scripts/vendor/icons/tabler/file-type-csv.svg
new file mode 100644
index 0000000..91992d4
--- /dev/null
+++ b/scripts/vendor/icons/tabler/file-type-csv.svg
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/file-type-txt.svg b/scripts/vendor/icons/tabler/file-type-txt.svg
new file mode 100644
index 0000000..32acaa7
--- /dev/null
+++ b/scripts/vendor/icons/tabler/file-type-txt.svg
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/file-type-xls.svg b/scripts/vendor/icons/tabler/file-type-xls.svg
new file mode 100644
index 0000000..67bb29f
--- /dev/null
+++ b/scripts/vendor/icons/tabler/file-type-xls.svg
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/file.svg b/scripts/vendor/icons/tabler/file.svg
new file mode 100644
index 0000000..ea942f3
--- /dev/null
+++ b/scripts/vendor/icons/tabler/file.svg
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/git-branch.svg b/scripts/vendor/icons/tabler/git-branch.svg
new file mode 100644
index 0000000..8cf2769
--- /dev/null
+++ b/scripts/vendor/icons/tabler/git-branch.svg
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/git-merge.svg b/scripts/vendor/icons/tabler/git-merge.svg
new file mode 100644
index 0000000..ef4ad6d
--- /dev/null
+++ b/scripts/vendor/icons/tabler/git-merge.svg
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/hexagon.svg b/scripts/vendor/icons/tabler/hexagon.svg
new file mode 100644
index 0000000..92501aa
--- /dev/null
+++ b/scripts/vendor/icons/tabler/hexagon.svg
@@ -0,0 +1,19 @@
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/key.svg b/scripts/vendor/icons/tabler/key.svg
new file mode 100644
index 0000000..7423ac8
--- /dev/null
+++ b/scripts/vendor/icons/tabler/key.svg
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/lock.svg b/scripts/vendor/icons/tabler/lock.svg
new file mode 100644
index 0000000..ee42eee
--- /dev/null
+++ b/scripts/vendor/icons/tabler/lock.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/package.svg b/scripts/vendor/icons/tabler/package.svg
new file mode 100644
index 0000000..c49b368
--- /dev/null
+++ b/scripts/vendor/icons/tabler/package.svg
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/refresh.svg b/scripts/vendor/icons/tabler/refresh.svg
new file mode 100644
index 0000000..40f59f7
--- /dev/null
+++ b/scripts/vendor/icons/tabler/refresh.svg
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/robot.svg b/scripts/vendor/icons/tabler/robot.svg
new file mode 100644
index 0000000..7bbc2ce
--- /dev/null
+++ b/scripts/vendor/icons/tabler/robot.svg
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/rocket.svg b/scripts/vendor/icons/tabler/rocket.svg
new file mode 100644
index 0000000..94267f6
--- /dev/null
+++ b/scripts/vendor/icons/tabler/rocket.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/search.svg b/scripts/vendor/icons/tabler/search.svg
new file mode 100644
index 0000000..78f3109
--- /dev/null
+++ b/scripts/vendor/icons/tabler/search.svg
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/server.svg b/scripts/vendor/icons/tabler/server.svg
new file mode 100644
index 0000000..1266679
--- /dev/null
+++ b/scripts/vendor/icons/tabler/server.svg
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/shield-lock.svg b/scripts/vendor/icons/tabler/shield-lock.svg
new file mode 100644
index 0000000..12ae407
--- /dev/null
+++ b/scripts/vendor/icons/tabler/shield-lock.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/sql.svg b/scripts/vendor/icons/tabler/sql.svg
new file mode 100644
index 0000000..0ebde42
--- /dev/null
+++ b/scripts/vendor/icons/tabler/sql.svg
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/stack-2.svg b/scripts/vendor/icons/tabler/stack-2.svg
new file mode 100644
index 0000000..5af5c9b
--- /dev/null
+++ b/scripts/vendor/icons/tabler/stack-2.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/tag.svg b/scripts/vendor/icons/tabler/tag.svg
new file mode 100644
index 0000000..bb5fe21
--- /dev/null
+++ b/scripts/vendor/icons/tabler/tag.svg
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/terminal.svg b/scripts/vendor/icons/tabler/terminal.svg
new file mode 100644
index 0000000..b270261
--- /dev/null
+++ b/scripts/vendor/icons/tabler/terminal.svg
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/test-pipe.svg b/scripts/vendor/icons/tabler/test-pipe.svg
new file mode 100644
index 0000000..2a0e98a
--- /dev/null
+++ b/scripts/vendor/icons/tabler/test-pipe.svg
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/topology-star.svg b/scripts/vendor/icons/tabler/topology-star.svg
new file mode 100644
index 0000000..2186404
--- /dev/null
+++ b/scripts/vendor/icons/tabler/topology-star.svg
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/user-shield.svg b/scripts/vendor/icons/tabler/user-shield.svg
new file mode 100644
index 0000000..67e0851
--- /dev/null
+++ b/scripts/vendor/icons/tabler/user-shield.svg
@@ -0,0 +1,21 @@
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/user.svg b/scripts/vendor/icons/tabler/user.svg
new file mode 100644
index 0000000..3f687db
--- /dev/null
+++ b/scripts/vendor/icons/tabler/user.svg
@@ -0,0 +1,20 @@
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/users.svg b/scripts/vendor/icons/tabler/users.svg
new file mode 100644
index 0000000..b870141
--- /dev/null
+++ b/scripts/vendor/icons/tabler/users.svg
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/wall.svg b/scripts/vendor/icons/tabler/wall.svg
new file mode 100644
index 0000000..9cb05a8
--- /dev/null
+++ b/scripts/vendor/icons/tabler/wall.svg
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/world-cog.svg b/scripts/vendor/icons/tabler/world-cog.svg
new file mode 100644
index 0000000..db7abfc
--- /dev/null
+++ b/scripts/vendor/icons/tabler/world-cog.svg
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/world-www.svg b/scripts/vendor/icons/tabler/world-www.svg
new file mode 100644
index 0000000..23ced18
--- /dev/null
+++ b/scripts/vendor/icons/tabler/world-www.svg
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/tabler/world.svg b/scripts/vendor/icons/tabler/world.svg
new file mode 100644
index 0000000..9f2fe14
--- /dev/null
+++ b/scripts/vendor/icons/tabler/world.svg
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/url/dagster.svg b/scripts/vendor/icons/url/dagster.svg
new file mode 100644
index 0000000..b5a601c
--- /dev/null
+++ b/scripts/vendor/icons/url/dagster.svg
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scripts/vendor/icons/url/hop.svg b/scripts/vendor/icons/url/hop.svg
new file mode 100644
index 0000000..8afcb57
--- /dev/null
+++ b/scripts/vendor/icons/url/hop.svg
@@ -0,0 +1,53 @@
+
+image/svg+xml
+
+
diff --git a/scripts/vendor/icons/url/pentaho.svg b/scripts/vendor/icons/url/pentaho.svg
new file mode 100644
index 0000000..570eaab
--- /dev/null
+++ b/scripts/vendor/icons/url/pentaho.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/scripts/vendor/icons/url/stata.svg b/scripts/vendor/icons/url/stata.svg
new file mode 100644
index 0000000..508b412
--- /dev/null
+++ b/scripts/vendor/icons/url/stata.svg
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/skills/diagram-design/SKILL.md b/skills/diagram-design/SKILL.md
index 1104423..c75671a 100644
--- a/skills/diagram-design/SKILL.md
+++ b/skills/diagram-design/SKILL.md
@@ -1,16 +1,16 @@
---
name: diagram-design
-description: Create technical and product diagrams — architecture, flowchart, sequence, state machine, ER / data model, timeline, swimlane, quadrant, nested, tree, org chart, layer stack, venn, pyramid — as standalone HTML files with inline SVG. Ships with a neutral editorial skin and a first-run gate that prompts users to customize the style guide (colors, fonts) from their own website before generating. Includes annotation-callout primitive and optional sketchy variant.
+description: Create technical and product diagrams — architecture, IT current-state, flowchart, sequence, state machine, ER / data model, timeline, swimlane, quadrant, radar / spider, nested, tree, org chart, layer stack, venn, pyramid / funnel, bar chart, line chart, Gantt, scatter plot, high-level, process, medallion, data flow, DP integration, DP security matrix — as standalone HTML files with inline SVG. Ships with a neutral editorial skin and a first-run gate that prompts users to customize the style guide (colors, fonts) from their own website before generating. Includes annotation-callout primitive and optional sketchy variant.
license: MIT
metadata:
- version: "1.0"
+ version: "2.0"
---
# Diagram Design
Create visual diagrams as self-contained HTML files with inline SVG and CSS, following an opinionated editorial design system.
-Fourteen diagram types. One shared design system, complexity budget, and taste gate. Type-specific conventions live in `references/` and are loaded only when you pick a type.
+Twenty-six diagram types. One shared design system, complexity budget, and taste gate. Type-specific conventions live in `references/` and are loaded only when you pick a type.
---
@@ -20,12 +20,15 @@ Fourteen diagram types. One shared design system, complexity budget, and taste g
Open [`references/style-guide.md`](references/style-guide.md) and check the default tokens. If they're still the shipped defaults (paper `#faf7f2`, ink `#1c1917`, accent `#b5523a` rust), **pause and ask the user**:
-> *"This is your first Schematic in this project. The style guide is still at the default (neutral stone + rust). Do you want to customize it to match your brand first? Options: (a) run onboarding — I'll pull colors and fonts from your website, (b) paste your tokens manually, (c) proceed with the default for now."*
+> *"This is your first Schematic in this project. The style guide is still at the default (neutral stone + rust). Do you want to customize it to match your brand first? Options: (a) pull from your website URL, (b) extract from an installed skill, (c) extract from a local folder / design-system directory, (d) paste tokens manually, (e) proceed with the default for now."*
Then branch:
-- **(a)** → follow [`references/onboarding.md`](references/onboarding.md) to fetch the site, extract palette + fonts, propose a diff, and write `style-guide.md`.
-- **(b)** → accept the user's tokens and write them into `style-guide.md` under a new "Custom tokens" section.
-- **(c)** → proceed; optionally remind the user they can run onboarding later.
+
+- **(a)** → follow [`references/onboarding.md § URL`](references/onboarding.md) to fetch the site, extract palette + fonts, propose a diff, and write `style-guide.md`.
+- **(b)** → follow [`references/onboarding.md § Skill`](references/onboarding.md) — ask which skill, read its SKILL.md / CSS / token files, map to semantic roles, propose diff.
+- **(c)** → follow [`references/onboarding.md § Folder`](references/onboarding.md) — ask for the path, glob for CSS/JSON/MD token files, map to semantic roles, propose diff.
+- **(d)** → accept the user's tokens and write them into `style-guide.md` under a new "Custom tokens" section.
+- **(e)** → proceed; optionally remind the user they can run onboarding later.
**Once the style guide has been customized** (or the user explicitly opted for default), skip this gate on subsequent runs. A simple way to detect customization: if the `accent` value in `style-guide.md` differs from `#b5523a`, assume custom.
@@ -40,6 +43,7 @@ Don't silently ship default-skinned diagrams into a branded project — that's t
From `.impeccable.md`: *"Confident restraint. Earn every element. One color accent, two families, a small spacing vocabulary. If removing it wouldn't hurt the page, remove it."*
Applied to schematics:
+
- Every node represents a distinct idea. Two nodes that always travel together are one node.
- Every connection carries information. If the relationship is obvious from layout, remove the line.
- Coral is **editorial, not a flag.** 1–2 focal nodes per diagram. Using it on 5 nodes erases the signal.
@@ -51,9 +55,10 @@ Applied to schematics:
## 2. When to Use
-Use for any of the 14 diagram types (§3) when a reader will learn more from a visual than from prose, a table, or a bulleted list.
+Use for any of the 26 diagram types (§3) when a reader will learn more from a visual than from prose, a table, or a bulleted list.
**Don't use for:**
+
- Quick unicode diagrams → use **wiretext**.
- Lists of things → table or bullets.
- Simple before/after → table.
@@ -70,6 +75,7 @@ Before drawing, ask: *Would the reader learn more from this than from a well-wri
| If you're showing… | Use | Reference |
|---|---|---|
| Components + connections in a system | **Architecture** | [type-architecture.md](references/type-architecture.md) |
+| Legacy IT landscape grouped by phase/department; documents the *before* state in modernization proposals | **IT current-state** | [type-it-state.md](references/type-it-state.md) |
| Decision logic with branches | **Flowchart** | [type-flowchart.md](references/type-flowchart.md) |
| Time-ordered messages between actors | **Sequence** | [type-sequence.md](references/type-sequence.md) |
| States + transitions + guards | **State machine** | [type-state.md](references/type-state.md) |
@@ -77,14 +83,26 @@ Before drawing, ask: *Would the reader learn more from this than from a well-wri
| Events positioned in time | **Timeline** | [type-timeline.md](references/type-timeline.md) |
| Cross-functional process with handoffs | **Swimlane** | [type-swimlane.md](references/type-swimlane.md) |
| Two-axis positioning / prioritization | **Quadrant** | [type-quadrant.md](references/type-quadrant.md) |
+| Multiple entities scored across 3–5 quantitative criteria | **Radar / Spider** | [type-radar.md](references/type-radar.md) |
| Hierarchy through containment / scope | **Nested** | [type-nested.md](references/type-nested.md) |
| Parent → children relationships | **Tree** | [type-tree.md](references/type-tree.md) |
| Human/agent/team ownership, reporting, routing, escalation | **Org chart** | [type-org-chart.md](references/type-org-chart.md) |
| Stacked abstraction levels | **Layer stack** | [type-layers.md](references/type-layers.md) |
| Overlap between sets | **Venn** | [type-venn.md](references/type-venn.md) |
| Ranked hierarchy or conversion drop-off | **Pyramid / funnel** | [type-pyramid.md](references/type-pyramid.md) |
+| Quantitative comparison across categories | **Bar chart** | [type-bar.md](references/type-bar.md) |
+| Continuous trends over time | **Line chart** | [type-line.md](references/type-line.md) |
+| Tasks and phases on a timeline | **Gantt** | [type-gantt.md](references/type-gantt.md) |
+| Distribution and correlation between two variables | **Scatter plot** | [type-scatter.md](references/type-scatter.md) |
+| End-to-end data stack on a container cluster | **High-Level** | [type-high-level.md](references/type-high-level.md) |
+| Multi-actor sequential process with data handoffs | **Process** | [type-process.md](references/type-process.md) |
+| Multi-tier data storage with quality levels and access policies | **Medallion** | [type-medallion.md](references/type-medallion.md) |
+| Role-scoped data flow: who does what at each pipeline step | **Data flow** | [type-data-flow.md](references/type-data-flow.md) |
+| Integration topology of a data platform — sources → core → consumers | **DP integration** | [type-dp-integration.md](references/type-dp-integration.md) |
+| Per-role / per-component access permissions matrix | **DP security matrix** | [type-dp-security-matrix.md](references/type-dp-security-matrix.md) |
Rules of thumb:
+
- If a 3-column table communicates the same thing, pick the table.
- If you're combining two types, pick the dominant axis — don't hybridize grammars.
- If you're past the complexity budget (§7), split into an overview + detail.
@@ -109,6 +127,11 @@ These mark "AI slop" schematics of any type:
| Shadow on any element | Shadows are out. Borders are in. |
| `rounded-2xl` on boxes | Max radius 6–10px or none |
| Coral on every "important" node | Coral is 1–2 editorial accents, not a signaling system |
+| Diagonal / slanted connectors between off-axis nodes | Rounded right-angle (orthogonal) elbows are mandatory — see §6 Mandatory connector rules |
+| Arrow label sitting on or touching its connector | Label must have a 6–10px gap above the line so the connector stays visible |
+| Two connectors overlapping or running on the same path | Each connection must be independently traceable — bridge crossings, offset parallels |
+| Two connectors sharing a single attach point on a box | Fan attach points along the edge (≥12px apart) so every arrow is clearly distinct — see §6 rule 4 |
+| Connector routed behind a non-endpoint box without need | Reroute around intervening boxes; the dashed-transit exception (§6 rule 5) only applies when an unavoidable intervening box sits on the direct path |
Type-specific anti-patterns live in each `references/type-*.md`.
@@ -165,8 +188,10 @@ Type-specific anti-patterns live in each `references/type-*.md`.
## 6. Core SVG Primitives
Universal building blocks. Type-specialized primitives (lifeline, activation bar, region) live in the relevant `references/type-*.md`. Optional primitives:
+
- Editorial callouts → [primitive-annotation.md](references/primitive-annotation.md)
- Hand-drawn variant → [primitive-sketchy.md](references/primitive-sketchy.md)
+- Icon set (laptop, server, DB, K8s, Docker, AWS, …) → [primitive-icons.md](references/primitive-icons.md). Browse the gallery at [`assets/icons.html`](../assets/icons.html).
### Background
@@ -213,6 +238,30 @@ Don't use the dot pattern when the diagram sits inside a product page, slide, or
**Draw arrows before boxes** so z-order puts lines behind nodes.
+### Mandatory connector rules
+
+These five rules are **non-negotiable**. Run the pre-output checklist (§9) to verify before producing any diagram.
+
+1. **Rounded right-angle (orthogonal) connectors are mandatory.** Never use diagonal `` or straight slanted paths between nodes that don't share an x or y axis. Every bend must be a quarter-arc with `r=8` (or `r=6` minimum for tight layouts). See `references/type-architecture.md` for the elbow-path formula. Reserve plain straight `` only for connections whose endpoints share the same x or y coordinate. Diagonal connectors are an automatic fail.
+
+2. **Label-to-connector margin: 6–10px gap, always.** A label must never sit *on* its arrow — the connector must remain visible. Place the label centered above (or beside, for vertical segments) the line with a **minimum 6px gap** between the bottom of the label's mask rect and the connector stroke. The opaque mask rect prevents the arrow from bleeding through, but the *visible* gap between mask edge and line preserves the reader's ability to trace the connection. If the label is large enough that 6px feels cramped, push it to 8–10px. Never let the mask rect touch or overlap the stroke.
+
+3. **No overlapping connectors.** Two connectors must never share the same stroke path, run parallel on top of each other, or be drawn on top of each other for any segment. When two orthogonal arrows must cross at a single point, apply the **bridge / hop** primitive (see `references/type-architecture.md` § Crossing arrows). When two arrows naturally want to overlap, offset their routing by ≥12px so each line is independently traceable. If you find yourself stacking connectors, redesign the layout — it means two nodes are too close, or the diagram is over budget (split into overview + detail).
+
+4. **Shared edge → fan the attach points.** When two or more connectors enter or exit the *same edge* of a box, each must have its own distinct attach point along that edge — **no two connectors may share a single point on a box**. Spread the attach points evenly along the edge with **≥12px** between adjacent points (8px minimum for very small boxes). Routing rules:
+ - For N connectors on an edge of length L, attach point `k` (1..N) sits at offset `L * k / (N + 1)` from the edge's leading corner.
+ - When the connectors fan out to destinations on different sides, route each one orthogonally from its own attach point — no merging strokes near the box.
+ - When two parallel connectors run in the same direction, keep them ≥12px apart along their entire length, not just at the attach point. Each arrow must remain independently traceable end-to-end.
+
+ No connector may hide another. If you can't tell two arrows apart at a glance, the layout has failed.
+
+5. **A connector must not pass behind a box that isn't its source or destination — except when the box is geometrically unavoidable on a direct orthogonal path.** Reroute around intervening boxes by default. The only legitimate exception is when a cross-cutting node (e.g., a footer service, a horizontal layer bar) physically sits between the connector's source and destination on the only straight path between them — for example, a `METRICS` arrow exiting an `Observability` footer bar and rising into a zone above must cross the `Active Directory` footer bar that sits between them. In that exception:
+ - The stroke must be **dashed** (e.g., `stroke-dasharray="4,3"`) to signal "transit, not interaction" — it tells the reader the intervening box is not an endpoint.
+ - The label sits at the **visible end** of the connector (typically near the source) so it doesn't fall behind the intervening box.
+ - No marker (arrowhead) may land on the intervening box's edge — the marker resolves at the true destination only.
+
+ When in doubt, reroute. The exception exists for the narrow case where rerouting is geometrically impossible, not as a shortcut to avoid layout work.
+
### Node box — full pattern
```svg
@@ -232,17 +281,23 @@ Don't use the dot pattern when the diagram sits inside a product page, slide, or
font-family="'Geist Mono', monospace" text-anchor="middle">tech:port
```
-### Arrow labels — always mask
+### Arrow labels — always mask, always with margin
-Every arrow label needs an opaque rect behind it. Without one it bleeds through the line.
+Every arrow label needs an opaque rect behind it. Without one it bleeds through the line. **And the label must sit with a visible gap above the connector — never on top of it.**
```svg
-
-
+
+WRITE
```
-Rules: ≤14 characters, all-caps, centered on segment midpoint, 8–10px above line. Never `writing-mode` vertical.
+Rules:
+
+- ≤14 characters, all-caps, centered on segment midpoint.
+- **Mandatory 6–10px gap** between the bottom of the mask rect and the arrow stroke. The connector must remain visible — a label that hides its own arrow is a hard fail.
+- Never `writing-mode` vertical.
+- For vertical segments, place the label to the side (not on the line) with the same 6–10px horizontal gap.
### Legend — horizontal strip at the bottom
@@ -297,6 +352,13 @@ Quick check: if a coordinate ends in 1, 2, 3, 5, 6, 7, 9 — fix it.
| Max layers (layer stack) | 6 |
| Max circles (venn) | 3 |
| Max layers (pyramid) | 6 |
+| Max radar axes | 5 |
+| Max radar series | 5 |
+| Max focal radar series | 1 |
+| Max bars (bar chart) | 8 |
+| Max series (line chart) | 5 |
+| Max tasks (Gantt) | 12 |
+| Max points (scatter plot) | 30 |
| Max annotation callouts | 2 |
If you exceed, split into two diagrams (overview + detail).
@@ -326,6 +388,7 @@ Don't use 3 identical generic cards. Vary the treatment:
```
Rules:
+
- `background: #ffffff` (not paper — slight lift without shadow)
- `border: 1px solid rgba(45,49,66,0.12)`
- `border-radius: 6px`, `padding: 1.25rem`
@@ -339,23 +402,32 @@ Rules:
Run before producing any diagram.
**Type fit:**
+
- [ ] Right type for what I'm showing? (§3 selection guide)
- [ ] Would a table / paragraph do the same job? (If yes — don't draw.)
- [ ] Loaded the matching `references/type-*.md`?
**Remove test:**
+
- [ ] Can I remove any node? (Would a reader still understand?)
- [ ] Can I merge any two nodes? (Do they always travel together?)
- [ ] Can I remove any arrow? (Is the relationship obvious from layout?)
- [ ] Can I remove any label? (Does color or shape already signal it?)
**Signal:**
+
- [ ] Coral used on ≤2 elements? If more, which actually deserve focal status?
- [ ] Legend covers every type used — and nothing extra?
- [ ] Within the type's complexity budget (§7)?
**Technical:**
+
- [ ] Arrows drawn before boxes?
+- [ ] **Every connector between off-axis nodes uses a rounded right-angle elbow (`r=8`)? No diagonal `` slants?**
+- [ ] **Every arrow label has a visible 6–10px gap above its connector? (Mask rect not touching the stroke.)**
+- [ ] **No two connectors overlap, share a stroke path, or run on top of each other? Crossings use the bridge/hop primitive?**
+- [ ] **When several connectors enter or exit the same edge of a box, each has its own attach point (≥12px apart)? No connector hides another?**
+- [ ] **No connector passes behind a non-endpoint box, except the unavoidable-intervening-box case (§6 rule 5) — and in that case, the stroke is dashed and the label sits at the visible end?**
- [ ] Every arrow label has an opaque `fill="#f5f5f5"` rect behind it?
- [ ] Legend is a horizontal bottom strip, not floating?
- [ ] No vertical `writing-mode` text?
@@ -363,6 +435,7 @@ Run before producing any diagram.
- [ ] Every font size, coord, width, height, gap divisible by 4?
**Typography:**
+
- [ ] Human-readable names in Geist sans, not Geist Mono?
- [ ] Technical sublabels (ports, commands, URLs) in Geist Mono?
- [ ] Page title in Instrument Serif?
@@ -396,8 +469,13 @@ Every diagram ships in three variants (see `assets/`):
## 11. Output
Always produce a single self-contained `.html` file:
+
- Embedded CSS (no external except Google Fonts)
- Inline SVG (no external images)
- No JavaScript required
Renders correctly in any modern browser.
+
+### Exporting to PNG / SVG
+
+When the user asks to export, save, rasterize, or convert a generated diagram to `.png` or `.svg`, load [`references/export.md`](references/export.md) and follow the procedure there. Both formats deliver the diagram only (the `` node) — editorial wrappers like cards and headers are dropped by design. Export is **manual** — never produce export files unprompted.
diff --git a/skills/diagram-design/assets/example-architecture-dark.html b/skills/diagram-design/assets/example-architecture-dark.html
index f82abf3..186d97a 100644
--- a/skills/diagram-design/assets/example-architecture-dark.html
+++ b/skills/diagram-design/assets/example-architecture-dark.html
@@ -71,24 +71,39 @@
+
+
+
+ CONTENT
+
-
-
+
+
+
+
+
HTTPS
+
+ RESP
+
SSR
-
- READ MDX
+
+ READ MDX
-
- QUERY
+
+ QUERY
@@ -156,6 +171,9 @@
Primary flow
+
+
+ Return / async
+
+
Bar · Diagram Design
+
Sprint velocity · 8-sprint view
+
+
+
+
+
+
+
+
+
+
+
+
+ STORY POINTS
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 20
+ 40
+ 60
+ 80
+ 100
+ 120
+
+
+
+
+
+ 72
+
+
+
+
+ 88
+
+
+
+
+ 95
+
+
+
+
+ 78
+
+
+
+
+ 110
+
+
+
+
+ 102
+
+
+
+
+ 85
+
+
+
+
+ 93
+
+
+ S1
+ S2
+ S3
+ S4
+ S5
+ S6
+ S7
+ S8
+
+
+
+ LEGEND
+
+
+ Sprint 5 · record high
+
+
+ Other sprints
+
+
+
diff --git a/skills/diagram-design/assets/example-architecture-full.html b/skills/diagram-design/assets/example-architecture-full.html
index e302710..6b89738 100644
--- a/skills/diagram-design/assets/example-architecture-full.html
+++ b/skills/diagram-design/assets/example-architecture-full.html
@@ -61,24 +61,39 @@
+
+
+
+ CONTENT
+
-
-
+
+
+
+
+
HTTPS
+
+ RESP
+
SSR
-
- READ MDX
+
+ READ MDX
-
- QUERY
+
+ QUERY
@@ -146,6 +161,9 @@
Primary flow
+
+
+ Return / async
diff --git a/skills/diagram-design/assets/example-architecture.html b/skills/diagram-design/assets/example-architecture.html
index e9d32fe..506a625 100644
--- a/skills/diagram-design/assets/example-architecture.html
+++ b/skills/diagram-design/assets/example-architecture.html
@@ -71,24 +71,40 @@
+
+
+
+ CONTENT
+
-
-
+
+
+
+
+
+
HTTPS
+
+ RESP
+
SSR
-
- READ MDX
+
+ READ MDX
-
- QUERY
+
+ QUERY
@@ -156,6 +172,9 @@
Primary flow
+
+
+ Return / async
diff --git a/skills/diagram-design/assets/example-bar-dark.html b/skills/diagram-design/assets/example-bar-dark.html
new file mode 100644
index 0000000..b140ef4
--- /dev/null
+++ b/skills/diagram-design/assets/example-bar-dark.html
@@ -0,0 +1,127 @@
+
+
+