From 5d8d7629e03c9363ddf2f468ba7f97a80e3604ac Mon Sep 17 00:00:00 2001
From: stiffneckjim <22213990+stiffneckjim@users.noreply.github.com>
Date: Mon, 25 May 2026 16:35:38 +0100
Subject: [PATCH 01/13] feat: add mermaid diagrams and node http-server for
local preview
- Add network architecture diagram showing Pi-hole placement
- Add DNS query flow sequence diagram (blocked vs allowed)
- Add demo flow diagram
- Enhance key takeaways and add questions slide with resources
- Add http-server as dev dependency on port 8001
- Add 'serve' and 'preview' npm scripts for local browsing
---
package.json | 5 +-
pnpm-lock.yaml | 353 +++++++++++++++++++++++++++++++++++++++++++++++++
slides.md | 89 ++++++++++---
3 files changed, 425 insertions(+), 22 deletions(-)
diff --git a/package.json b/package.json
index f5de029..75f9b3f 100644
--- a/package.json
+++ b/package.json
@@ -9,10 +9,13 @@
"scripts": {
"dev": "pnpm exec marp slides.md --server --allow-local-files",
"build": "node scripts/build.mjs",
+ "serve": "http-server dist -p 8001 -o",
+ "preview": "pnpm build && pnpm serve",
"export": "pnpm exec marp slides.md --pdf --allow-local-files --output dist/slides.pdf",
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\""
},
"devDependencies": {
- "@marp-team/marp-cli": "^4.1.0"
+ "@marp-team/marp-cli": "^4.1.0",
+ "http-server": "^14.1.0"
}
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index b769a60..17872de 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -11,6 +11,9 @@ importers:
'@marp-team/marp-cli':
specifier: ^4.1.0
version: 4.4.0
+ http-server:
+ specifier: ^14.1.0
+ version: 14.1.1
packages:
@@ -103,6 +106,9 @@ packages:
resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==}
engines: {node: '>=4'}
+ async@3.2.6:
+ resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
+
b4a@1.8.1:
resolution: {integrity: sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==}
peerDependencies:
@@ -152,6 +158,10 @@ packages:
bare-url@2.4.3:
resolution: {integrity: sha512-Kccpc7ACfXaxfeInfqKcZtW4pT5YBn1mesc4sCsun6sRwtbJ4h+sNOaksUpYEJUKfN65YWC6Bw2OJEFiKxq8nQ==}
+ basic-auth@2.0.1:
+ resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==}
+ engines: {node: '>= 0.8'}
+
basic-ftp@5.3.1:
resolution: {integrity: sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==}
engines: {node: '>=10.0.0'}
@@ -162,10 +172,22 @@ packages:
buffer-crc32@0.2.13:
resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
+ call-bind-apply-helpers@1.0.2:
+ resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
+ engines: {node: '>= 0.4'}
+
+ call-bound@1.0.4:
+ resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
+ engines: {node: '>= 0.4'}
+
callsites@3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
+ chalk@4.1.2:
+ resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+ engines: {node: '>=10'}
+
chokidar@4.0.3:
resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
engines: {node: '>= 14.16.0'}
@@ -197,6 +219,10 @@ packages:
resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==}
engines: {node: '>= 12'}
+ corser@2.0.1:
+ resolution: {integrity: sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ==}
+ engines: {node: '>= 0.4.0'}
+
cosmiconfig@9.0.1:
resolution: {integrity: sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==}
engines: {node: '>=14'}
@@ -246,6 +272,10 @@ packages:
devtools-protocol@0.0.1608973:
resolution: {integrity: sha512-Tpm17fxYzt+J7VrGdc1k8YdRqS3YV7se/M6KeemEqvUbq/n7At1rWVuXMxQgpWkdwSdIEKYbU//Bve+Shm4YNQ==}
+ dunder-proto@1.0.1:
+ resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
+ engines: {node: '>= 0.4'}
+
emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
@@ -263,6 +293,18 @@ packages:
error-ex@1.3.4:
resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==}
+ es-define-property@1.0.1:
+ resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
+ engines: {node: '>= 0.4'}
+
+ es-errors@1.3.0:
+ resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
+ engines: {node: '>= 0.4'}
+
+ es-object-atoms@1.1.2:
+ resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==}
+ engines: {node: '>= 0.4'}
+
escalade@3.2.0:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
@@ -292,6 +334,9 @@ packages:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
+ eventemitter3@4.0.7:
+ resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
+
events-universal@1.0.1:
resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==}
@@ -306,10 +351,30 @@ packages:
fd-slicer@1.1.0:
resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
+ follow-redirects@1.16.0:
+ resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==}
+ engines: {node: '>=4.0'}
+ peerDependencies:
+ debug: '*'
+ peerDependenciesMeta:
+ debug:
+ optional: true
+
+ function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
get-caller-file@2.0.5:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
+ get-intrinsic@1.3.0:
+ resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
+ engines: {node: '>= 0.4'}
+
+ get-proto@1.0.1:
+ resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
+ engines: {node: '>= 0.4'}
+
get-stream@5.2.0:
resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
engines: {node: '>=8'}
@@ -318,10 +383,34 @@ packages:
resolution: {integrity: sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==}
engines: {node: '>= 14'}
+ gopd@1.2.0:
+ resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
+ engines: {node: '>= 0.4'}
+
+ has-flag@4.0.0:
+ resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+ engines: {node: '>=8'}
+
+ has-symbols@1.1.0:
+ resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
+ engines: {node: '>= 0.4'}
+
+ hasown@2.0.3:
+ resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==}
+ engines: {node: '>= 0.4'}
+
+ he@1.2.0:
+ resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
+ hasBin: true
+
highlight.js@11.11.1:
resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==}
engines: {node: '>=12.0.0'}
+ html-encoding-sniffer@3.0.0:
+ resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==}
+ engines: {node: '>=12'}
+
http-errors@1.8.1:
resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==}
engines: {node: '>= 0.6'}
@@ -330,10 +419,23 @@ packages:
resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
engines: {node: '>= 14'}
+ http-proxy@1.18.1:
+ resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==}
+ engines: {node: '>=8.0.0'}
+
+ http-server@14.1.1:
+ resolution: {integrity: sha512-+cbxadF40UXd9T01zUHgA+rlo2Bg1Srer4+B4NwIHdaGxAGGv59nYRnGGDJ9LBk7alpS0US+J+bLLdQOOkJq4A==}
+ engines: {node: '>=12'}
+ hasBin: true
+
https-proxy-agent@7.0.6:
resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
engines: {node: '>= 14'}
+ iconv-lite@0.6.3:
+ resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
+ engines: {node: '>=0.10.0'}
+
import-fresh@3.3.1:
resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
engines: {node: '>=6'}
@@ -386,6 +488,10 @@ packages:
resolution: {integrity: sha512-1TGiQiJVRQ3NPmZH6sx5Cfnmg6GQm9jvC1ch4TK511NjSJvjzKLzn5pPfZRNZkRPZP0HqCioSndqH8v2nRaWVQ==}
hasBin: true
+ math-intrinsics@1.1.0:
+ resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
+ engines: {node: '>= 0.4'}
+
mathjax-full@3.2.2:
resolution: {integrity: sha512-+LfG9Fik+OuI8SLwsiR02IVdjcnRCy5MufYLi0C3TdMT56L/pjB0alMVGgoWJF8pN9Rc7FESycZB9BMNWIid5w==}
deprecated: Version 4 replaces this package with the scoped package @mathjax/src
@@ -404,6 +510,14 @@ packages:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
+ mime@1.6.0:
+ resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
+ engines: {node: '>=4'}
+ hasBin: true
+
+ minimist@1.2.8:
+ resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
+
mitt@3.0.1:
resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
@@ -429,9 +543,17 @@ packages:
resolution: {integrity: sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==}
engines: {node: '>= 0.4.0'}
+ object-inspect@1.13.4:
+ resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
+ engines: {node: '>= 0.4'}
+
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+ opener@1.5.2:
+ resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==}
+ hasBin: true
+
pac-proxy-agent@7.2.0:
resolution: {integrity: sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==}
engines: {node: '>= 14'}
@@ -458,6 +580,10 @@ packages:
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+ portfinder@1.0.38:
+ resolution: {integrity: sha512-rEwq/ZHlJIKw++XtLAO8PPuOQA/zaPJOZJ37BVuN97nLpMJeuDVLVGRwbFoBgLudgdTMP2hdRJP++H+8QOA3vg==}
+ engines: {node: '>= 10.12'}
+
postcss-nesting@13.0.2:
resolution: {integrity: sha512-1YCI290TX+VP0U/K/aFxzHzQWHWURL+CtHMSbex1lCdpXD1SoR2sYuxDu5aNI9lPoXpKTCggFZiDJbwylU0LEQ==}
engines: {node: '>=18'}
@@ -494,6 +620,10 @@ packages:
resolution: {integrity: sha512-T5ScUMAsmhdNbgDR41AGESYeS6V9MSgetkSnVhhW+gXvzC42VesKCn5ld87gAZDJ6vLHL9GkRvY9WtQWSnwFbw==}
engines: {node: '>=18'}
+ qs@6.15.2:
+ resolution: {integrity: sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==}
+ engines: {node: '>=0.6'}
+
readdirp@4.1.2:
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
engines: {node: '>= 14.18.0'}
@@ -502,10 +632,22 @@ packages:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'}
+ requires-port@1.0.0:
+ resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
+
resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
+ safe-buffer@5.1.2:
+ resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
+
+ safer-buffer@2.1.2:
+ resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+
+ secure-compare@3.0.1:
+ resolution: {integrity: sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==}
+
semver@7.8.1:
resolution: {integrity: sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==}
engines: {node: '>=10'}
@@ -518,6 +660,22 @@ packages:
setprototypeof@1.2.0:
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
+ side-channel-list@1.0.1:
+ resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==}
+ engines: {node: '>= 0.4'}
+
+ side-channel-map@1.0.1:
+ resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
+ engines: {node: '>= 0.4'}
+
+ side-channel-weakmap@1.0.2:
+ resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
+ engines: {node: '>= 0.4'}
+
+ side-channel@1.1.0:
+ resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
+ engines: {node: '>= 0.4'}
+
smart-buffer@4.2.0:
resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==}
engines: {node: '>= 6.0.0', npm: '>= 3.0.0'}
@@ -557,6 +715,10 @@ packages:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
+ supports-color@7.2.0:
+ resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+ engines: {node: '>=8'}
+
tar-fs@3.1.2:
resolution: {integrity: sha512-QGxxTxxyleAdyM3kpFs14ymbYmNFrfY+pHj7Z8FgtbZ7w2//VAgLMac7sT6nRpIHjppXO2AwwEOg0bPFVRcmXw==}
@@ -589,12 +751,24 @@ packages:
undici-types@7.24.6:
resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==}
+ union@0.5.0:
+ resolution: {integrity: sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==}
+ engines: {node: '>= 0.8.0'}
+
+ url-join@4.0.1:
+ resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==}
+
util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
webdriver-bidi-protocol@0.4.1:
resolution: {integrity: sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw==}
+ whatwg-encoding@2.0.0:
+ resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==}
+ engines: {node: '>=12'}
+ deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation
+
wicked-good-xpath@1.3.0:
resolution: {integrity: sha512-Gd9+TUn5nXdwj/hFsPVx5cuHHiF5Bwuc30jZ4+ronF1qHK5O7HD0sgmXWSEgwKquT3ClLoKPVbO6qGwVwLzvAw==}
@@ -756,6 +930,8 @@ snapshots:
dependencies:
tslib: 2.8.1
+ async@3.2.6: {}
+
b4a@1.8.1: {}
bare-events@2.8.3: {}
@@ -790,14 +966,33 @@ snapshots:
dependencies:
bare-path: 3.0.0
+ basic-auth@2.0.1:
+ dependencies:
+ safe-buffer: 5.1.2
+
basic-ftp@5.3.1: {}
batch@0.6.1: {}
buffer-crc32@0.2.13: {}
+ call-bind-apply-helpers@1.0.2:
+ dependencies:
+ es-errors: 1.3.0
+ function-bind: 1.1.2
+
+ call-bound@1.0.4:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ get-intrinsic: 1.3.0
+
callsites@3.1.0: {}
+ chalk@4.1.2:
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+
chokidar@4.0.3:
dependencies:
readdirp: 4.1.2
@@ -826,6 +1021,8 @@ snapshots:
commander@8.3.0: {}
+ corser@2.0.1: {}
+
cosmiconfig@9.0.1:
dependencies:
env-paths: 2.2.1
@@ -857,6 +1054,12 @@ snapshots:
devtools-protocol@0.0.1608973: {}
+ dunder-proto@1.0.1:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ es-errors: 1.3.0
+ gopd: 1.2.0
+
emoji-regex@8.0.0: {}
end-of-stream@1.4.5:
@@ -871,6 +1074,14 @@ snapshots:
dependencies:
is-arrayish: 0.2.1
+ es-define-property@1.0.1: {}
+
+ es-errors@1.3.0: {}
+
+ es-object-atoms@1.1.2:
+ dependencies:
+ es-errors: 1.3.0
+
escalade@3.2.0: {}
escape-html@1.0.3: {}
@@ -891,6 +1102,8 @@ snapshots:
esutils@2.0.3: {}
+ eventemitter3@4.0.7: {}
+
events-universal@1.0.1:
dependencies:
bare-events: 2.8.3
@@ -913,8 +1126,30 @@ snapshots:
dependencies:
pend: 1.2.0
+ follow-redirects@1.16.0: {}
+
+ function-bind@1.1.2: {}
+
get-caller-file@2.0.5: {}
+ get-intrinsic@1.3.0:
+ dependencies:
+ call-bind-apply-helpers: 1.0.2
+ es-define-property: 1.0.1
+ es-errors: 1.3.0
+ es-object-atoms: 1.1.2
+ function-bind: 1.1.2
+ get-proto: 1.0.1
+ gopd: 1.2.0
+ has-symbols: 1.1.0
+ hasown: 2.0.3
+ math-intrinsics: 1.1.0
+
+ get-proto@1.0.1:
+ dependencies:
+ dunder-proto: 1.0.1
+ es-object-atoms: 1.1.2
+
get-stream@5.2.0:
dependencies:
pump: 3.0.4
@@ -927,8 +1162,24 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ gopd@1.2.0: {}
+
+ has-flag@4.0.0: {}
+
+ has-symbols@1.1.0: {}
+
+ hasown@2.0.3:
+ dependencies:
+ function-bind: 1.1.2
+
+ he@1.2.0: {}
+
highlight.js@11.11.1: {}
+ html-encoding-sniffer@3.0.0:
+ dependencies:
+ whatwg-encoding: 2.0.0
+
http-errors@1.8.1:
dependencies:
depd: 1.1.2
@@ -944,6 +1195,33 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ http-proxy@1.18.1:
+ dependencies:
+ eventemitter3: 4.0.7
+ follow-redirects: 1.16.0
+ requires-port: 1.0.0
+ transitivePeerDependencies:
+ - debug
+
+ http-server@14.1.1:
+ dependencies:
+ basic-auth: 2.0.1
+ chalk: 4.1.2
+ corser: 2.0.1
+ he: 1.2.0
+ html-encoding-sniffer: 3.0.0
+ http-proxy: 1.18.1
+ mime: 1.6.0
+ minimist: 1.2.8
+ opener: 1.5.2
+ portfinder: 1.0.38
+ secure-compare: 3.0.1
+ union: 0.5.0
+ url-join: 4.0.1
+ transitivePeerDependencies:
+ - debug
+ - supports-color
+
https-proxy-agent@7.0.6:
dependencies:
agent-base: 7.1.4
@@ -951,6 +1229,10 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ iconv-lite@0.6.3:
+ dependencies:
+ safer-buffer: 2.1.2
+
import-fresh@3.3.1:
dependencies:
parent-module: 1.0.1
@@ -997,6 +1279,8 @@ snapshots:
punycode.js: 2.3.1
uc.micro: 2.1.0
+ math-intrinsics@1.1.0: {}
+
mathjax-full@3.2.2:
dependencies:
esm: 3.2.25
@@ -1014,6 +1298,10 @@ snapshots:
dependencies:
mime-db: 1.52.0
+ mime@1.6.0: {}
+
+ minimist@1.2.8: {}
+
mitt@3.0.1: {}
mj-context-menu@0.6.1: {}
@@ -1028,10 +1316,14 @@ snapshots:
netmask@2.1.1: {}
+ object-inspect@1.13.4: {}
+
once@1.4.0:
dependencies:
wrappy: 1.0.2
+ opener@1.5.2: {}
+
pac-proxy-agent@7.2.0:
dependencies:
'@tootallnate/quickjs-emscripten': 0.23.0
@@ -1067,6 +1359,13 @@ snapshots:
picocolors@1.1.1: {}
+ portfinder@1.0.38:
+ dependencies:
+ async: 3.2.6
+ debug: 4.4.3
+ transitivePeerDependencies:
+ - supports-color
+
postcss-nesting@13.0.2(postcss@8.5.15):
dependencies:
'@csstools/selector-resolve-nested': 3.1.0(postcss-selector-parser@7.1.1)
@@ -1126,12 +1425,24 @@ snapshots:
- supports-color
- utf-8-validate
+ qs@6.15.2:
+ dependencies:
+ side-channel: 1.1.0
+
readdirp@4.1.2: {}
require-directory@2.1.1: {}
+ requires-port@1.0.0: {}
+
resolve-from@4.0.0: {}
+ safe-buffer@5.1.2: {}
+
+ safer-buffer@2.1.2: {}
+
+ secure-compare@3.0.1: {}
+
semver@7.8.1: {}
serve-index@1.9.2:
@@ -1148,6 +1459,34 @@ snapshots:
setprototypeof@1.2.0: {}
+ side-channel-list@1.0.1:
+ dependencies:
+ es-errors: 1.3.0
+ object-inspect: 1.13.4
+
+ side-channel-map@1.0.1:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ object-inspect: 1.13.4
+
+ side-channel-weakmap@1.0.2:
+ dependencies:
+ call-bound: 1.0.4
+ es-errors: 1.3.0
+ get-intrinsic: 1.3.0
+ object-inspect: 1.13.4
+ side-channel-map: 1.0.1
+
+ side-channel@1.1.0:
+ dependencies:
+ es-errors: 1.3.0
+ object-inspect: 1.13.4
+ side-channel-list: 1.0.1
+ side-channel-map: 1.0.1
+ side-channel-weakmap: 1.0.2
+
smart-buffer@4.2.0: {}
socks-proxy-agent@8.0.5:
@@ -1195,6 +1534,10 @@ snapshots:
dependencies:
ansi-regex: 5.0.1
+ supports-color@7.2.0:
+ dependencies:
+ has-flag: 4.0.0
+
tar-fs@3.1.2:
dependencies:
pump: 3.0.4
@@ -1244,10 +1587,20 @@ snapshots:
undici-types@7.24.6:
optional: true
+ union@0.5.0:
+ dependencies:
+ qs: 6.15.2
+
+ url-join@4.0.1: {}
+
util-deprecate@1.0.2: {}
webdriver-bidi-protocol@0.4.1: {}
+ whatwg-encoding@2.0.0:
+ dependencies:
+ iconv-lite: 0.6.3
+
wicked-good-xpath@1.3.0: {}
wrap-ansi@7.0.0:
diff --git a/slides.md b/slides.md
index 49b54e5..3ff34ec 100644
--- a/slides.md
+++ b/slides.md
@@ -21,40 +21,87 @@ CodeHub meetup deck
- Where Pi-hole fits in the stack
- DNS, DHCP, and device discovery in plain language
- A practical setup path you can repeat later
+- A little extra security
---
-## Home network map
+## Home network architecture
+
+```mermaid
+graph TD
+ Internet["🌐 Internet"]
+ ISP["ISP/Modem"]
+ Router["Router"]
+ WiFi["Wi-Fi AP"]
+ PiHole["🔒 Pi-hole
(DNS Server)"]
+ Devices["📱 Client Devices
Phones, Laptops, Smart TV"]
+
+ Internet -->|Connection| ISP
+ ISP -->|LAN| Router
+ Router -->|Ethernet| PiHole
+ Router -->|Wi-Fi| WiFi
+ WiFi -->|DHCP + DNS| Devices
+ Devices -->|DNS Queries| PiHole
+ PiHole -->|Block/Forward| Router
+```
-- Internet connection
-- Router or gateway
-- Wi-Fi access point or mesh nodes
-- Client devices
-- Pi-hole as the DNS filter and visibility layer
+---
+
+## DNS query flow with Pi-hole
+
+```mermaid
+sequenceDiagram
+ participant Device as Device
+ participant PiHole as Pi-hole
+ participant Blocklist as Blocklist
+ participant Upstream as Upstream DNS
+
+ Device->>PiHole: DNS query for ads.example.com
+ PiHole->>Blocklist: Check against lists
+ alt Blocked Domain
+ Blocklist-->>PiHole: ✗ In blocklist
+ PiHole-->>Device: NXDOMAIN (blocked)
+ else Allowed Domain
+ Blocklist-->>PiHole: ✓ Not in list
+ PiHole->>Upstream: Forward to 8.8.8.8
+ Upstream-->>PiHole: IP address
+ PiHole-->>Device: ✓ Return result
+ end
+```
---
-## Pi-hole in practice
+## Demo: What we'll show
-- Point clients or the router at Pi-hole for DNS
-- Filter obvious ad and telemetry domains
-- Use the query log to understand what devices are doing
-- Keep the setup simple enough for the rest of the household
+```mermaid
+graph LR
+ A["Query Log"] -->|Live traffic| B["Blocked Domains"]
+ B -->|Ads, Trackers| C["Client Analysis"]
+ C -->|Who requests what| D["Dashboard"]
+ D -->|Stats & Config| E["Blocklists"]
+```
+
+**Live demo steps:**
+1. Show network layout and device configuration
+2. Open Pi-hole admin dashboard
+3. Inspect recent queries in real-time
+4. Highlight blocked vs allowed domains
+5. Review performance impact and statistics
---
-## Demo flow
+## Key takeaways
-- Show the network layout
-- Open Pi-hole admin and inspect recent queries
-- Explain what a blocked request looks like
-- Call out any caveats before people copy the setup
+- **Visibility first**: Query logs show you what's happening on your network
+- **DNS is powerful**: One DNS change affects all devices automatically
+- **Block thoughtfully**: Start conservative, expand blocklists gradually
+- **Learn & iterate**: Use Pi-hole as a learning tool, not just an ad blocker
+- **Keep it simple**: Simple setups are easier to maintain and explain to others
---
-## Wrap-up
+## Questions?
+
+Pi-hole docs: https://docs.pi-hole.net/
-- Start with visibility before adding complexity
-- Keep DNS and DHCP decisions deliberate
-- Use Pi-hole as a tool for learning, not just blocking ads
-- Leave room for gradual improvement
+Thank you!
From 1665abbcfcee362deb3e1b8a611672c6fe7dee09 Mon Sep 17 00:00:00 2001
From: stiffneckjim <22213990+stiffneckjim@users.noreply.github.com>
Date: Mon, 25 May 2026 16:39:28 +0100
Subject: [PATCH 02/13] fix: enable mermaid diagram rendering
- Add marp.config.js with Mermaid configuration
- Create inject-mermaid.mjs post-build script to load mermaid.js CDN
- Update build.mjs to run Mermaid injection after Marp build
- Diagrams now render properly in browser
---
marp.config.js | 10 ++++++++++
scripts/build.mjs | 13 ++++++++++---
scripts/inject-mermaid.mjs | 21 +++++++++++++++++++++
3 files changed, 41 insertions(+), 3 deletions(-)
create mode 100644 marp.config.js
create mode 100644 scripts/inject-mermaid.mjs
diff --git a/marp.config.js b/marp.config.js
new file mode 100644
index 0000000..873d776
--- /dev/null
+++ b/marp.config.js
@@ -0,0 +1,10 @@
+module.exports = {
+ html: true,
+ markdown: {
+ html: true,
+ },
+ mermaid: {
+ startOnLoad: true,
+ theme: 'default',
+ },
+};
diff --git a/scripts/build.mjs b/scripts/build.mjs
index 0793dba..b220c2f 100644
--- a/scripts/build.mjs
+++ b/scripts/build.mjs
@@ -2,6 +2,9 @@ import { execFileSync } from 'node:child_process';
import { constants } from 'node:fs';
import { access, cp, mkdir, rm } from 'node:fs/promises';
import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
const rootDir = process.cwd();
const distDir = path.join(rootDir, 'dist');
@@ -10,7 +13,7 @@ const assetsDir = path.join(rootDir, 'assets');
const outputFile = path.join(distDir, 'index.html');
function runMarpBuild() {
- execFileSync('pnpm', ['exec', 'marp', slidesFile, '--allow-local-files', '--output', outputFile], {
+ execFileSync('pnpm', ['exec', 'marp', slidesFile, '--allow-local-files', '--config-file', 'marp.config.js', '--output', outputFile], {
stdio: 'inherit',
});
}
@@ -26,8 +29,12 @@ async function main() {
// The deck starts without images. Copy assets only when they exist.
}
- await runMarpBuild();
-}
+ await runMarpBuild();
+ // Inject Mermaid.js into the generated HTML
+ execFileSync('node', [path.join(__dirname, 'inject-mermaid.mjs')], {
+ cwd: distDir,
+ stdio: 'inherit',
+ });}
main().catch((error) => {
console.error(error);
diff --git a/scripts/inject-mermaid.mjs b/scripts/inject-mermaid.mjs
new file mode 100644
index 0000000..1448e13
--- /dev/null
+++ b/scripts/inject-mermaid.mjs
@@ -0,0 +1,21 @@
+import { readFileSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+
+const distDir = process.cwd();
+const outputFile = path.join(distDir, 'index.html');
+
+// Read the generated HTML
+let html = readFileSync(outputFile, 'utf-8');
+
+// Add Mermaid.js library before closing body tag if not already present
+if (!html.includes('mermaid.min.js')) {
+ const mermaidScript = `