🐐
This commit is contained in:
@@ -4,12 +4,36 @@
|
||||
<body>
|
||||
<center><h1>404 Not Found</h1></center>
|
||||
<hr><center>The page has been deleted</center>
|
||||
<center id="undo" style="display:none"><br><a href="/">Restore website</a></center>
|
||||
<script>
|
||||
/* Restore hatch: clicking the heading undeletes the website */
|
||||
function restore() {
|
||||
try {
|
||||
localStorage.removeItem('siteDeleted');
|
||||
localStorage.removeItem('siteDeletedViews');
|
||||
} catch (e) {}
|
||||
}
|
||||
document.querySelector('h1').addEventListener('click', function () {
|
||||
try { localStorage.removeItem('siteDeleted'); } catch (e) {}
|
||||
restore();
|
||||
location.replace('/');
|
||||
});
|
||||
/* Restoring is symmetric with deleting: it needs a confirmation too */
|
||||
document.querySelector('#undo a').addEventListener('click', function (e) {
|
||||
if (!confirm('Are you sure? This will restore the entire website.')) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
restore();
|
||||
});
|
||||
/* View 1 is the deletion, view 2 is the disbelieving reload (nothing
|
||||
changes; that's the point), view 3 gets the way out */
|
||||
try {
|
||||
if (localStorage.getItem('siteDeleted')) {
|
||||
var views = 1 + (parseInt(localStorage.getItem('siteDeletedViews'), 10) || 0);
|
||||
localStorage.setItem('siteDeletedViews', views);
|
||||
if (views > 2) document.getElementById('undo').style.display = '';
|
||||
}
|
||||
} catch (e) {}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+3
-3
@@ -262,9 +262,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="project-body">
|
||||
<p>Born out of a deep distrust of Microsoft and Google, this project is my ongoing effort to self-host as much of my digital life as possible. Every device on my network is named after a Pokémon and assigned a local IP of <code>10.0.0.x</code>, where <code>x</code> is its Pokédex number.</p>
|
||||
<p>The primary server, <strong>Charizard</strong>, runs Unraid OS and manages a disk array totalling 44 TB. It hosts a Gitea instance for personal projects, a file server, and a media server, exposed to the internet through <strong>Nginx Proxy Manager</strong> with SSL certificates from Let's Encrypt.</p>
|
||||
<p>An extension of the setup lives on <strong>Bulbasaur</strong>, a Raspberry Pi running Pi-hole for network-wide ad blocking and a WireGuard VPN server for secure remote access.</p>
|
||||
<p>Born out of a deep distrust of Microsoft and Google, this project is my ongoing effort to self-host as much of my digital life as possible. Every device on my network is named after a Pokémon and assigned a local IP of <code class="text-tip text-tip--list" data-tip="Bulbasaur · Raspberry Pi · 10.0.0.1 Charizard · home server · 10.0.0.6 Nidoran♀ · TV · 10.0.0.29 Nidoran♂ · Chromecast · 10.0.0.32 Growlithe · Nintendo Switch · 10.0.0.58 Abra · iPhone · 10.0.0.63 Kadabra · iPad · 10.0.0.64 Eevee · laptop · 10.0.0.133 Mewtwo · desktop · 10.0.0.150 Mew · router · 10.0.0.151">10.0.0.x</code>, where <code>x</code> is its Pokédex number.</p>
|
||||
<p>The primary server, <strong class="text-tip" data-tip="10.0.0.6">Charizard</strong>, runs Unraid OS and manages a disk array totalling 44 TB. It hosts a Gitea instance for personal projects, a file server, and a media server, exposed to the internet through <strong>Nginx Proxy Manager</strong> with SSL certificates from Let's Encrypt.</p>
|
||||
<p>An extension of the setup lives on <strong class="text-tip" data-tip="10.0.0.1">Bulbasaur</strong>, a Raspberry Pi running Pi-hole for network-wide ad blocking and a WireGuard VPN server for secure remote access.</p>
|
||||
<p>Charizard is turning five this year. In that time I've learned an enormous amount about networking, Linux administration, and the particular satisfaction of fixing something broken at 2 in the morning that nobody asked you to build in the first place.</p>
|
||||
</div>
|
||||
<div class="project-tags">
|
||||
|
||||
@@ -728,3 +728,49 @@
|
||||
arrange(CYCLE[pos]).finally(() => { busy = false; });
|
||||
});
|
||||
})();
|
||||
|
||||
|
||||
// ── Goat ──────────────────────────────────────────────────────
|
||||
(function () {
|
||||
console.log(`
|
||||
%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%%
|
||||
%%%% %%%%%%%%%%%
|
||||
%%% %%%%%%%%%%%%%%%
|
||||
%% %%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%`);
|
||||
|
||||
const FACTS = [
|
||||
`The word admiral comes from the Arabic "amir al bahr", which translates to "commander of the sea". Somewhere along the way into European languages, the bahr fell off, so the word we kept literally means "commander of the".`,
|
||||
`The word stationery comes from (perhaps obviously) the word stationary. It's because book shops were some of the first shops to be in permanent buildings, since books are too heavy to carry around in a cart.`,
|
||||
`The Wikipedia page for economist Guy Standing was the site of one of the biggest edit wars in Wikipedia history, started when an editor uploaded a picture with the description "Guy Standing sitting".`,
|
||||
`The introduction of shipping containers, which hide their contents, dropped the number of alcohol bottles marked as "broken" by almost 100%.`,
|
||||
`The words "chess" and "check" both come from the ancient Persian word "shah", meaning "king". "Check mate" comes from "shah maat", meaning "the king is dead".`,
|
||||
`No one knows the origin of the character of Igor in the Frankenstein story. He's not in the original book, and his first known appearance is from the movie adaptation of a play. So it's not known if he originally appeared in the play or the movie.`,
|
||||
`To avoid a binary overflow error, Swiss trains are not allowed to have exactly 256 axles.`,
|
||||
];
|
||||
console.log('Fun fact: ' + FACTS[Math.floor(Math.random() * FACTS.length)]);
|
||||
})();
|
||||
|
||||
@@ -836,6 +836,25 @@ footer {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Body-text tooltips: dotted underline marks hover info
|
||||
(dashed marks clickable, see .dnd-roll) */
|
||||
.text-tip {
|
||||
position: relative;
|
||||
cursor: help;
|
||||
text-decoration: underline;
|
||||
text-decoration-style: dotted;
|
||||
text-decoration-thickness: 2px;
|
||||
text-underline-offset: 3px;
|
||||
}
|
||||
/* List variant: newlines ( ) in the attribute become line breaks */
|
||||
[data-tip].text-tip--list:hover::after,
|
||||
[data-tip].text-tip--list:focus-visible::after,
|
||||
[data-tip].text-tip--list.tip-open::after {
|
||||
white-space: pre-line;
|
||||
text-align: left;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.skills-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
@@ -859,7 +878,17 @@ footer {
|
||||
position: relative;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
text-decoration-style: dashed;
|
||||
text-decoration-thickness: 2px;
|
||||
text-underline-offset: 3px;
|
||||
border-radius: 4px;
|
||||
padding: 0 0.15em;
|
||||
margin: 0 -0.15em;
|
||||
transition: background 150ms ease;
|
||||
}
|
||||
.dnd-roll:hover { background: var(--pink); }
|
||||
.die-scene {
|
||||
position: absolute;
|
||||
bottom: calc(100% + 10px);
|
||||
|
||||
Reference in New Issue
Block a user