Merge branch 'main' into drafts

This commit is contained in:
John Bowdre 2024-10-26 17:19:22 -05:00
commit 6129e77698
20 changed files with 72 additions and 192 deletions

View file

@ -68,8 +68,4 @@ jobs:
pullZoneId: "${{ secrets.BUNNY_ZONE_ID }}"
upload: "true"
remove: "true"
purgePullZone: "true"
- name: Deploy GMI to Agate
run: |
rsync -avz --delete --exclude='*.html' --exclude='*.css' --exclude='*.js' -e ssh public/ deploy@${{ secrets.GMI_HOST }}:${{ secrets.GMI_CONTENT_PATH }}
purgePullZone: "true"

View file

@ -7,33 +7,21 @@ DefaultContentLanguage = "en"
enableInlineShortcodes = true
enableRobotsTXT = true
# define gemini media type
[mediaTypes]
[mediaTypes.'text/gemini']
suffixes = ["gmi"]
# Automatically add content sections to main menu
# sectionPagesMenu = "main"
[outputs]
home = ['html', 'rss', 'gemini']
home = ['html', 'rss']
section = ['html']
taxonomy = ['html']
term = ['html', 'rss', 'gemini']
page = ['html', 'rss', 'gemini']
term = ['html', 'rss']
page = ['html', 'rss']
# rename rss output from index.xml to feed.xml
[outputFormats]
[outputFormats.rss]
mediatype = "application/rss"
baseName = "feed"
# gemini output
[outputFormats.gemini]
mediatype = "text/gemini"
isPlainText = true
isHTML = false
protocol = "gemini://"
permalinkable = true
[permalinks]
posts = ":filename"

View file

@ -19,7 +19,7 @@ reply = true
name = "John Bowdre"
email = "jbowdre@omg.lol"
username = "jbowdre"
fedi = "@jbowdre@social.lol"
fedi = "@john@srsbsns.lol"
[theme]
palette = "runtimeterror"
@ -46,6 +46,7 @@ taglines = [
"coding crimes",
"connection reset by peer",
"converting caffeine into code",
"cowardly refusing to display an empty web page",
"creating new and exciting bugs",
"cyclic dependency detected",
"destructor cannot be overloaded",
@ -123,6 +124,7 @@ taglines = [
"write error: no space left on device",
"you can't handle the exception",
"you gotta stop letting your mama test you, man",
"your browser is deprecated. please upgrade.",
]
# Sidebar: social links
@ -145,11 +147,6 @@ icon = "fa-solid fa-pen-to-square"
title = "Weblog"
url = "https://srsbsns.lol"
[[socialLinks]]
icon = "fa-solid fa-satellite"
title = "Gemini Capsule"
url = "gemini://capsule.jbowdre.lol"
[[socialLinks]]
icon = "fa-solid fa-circle-user"
title = "CounterSocial"
@ -158,7 +155,7 @@ url = "https://counter.social/@john_b"
[[socialLinks]]
icon = "fa fa-mastodon"
title = "Mastodon"
url = "https://social.lol/@jbowdre"
url = "https://goto.srsbsns.lol/@john"
[[socialLinks]]
icon = "fa-solid fa-envelope"
@ -203,10 +200,6 @@ url = "https://proven.lol/cd10d3"
title = "CounterSocial"
url = "https://counter.social/@john_b"
[[verifyLinks]]
title = "Mastodon"
url = "https://social.lol/@jbowdre"
[[verifyLinks]]
title = "GitHub"
url = "https://github.com/jbowdre"

View file

@ -28,14 +28,13 @@ And in the free time I have left, I game on my Steam Deck.
### See what I've been up to on:
- [GitHub](https://github.com/jbowdre)
- [Weblog](https://srsbsns.lol)
- [Gemlog](https://capsule.jbowdre.lol/gemlog/)
- [status.lol](https://status.jbowdre.lol)
- [social.lol](https://social.lol/@jbowdre)
- [Fediverse](https://goto.srsbsns.lol/@john)
- [CounterSocial](https://counter.social/@john_b)
- [/now](https://now.jbowdre.lol)
### Connect with me via:
- [SimpleX Chat](/simplex/)
- [SimpleX Chat](https://l.runtimeterror.dev/simplex-chat-invite)
- [Signal](https://signal.me/#eu/lyHZbMnlM16O0w48j3rshYBofO0K-iXOt9LGwln7TS-fNKEHCrxH3La325q8IjRU)
- [Matrix](https://matrix.to/#/@jbowdre:omg.lol)
- [XMPP](https://conversations.im/i/jbowdre@omg.lol?omemo-sid-1374125881=a620f3c57733601a6646f6f13a71c86fc9be8dd4126fd158ef3e0a26beb0b434)

View file

@ -1,7 +1,7 @@
---
title: "/changelog"
date: "2024-05-26T21:19:08Z"
lastmod: "2024-08-21T03:11:27Z"
lastmod: "2024-10-20T03:51:49Z"
description: "Maybe I should keep a log of all my site-related tinkering?"
featured: false
toc: false
@ -10,6 +10,9 @@ categories: slashes
---
*Running list of config/layout changes to the site. The full changelog is of course [on GitHub](https://github.com/jbowdre/runtimeterror/commits/main/).*
**2024-10-19:**
- Shut down Gemini mirror, removed links pointing to it
**2024-08-20:**
- Added anchor links on section headings

View file

@ -1,7 +1,7 @@
---
title: "/colophon"
date: "2024-05-26T22:30:58Z"
lastmod: "2024-08-02T21:16:41Z"
lastmod: "2024-10-20T03:51:35Z"
description: "There's a lot that goes into this site. Let me tell you how it works."
featured: false
toc: true
@ -21,7 +21,6 @@ categories: slashes
- displays my latest status from [omg.lol](https://home.omg.lol/referred-by/jbowdre).
- resolves via [Bunny DNS](https://bunny.net/dns/).
- is published to / hosted on [Bunny Storage](https://bunny.net/storage/) and [Bunny CDN](https://bunny.net/cdn/) with a [GitHub Actions workflow](//further-down-the-bunny-hole/).
- has a [Gemini](https://geminiprotocol.net) mirror at `gemini://gmi.runtimeterror.dev`. This is generated from a [Hugo gemtext post layout](https://github.com/jbowdre/runtimeterror/blob/main/layouts/_default/single.gmi), deployed to a [Vultr](https://www.vultr.com/) VPS through that same GitHub Actions workflow, and served with [Agate](https://github.com/mbrubeck/agate).
The post content is licensed under [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/); the site code is under the [MIT License](https://github.com/jbowdre/runtimeterror/blob/main/LICENSE).

View file

@ -1,7 +1,7 @@
---
title: "/homelab"
date: "2024-05-26T21:30:51Z"
lastmod: "2024-09-22T19:16:04Z"
lastmod: "2024-10-23T02:10:13Z"
aliases:
- playground
description: "The systems I use for fun and enrichment."
@ -14,7 +14,7 @@ categories: slashes
Everything is connected to my [Tailscale](https://tailscale.com) tailnet, with a GitOps-managed ACL to allow access as needed. This lets me access and manage systems without really caring if they're local or remote. [Tailscale is magic](/secure-networking-made-simple-with-tailscale/).
The Docker containers are (generally) managed with [Portainer](https://www.portainer.io/).
The Docker containers are (generally) managed with [Portainer](https://www.portainer.io/) using configs [on GitHub](https://github.com/jbowdre/compositions).
### On Premise
@ -35,9 +35,13 @@ The Proxmox cluster hosts a number of VMs and LXC containers:
- `doc`: Ubuntu 22.04 Docker host for various on-prem container workloads, served via [Tailscale Serve](/tailscale-ssh-serve-funnel/#tailscale-serve) / [Caddy + Tailscale](/caddy-tailscale-alternative-cloudflare-tunnel/):
- [Calibre Web](https://github.com/janeczku/calibre-web) for managing my ebooks
- [Cyberchef](https://github.com/gchq/CyberChef), the Cyber Swiss Army Knife
- [Golink](https://github.com/tailscale/golink), a private shortlink service for tailnets
- [Hashicorp Vault](https://www.vaultproject.io/) for secrets management
- [Heimdall](https://github.com/linuxserver/Heimdall), an application dashboard and launcher
- [IT-Tools](https://github.com/CorentinTh/it-tools) for handy online development-related tools
- [Linkding](https://github.com/sissbruecker/linkding) bookmark manager serving [links.bowdre.net](https://links.bowdre.net/bookmarks/shared)
- [RIPE Atlas Probe](https://www.ripe.net/analyse/internet-measurements/ripe-atlas/) for measuring internet connectivity
- [SilverBullet](https://silverbullet.md), a web-based personal knowledge management system ([post](https://srsbsns.lol/is-silverbullet-the-note-keeping-silver-bullet/))
- [SilverBullet](https://silverbullet.md), a web-based personal knowledge management system ([post](/publish-silverbullet-notes-quartz/))
- [Tailscale Golink](https://github.com/tailscale/golink), a private shortlink service ([post](/tailscale-golink-private-shortlinks-tailnet/))
- `files`: Ubuntu 20.04 file server. Serves (selected) files semi-publicly through [Tailscale Funnel](/tailscale-ssh-serve-funnel/#tailscale-funnel)
- `hassos`: [Home Assistant OS](https://www.home-assistant.io/installation/), manages all my "smart home" stuff ([post](/automating-camera-notifications-home-assistant-ntfy/))
@ -63,11 +67,13 @@ This triad of cute little single-board computers will *eventually* be a combinat
I like to know what's flying overhead, and I'm also feeding flight data to [flightaware.com](https://flightaware.com) and [adsb.fi](https://adsb.fi).
### Cloud
**Federated Raspberry Pi**
- Raspberry Pi 4 Model B
- 64GB Sandisk USB Drive
**[Oracle Cloud Infrastructure](https://www.oracle.com/cloud/free/)**
- `git`: Ubuntu 22.04 [Forgejo](https://forgejo.org/) server for [git.bowdre.net](https://git.bowdre.net/explore/repos)
- `smp2`: Ubuntu 22.04 [SimpleX](/simplex/) server
Runs [GoToSocial](https://gotosocial.org/) in Docker to host my personal Mastodon-compatible ActivityPub server, [goto.srsbsns.lol](https://goto.srsbsns.lol) ([post](https://srsbsns.lol/going-to-gotosocial/)).
### Cloud
**[Google Cloud Platform](https://cloud.google.com/free/docs/free-cloud-features)**
- `smp`: Ubuntu 22.04 [SimpleX](/simplex/) server
@ -75,10 +81,8 @@ I like to know what's flying overhead, and I'm also feeding flight data to [flig
**[Vultr](https://www.vultr.com)**
- `volly`: Ubuntu 22.04 Docker host for various workloads, served either through [Caddy](https://caddyserver.com/) or [Caddy + Tailscale](/caddy-tailscale-alternative-cloudflare-tunnel/):
- [Agate](https://github.com/mbrubeck/agate) Gemini server ([post](/gemini-capsule-gempost-github-actions/))
- [Kineto](https://github.com/beelux/kineto) Gemini-to-HTTP proxy ([post](/gemini-capsule-gempost-github-actions/))
- [Linkding](https://github.com/sissbruecker/linkding) bookmark manager serving [links.bowdre.net](https://links.bowdre.net/bookmarks/shared)
- [Forgejo](https://forgejo.org/) server for [git.bowdre.net](https://git.bowdre.net/explore/repos) ([post](/gitea-self-hosted-git-server/))
- [ntfy](https://ntfy.sh/) notification service ([post](/easy-push-notifications-with-ntfy/))
- [SearXNG](https://docs.searxng.org/) self-hosted metasearch engine serving [grep.vpota.to](https://grep.vpota.to) ([post](https://srsbsns.lol/post/self-hosting-a-search-engine-iyjdlk6y))
- [SimpleX](/simplex/) server (`smp2`)
- [Uptime Kuma](https://github.com/louislam/uptime-kuma) for monitoring internal services (via Tailscale)
- [vault-unseal](https://github.com/lrstanley/vault-unseal) to auto-unseal my on-prem Vault instance

View file

@ -1,7 +1,7 @@
---
title: "Self-Hosted Gemini Capsule with gempost and GitHub Actions"
date: "2024-03-23T21:33:19Z"
lastmod: "2024-04-05T21:07:38Z"
lastmod: "2024-10-26T21:26:17Z"
description: "Deploying a Gemini capsule, powered by Agate, gempost, kineto, Tailscale, and GitHub Actions"
featured: false
toc: true
@ -13,11 +13,17 @@ tags:
- selfhosting
- tailscale
---
{{% notice note "Exiting Geminispace..." %}}
After several months of experimentation, I decided to stop exploring Gemini. I still think the concept is really neat but ultimately would rather focus my efforts here in the real world. I'll leave this article in place but my capsule has since been deorbited.
{{% /notice %}}
I've recently been exploring some indieweb/smolweb technologies, and one of the most interesting things I've come across is [Project Gemini](https://geminiprotocol.net/):
> Gemini is a new internet technology supporting an electronic library of interconnected text documents. That's not a new idea, but it's not old fashioned either. It's timeless, and deserves tools which treat it as a first class concept, not a vestigial corner case. Gemini isn't about innovation or disruption, it's about providing some respite for those who feel the internet has been disrupted enough already. We're not out to change the world or destroy other technologies. We are out to build a lightweight online space where documents are just documents, in the interests of every reader's privacy, attention and bandwidth.
I thought it was an interesting idea, so after a bit of experimentation with various hosted options I created a self-hosted [Gemini capsule (Gemini for "web site") to host a lightweight text-focused Gemlog ("weblog")](https://capsule.jbowdre.lol/gemlog/2024-03-05-hello-gemini.gmi). After further tinkering, I arranged to serve the capsule both on the Gemini network as well as the traditional HTTP-based web, and I set up a GitHub Actions workflow to handle posting updates. This post will describe how I did that.
I thought it was an interesting idea, so after a bit of experimentation with various hosted options I created a self-hosted Gemini capsule (Gemini for "web site") to host a lightweight text-focused Gemlog ("weblog"). After further tinkering, I arranged to serve the capsule both on the Gemini network as well as the traditional HTTP-based web, and I set up a GitHub Actions workflow to handle posting updates. This post will describe how I did that.
### Gemini Server: Agate
There are a number of different [Gemini server applications](https://github.com/kr1sp1n/awesome-gemini?tab=readme-ov-file#servers) to choose from. I decided to use [Agate](https://github.com/mbrubeck/agate), not just because it was at the top of the Awesome Gemini list but also because seems to be widely recommended, regularly updated, and easy to use. Plus it will automatically generates certs for me, which is nice since Gemini *requires* valid certificates for all connections.
@ -602,5 +608,5 @@ And the capsule is live at both `https://capsule.jbowdre.lol` and `gemini://caps
![Gemini capsule served over gemini://](gemini-capsule.png)
Come check it out!
- [My Capsule on Gemini](gemini://capsule.jbowdre.lol)
- [My Capsule on the web](https://capsule.jbowdre.lol)
- My Capsule on Gemini
- My Capsule on the web

View file

@ -160,7 +160,8 @@ No users have added their keys to Gitea just yet so if you look at `/home/git/.s
So I'll go ahead and create that extra command:
```shell
cat <<"EOF" | sudo tee /usr/local/bin/gitea # [tl! .cmd]
# [tl! .cmd:1,1]
cat <<EOF | sudo tee /usr/local/bin/gitea
#!/bin/sh
ssh -p 2222 -o StrictHostKeyChecking=no git@127.0.0.1 "SSH_ORIGINAL_COMMAND=\"$SSH_ORIGINAL_COMMAND\" $0 $@"
EOF

View file

@ -1,5 +1,5 @@
---
title: "Publishing SilverBullet Notes with Quartz and GitHub Actions"
title: "Publishing (Selected) SilverBullet Notes with Quartz and GitHub Actions"
date: "2024-09-29T20:27:03Z"
# lastmod: 2024-09-28
description: "A long note about how I publish short notes from SilverBullet using Quartz, Tailscale, Caddy, and GitHub Actions."

View file

@ -1,7 +1,7 @@
---
title: "Tailscale Serve in a Docker Compose Sidecar"
date: 2023-12-30
lastmod: 2024-02-07
lastmod: "2024-10-21T01:37:12Z"
description: "Using Docker Compose to deploy containerized applications and make them available via Tailscale Serve and Tailscale Funnel"
featured: false
toc: true
@ -86,6 +86,31 @@ Tailscale [just published a blog post](https://tailscale.com/blog/docker-tailsca
Replace the ports and protocols and hostnames and such, and you'll be good to go.
**Update 2024-10-20**: I recently learned that you can use the `${TS_CERT_DOMAIN}` placeholder to avoid having to hardcode a hostname into the `serve-config.json`. That makes the config even easier to reuse:
```json
// torchlight! {"lineNumbers": true}
{ // [tl! collapse:start]
"TCP": {
"443": {
"HTTPS": true
}
},// [tl! collapse:end]
"Web": {
"${TS_CERT_DOMAIN}:443": { // [tl! collapse:start]
"Handlers": {
"/": {
"Proxy": "http://127.0.0.1:8000"
}
}
}
}//, uncomment to enable funnel [tl! collapse:end]
// "AllowFunnel": {
// "${TS_CERT_DOMAIN}:443": true
// }
}
```
A compose config using this setup might look something like this:
```yaml

View file

@ -1,53 +1,4 @@
+++
reply = false
toc = false
usePageBundles = false
showDate = false
showShare = false
showReadTime = false
timeless = true
title = "SimpleX Chat"
+++
> You can [contact me on SimpleX Chat](https://l.runtimeterror.dev/simplex-chat-invite) by clicking that link or scanning the QR code below.
![QR code](/images/simplex-invite.png)
[SimpleX Chat](https://simplex.chat/) is a secure messaging solution with a strong emphasis on user privacy. It's (naturally) end-to-end encrypted, doesn't require (or collect) *any* information about you in order to sign up, doesn't use any persistent user identifiers (not even a randomly-generated one), is fully decentralized, and is *not* affiliated with any cryptocurrency project/scam.
Incoming messages are routed through a pool of servers so that your conversations don't all follow the same path - and no server knows anything about conversations that aren't routed through it. Servers only hold your messages long enough to ensure they get to you, and those messages exist only in the encrypted database on your device once they've been delivered. (Fortunately, SimpleX makes it easy to back up that database and restore it on a new device so you don't lose any messages or contacts.)
The app is also packed with other features like disappearing messages, encrypted file transfers, encrypted voice messages, encrypted audio and video calls, decentralized private groups, and a cool incognito mode which connects new conversations to a randomly-generated profile instead of your primary one. There's even a [CLI client](https://github.com/simplex-chat/simplex-chat/blob/stable/docs/CLI.md)!
## Servers
You can easily host your own [simplexmq server](https://github.com/simplex-chat/simplexmq) for handling your inbound message queue, and I've done just that; in fact, I've deployed three! And, as one of my closest internet friends, *you're welcome to use them as well.*
Just add these in the SimpleX app at **Settings > Network & servers > SMP servers > + Add server...**. Enable the option to use them for new connections, and they'll be added to the pool used for incoming messages in new conversations. If you want to use them immediately for existing conversations, go into each conversation's options menu and use the **Switch receiving address** option. You can also *disable* the option to use the default servers for new conversations if you only want messages to be routed through specific servers, but that does increase the likelikhood of concurrent conversations being routed the same way. More servers, more path options, less metadata in any one place.
---
![QR code](/images/smp-vpota-to.png)
`smp://kYx5LmVD9FMM8hJN4BQqL4WmeUNZn8ipXsX2UkBoiHE=@smp.vpota.to`
[![Uptime](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fjbowdre%2Fupptime%2Fmaster%2Fapi%2Fsmp-vpota-to-5223%2Fuptime.json)](https://status.runtimeterror.dev/history/smp-vpota-to-5223)
[netdata](https://l.runtimeterror.dev/smp_status)
---
![QR code](/images/smp1-vpota-to.png)
`smp://TbUrGydawdVKID0Lvix14UkaN-WarFgqXx4kaEG8Trw=@smp1.vpota.to`
[![Uptime](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fjbowdre%2Fupptime%2Fmaster%2Fapi%2Fsmp1-vpota-to-5223%2Fuptime.json)](https://status.runtimeterror.dev/history/smp1-vpota-to-5223)
[netdata](https://l.runtimeterror.dev/smp1_status)
---
![QR code](/images/smp2-vpota-to.png)
`smp://tNfQisxTQ9MhKpFDTbx9RnjgWigtxF1a26jroy5-rR4=@smp2.vpota.to`
[![Uptime](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fjbowdre%2Fupptime%2Fmaster%2Fapi%2Fsmp2-vpota-to-5223%2Fuptime.json)](https://status.runtimeterror.dev/history/smp2-vpota-to-5223)
[netdata](https://l.runtimeterror.dev/smp2_status)
type: redirect
target: https://l.runtimeterror.dev/simplex-chat-invite
---

View file

@ -1,4 +0,0 @@
#!/usr/bin/env bash
# Quick script to serve gemini locally
hugo --environment local -D
agate --content public --hostname localhost

View file

@ -1,12 +0,0 @@
# [runtimeterror $]
=> /about Adventures in self-hosting and other technological frustrations.
{{ $pages := .Pages -}}
{{ $pages = where site.RegularPages "Type" "in" site.Params.mainSections -}}
### Posts
{{ range $pages }}
=> {{ .RelPermalink }} {{ .Date.Format "2006-01-02" }} {{ .Title }}
{{- end }}
---
=> https://runtimeterror.dev This site on the big web

View file

@ -1,10 +0,0 @@
=> / 💻 [runtimeterror $]
# {{ .Title }}
{{- range .Pages }}
=> {{ .RelPermalink }} {{ .Date.Format "2006-01-02" }} {{ .Title }}
{{- end }}
---
=> / Home
=> https://runtimeterror.dev{{ replace (replace .RelPermalink "/gemini" "" 1) "index.gmi" "" }} This page on the big web

View file

@ -1,59 +0,0 @@
{{- $scratch := newScratch -}}{{- $scratch.Set "ref" 1 -}}
=> / 💻 [runtimeterror $]
{{ if .Params.Date }}
{{- $postDate := .Date.Format "2006-01-02" }}
{{- $updateDate := .Lastmod.Format "2006-01-02" }}
{{- $postDate }}{{ if ne $postDate $updateDate }} ~ {{ $updateDate }}{{ end }}
{{- end }}
# {{ .Title }}
{{/* The bulk of this regex magic was inspired by https://brainbaking.com/post/2021/04/using-hugo-to-launch-a-gemini-capsule/ */}}
{{ range $content := split .RawContent "\n\n" }}
{{- $blockRef := $scratch.Get "ref" -}}
{{- $content := $content | replaceRE `#{4,} ` "### " -}}{{/* reduce headings to a max of 3 levels */}}
{{- $content := $content | replaceRE `(?m:^- (.+?)$)` "\n* $1" -}}{{/* convert unordered lists */}}
{{- $content := $content | replaceRE `(?m:^(?:\d+). (.+?)$)` "* $1" -}}{{/* convert ordered lists */}}
{{- $content := $content | replaceRE `\n?\[\^(.+?)\]:\s*.*` "" -}}{{/* remove footnote definitions */}}
{{- $content := $content | replaceRE `\[\^(.+?)\]` "" -}}{{/* remove footnote anchors */}}
{{- $content := $content | replaceRE `((?m:^(?:\|.*\|)+\n?)+)` "```\n$1\n```\n" -}}{{/* render markdown tables as plaintext ascii */}}
{{- $content := $content | replaceRE "(?m:^`([^`]*)`$)" "```\n$1\n```\n" -}}{{/* convert single-line inline code to blocks */}}
{{- $content := $content | replaceRE `\{\{%\snotice.*%\}\}` "<-- note -->" -}}{{/* convert hugo notices */}}
{{- $content := $content | replaceRE `\{\{%\s/notice.*%\}\}` "<-- /note -->" -}}
{{- $content := $content | replaceRE `(?:(?:<!--)|(?:#)|(?:\/\/))\s*torchlight!.*\n` "" -}}{{/* remove torchlight markup */}}
{{- $content := $content | replaceRE `(?:(?:<!--)|(?:#)|(?:\/\/))*\s*\[tl!.*\].*` "" -}}
{{- $content := $content | replaceRE `(?m:^\[!\[(.*)\]\(.*\)\]\((.*)\)$)` "=> $2 $1" -}}{{/* remove images from uptime links */}}
{{- $content := $content | replaceRE `(?m:^\s*(?:(?:\*|\-)\s+)?\[(.*)\]\((.*)\)$)` "=> $2 $1" -}}{{/* convert links already on own line */}}
{{- $content := $content | replaceRE `(?m:^!\[(.*)\]\((.+?)\)$)` "=> $2 Image: $1" -}}{{/* convert embedded images */}}
{{- $links := findRE `\[.+?\]\(.+?\)` $content -}}
{{- $scratch.Set "content" $content -}}
{{- range $links -}}
{{- $ref := $scratch.Get "ref" -}}
{{- $contentInLoop := $scratch.Get "content" -}}
{{- $url := (printf "%s #%d" . $ref) -}}
{{- $contentInLoop := replace $contentInLoop . $url -}}
{{- $scratch.Set "content" $contentInLoop -}}
{{- $scratch.Set "ref" (add $ref 1) -}}
{{- end -}}
{{- $content := $scratch.Get "content" | replaceRE `\[(.+?)\]\((.+?)\) #(\d+)` "$1 [$3]" }}
{{- $content | safeHTML }}
{{- range $links -}}
{{- $ref := $scratch.Get "ref" -}}
{{- $url := (printf "%s #%d" . $blockRef) }}
=> {{ $url | replaceRE `\[(.+?)\]\((.+?)\) #(\d+)` "$2 [$3] $1" }}
{{- $blockRef = add $blockRef 1 -}}
{{ end }}
{{ end }}
---
{{ $subject := printf "Re: %s" .Title -}}
{{ $subject := urlquery $subject | replaceRE `\+` "%20" }}
=> mailto:wheel.east.brief@clkdmail.com?subject={{ $subject }} 📧 Reply by email
{{ $related := first 3 (where (where .Site.RegularPages.ByDate.Reverse ".Params.tags" "intersect" .Params.tags) "Permalink" "!=" .Permalink) }}
{{ if $related }}
## Related articles
{{ range $related }}
=> {{ replace .RelPermalink "/gemini" "" 1}} {{ .Title }}{{ end }}{{ end }}
---
=> / Home
=> https://runtimeterror.dev{{ replace (replace .RelPermalink "/gemini" "" 1) "index.gmi" "" }} This page on the big web

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB