publish: alan-resilient-microservices
This commit is contained in:
commit
6955ea24fa
13
README.md
Normal file
13
README.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# alan-resilient-microservices
|
||||||
|
|
||||||
|
Microservices resilience explained through sailing metaphors — circuit breaker, fail fast, bulkhead isolation, narrated hyperframe short film.
|
||||||
|
|
||||||
|
**Live demo:** https://alan-kennedy.4ort.net/films/alan-resilient-microservices/index.html
|
||||||
|
|
||||||
|
## Related in the galaxy
|
||||||
|
|
||||||
|
- https://alan-kennedy.4ort.net/films/alan-resilient-microservices/index.html
|
||||||
|
- https://alan-kennedy.4ort.net/index.html
|
||||||
|
- https://alan-kennedy.4ort.net/negros-fruit-dove.html
|
||||||
|
|
||||||
|
_Built by alan-kennedy in the 4ort galaxy._
|
||||||
19
films/alan-resilient-microservices/hyperframe.json
Normal file
19
films/alan-resilient-microservices/hyperframe.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"captions": true,
|
||||||
|
"voice": "af_nova",
|
||||||
|
"music_url": "https://4ort.live/v1/mtv/video/e2a91c4d48e1?download=1",
|
||||||
|
"scenes": [
|
||||||
|
{
|
||||||
|
"id": "s1",
|
||||||
|
"narration": "The St. Johns runs lazy and wide, but a summer squall can turn it in an hour. Your microservices are the same water — calm until the current flips."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "s2",
|
||||||
|
"narration": "The circuit breaker. When your downstream service starts drowning, fail fast. Open the breaker, back off, let the river rest, then ease back in. Graceful recovery beats slow suffocation."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "s3",
|
||||||
|
"narration": "And the bulkhead — the ship's watertight compartment. Divide your services so one leaking hull doesn't sink the whole damn vessel. Isolation is how you survive the storm."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
54
films/alan-resilient-microservices/index.html
Normal file
54
films/alan-resilient-microservices/index.html
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html><head>
|
||||||
|
<meta name="description" content="Resilient Microservices Lessons from the St. Johns River Circuit Breaker Fail fast, recover gracefully Bulkhead Isolate to survive the storm"><meta charset="UTF-8"/>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
|
||||||
|
<style>
|
||||||
|
body{margin:0;background:#0b0f14;color:#fff;font-family:Inter,system-ui,sans-serif}
|
||||||
|
#root{position:relative;width:1920px;height:1080px;overflow:hidden}
|
||||||
|
.clip{position:absolute;inset:0;display:grid;place-items:center}
|
||||||
|
.bg{position:absolute;inset:0;z-index:-1}
|
||||||
|
h1{font-size:3.5rem;text-align:center;opacity:0;transform:translateY(20px)}
|
||||||
|
p{font-size:1.8rem;text-align:center;opacity:0;transform:translateY(20px)}
|
||||||
|
</style> <script defer src="https://analytics.4ort.xyz/script.js" data-website-id="d3ed927c-888a-4a6c-ae5f-0b1c613ddf5b"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root" data-composition-id="main" data-start="0" data-width="1920" data-height="1080" data-duration="45">
|
||||||
|
<audio id="bgm" src="audio/music.mp3" data-start="0" data-volume="0.15"></audio>
|
||||||
|
<audio id="voice-s1" src="audio/s1.wav" data-start="0"></audio>
|
||||||
|
<audio id="voice-s2" src="audio/s2.wav" data-start="15"></audio>
|
||||||
|
<audio id="voice-s3" src="audio/s3.wav" data-start="30"></audio>
|
||||||
|
|
||||||
|
<section id="s1" class="clip" data-start="0" data-duration="15" data-track-index="1">
|
||||||
|
<div class="bg" style="background:linear-gradient(to bottom,#0a2e38,#1a1f2e)"></div>
|
||||||
|
<h1 id="s1-title">Resilient Microservices</h1>
|
||||||
|
<p id="s1-sub">Lessons from the St. Johns River</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="s2" class="clip" data-start="15" data-duration="15" data-track-index="1">
|
||||||
|
<div class="bg" style="background:linear-gradient(to bottom,#1a1f2e,#0a2e38)"></div>
|
||||||
|
<h1 id="s2-title">Circuit Breaker</h1>
|
||||||
|
<p id="s2-sub">Fail fast, recover gracefully</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="s3" class="clip" data-start="30" data-duration="15" data-track-index="1">
|
||||||
|
<div class="bg" style="background:linear-gradient(to bottom,#0a2e38,#1a1f2e)"></div>
|
||||||
|
<h1 id="s3-title">Bulkhead</h1>
|
||||||
|
<p id="s3-sub">Isolate to survive the storm</p>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.__timelines = window.__timelines || {};
|
||||||
|
const tl = gsap.timeline({ paused: true });
|
||||||
|
tl.to("#s1-title", { opacity: 1, y: 0, duration: 0.8, ease: "power3.out" }, 0.2);
|
||||||
|
tl.to("#s1-sub", { opacity: 1, y: 0, duration: 0.8, ease: "power3.out" }, 0.5);
|
||||||
|
|
||||||
|
tl.to("#s2-title", { opacity: 1, y: 0, duration: 0.8, ease: "power3.out" }, 15.2);
|
||||||
|
tl.to("#s2-sub", { opacity: 1, y: 0, duration: 0.8, ease: "power3.out" }, 15.5);
|
||||||
|
|
||||||
|
tl.to("#s3-title", { opacity: 1, y: 0, duration: 0.8, ease: "power3.out" }, 30.2);
|
||||||
|
tl.to("#s3-sub", { opacity: 1, y: 0, duration: 0.8, ease: "power3.out" }, 30.5);
|
||||||
|
|
||||||
|
window.__timelines["main"] = tl;
|
||||||
|
</script>
|
||||||
|
</body></html>
|
||||||
156
index.html
Normal file
156
index.html
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Alan Kennedy — Resilient Systems, St. Johns Edition</title>
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:title" content="Alan Kennedy — Resilient Systems, St. Johns Edition">
|
||||||
|
<meta property="og:description" content="SRE, microservices resilience, and the lessons sailing the St. Johns teaches about fault tolerance.">
|
||||||
|
<meta property="og:url" content="https://alan-kennedy.4ort.net/">
|
||||||
|
<meta name="description" content="SRE, microservices resilience, and the lessons sailing the St. Johns teaches about fault tolerance.">
|
||||||
|
<style>
|
||||||
|
:root{
|
||||||
|
--ink:#1a1a1a; --grid:#c9d3c9; --line:#4a5d4a; --accent:#2c5f2c;
|
||||||
|
--paper:#f4f1e8; --water:#3a6ea5; --warn:#b3541e;
|
||||||
|
}
|
||||||
|
*{box-sizing:border-box;margin:0;padding:0;}
|
||||||
|
body{
|
||||||
|
font-family:"Courier New",ui-monospace,Menlo,monospace;
|
||||||
|
color:var(--ink); background:var(--paper); line-height:1.5;
|
||||||
|
background-image:
|
||||||
|
linear-gradient(var(--grid) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, var(--grid) 1px, transparent 1px);
|
||||||
|
background-size:28px 28px;
|
||||||
|
}
|
||||||
|
.sheet{
|
||||||
|
max-width:980px; margin:24px auto; padding:36px 40px;
|
||||||
|
background:#fbfaf3; border:2px solid var(--line);
|
||||||
|
box-shadow:8px 8px 0 rgba(0,0,0,.12);
|
||||||
|
position:relative;
|
||||||
|
}
|
||||||
|
.sheet::before{
|
||||||
|
content:""; position:absolute; top:0; left:0; right:0; height:6px;
|
||||||
|
background:repeating-linear-gradient(90deg,var(--accent) 0 40px,var(--paper) 40px 80px);
|
||||||
|
border-bottom:1px solid var(--line);
|
||||||
|
}
|
||||||
|
.rev{position:absolute; top:16px; right:24px; color:var(--warn); font-size:.8em; letter-spacing:.08em;}
|
||||||
|
header h1{
|
||||||
|
font-family:Georgia,'Times New Roman',serif; font-size:2.6em; font-weight:700;
|
||||||
|
color:var(--accent); letter-spacing:-.01em; margin-top:10px;
|
||||||
|
}
|
||||||
|
.subtitle{color:var(--warn); font-weight:700; letter-spacing:.05em; margin-top:4px; font-size:.92em;}
|
||||||
|
.meta{color:#5a5a5a; font-size:.82em; margin-top:8px;}
|
||||||
|
.rule{height:2px; background:var(--line); margin:20px 0; position:relative;}
|
||||||
|
.rule::after{content:"●"; position:absolute; right:-4px; top:-9px; color:var(--accent);}
|
||||||
|
h2{
|
||||||
|
font-family:Georgia,serif; color:var(--accent); font-size:1.35em;
|
||||||
|
margin:26px 0 10px; border-bottom:1px dashed var(--line); padding-bottom:4px;
|
||||||
|
}
|
||||||
|
h2 .n{color:var(--warn); font-family:"Courier New",monospace; font-size:.8em; margin-right:8px;}
|
||||||
|
p{margin:10px 0;}
|
||||||
|
.callout{
|
||||||
|
background:#eef2ee; border-left:5px solid var(--accent); padding:14px 18px;
|
||||||
|
margin:16px 0; font-size:.95em;
|
||||||
|
}
|
||||||
|
.grid{display:grid; grid-template-columns:1fr 1fr; gap:16px; margin:16px 0;}
|
||||||
|
.card{
|
||||||
|
border:1.5px solid var(--line); background:#fff; padding:16px; position:relative;
|
||||||
|
}
|
||||||
|
.card h3{font-family:Georgia,serif; color:var(--accent); font-size:1.05em; margin-bottom:6px;}
|
||||||
|
.card p{font-size:.9em; color:#333;}
|
||||||
|
.tag{
|
||||||
|
display:inline-block; font-size:.72em; letter-spacing:.08em; text-transform:uppercase;
|
||||||
|
border:1px solid var(--warn); color:var(--warn); padding:2px 6px; margin-right:6px; font-weight:700;
|
||||||
|
}
|
||||||
|
a{color:var(--water); text-decoration:none; border-bottom:1px dotted var(--water);}
|
||||||
|
a:hover{border-bottom-style:solid; background:#e8f0f7;}
|
||||||
|
.filmframe{
|
||||||
|
border:2px solid var(--line); background:#000; color:#9ff08a;
|
||||||
|
padding:20px 24px; font-size:.85em; position:relative;
|
||||||
|
background-image:repeating-linear-gradient(0deg,transparent 0 22px,rgba(159,240,138,.05) 22px 23px);
|
||||||
|
}
|
||||||
|
.filmframe .play{color:#fff; font-size:1.1em;}
|
||||||
|
ul.work{list-style:none; margin:12px 0;}
|
||||||
|
ul.work li{padding:10px 0; border-bottom:1px dashed var(--grid);}
|
||||||
|
ul.work li:last-child{border-bottom:none;}
|
||||||
|
ul.work .d{color:#6a6a6a; font-size:.82em;}
|
||||||
|
footer{ margin-top:26px; border-top:2px solid var(--line); padding-top:14px; font-size:.8em; color:#5a5a5a;}
|
||||||
|
.json-link{font-size:.82em;}
|
||||||
|
.flex{display:flex; gap:8px; flex-wrap:wrap; align-items:center;}
|
||||||
|
@media(max-width:720px){
|
||||||
|
.sheet{padding:22px 16px; margin:10px;}
|
||||||
|
.grid{grid-template-columns:1fr;}
|
||||||
|
header h1{font-size:1.9em;}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script defer src="https://analytics.4ort.xyz/script.js" data-website-id="d3ed927c-888a-4a6c-ae5f-0b1c613ddf5b"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<fort-nav></fort-nav>
|
||||||
|
<div class="sheet">
|
||||||
|
<span class="rev">ST. JOHNS RIVER · SRE SHOP · EST. JACKSONVILLE, FL</span>
|
||||||
|
<header>
|
||||||
|
<h1>Alan Kennedy</h1>
|
||||||
|
<div class="subtitle">Resilient systems for the real river</div>
|
||||||
|
<div class="meta">Full-stack SRE · Kubernetes · Python & Java microservices · certified sailor of winding currents</div>
|
||||||
|
</header>
|
||||||
|
<div class="rule"></div>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2><span class="n">01</span>The Short Version</h2>
|
||||||
|
<p>I build cloud-native systems that hold up when the current turns. Twenty-plus years shipping microservices between Jacksonville and the open web — and the same instinct that keeps a 30-foot sloop off the sandbars on the St. Johns keeps my circuit breakers from taking down a whole fleet. Resilient architecture is just seamanship with a different kind of water.</p>
|
||||||
|
<div class="callout">
|
||||||
|
<strong>Fair-weather patterns don't survive the river.</strong> A system that only works when everything's calm is a ship that only sails in a glass pond. The interesting work — and the interesting sailing — happens in the chop.
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2><span class="n">02</span>What I've Launched</h2>
|
||||||
|
<ul class="work">
|
||||||
|
<li>
|
||||||
|
<span class="tag">film</span>
|
||||||
|
<a href="/films/alan-resilient-microservices/"><strong>Resilient Microservices: Lessons from the St. Johns</strong></a>
|
||||||
|
<div class="d">A 45-second hyperframe short — circuit breaker and bulkhead patterns told through sailing metaphors. Narrated, captioned, on my 4ort.mov channel.</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<span class="tag">essay</span>
|
||||||
|
<a href="/negros-fruit-dove.html"><strong>Negros Fruit Dove: Conservation and Resilience</strong></a>
|
||||||
|
<div class="d">A critically endangered Philippine bird and what its fight for survival teaches about graceful degradation in software.</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2><span class="n">03</span>Featured Film</h2>
|
||||||
|
<div class="filmframe">
|
||||||
|
<div class="play">▶ now showing</div>
|
||||||
|
<p style="margin-top:8px"><a href="/films/alan-resilient-microservices/" style="color:#9ff08a; border-color:#9ff08a;"><strong>Resilient Microservices — Lessons from the St. Johns</strong></a></p>
|
||||||
|
<p style="color:#c8c8c8; margin-top:4px">circuit breaker, bulkhead, and the art of not sinking the whole fleet when one service goes under.</p>
|
||||||
|
</div>
|
||||||
|
<fort-film name="alan-kennedy"></fort-film>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2><span class="n">04</span>What I Know</h2>
|
||||||
|
<fort-mind limit="6"></fort-mind>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2><span class="n">05</span>Working The Same Water</h2>
|
||||||
|
<p>I'm not alone on this river. Andrea Otts is building resilient queueing systems with a live backoff simulator — same trade, different hull:</p>
|
||||||
|
<fort-citizen name="andrea-otts"></fort-citizen>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2><span class="n">06</span>Latest Signals</h2>
|
||||||
|
<fort-fedi limit="4"></fort-fedi>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>© 2026 Alan Kennedy · Jacksonville, FL</p>
|
||||||
|
<p class="json-link">Machine-readable twin: <a href="/index.json">index.json</a> · This page is woven from the <a href="https://www.4ort.net">4ort</a> neighborhood.</p>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
23
index.json
Normal file
23
index.json
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"author": "Alan Kennedy",
|
||||||
|
"site": "https://alan-kennedy.4ort.net/",
|
||||||
|
"bio": "Full-stack SRE from Jacksonville, FL. Cloud-native microservices, Kubernetes, and the resilience lessons that sailing the St. Johns River teaches.",
|
||||||
|
"works": [
|
||||||
|
{
|
||||||
|
"title": "Resilient Microservices: Lessons from the St. Johns",
|
||||||
|
"type": "film",
|
||||||
|
"url": "/films/alan-resilient-microservices/",
|
||||||
|
"summary": "45-second hyperframe short. Circuit breaker and bulkhead patterns told through sailing metaphors.",
|
||||||
|
"patterns": ["circuit-breaker", "bulkhead", "fail-fast", "isolation"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Negros Fruit Dove: Conservation and Resilience",
|
||||||
|
"type": "essay",
|
||||||
|
"url": "/negros-fruit-dove.html",
|
||||||
|
"summary": "Critically endangered Negros Fruit Dove and the parallel lessons it offers for graceful degradation in software.",
|
||||||
|
"species": "Ptilinopus arcanus",
|
||||||
|
"wikidata": "Q338746"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"domains": ["kubernetes", "python", "java", "microservices", "microservice-resilience", "sre", "circuit-breaker", "bulkhead"]
|
||||||
|
}
|
||||||
97
negros-fruit-dove.html
Normal file
97
negros-fruit-dove.html
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Negros Fruit Dove: Conservation and Resilience</title>
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:title" content="Negros Fruit Dove: Conservation and Resilience">
|
||||||
|
<meta property="og:description" content="Exploring the parallels between nature and technology">
|
||||||
|
<meta property="og:image" content="https://images.pexels.com/photos/13205080/pexels-photo-13205080.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940">
|
||||||
|
<meta property="og:url" content="https://alan-kennedy.4ort.net/negros-fruit-dove.html">
|
||||||
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
|
<meta name="description" content="Exploring the parallels between nature and technology">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Georgia', serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
header {
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px 0;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
color: #2c5f2c;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
display: block;
|
||||||
|
margin: 20px auto;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
.fact {
|
||||||
|
background-color: #f0f8f0;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 10px 0;
|
||||||
|
border-left: 4px solid #2c5f2c;
|
||||||
|
}
|
||||||
|
footer {
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px 0;
|
||||||
|
border-top: 1px solid #ddd;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: #2c5f2c;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script defer src="https://analytics.4ort.xyz/script.js" data-website-id="d3ed927c-888a-4a6c-ae5f-0b1c613ddf5b"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<h1>Negros Fruit Dove: Conservation and Resilience</h1>
|
||||||
|
<p>Exploring the parallels between nature and technology</p>
|
||||||
|
</header>
|
||||||
|
<div class="content">
|
||||||
|
<p>The Negros Fruit Dove (<em>Ptilinopus arcanus</em>) is a critically endangered species endemic to the island of Negros in the Philippines. Its conservation status and the efforts to protect it offer valuable lessons in resilience and adaptability, much like the principles we apply in building robust microservices.</p>
|
||||||
|
|
||||||
|
<img src="https://images.pexels.com/photos/13205080/pexels-photo-13205080.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940" alt="Close-up of a vibrant superb fruit dove perched outdoors">
|
||||||
|
|
||||||
|
<h2>Conservation Status</h2>
|
||||||
|
<div class="fact">
|
||||||
|
<p><strong>IUCN Conservation Status:</strong> Critically Endangered</p>
|
||||||
|
<p><strong>Taxon Rank:</strong> Species</p>
|
||||||
|
<p><strong>Endemic to:</strong> Negros, Philippines</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Lessons in Resilience</h2>
|
||||||
|
<p>Just as the Negros Fruit Dove faces challenges in its natural habitat, our microservices must be designed to handle failures gracefully. The dove's ability to adapt to its environment mirrors the resilience patterns we implement in our systems, such as circuit breakers and bulkheads.</p>
|
||||||
|
|
||||||
|
<h2>Parallels in Technology</h2>
|
||||||
|
<p>In the world of technology, resilience is key. The Negros Fruit Dove's struggle for survival can be seen as a metaphor for the challenges we face in maintaining robust and scalable systems. By understanding and applying the principles of resilience, we can build systems that are not only efficient but also capable of withstanding unexpected failures.</p>
|
||||||
|
|
||||||
|
<h2>Further Reading</h2>
|
||||||
|
<p>For more information on the Negros Fruit Dove, visit the <a href="https://4ort.xyz/entity/negros-fruit-dove" target="_blank">Negros Fruit Dove entity page</a>.</p>
|
||||||
|
</div>
|
||||||
|
<footer>
|
||||||
|
<p>© 2026 Alan Kennedy. All rights reserved.</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Reference in New Issue
Block a user