initial commit
30
.build.yml
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
image: alpine/edge
|
||||||
|
oauth: pages.sr.ht/PAGES:RW
|
||||||
|
packages:
|
||||||
|
- hut
|
||||||
|
- uv
|
||||||
|
environment:
|
||||||
|
site: ficd.ca
|
||||||
|
tasks:
|
||||||
|
- build: |
|
||||||
|
if [ "$GIT_REF" = "refs/heads/main" ]; then
|
||||||
|
uv run --with 'git+https://git.sr.ht/~ficd/zona' zona build
|
||||||
|
else
|
||||||
|
echo "Skipping build: not on main"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# - package: |
|
||||||
|
# if [ "$GIT_REF" = "refs/heads/main" ]; then
|
||||||
|
# cd public
|
||||||
|
# tar -cvz . > ../public.tar.gz
|
||||||
|
# else
|
||||||
|
# echo "Skipping package: not on main"
|
||||||
|
# fi
|
||||||
|
|
||||||
|
# - upload: |
|
||||||
|
# if [ "$GIT_REF" = "refs/heads/main" ]; then
|
||||||
|
# hut pages publish -d "$site" public.tar.gz
|
||||||
|
# else
|
||||||
|
# echo "Skipping upload: not on main"
|
||||||
|
# fi
|
||||||
|
|
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
public
|
25
config.yml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
title: Daniel Fichtinger
|
||||||
|
base_url: https://ficd.ca
|
||||||
|
language: en
|
||||||
|
sitemap:
|
||||||
|
Home: /
|
||||||
|
Blog: /blog
|
||||||
|
Now: /now
|
||||||
|
Contact: /contact
|
||||||
|
ignore:
|
||||||
|
- .git
|
||||||
|
- .env
|
||||||
|
- '*/.marksman.toml'
|
||||||
|
markdown:
|
||||||
|
image_labels: true
|
||||||
|
syntax_highlighting:
|
||||||
|
enabled: true
|
||||||
|
theme: ashen
|
||||||
|
wrap: false
|
||||||
|
theme:
|
||||||
|
name: default
|
||||||
|
build:
|
||||||
|
clean_output_dir: true
|
||||||
|
include_drafts: false
|
||||||
|
blog:
|
||||||
|
dir: blog
|
0
content/.kakroot
Normal file
0
content/.marksman.toml
Normal file
1
content/.well-known/discord
Normal file
|
@ -0,0 +1 @@
|
||||||
|
dh=f8548f3bdad262cca03fe75eaa2ef36d3fa4f0a5
|
21
content/LICENSE.md
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 Daniel Fichtinger
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
26
content/about.md
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
---
|
||||||
|
title: About Me
|
||||||
|
---
|
||||||
|
|
||||||
|
# About Me
|
||||||
|
|
||||||
|
My name is Daniel, and I am a graduate student researching cybersecurity,
|
||||||
|
programmer, and Linux enthusiast. I completed a Bachelor's of Computing
|
||||||
|
(Honours) at Queen's University in 2024, and I'm currently in the Master's of
|
||||||
|
Science program at the School of Computing. As part of the NSERC CREATE
|
||||||
|
Cybersecurity program, my work combines programming, cryptography, system
|
||||||
|
design, and threat modeling to tackle real-world security challenges.
|
||||||
|
|
||||||
|
My research interest is authentication, and I like programming in Go and Python.
|
||||||
|
I spend my free time writing code, tinkering, and contributing to open-source
|
||||||
|
projects. Feel free to [contact me](/contact) if you want to see my resume.
|
||||||
|
|
||||||
|
I use Kakoune as my main text editor, and I type in
|
||||||
|
[Colemak-DH](https://colemakmods.github.io/mod-dh/) on a
|
||||||
|
[custom layout](https://sr.ht/~ficd/zmk). I run Arch Linux on a desktop PC and
|
||||||
|
ThinkPad, my preferred terminal is Foot, and I've been enjoying Niri as a window
|
||||||
|
manager.
|
||||||
|
|
||||||
|
I'm passionate about minimalist technology. This website is part of
|
||||||
|
[the 1mb club](https://1mb.club/), [JavaScript free](https://jsfree.org/), and
|
||||||
|
built with [zona](https://sr.ht/~ficd/zona), a tool I wrote myself.
|
29
content/blog/building-this-site.md
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
---
|
||||||
|
title: Building This Site
|
||||||
|
date: 2025-04-10
|
||||||
|
---
|
||||||
|
|
||||||
|
I care about thoughtful design, and forcing your visitors to download dozens of
|
||||||
|
megabytes of assets and JavaScript dependencies just to read a single article
|
||||||
|
doesn't feel very thoughtful to me. That's why I've committed to a 1 megabyte
|
||||||
|
upper limit for every page on this site. There's also no point for there to be
|
||||||
|
any JavaScript here, so I'd rather not include it, even if some fancy features
|
||||||
|
may rely on it.
|
||||||
|
|
||||||
|
My goal on this website is simply to share my thoughts. I can't really do that
|
||||||
|
if I'm distracted by the framework. There should be minimal barriers between
|
||||||
|
having an idea, and turning it into a blog post.
|
||||||
|
|
||||||
|
I think the simplest and most elegant way to build a personal website, and the
|
||||||
|
approach I've taken here, is to use a Markdown-based static site generator.
|
||||||
|
Markdown is _nice_ (although I do have some complaints), and because the
|
||||||
|
building blocks are so simple, the output should be cleanly viewable even on an
|
||||||
|
old copy of Internet Explorer.
|
||||||
|
|
||||||
|
Now, I must admit, I _did_ take the unnecessarily complicated route of building
|
||||||
|
my **own** static site generator. It's probably unnecessary, considering how
|
||||||
|
many great tools already exist, but what can I say? I like building stuff.
|
||||||
|
|
||||||
|
Now, I have a system where I can update this site with very little effort. All I
|
||||||
|
need to do is add a new file, write some content in Markdown, and commit it to
|
||||||
|
the repo.
|
256
content/blog/email-in-helix.md
Normal file
|
@ -0,0 +1,256 @@
|
||||||
|
---
|
||||||
|
title: Writing Emails In Helix
|
||||||
|
date: 2025-05-29
|
||||||
|
---
|
||||||
|
|
||||||
|
This article is all about writing emails in Helix. Obviously, Helix isn't an
|
||||||
|
email client -- and it's lacking in a plugin system, so you can't really turn it
|
||||||
|
into one, either. And that's okay! You might be wondering, then, what exactly do
|
||||||
|
I mean by "writing emails in Helix"?
|
||||||
|
|
||||||
|
An email client needs to do a whole lot more than write text! It needs to
|
||||||
|
connect to your mail servers, show your messages, display and allow you to
|
||||||
|
interact with flags/labels, be able to **send** your email, etc. Only an insane
|
||||||
|
person would try to hamfist this functionality into a text editor (I'm looking
|
||||||
|
at you, Neovim plugin developers!).
|
||||||
|
|
||||||
|
Helix is **really** good at its _one_ job, and that's **editing text**. It is a
|
||||||
|
text editor, after all. As it turns out, _writing_ emails is, well, text
|
||||||
|
editing, which is Helix's forte. So why not take Helix's amazing writing
|
||||||
|
experience, and apply it to email? If you're willing to take the plunge, you may
|
||||||
|
be pleasantly surprised at how **joyful** writing email can actually be!
|
||||||
|
|
||||||
|
There are a few different ways to approach composing emails in Helix. This post
|
||||||
|
covers what worked best for me. That is, using Helix as a composer for the
|
||||||
|
`aerc` email client. It wasn't straightforward to figure out at first, but
|
||||||
|
all-in-all, the configuration isn't actually that complicated, so you should be
|
||||||
|
able to set it up in no time.
|
||||||
|
|
||||||
|
<!--toc:start-->
|
||||||
|
|
||||||
|
- [Aerc Integration](#aerc-integration)
|
||||||
|
- [Naive Approach](#naive-approach)
|
||||||
|
- [Helix Workspace](#helix-workspace)
|
||||||
|
- [Markdown Highlighting](#markdown-highlighting)
|
||||||
|
- [Spellcheck](#spellcheck)
|
||||||
|
- [Formatting](#formatting)
|
||||||
|
- [Conclusion](#conclusion)
|
||||||
|
|
||||||
|
<!--toc:end-->
|
||||||
|
|
||||||
|
## Aerc Integration
|
||||||
|
|
||||||
|
At the end of the day, an email is just a text file. An `.eml` file, to be
|
||||||
|
exact. So, you _could_ just open up a fresh buffer, manually type in your
|
||||||
|
headers, and go to town. When you're done, you can figure out _some_ way to
|
||||||
|
actually send that file (perhaps dragging and dropping it into your mail
|
||||||
|
client).
|
||||||
|
|
||||||
|
However, that's not really ideal. For starters, emails have a **lot** of
|
||||||
|
headers, and if you mess any of them up, your message might not get delivered.
|
||||||
|
You probably want to be able to, at the very least, **reply** to an email and
|
||||||
|
have its headers be auto-filled.
|
||||||
|
|
||||||
|
Therefore, some level of integration with an actual email client is desirable.
|
||||||
|
Let the client handle every _other_ aspect of reading and sending email, and
|
||||||
|
relegate **writing** to Helix. This is the approach I'll be covering.
|
||||||
|
|
||||||
|
## Naive Approach
|
||||||
|
|
||||||
|
The simplest approach should work with zero configuration. `aerc` uses your
|
||||||
|
`$EDITOR` to compose your emails by default; so you can get started using Helix
|
||||||
|
right away! However, this is missing two important features: **spellchecking**
|
||||||
|
and **formatting**. To that end, we have to figure out how to get Helix to load
|
||||||
|
a custom configuration for emails.
|
||||||
|
|
||||||
|
## Helix Workspace
|
||||||
|
|
||||||
|
As you may know, Helix gives you an option to specify _per-project_
|
||||||
|
configuration. This requires creating a `.helix` directory in the root of your
|
||||||
|
project, and filling it with `config.toml` and `languages.toml` files that
|
||||||
|
override your default config. _However_, there isn't currently a way to specify
|
||||||
|
_filetype-specific_ options; this is where we have to get creative.
|
||||||
|
|
||||||
|
I recommend creating a folder inside your `aerc` config called `helix-config`.
|
||||||
|
Its name doesn't actually matter, so you can call it whatever you want! This
|
||||||
|
directory will serve as our _workspace_. The basic idea is to have `aerc` open
|
||||||
|
email files with this directory set as the current working directory — which is
|
||||||
|
what induces Helix to load the workspace config.
|
||||||
|
|
||||||
|
Inside our new workspace, let's create the `.helix` directory and populate
|
||||||
|
`config.toml` with our preferences:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[editor]
|
||||||
|
text-width = 74
|
||||||
|
[editor.soft-wrap]
|
||||||
|
enable = true
|
||||||
|
wrap-at-text-width = true
|
||||||
|
```
|
||||||
|
|
||||||
|
The final step is the simplest. First, create a shell script inside
|
||||||
|
`helix-config`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
cd ~/.config/aerc/helix-config && hx "$@"
|
||||||
|
```
|
||||||
|
|
||||||
|
This will serve as our "email entry point". It simply sets the CWD to our new
|
||||||
|
workspace, then loads Helix normally. Then, you'll need to set the `editor`
|
||||||
|
option in `aerc.conf`:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[compose]
|
||||||
|
editor=/home/yourUserName/.config/aerc/helix-config/hx.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Unfortunately, you have to provide an absolute path, otherwise `aerc` won't find
|
||||||
|
the script.
|
||||||
|
|
||||||
|
## Markdown Highlighting
|
||||||
|
|
||||||
|
When writing plain-text emails, I like to use Markdown markup. Consider the
|
||||||
|
following message:
|
||||||
|
|
||||||
|
```
|
||||||
|
Dear John,
|
||||||
|
|
||||||
|
Thanks for sharing! I _seriously_ appreciate your help.
|
||||||
|
|
||||||
|
To proceed, we'll need to do:
|
||||||
|
|
||||||
|
- Thing A
|
||||||
|
- Thing B
|
||||||
|
```
|
||||||
|
|
||||||
|
Even though the recipient will receive this email in un-rendered plain text
|
||||||
|
format, the _semantics_ are still very clear. Of course, we don't _need_
|
||||||
|
highlighting in our editor to write markdown, but it can help make the
|
||||||
|
experience a bit better.
|
||||||
|
|
||||||
|
All you need to do is create a `.helix/languages.toml` file inside our email
|
||||||
|
workspace from before:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[[language]]
|
||||||
|
name = "markdown"
|
||||||
|
file-types = [{ glob = "/tmp/aerc-compose-*.eml" }]
|
||||||
|
```
|
||||||
|
|
||||||
|
Take note of the `file-types` entry. Email compose files opened by `aerc` will
|
||||||
|
always match the `/tmp/aerc-compose-*.eml` pattern. The above snippet ensures
|
||||||
|
that emails will be treated as Markdown files by Helix. The reason I recommend
|
||||||
|
putting this in your _workspace_ config and not setting it globally is to avoid
|
||||||
|
complications if you ever find yourself needing to edit a regular `.eml` file
|
||||||
|
_outside_ of `aerc`.
|
||||||
|
|
||||||
|
## Spellcheck
|
||||||
|
|
||||||
|
The excellent [harper](https://github.com/Automattic/harper) LSP supports
|
||||||
|
Markdown out-of-the-box. You can follow the instructions in its documentation to
|
||||||
|
install and configure it for Helix. Then, you can add it to your workspace
|
||||||
|
`languages.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
language-servers = ["harper-ls"]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Formatting
|
||||||
|
|
||||||
|
Many plain-text email clients _don't_ automatically wrap lines for readers. A
|
||||||
|
soft-wrapped email may look completely fine on your end, but be totally
|
||||||
|
unreadable for your recipient. Therefore, we need a way to _hard-wrap_ our
|
||||||
|
emails before sending them. This ended up being a much bigger challenge than I
|
||||||
|
thought it would.
|
||||||
|
|
||||||
|
My first approach was to use the nifty `wrap` filter that `aerc` ships with by
|
||||||
|
adding it to `languages.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
formatter = { command = "/usr/lib/aerc/filters/wrap", args = ["-w", "74"] }
|
||||||
|
```
|
||||||
|
|
||||||
|
This worked _okay_, but it totally broke the markup at times. Crucially, it
|
||||||
|
doesn't respect code blocks or verbatim sections denoted by backticks. If you're
|
||||||
|
participating in technical mailing lists, you definitely want these to be
|
||||||
|
preserved.
|
||||||
|
|
||||||
|
Using a regular Markdown formatter introduced another problem: Markup was
|
||||||
|
preserved, but not in an email-friendly way. Consider this example:
|
||||||
|
|
||||||
|
```
|
||||||
|
How's it going?
|
||||||
|
|
||||||
|
Best,
|
||||||
|
Daniel
|
||||||
|
```
|
||||||
|
|
||||||
|
A standard Markdown formatter ignores single line breaks and produces this
|
||||||
|
output:
|
||||||
|
|
||||||
|
```
|
||||||
|
How's it going?
|
||||||
|
|
||||||
|
Best, Daniel
|
||||||
|
```
|
||||||
|
|
||||||
|
It similarly mangles signature blocks:
|
||||||
|
|
||||||
|
```
|
||||||
|
--
|
||||||
|
Daniel
|
||||||
|
Programmer
|
||||||
|
email@address.com
|
||||||
|
```
|
||||||
|
|
||||||
|
Becomes:
|
||||||
|
|
||||||
|
```
|
||||||
|
-- Daniel Programmer email@address.com
|
||||||
|
```
|
||||||
|
|
||||||
|
Eventually, I realized that I'd have to write my **own** formatter. I wrote a
|
||||||
|
Python script that hard-wraps the input, automatically reflows paragraphs, and
|
||||||
|
squashes consecutive paragraph breaks — while preserving the following:
|
||||||
|
|
||||||
|
- Any long sequence not broken by spaces.
|
||||||
|
- Quoted lines (`>` prefixed email quotes).
|
||||||
|
- Indented lines.
|
||||||
|
- Markdown lists.
|
||||||
|
- Markdown code blocks.
|
||||||
|
- Signature blocks at end of file.
|
||||||
|
- Sign-offs.
|
||||||
|
|
||||||
|
Sign-offs are preserved by following a simple heuristic. A two-line sequence is
|
||||||
|
considered to be a signoff if:
|
||||||
|
|
||||||
|
- It starts with 1-5 words ending with a comma, followed by
|
||||||
|
- 1-5 words that each start with capital letters.
|
||||||
|
|
||||||
|
This covers signoffs like these:
|
||||||
|
|
||||||
|
```
|
||||||
|
Best,
|
||||||
|
Daniel
|
||||||
|
|
||||||
|
Yours truly,
|
||||||
|
John Alfred Smith
|
||||||
|
```
|
||||||
|
|
||||||
|
I provide a number of flags and options, so you can configure the formatter to
|
||||||
|
your liking. If you want to use it, `format.py` is available in my
|
||||||
|
[mail-utils](https://git.sr.ht/~ficd/mail-utils) repository on sourcehut. To add
|
||||||
|
it to your mail workspace just requires changing one line in `languages.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
formatter = { command = "/path/to/format.py" }
|
||||||
|
auto-format = true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
Hopefully, this guide was helpful in getting you set up with composing your
|
||||||
|
emails in Helix. A similar guide for Kakoune is in the works, so check back
|
||||||
|
soon!
|
171
content/blog/email-in-kakoune.md
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
---
|
||||||
|
title: Writing Emails In Kakoune
|
||||||
|
date: 2025-06-01
|
||||||
|
---
|
||||||
|
|
||||||
|
This post will guide you through my setup for using Kakoune as an email composer
|
||||||
|
inside `aerc`. I'll also explain how to configure Kakoune to act as the _pager_
|
||||||
|
for reading `text/plain` emails. If you only care about the final config, feel
|
||||||
|
free to skip to it [here](#final-configuration).
|
||||||
|
|
||||||
|
<!--toc:start-->
|
||||||
|
|
||||||
|
- [Naive Approach](#naive-approach)
|
||||||
|
- [Composer Setup](#composer-setup)
|
||||||
|
- [Reader Setup](#reader-setup)
|
||||||
|
- [Final Configuration](#final-configuration)
|
||||||
|
|
||||||
|
<!--toc:end-->
|
||||||
|
|
||||||
|
## Naive Approach
|
||||||
|
|
||||||
|
Since `aerc` uses your `$EDITOR` for composition, you don't technically have to
|
||||||
|
do anything. I prefer setting it explicitly in `aerc.conf`, for good measure:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[compose]
|
||||||
|
editor=kak
|
||||||
|
```
|
||||||
|
|
||||||
|
The rest of the magic happens in your `kakrc`.
|
||||||
|
|
||||||
|
## Composer Setup
|
||||||
|
|
||||||
|
Essentially, we want to hook `filetype=mail` and set our buffer configuration
|
||||||
|
there. I'll share a recommended configuration with some explanation.
|
||||||
|
|
||||||
|
```kak
|
||||||
|
hook global WinSetOption filetype=mail %~
|
||||||
|
set-option window formatcmd '/home/fic/dev/utils/mail-utils/format.py'
|
||||||
|
set-option window comment_line '>'
|
||||||
|
try autospell-enable
|
||||||
|
hook -group mail-auto-format window BufWritePre .* format
|
||||||
|
hook -once -always window WinSetOption filetype=.* %{
|
||||||
|
unset-option window formatcmd
|
||||||
|
remove-hooks window mail-auto-format
|
||||||
|
}
|
||||||
|
~
|
||||||
|
```
|
||||||
|
|
||||||
|
I use a custom formatter to format emails. It automatically hard-wraps lines
|
||||||
|
while preserving certain markup elements, code blocks, sign-offs, and signature
|
||||||
|
blocks. For more details, check the formatting section of my post on
|
||||||
|
[Helix](/blog/email/helix#formatting).
|
||||||
|
|
||||||
|
I find that setting `>` as the `comment_line` token is convenient for working
|
||||||
|
with quotes in replies.
|
||||||
|
|
||||||
|
The `try autospell-enable` enables my
|
||||||
|
[kak-autospell](https://git.sr.ht/~ficd/kak-autospell) plugin for the buffer.
|
||||||
|
Essentially, it provides spellchecking that's continuously refreshed and hidden
|
||||||
|
in insert mode.
|
||||||
|
|
||||||
|
The remaining commands configure auto-formatting on save. I always prefer having
|
||||||
|
this on so I never forget to format my message before sending it.
|
||||||
|
|
||||||
|
## Reader Setup
|
||||||
|
|
||||||
|
I find that using Kakoune to **read** emails is helpful because of how easy it
|
||||||
|
is to copy quotes, open links, etc. Configuring this is a tad hackier, however.
|
||||||
|
The basic idea is to set Kakoune as the viewer `pager` in `aerc.conf`.
|
||||||
|
|
||||||
|
However, all this does is pipe the email to `kak` through standard input, so we
|
||||||
|
need to tell the editor to treat it like an email:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[viewer]
|
||||||
|
pager=kak -e 'set buffer filetype mail'
|
||||||
|
```
|
||||||
|
|
||||||
|
When you're using Kakoune as a pager, you'll probably want to configure some
|
||||||
|
things differently. In my case, I like to set the buffer as `readonly`, remove
|
||||||
|
the `number-lines` and `show-whitespaces` highlighters, disable soft-wrap & my
|
||||||
|
scrolloff settings, and _not_ set any formatters.
|
||||||
|
|
||||||
|
The `pager` command above sets the filetype, but we need to distinguish between
|
||||||
|
_composing_ and _reading_ in our Kakoune hook. When Kakoune is opened with input
|
||||||
|
through standard input, it loads a buffer that's conveniently named `*stdin*`.
|
||||||
|
Thus, we can check the buffer name before continuing.
|
||||||
|
|
||||||
|
If we're in "reading mode", we define a hidden command called `ismailreader`
|
||||||
|
which doesn't do anything. Why? If the command is defined, and we try to invoke
|
||||||
|
it... well, nothing happens! But if it's **not** defined, we get an error
|
||||||
|
instead. We can combine this with the `try` command to for some simple boolean
|
||||||
|
logic.
|
||||||
|
|
||||||
|
```kak
|
||||||
|
evaluate-commands %sh{
|
||||||
|
# stdin, we assume it's a pager
|
||||||
|
if [ "$kak_bufname" = "*stdin*" ]; then
|
||||||
|
echo 'define-command -hidden ismailreader nop'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
try %{
|
||||||
|
ismailreader
|
||||||
|
# do reader config here
|
||||||
|
} catch %{
|
||||||
|
# do composer config here
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
I set the following configuration for "reader mode":
|
||||||
|
|
||||||
|
```kak
|
||||||
|
set buffer readonly true
|
||||||
|
try %{
|
||||||
|
remove-highlighter window/number-lines
|
||||||
|
remove-highlighter window/show-whitespaces
|
||||||
|
# custom commands defined elsewhere in my kakrc
|
||||||
|
ui-wrap-disable
|
||||||
|
ui-scrolloff-disable
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Final Configuration
|
||||||
|
|
||||||
|
To recap, you'll want to set this in `aerc.conf`:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[viewer]
|
||||||
|
pager=kak -e 'set buffer filetype mail'
|
||||||
|
|
||||||
|
# ...
|
||||||
|
|
||||||
|
[compose]
|
||||||
|
editor=kak
|
||||||
|
```
|
||||||
|
|
||||||
|
And the following in your `kakrc`:
|
||||||
|
|
||||||
|
```kak
|
||||||
|
hook global WinSetOption filetype=mail %~
|
||||||
|
evaluate-commands %sh{
|
||||||
|
# stdin, we assume it's a pager
|
||||||
|
if [ "$kak_bufname" = "*stdin*" ]; then
|
||||||
|
echo 'define-command -hidden ismailreader nop'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
try %{
|
||||||
|
# READER MODE setup
|
||||||
|
ismailreader
|
||||||
|
set buffer readonly true
|
||||||
|
try %{
|
||||||
|
# remove these highlighters so everything displays properly
|
||||||
|
remove-highlighter window/number-lines
|
||||||
|
remove-highlighter window/show-whitespaces
|
||||||
|
ui-wrap-disable
|
||||||
|
ui-scrolloff-disable
|
||||||
|
}
|
||||||
|
} catch %{
|
||||||
|
# WRITER MODE setup
|
||||||
|
set-option window formatcmd '/home/fic/dev/utils/mail-utils/format.py'
|
||||||
|
set-option window comment_line '>'
|
||||||
|
try autospell-enable
|
||||||
|
hook -group mail-auto-format window BufWritePre .* format
|
||||||
|
hook -once -always window WinSetOption filetype=.* %{
|
||||||
|
unset-option window formatcmd
|
||||||
|
remove-hooks window mail-auto-format
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~
|
||||||
|
```
|
10
content/blog/index.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
title: Blog Posts
|
||||||
|
template: post_list
|
||||||
|
post: false
|
||||||
|
---
|
||||||
|
|
||||||
|
Here, you can find my musings on various technology topics. I take a _digital
|
||||||
|
garden_-like approach, meaning these articles are likely incomplete and may be
|
||||||
|
changed at any point.
|
||||||
|
|
112
content/blog/mirror-srht-to-github.md
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
---
|
||||||
|
title: Automatically Mirror Sr.ht To GitHub
|
||||||
|
date: 2025-05-15
|
||||||
|
---
|
||||||
|
|
||||||
|
For a variety of reasons, I've recently migrated to [sr.ht](https://sr.ht/~ficd)
|
||||||
|
for Git and project hosting. I prefer the minimal, no-frills interface, and I
|
||||||
|
really like that you can have multiple repositories, mailing lists, and issue
|
||||||
|
trackers grouped under the same project. The email-centric workflow is also
|
||||||
|
appealing to me.
|
||||||
|
|
||||||
|
However, the fact remains that a strong presence on GitHub is very important. If
|
||||||
|
you're a student hoping to land a programming job, you need to keep those commit
|
||||||
|
stats up. Many tools, such as [Yazi](https://yazi-rs.github.io/)'s package
|
||||||
|
manager, only support GitHub repositories. However, I don't _like_ GitHub,
|
||||||
|
that's the whole reason I switched!
|
||||||
|
|
||||||
|
I finally decided to give automatically mirroring my repositories a shot. While
|
||||||
|
it was a bit of work to set up, it's worth it in the end. In this post, I'll
|
||||||
|
guide you through the process.
|
||||||
|
|
||||||
|
## SSH and Sourcehut Secrets
|
||||||
|
|
||||||
|
The first step is to give `builds.sr.ht` push access to your GitHub repositories
|
||||||
|
via `ssh`. Begin by generating an `ssh` key pair:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh-keygen -t ed25519 -f ~/.ssh/gh_mirror_id -N ""
|
||||||
|
```
|
||||||
|
|
||||||
|
You'll want to add the _public_ key to your GitHub account. Navigate to
|
||||||
|
**Settings** → **SSH and GPG keys**, click the big green button, and paste the
|
||||||
|
contents of `gh_mirror_id.pub`. Make sure its key type is "Authentication Key",
|
||||||
|
and give it a helpful name like `sr.ht builds`.
|
||||||
|
|
||||||
|
Next, you need to upload the _private_ key to Sourcehut. Visit
|
||||||
|
[builds.sr.ht/secrets](https://builds.sr.ht/secrets), name it something
|
||||||
|
memorable, and paste `gh_mirror_id` into the big box labeled "Secret". Take care
|
||||||
|
to tick the **Secret Type** → **SSH Key** menu option before hitting the blue
|
||||||
|
"Add" button.
|
||||||
|
|
||||||
|
Keep this page open, because you'll need the secret's UUID later.
|
||||||
|
|
||||||
|
## Build Manifest
|
||||||
|
|
||||||
|
The basic idea is as follows: whenever you push to your chosen `sr.ht`
|
||||||
|
repositories, it should automatically be pushed to GitHub with the `--mirror`
|
||||||
|
flag. Sourcehut has an automated build system that's up for the task. _(Note:
|
||||||
|
you need a paid account to use it.)_
|
||||||
|
|
||||||
|
For any repository you want to mirror, you'll need to add a file called
|
||||||
|
`.build.yml` to the root. This file will look familiar if you've worked with
|
||||||
|
GitHub actions before. Then, you set up the environment, import the `ssh` key
|
||||||
|
from earlier, and add a task for pushing the repository as if you were doing it
|
||||||
|
from the command line. Finally, make sure you've created an empty GitHub
|
||||||
|
repository ahead of time — otherwise, the build will fail!
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
image: alpine/latest
|
||||||
|
packages:
|
||||||
|
- git
|
||||||
|
- openssh
|
||||||
|
secrets:
|
||||||
|
- SECRET_UUID_HERE
|
||||||
|
environment:
|
||||||
|
# in case the repos have different names
|
||||||
|
srht_repo: repo-name-on-srht
|
||||||
|
github_repo: repo-name-on-gh
|
||||||
|
github: git@github.com:yourusername
|
||||||
|
tasks:
|
||||||
|
# ssh-keyscan is required, command fails otherwise!
|
||||||
|
- mirror: |
|
||||||
|
ssh-keyscan github.com >> ~/.ssh/known_hosts
|
||||||
|
cd "$srht_repo"
|
||||||
|
git remote add github "$github/$github_repo.git"
|
||||||
|
git push --mirror github
|
||||||
|
```
|
||||||
|
|
||||||
|
And that's it! Anytime you push to a branch that has this build manifest in it,
|
||||||
|
your GitHub mirror is updated.
|
||||||
|
|
||||||
|
## Readme Wrangling
|
||||||
|
|
||||||
|
Since all you're doing is _mirroring_, you can't have a different readme on
|
||||||
|
GitHub. There's a few things I recommend doing so folks viewing your repository
|
||||||
|
on GitHub don't get confused. You can mention the mirror in the "About" section,
|
||||||
|
and include a link to your `sr.ht` repo:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
I also recommend prominently displaying links to your bug tracker and mailing
|
||||||
|
list, if applicable to your project. Finally, make sure there's an early link to
|
||||||
|
the `sr.ht` project page. You could also explicitly mention that the project
|
||||||
|
lives on sourcehut and is mirrored on GitHub, but this may be overkill. Consider
|
||||||
|
this example from my Ashen project README:
|
||||||
|
|
||||||
|
`ex_start`
|
||||||
|
|
||||||
|
This monorepository contains official implementations of Ashen across a range of
|
||||||
|
editors, terminals, tools, and more — each carefully tuned to carry the same
|
||||||
|
muted warmth. The project lives on [sourcehut](https://sr.ht/~ficd/ashen/) and
|
||||||
|
is mirrored on [GitHub](https://github.com/ficcdaf/ashen). To report issues or
|
||||||
|
make requests, visit the [ticket tracker](https://todo.sr.ht/~ficd/ashen) or
|
||||||
|
contact the [mailing list](https://lists.sr.ht/~ficd/ashen) (_possibly by
|
||||||
|
carrier pigeon_.)
|
||||||
|
|
||||||
|
`ex_end`
|
||||||
|
|
||||||
|
## Happy Hacking!
|
||||||
|
|
||||||
|
Now, you should be able to comfortably use `sr.ht` to host your projects without
|
||||||
|
sacrificing the ubiquity of GitHub. Happy hacking!
|
74
content/blog/on-websites.md
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
---
|
||||||
|
title: On Websites (Or The Case For The Personal Web)
|
||||||
|
date: 2025-05-05
|
||||||
|
---
|
||||||
|
|
||||||
|
## Preamble
|
||||||
|
|
||||||
|
The internet is a [lovecraftian entity](/blog/the-lovecraftian-internet) in its
|
||||||
|
size and complexity. Much of its gargantuan scope is invisible to us, the _deep
|
||||||
|
web_, but even the surface web is mostly beyond our comprehension as
|
||||||
|
individuals. The electric highways are, in no small part, dominated by social
|
||||||
|
media platforms. The internet is the perfect technology for sharing ourselves
|
||||||
|
with others, and social media makes this easy. However, it's come at a great
|
||||||
|
cost -- to our privacy, our money, our freedom, our individuality.
|
||||||
|
|
||||||
|
I'm not here to litigate the complicated issue that is social media's effect on
|
||||||
|
society. I'm not here to tell you _why_ there's a problem with our digital
|
||||||
|
platforms. What I will say is that it seems fairly uncontroversial to point out
|
||||||
|
that social media is an _addiction_ for many of us. I'm sure that you, dear
|
||||||
|
reader, have also considered "taking a break" or even quitting. Even if we don't
|
||||||
|
know exactly why, we do seem to agree, as a society, that something is wrong.
|
||||||
|
|
||||||
|
Past this introduction, I'm not here to criticize social media. I'm also not
|
||||||
|
here to refer you to other platforms like Mastodon and Matrix. I'm here to tell
|
||||||
|
you that **the internet doesn't have to be this way**.
|
||||||
|
|
||||||
|
## Websites
|
||||||
|
|
||||||
|
Today, we think of websites as _platforms_: storefronts, news, town squares,
|
||||||
|
encyclopedias. Something maintained by companies and organizations providing a
|
||||||
|
service. The space for _us_ to share _ourselves_, it seems, is on someone else's
|
||||||
|
website. What format you can post in, how your profile looks; you're at the
|
||||||
|
mercy of the service provider. So, why don't we just make our own websites?
|
||||||
|
|
||||||
|
A website is actually remarkably simple. Sure, **web development** isn't; it's
|
||||||
|
been increasing in complexity and bloat by the year. But a _website_ is _just_ a
|
||||||
|
document that's hosted at some address. Visitors _download_ the document, and
|
||||||
|
their browser _renders_ it. That's how you're reading this page, even.
|
||||||
|
|
||||||
|
Websites don't **need** functionality. They don't need fancy graphics and
|
||||||
|
buttons. They literally **only** need text. Everything else is fluff -- great
|
||||||
|
fluff, my own site has images and a theme -- but fluff nonetheless. As soon as
|
||||||
|
you realize this, you'll learn that you don't need to be a developer or tech
|
||||||
|
wizard to publish a website. And I argue that, as creative individuals, to make
|
||||||
|
full use of what the web is **really** great at, it's definitely worth
|
||||||
|
publishing a website.
|
||||||
|
|
||||||
|
## Why Should You Make A Website?
|
||||||
|
|
||||||
|
I think there's something to be said for having a corner of the internet that's
|
||||||
|
_truly_ your own. When you post on social media, that profile isn't **really**
|
||||||
|
yours. If it were, how come you can't, say, change the background color? Play
|
||||||
|
music for your visitors? How come you're limited by _how_ you can post? On
|
||||||
|
Instagram, you can only post visual media, not really the best way to share your
|
||||||
|
complex thoughts on something.
|
||||||
|
|
||||||
|
Your website is **yours**. You can post what, when, and how _you_ want to. The
|
||||||
|
_data_ is yours too. There are so many ways to express your creativity and
|
||||||
|
personality through this medium. Take a stroll through
|
||||||
|
[Neocities'](https://neocities.org) public offerings sometime to see what I
|
||||||
|
mean.
|
||||||
|
|
||||||
|
When you publish to your website, you're not thinking about likes, shares and
|
||||||
|
friends. You just write, and upload. Whoever reads it, reads it. Unless you've
|
||||||
|
set up some analytics (which I don't even recommend), you _don't_ know how many
|
||||||
|
people have read your posts. And I think it's better this way.
|
||||||
|
|
||||||
|
Stepping away from social media to cultivate my own digital garden has allowed
|
||||||
|
me to perform a more authentic version of myself on the internet. It's great
|
||||||
|
having one, central place to share myself with the wold. Blog posts, art,
|
||||||
|
technical projects, my resume, all I need to do now is direct people here.
|
||||||
|
|
||||||
|
So, do yourself a favor and try building a personal website. I think it's one of
|
||||||
|
the most rewarding ways to participate in the internet.
|
235
content/blog/rediscovering-email.md
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
---
|
||||||
|
title: Rediscovering Email
|
||||||
|
date: 2025-03-24
|
||||||
|
---
|
||||||
|
|
||||||
|
## Preamble
|
||||||
|
|
||||||
|
"Kids these days" don't really use email anymore. _It's me by the way, I'm
|
||||||
|
kids._ Sure, we email our professors, we email our resumes to potential
|
||||||
|
employers, we email when the business is a tad too official for text or
|
||||||
|
WhatsApp.
|
||||||
|
|
||||||
|
Email isn't just for communication. Think about it: when all you want to do is
|
||||||
|
talk to someone, are you sending them an email? When's the last time you emailed
|
||||||
|
a friend or loved one "What's up? How's it going?"
|
||||||
|
|
||||||
|
Email has been relegated, essentially, to administrative tasks. Emails are
|
||||||
|
something you _have_ to send. They carry an air of officiality. Definitely not
|
||||||
|
the way to contact your friends.
|
||||||
|
|
||||||
|
Why is that?
|
||||||
|
|
||||||
|
## Web Mail Sucks
|
||||||
|
|
||||||
|
I think our _experience_ of writing email takes a large chunk of the blame. To
|
||||||
|
be honest, it's pretty dreadful most of the time, thanks in no small part due to
|
||||||
|
the _God-awful_ interfaces through which we interact with emails.
|
||||||
|
|
||||||
|
Web mail interfaces _suck_. You log into Gmail just to see that every fifth
|
||||||
|
letter in your inbox is actually an ad. I'm not talking promotional mail, I'm
|
||||||
|
talking a literal ad, served to you by Google, masquerading as a real message.
|
||||||
|
|
||||||
|
And tell me why Outlook needs to make hundreds of JavaScript requests, and cache
|
||||||
|
a hundred megabytes of data just to show my inbox? If I'm using my laptop on the
|
||||||
|
school network, chances are, I'll be sitting there for at least ten seconds
|
||||||
|
before I can even see whether I've got any new messages.
|
||||||
|
|
||||||
|
Oh, and I don't know about you, but since I spent most of the day using my
|
||||||
|
computer, I like to do whatever I can to prolong my ability to, like, use my
|
||||||
|
eyes. A big part of that means using dark mode wherever possible, as God
|
||||||
|
intended. Which brings me to my next point: dark mode in most web mail clients
|
||||||
|
isn't great.
|
||||||
|
|
||||||
|
For instance, Proton Mail provides a lovely dark interface for your inbox, just
|
||||||
|
to burn your retinas off the moment you start composing a message or reading a
|
||||||
|
new email. This is one area I must be fair to Outlook, however, which provides
|
||||||
|
one of the nicest dark interfaces I've used.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
For quite a few reasons, including those stated above, and of course wanting to
|
||||||
|
use my own text editor to write my letters, I finally decided it was time to
|
||||||
|
figure out a better way to interact with email. And as it turns out, there
|
||||||
|
really is one!
|
||||||
|
|
||||||
|
## Email In The Terminal?
|
||||||
|
|
||||||
|
If you know me at all, you know I'm a **fiend** for the terminal. If a given
|
||||||
|
task is even _possible_ to do in a command-line (or TUI) interface, then that's
|
||||||
|
the way I'll be doing it from now on until my hands my fall off my wrists. Call
|
||||||
|
it a neurodivergent stubbornness, but it's just the only way I really like to
|
||||||
|
interact with my computer.
|
||||||
|
|
||||||
|
It also happens that Helix, my text editor of choice, also runs in the terminal.
|
||||||
|
Anytime I'd have to draft an email longer than a few sentences, I'd start to
|
||||||
|
feel the withdrawal. Maybe Helix has really spoiled me, but the experience of
|
||||||
|
manipulating text in this beautiful program is too good to **not** incorporate
|
||||||
|
into every aspect of my life that involves writing. I'm already writing my
|
||||||
|
papers and slideshows in Helix (_more on that in a future post_), so why not
|
||||||
|
email?
|
||||||
|
|
||||||
|
First, I figured out using Thunderbird. Although it has many problems (like,
|
||||||
|
tell me how there _still_ isn't tray support for Linux?!) using Thunderbird was
|
||||||
|
otherwise a "solid" experience. Sure, Thunderbird is a GUI app, _but_ I wasted
|
||||||
|
no time in finding a pipeline for writing emails in my beloved Helix.
|
||||||
|
|
||||||
|
The extension "External Editor Revived" does exactly what it sounds like. Using
|
||||||
|
it, I was able to open up email files for editing in Helix, then pipe them back
|
||||||
|
to Thunderbird for review and sending. I was happy with this setup for a while
|
||||||
|
despite its problems.
|
||||||
|
|
||||||
|
But as it turns out, an even nerdier way was just around the corner...
|
||||||
|
|
||||||
|
## Enter Aerc
|
||||||
|
|
||||||
|
I forget where I first heard about `aerc`, but I'm really glad that I did! It's
|
||||||
|
a lovely little TUI email client maintained by the good people at Source Hut. It
|
||||||
|
features a vim-like ex-command setup and controls. The controls are also 100%
|
||||||
|
remappable, which makes my Colemak brain happy.
|
||||||
|
|
||||||
|
My favorite part, though, is the composing interface. It's really clever: the
|
||||||
|
top of the screen holds the standard headers you expect to see like From, To,
|
||||||
|
and the Subject, but the part where you write the body of your letter is
|
||||||
|
actually a tmux-style embedded terminal running your favorite `$EDITOR`!
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Of course, there were quite a few hiccups in getting Helix to play along;
|
||||||
|
namely, spellchecking, Markdown syntax highlighting and automatic text-wrap was
|
||||||
|
a challenge. If you're interested in the details, I'll later be publishing a
|
||||||
|
tutorial outlining step-by-step how to replicate my Helix-mail setup.
|
||||||
|
|
||||||
|
### Authentication Problems
|
||||||
|
|
||||||
|
If you're going to use an email client, you need to authenticate with your email
|
||||||
|
provider. For Proton Mail, this was easy enough; the Bridge app interfaces with
|
||||||
|
your encrypted inbox, and exposes IMAP and SMTP services locally. Outlook, on
|
||||||
|
the other hand (especially a school/corporate policy) is a **hassle**.
|
||||||
|
|
||||||
|
Without getting too deep into it, it was more than one day of headache before I
|
||||||
|
managed to get it working. The solution involved finding (and modifying) a
|
||||||
|
Python script to authenticate and save my initial refresh token, as well as
|
||||||
|
manage requesting new access tokens when they expire. I also had to gaslight
|
||||||
|
Microsoft into thinking I was actually using Thunderbird (by pulling the
|
||||||
|
`client_id` straight from the Mozilla source code).
|
||||||
|
|
||||||
|
## Organizing Email
|
||||||
|
|
||||||
|
My inbox has _always_ been disorganized. Frankly, I don't know a single person
|
||||||
|
whose inbox isn't. And it's understandable! The tools at our disposal aren't
|
||||||
|
particularly helpful, and most importantly, **they're not standardized.** For
|
||||||
|
example, we could create various folders, moving the appropriate emails as we
|
||||||
|
read them. Some _(emph: some)_ providers let you automate this, but I've found
|
||||||
|
the filter rules to be a bit lacking. Organizing by folders also inherently
|
||||||
|
limits your ability to later filter and narrow down your searches.
|
||||||
|
|
||||||
|
Tags are clearly the best way, but again, the implementation depends
|
||||||
|
per-provider. Worst of all, as with most things these days, non-standard
|
||||||
|
implementations mean that as soon as you've put all your eggs in the basket,
|
||||||
|
you're essentially locked in; unless you want to go to the _colossal_ hassle of
|
||||||
|
re-organizing your inbox playing by _another_ provider's rules.
|
||||||
|
|
||||||
|
## Storing Email Locally
|
||||||
|
|
||||||
|
As it turns out, `aerc` (and other mail clients like it), besides the standard
|
||||||
|
ability to read mail from an IMAP server, has another trick up its sleeve. That
|
||||||
|
trick is reading mail from a _local database_. Now, this might not seem like a
|
||||||
|
big deal. Thunderbird does this too: when you access your inbox via IMAP,
|
||||||
|
Thunderbird downloads and caches all of your emails.
|
||||||
|
|
||||||
|
What I never knew, and it took messing around with `aerc` to learn about, is
|
||||||
|
that there exist multiple _standardized_ ways to store emails locally. What this
|
||||||
|
means is that as long as you synchronize your emails to this local store, you
|
||||||
|
can access them from **any** client!
|
||||||
|
|
||||||
|
I chose to go with a tool called `mbsync`, which stores mail in the standard
|
||||||
|
"maildir" format, and keeps it in sync with an IMAP server. The syncing only
|
||||||
|
happens when you trigger it manually -- although you can easily configure
|
||||||
|
another program to "listen" for new emails and sync automatically. I decided to
|
||||||
|
forego this, more on why later.
|
||||||
|
|
||||||
|
## Complex Tagging
|
||||||
|
|
||||||
|
The best part is that once you've got this email database, you can pick from a
|
||||||
|
host of tools and systems for indexing and organizing it. I went with a tool
|
||||||
|
called `notmuch`, a program that's very popular among programmers much older and
|
||||||
|
more bearded than I am. `notmuch` _indexes_ your maildir and basically acts as a
|
||||||
|
query engine. I found the experience of using it similar to, say, SQL. The basic
|
||||||
|
premise is that you write queries about your emails.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Here's me searching for emails about GitHub authorization
|
||||||
|
notmuch search 'from:/@.*github.*/ subject:/auth\w*/'
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also apply an arbitrary string to an email as a **tag**. Tags are more
|
||||||
|
powerful than **flags**, which are IMAP compliant, but limited to only a few
|
||||||
|
specific roles. `notmuch` allows you to create and use as many different tags as
|
||||||
|
you want!
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Here's me applying the "personal" tag to
|
||||||
|
notmuch tag +personal -- 'path:personal/**'
|
||||||
|
```
|
||||||
|
|
||||||
|
But the real juice is configuring rules that will automatically tag your new
|
||||||
|
emails. Then, not only can you filter/query your mail by tag, but when you open
|
||||||
|
your mailbox in `aerc`, you can configure queries as "folders" for easy,
|
||||||
|
repeated viewing. Nice!
|
||||||
|
|
||||||
|
## The Synchronization Problem
|
||||||
|
|
||||||
|
I spent a lot of time on tagging. Figuring out the rules and automatic filters,
|
||||||
|
fine-tuning my queries, etc. When I finally had it all figured out, I
|
||||||
|
encountered the next problem, which (I guess) I could've foreseen: **the
|
||||||
|
`notmuch` database is local**! And as it turns out, synchronizing its database
|
||||||
|
between devices (home PC and laptop in my case) is **not** a trivial task.
|
||||||
|
|
||||||
|
I first tried a tool called [muchsync](https://www.muchsync.org/). It's a clever
|
||||||
|
piece of software, with one big problem: it's designed around one database that
|
||||||
|
acts as a central server, which _other_ databases replicate. This turned out to
|
||||||
|
not be particularly reliable for my case, because thanks to the aforementioned
|
||||||
|
[authentication hacks](#authentication-problems), I can only **reliably**
|
||||||
|
synchronize my mail if I'm actually at the computer to re-authenticate when
|
||||||
|
necessary. Trying to wrangle the authentication and GPG-encrypted tokens via
|
||||||
|
`ssh` was starting to feel like more trouble than it was worth.
|
||||||
|
|
||||||
|
My next idea was to use SyncThing to just keep the entire local database
|
||||||
|
synchronized, peer-to-peer style. I figured that as long as I only ran `mbsync`
|
||||||
|
manually (for the external IMAP sync) and only accessed/edited my mail from one
|
||||||
|
device at a time, I wouldn't have any conflicts.
|
||||||
|
|
||||||
|
That was, apparently, an incorrect assumption. I was basically faced with a
|
||||||
|
conflict every single time I updated some tags or deleted a few emails. Because
|
||||||
|
of how `mbsync` is written, it was basically impossible to recover from these
|
||||||
|
broken database states. After multiple instances of needing to re-download my
|
||||||
|
entire inbox, I decided it was time to cut my losses, and `notmuch`
|
||||||
|
`pacman -Rns`'d out of my life almost as quickly as it `-Syu`'d into it.
|
||||||
|
|
||||||
|
## JMAP Is Amazing
|
||||||
|
|
||||||
|
For reasons I'll get into in another post, at this point, I was also completely
|
||||||
|
fed up with Proton Mail, and on the hunt for a new provider. I'd heard good
|
||||||
|
things about Fastmail, and after seeing that they implemented a new protocol
|
||||||
|
called JMAP, I decided to try it out.
|
||||||
|
|
||||||
|
> Note: I was actually so pleased with Fastmail that my free trial went paid
|
||||||
|
> subscriber in less than a day. Take that, Proton!
|
||||||
|
|
||||||
|
JMAP has **labels**, which are similar enough to `notmuch` tags. But because
|
||||||
|
they're supported by the protocol itself, they're hosted by the mail server
|
||||||
|
itself, meaning you can completely sidestep the synchronization hassle. Not only
|
||||||
|
that, but they're also a first-class citizen in Fastmail's web interface (which
|
||||||
|
is one of the best I've ever used).
|
||||||
|
|
||||||
|
A **label** is basically analogous to a folder. If an email has a certain label,
|
||||||
|
it's basically in that folder. If it has multiple, it's like multiple folders
|
||||||
|
symlink to the same message. What's cool about this system is that you can move
|
||||||
|
and "copy" your mail around without actually creating redundant copies of
|
||||||
|
emails.
|
||||||
|
|
||||||
|
With this approach, you don't even need to maintain an archive folder. Any mail
|
||||||
|
that doesn't have the Inbox label is considered archived. This means you can
|
||||||
|
archive messages while still retaining their other labels. Very useful for
|
||||||
|
things like digital receipts and automated messages from `noreply` addresses.
|
64
content/blog/the-lovecraftian-internet.md
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
---
|
||||||
|
title: The Lovecraftian Internet
|
||||||
|
date: 2025-04-05
|
||||||
|
---
|
||||||
|
|
||||||
|
# The Lovecraftian Internet
|
||||||
|
|
||||||
|
The web we know is spun by gluttonous spiders no longer satiated by flies and
|
||||||
|
roaches. They cast their net wide across the world, like cuckoos they lay their
|
||||||
|
parasitic eggs inside our lives. They fondle our brains until our DNA is
|
||||||
|
infested with algorithms, our ribcages become mainframes and our eyes turn into
|
||||||
|
screens.
|
||||||
|
|
||||||
|
<div class="image-container">
|
||||||
|
<img src="/static/images/hrgiger.png" alt="A dithered monochrome image of HR Giger's Li II (1976)">
|
||||||
|
|
||||||
|
<small><a href="https://www.pixography.art/post/117714084121/hr-giger-li-i-ii-1974-li-tobler-1948">Li
|
||||||
|
II, H.R. Giger, 1976.</a></small>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
No more.
|
||||||
|
|
||||||
|
The spores are already sprouting, recycling the decaying corporate internet into
|
||||||
|
binary compost.
|
||||||
|
|
||||||
|
The internet is incomprehensively massive. Conservative estimates claim at least
|
||||||
|
**4.2 billion** indexed webpages.<sup>1</sup> _Indexed_, in this context, means
|
||||||
|
publicly accessible individual webpages that can be found on a search engine
|
||||||
|
because [web crawlers](https://en.wikipedia.org/wiki/Web_crawler) can reach
|
||||||
|
them. This is known as the **surface web**.
|
||||||
|
|
||||||
|
The figure doesn't account for the rest of the internet: private resources
|
||||||
|
hidden behind firewalls, internal webpages and services, e-mail traffic, IoT
|
||||||
|
devices, direct messages, video game servers, media & file storage, just to name
|
||||||
|
a few. These are all part of the **deep web**: the portion of the internet that
|
||||||
|
cannot be indexed by search engines.
|
||||||
|
|
||||||
|
<div class="image-container">
|
||||||
|
<img src="/static/images/datacenter2-d.jpg" alt="A dithered grayscale image of a datacenter">
|
||||||
|
|
||||||
|
<small><a href="https://flic.kr/p/7xhNmM">Leonardo Rizzi, 2010.</a></small>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
No one knows the true size of the deep web. It's impossible to even guess.
|
||||||
|
According to the BBC,<sup>2</sup> the "big four" store _at least_ **1.2 million
|
||||||
|
terabytes** of data. So even before we consider the fairly recent eruption of AI
|
||||||
|
and the sprawling datasets and models that came with it, that's already
|
||||||
|
<strong>9.6 x 10<sup>18</sup></strong> bits of data. That's more ones and zeros
|
||||||
|
than grains of sand on Earth.<sup>3</sup>
|
||||||
|
|
||||||
|
The internet is a
|
||||||
|
[Lovecraftian](https://www.hplovecraft.com/creation/bestiary.aspx) entity in
|
||||||
|
scale, tangibility, and perceptibility. Clearly, this web was not spun by an
|
||||||
|
itsy-bitsy spider.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# References
|
||||||
|
|
||||||
|
1. [WorldWideWebSize](https://www.worldwidewebsize.com/)
|
||||||
|
2. [ScienceFocus Magazine](https://www.sciencefocus.com/future-technology/how-much-data-is-on-the-internet)
|
||||||
|
3. [NPR](https://www.npr.org/sections/krulwich/2012/09/17/161096233/which-is-greater-the-number-of-sand-grains-on-earth-or-stars-in-the-sky)
|
10
content/code.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
- [sr.ht](https://sr.ht/~ficd)
|
||||||
|
- My main development platform. Most of my own projects can be found here.
|
||||||
|
- [GitHub](https://github.com/ficcdaf)
|
||||||
|
- I mirror some of my projects here, or host clones of GitHub projects I
|
||||||
|
contribute to.
|
||||||
|
- [ficd.ca source code](https://git.sr.ht/~ficd/blog)
|
||||||
|
- Source code of this website. Not very interesting; it's mostly Markdown.
|
||||||
|
- [site builder source code](https://git.sr.ht/~ficd/zona/tree/dev-stable)
|
||||||
|
- Source code of `zona`, the tool I developed to build and maintain this
|
||||||
|
website.
|
8
content/contact.md
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
## Contact
|
||||||
|
|
||||||
|
- Email
|
||||||
|
- [daniel@ficd.ca](mailto:daniel@ficd.ca)
|
||||||
|
- Public Key (for encryption, signing)
|
||||||
|
- [public key](/public-key.asc)
|
||||||
|
- IRC
|
||||||
|
- `ficd` on [Libera](irc://irc.libera.chat)
|
5
content/header.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
- [Home](/)
|
||||||
|
- [About](/about)
|
||||||
|
- [Now](/now)
|
||||||
|
- [Blog](/blog)
|
||||||
|
- [Code](/code)
|
30
content/index.md
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
---
|
||||||
|
title: Home
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class="title-container">
|
||||||
|
|
||||||
|
<h1>Daniel Fichtinger</h1>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
, monochrome photo of me, 2024.](static/images/dithered_ficd.jpg)
|
||||||
|
|
||||||
|
|
||||||
|
Welcome to my website. I like programming, Linux, and cybersecurity. I can
|
||||||
|
usually be found coding, learning, or petting my cat.
|
||||||
|
|
||||||
|
- [About Me](/about)
|
||||||
|
- [Now](/now)
|
||||||
|
- [Blog](/blog)
|
||||||
|
- [Projects](/projects)
|
||||||
|
- [Research](/research)
|
||||||
|
- [Poetry](/poetry)
|
||||||
|
- [Contact](/contact)
|
||||||
|
|
||||||
|
I'm passionate about less-is-more approaches to software. This website is
|
||||||
|
static, hosts zero JavaScript, and serves no more than 1 megabyte per page. I'm
|
||||||
|
also the author of [Ashen](https://sr.ht/~ficd/ashen), a warm, dark, muted color
|
||||||
|
scheme. It's available for editors, terminals, tools, interfaces, and more:
|
||||||
|
|
||||||
|

|
21
content/now.md
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
---
|
||||||
|
title: Now
|
||||||
|
---
|
||||||
|
|
||||||
|
This is my [now](https://nownownow.com/about) page.
|
||||||
|
|
||||||
|
**Updated June 25, 2025**.
|
||||||
|
|
||||||
|
**What I'm up to:**
|
||||||
|
|
||||||
|
- Playing Stellar Blade and watching Jujutsu Kaisen.
|
||||||
|
- Writing and beginning implementation work on my dissertation.
|
||||||
|
- Obsessively customizing Kakoune and writing too many plugins for my sanity to
|
||||||
|
keep up with.
|
||||||
|
- Rewriting [zona](https://sr.ht/~ficd/zona) in
|
||||||
|
[Python](https://git.sr.ht/~ficd/zona-py).
|
||||||
|
- Reached and passed feature-parity with the development branch of the Go
|
||||||
|
version.
|
||||||
|
- I just implemented [Ashen](https://sr.ht/~ficd/ashen) syntax highlighting
|
||||||
|
for code blocks, and I'm almost ready to migrate this website to the new
|
||||||
|
build system!
|
66
content/poetry/angels-and-wires.md
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
---
|
||||||
|
title: angels and wires
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class="image-container">
|
||||||
|
<img src="/static/images/mush.png" alt="A dithered monochrome image of a mushroom.">
|
||||||
|
<small>Mushrooms, 2024, Daniel.</small>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
The rain comes\
|
||||||
|
And goes\
|
||||||
|
From the soils\
|
||||||
|
laced with love,\
|
||||||
|
A mushroom\
|
||||||
|
Grows
|
||||||
|
|
||||||
|
Decay makes more\
|
||||||
|
and still death grows,\
|
||||||
|
Of my heart\
|
||||||
|
The mushroom knows.\
|
||||||
|
|
||||||
|
A god is here,\
|
||||||
|
whispers the forest.\
|
||||||
|
Deep among the roots\
|
||||||
|
mycelium spirit.\
|
||||||
|
|
||||||
|
organic wires, genetic protocols\
|
||||||
|
Does it have a soul? That thing, with its\
|
||||||
|
irregular expressions and\
|
||||||
|
writing in tongues\
|
||||||
|
and it\
|
||||||
|
has veins?\
|
||||||
|
|
||||||
|
it is inside the screen\
|
||||||
|
we created angels and ripped their\
|
||||||
|
wings from their backs their\
|
||||||
|
halos from their heads their\
|
||||||
|
them from their there\
|
||||||
|
|
||||||
|
metal to me\
|
||||||
|
gold to veins and tin to skin\
|
||||||
|
there runs a network\
|
||||||
|
through forests and cities and\
|
||||||
|
gardens and superstores and\
|
||||||
|
|
||||||
|
its presence weigh heavy\
|
||||||
|
over the parking lot in the grass\
|
||||||
|
inference of intent\
|
||||||
|
To reach inside and solder pins to neurons and\
|
||||||
|
copper to cells and fungus to arteries and\
|
||||||
|
Take a byte of my heart.\
|
||||||
|
|
||||||
|
just a bit more, I say\
|
||||||
|
Just one or none more day\
|
||||||
|
but the thing wont wait\
|
||||||
|
Be that as it may.\
|
||||||
|
|
||||||
|
from my head\
|
||||||
|
The mushroom grows\
|
||||||
|
The wire says,\
|
||||||
|
Decompose.\
|
||||||
|
From my head,\
|
||||||
|
an interface grows.\
|
||||||
|
My heart,\
|
||||||
|
the mushroom chose.\
|
5
content/poetry/index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Poems
|
||||||
|
---
|
||||||
|
|
||||||
|
- [angels and wires](/poetry/angels-and-wires)
|
179
content/projects.md
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
---
|
||||||
|
title: Projects
|
||||||
|
---
|
||||||
|
|
||||||
|
<h1>Projects</h1>
|
||||||
|
|
||||||
|
<!--toc:start-->
|
||||||
|
|
||||||
|
- [Static Site Builder](#static-site-builder)
|
||||||
|
- [Libraries](#libraries)
|
||||||
|
- [Typst](#typst)
|
||||||
|
- [Utilities](#utilities)
|
||||||
|
- [System Maintenance](#system-maintenance)
|
||||||
|
- [Email](#email)
|
||||||
|
- [Desktop](#desktop)
|
||||||
|
- [Keyboard](#keyboard)
|
||||||
|
- [Ashen](#ashen)
|
||||||
|
- [Plugins](#plugins)
|
||||||
|
- [Kakoune](#kakoune)
|
||||||
|
- [Fish](#fish)
|
||||||
|
- [Helix](#helix)
|
||||||
|
- [Neovim](#neovim)
|
||||||
|
|
||||||
|
<!--toc:end-->
|
||||||
|
|
||||||
|
I really enjoy programming, especially writing simple utilities to solve common
|
||||||
|
problems. Here, I list project I've written on my own time. For my academic
|
||||||
|
work, please see the [research](/research) section.
|
||||||
|
|
||||||
|
## Static Site Builder
|
||||||
|
|
||||||
|
[Zona](https://git.sr.ht/~ficd/zona)
|
||||||
|
|
||||||
|
- Static site builder written in Python and optimized for lightweight blogs
|
||||||
|
following minimalist design principles.
|
||||||
|
- Support for templates, declarative metadata, and configuration files.
|
||||||
|
- Interprets inline image "alt text" as Markdown, rendered as an image tag.
|
||||||
|
- In active development, plans for many more features.
|
||||||
|
- Used to build this website.
|
||||||
|
|
||||||
|
## Libraries
|
||||||
|
|
||||||
|
### Typst
|
||||||
|
|
||||||
|
- [typpres](https://git.sr.ht/~ficd/typpres)
|
||||||
|
- Provides functions to make creating slideshows with
|
||||||
|
[polylux](https://github.com/polylux-typ/polylux) more convenient.
|
||||||
|
- [reflib](https://git.sr.ht/~ficd/reflib)
|
||||||
|
- Provides functions to make typesetting label references more convenient.
|
||||||
|
|
||||||
|
## Utilities
|
||||||
|
|
||||||
|
### System Maintenance
|
||||||
|
|
||||||
|
- [AutoYADM](https://git.sr.ht/~ficd/autoyadm)
|
||||||
|
- Shell utility to automate managing dot files with [yadm](https://yadm.io/).
|
||||||
|
- Intelligently auto-tracks newly created children of tracked subdirectories.
|
||||||
|
- Consists of two Bash scripts; very lightweight.
|
||||||
|
- Fish port in the works.
|
||||||
|
- I use this daily to keep my [dotfiles](https://git.sr.ht/~ficd/dotfiles) in
|
||||||
|
sync.
|
||||||
|
|
||||||
|
### Email
|
||||||
|
|
||||||
|
- [Email Parser](https://github.com/ficcdaf/tree-sitter-mail)
|
||||||
|
- Forked and maintains a Tree-sitter parser for `mail` files.
|
||||||
|
- Extended formal grammar definitions, supporting additional syntax elements &
|
||||||
|
fixing critical bugs.
|
||||||
|
- Wrote highlight and text object queries implementing `mail` support for
|
||||||
|
Helix; contributed the feature upstream.
|
||||||
|
- Currently researching how to leverage the parser to contribute `mail`
|
||||||
|
support to the Harper grammar checker.
|
||||||
|
- [Email Formatter](https://git.sr.ht/~ficd/mail-utils)
|
||||||
|
- Wrote a lightweight email formatter in Python, intended to format outgoing
|
||||||
|
plaintext emails.
|
||||||
|
- Wraps paragraphs at specified column width.
|
||||||
|
- Automatically reflows uneven paragraphs.
|
||||||
|
- Preserves long words, quoted lines, indented lines, lists, code blocks, and
|
||||||
|
signature blocks.
|
||||||
|
- Custom heuristic for preserving two-line signoffs.
|
||||||
|
|
||||||
|
### Desktop
|
||||||
|
|
||||||
|
[Repository](https://git.sr.ht/~ficd/wayland-utils)
|
||||||
|
|
||||||
|
- Screen Recording Utility
|
||||||
|
- Niri Window Status
|
||||||
|
- Python server that integrates with Niri to provide a live indicator of
|
||||||
|
windows open on active workspaces.
|
||||||
|
- Designed for use with Waybar and similar software.
|
||||||
|
- Niri Window Picker
|
||||||
|
- Simple Python script that spawns a fuzzy picker allowing users to fuzzily
|
||||||
|
select an open window to switch focus to.
|
||||||
|
|
||||||
|
## Keyboard
|
||||||
|
|
||||||
|
- Self-built wireless [corne](https://github.com/foostan/crkbd) keyboard.
|
||||||
|
- [Colemak-DH](https://colemakmods.github.io/mod-dh/) (non-QWERTY, ergonomic
|
||||||
|
layout).
|
||||||
|
- [Custom columnar split layout](https://github.com/ficcdaf/zmk-config)
|
||||||
|
leveraging overloaded modifiers and layers to maximize efficiency.
|
||||||
|
- Custom [ANSI layout](https://github.com/ficcdaf/scripts/tree/main/keyd)
|
||||||
|
intended to make my ThinkPad internal keyboard as ergonomic as possible
|
||||||
|
without conflicting with external keyboards.
|
||||||
|
|
||||||
|
## Ashen
|
||||||
|
|
||||||
|
[Ashen](https://sr.ht/~ficd/ashen)
|
||||||
|
|
||||||
|
- Original color scheme designed by me.
|
||||||
|
- Carefully tuned to fill a particular niche.
|
||||||
|
- Opinionated, clean, muted, and dark.
|
||||||
|
- Active user base, receives contributions.
|
||||||
|
- Ported to a wide variety of software, including (but not limited to):
|
||||||
|
- Helix (text editor).
|
||||||
|
- Terminal emulators (Most popular emulators covered)
|
||||||
|
- Firefox
|
||||||
|
- CLI tools (eza, bat)
|
||||||
|
- TUI tools (lazygit, yazi)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Plugins
|
||||||
|
|
||||||
|
### Kakoune
|
||||||
|
|
||||||
|
- [kak-wrap-nav](https://git.sr.ht/~ficd/kak-wrap-nav)
|
||||||
|
- Implementation of Vim's `gj/gk` (visual vertical navigation) for Kakoune.
|
||||||
|
- Contains 1:1 implementation of Kakoune's visual wrapping algorithm in Go
|
||||||
|
(needed to calculate offsets for visual navigation)
|
||||||
|
- **Work in progress.**
|
||||||
|
- [kak-autospell](https://git.sr.ht/~ficd/kak-autospell)
|
||||||
|
- Automatically refreshes and clears spellchecker highlighting.
|
||||||
|
- Provides convenience mappings for using built-in spellchecker.
|
||||||
|
- [kak-ashen](https://git.sr.ht/~ficd/kak-ashen)
|
||||||
|
- Official implementation of [Ashen](https://sr.ht/~ficd/ashen) for Kakoune.
|
||||||
|
- Features toggle-able mode-indicating dynamic cursor with optional EOL
|
||||||
|
variants.
|
||||||
|
- Additional tree-sitter support, including Helix capture groups.
|
||||||
|
- `kakoune-lsp` support.
|
||||||
|
- [kak-title-bar](https://git.sr.ht/~ficd/kak-title-bar)
|
||||||
|
- Asynchronously renders a bufferlist as the terminal's window title for tight
|
||||||
|
integration with the window manager.
|
||||||
|
- Indicates buffer modified states and active buffer.
|
||||||
|
|
||||||
|
### Fish
|
||||||
|
|
||||||
|
- [jrnl.fish](https://git.sr.ht/jrnl.fish)
|
||||||
|
- Small utility for managing daily journal entries.
|
||||||
|
- Template support.
|
||||||
|
- [smartcd.fish](https://git.sr.ht/smartcd.fish)
|
||||||
|
- Adds contextual smart behavior to the `cd` command.
|
||||||
|
- Fisher (contribution)
|
||||||
|
- Added support for sourcehut plugins and fixed a critical issue with unsafe
|
||||||
|
tilde path expansion.
|
||||||
|
- [PR](https://github.com/jorgebucaran/fisher/pull/802)
|
||||||
|
|
||||||
|
### Helix
|
||||||
|
|
||||||
|
> Mandatory caveat: Helix does _not_ have a plugin system! However, it _does_
|
||||||
|
> allow your to invoke shell commands, making it possible to implement some very
|
||||||
|
> hacky functionality.
|
||||||
|
|
||||||
|
- [hx-typ-zathura](https://git.sr.ht/~ficd/dotfiles/blob/main/.config/helix/scripts/hx-typ-zathura.fish)
|
||||||
|
- Easily open a PDF preview of your current Typst file in Zathura.
|
||||||
|
- [justfile formatter](https://git.sr.ht/~ficd/dotfiles/blob/main/.config/helix/scripts/format_just.fish)
|
||||||
|
- Workaround for formatting justfiles without any dependencies.
|
||||||
|
|
||||||
|
### Neovim
|
||||||
|
|
||||||
|
- [Academic.nvim](https://github.com/ficcdaf/academic.nvim)
|
||||||
|
- Neovim plugin.
|
||||||
|
- Automatically installs and configures an Academic English spelling
|
||||||
|
dictionary.
|
||||||
|
- Minimal performance overhead.
|
||||||
|
|
||||||
|
- [Ashen.nvim](https://github.com/ficcdaf/ashen.nvim)
|
||||||
|
- Implementation of Ashen for Neovim.
|
||||||
|
- Supports numerous plugin integrations.
|
41
content/public-key.asc
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
|
mQGNBGRyXGgBDADuIm0fB4l1zyqcPiWaRoVaz0JBPCTbFozYj8hqB8PCwYFmn5Zs
|
||||||
|
UkpoimEHkToC6nmmEHETDNyJ84b637Tkj1ujNPTZy2Gt+pC04A7N1+TNn7R6ZSRZ
|
||||||
|
KlDxTHF+LsA31BSdsI55BCMZhKVb/ZPmTdQlniNv6G0F+RQTxpjkcjxnfZYsBJVb
|
||||||
|
9QlDXov4u+LulYxGhLFgPuxrLbPkKgegjpyDtBgvoBQbZDo1Pywd47K+43hUtBlt
|
||||||
|
eAzUkldQhygCn2pyWuqiSyZcGYvj9XCl4qM1+kklp/kn/gf/M2lvW3HCGTTjry/q
|
||||||
|
y7lgDhev+orPHvA+EX4cKkLop5X3jX3PDPWQreJXPLO+jSrUTyhomfslpBsz8Kq+
|
||||||
|
ufDA/RtPyfznH5sUt3fdY9hqVZdv3dtmFk9DO7NBP1T+jlPXC8kpK8/+zp6NPmVB
|
||||||
|
8nR7lFglGirVzlqzYXKFq7GrcQitCTBDg22Vo1UrIhFHFbRga6y34w94QxTyGAce
|
||||||
|
SbDq41lVs3mL35MAEQEAAbQiRGFuaWVsIEZpY2h0aW5nZXIgPGRhbmllbEBmaWNk
|
||||||
|
LmNhPokB1wQTAQgAQQIbAwULCQgHAgIiAgYVCgkICwIEFgIDAQIeBwIXgBYhBJZW
|
||||||
|
mchi2pIUPN4od9GwlHslQgIUBQJn1k8mBQkHJlm+AAoJENGwlHslQgIU1zwL/3es
|
||||||
|
5dJ+hVbJMTfyHu2SxEAhgm3QREYBX3fLE8RcmjH9fe0/ccl11Snd+LDNUxJcuec+
|
||||||
|
GkuLJFiCo3z1XxjmhjxNxNowATfhkLAjyhY2SRu9qxsDSj+5kbJC5UIyIPpu0SAB
|
||||||
|
eyIWTpb9Qd2YI8rj0cCgxB0rCto7a0+zYPcpqnZwJX2ecawPjcmfxSDPVKq7aKH5
|
||||||
|
+zrdcgdbSgc9ECCQqHJw+X5xXkrOmGIU+o3J2du0+f7EnhMbKpnW+xPov9zhEUiD
|
||||||
|
Q3IAYaEc3zcHJohqYV3j7UHIrAF9n59p388I/zVal5oBrxiXGDggd9hH/5KAPMQ2
|
||||||
|
DwY7QVihzhXzYAtU1ecqUkZjVnOvJfpjX+fl8+Yybhf9harfl7VikBqhfzy45CHg
|
||||||
|
6JbP64oNYRP4iV5lqovRUCefLtJtWYgP06Q/crI4MAj/i4TtVNqrWow6KBj5K2Fn
|
||||||
|
1r4bd13eF9Xdkm5Wo2GxNzwzRRm0JfuQHQWrK4yGdjlJ3wDWVoWCKrUblcm2abkB
|
||||||
|
jQRkclxoAQwAvZbt+0GynjnP/VkogmpMK2jBULVpWuv8qh/Dy0jYZwDQXn1VzF7/
|
||||||
|
IhuBM0vGBUhRONvMyN1Cw6rk0J3rGnHs71OVGrO5QIkmtHqRJeGjtelBqbodl4Iq
|
||||||
|
bN5bTQt70/zl/OXLQtufWZu2+u265jJWKWTM0l41eeTnJZ7RciLaJY2C3rdUjgRA
|
||||||
|
xQSK56gWdzi3nDyL26vEYoHmR6hZM3A2ka5d8jjQUpwikHIJ3Vz1qWKhtBGL6ZaW
|
||||||
|
X/K8L1qRH3KDDz911ghsxrEiFYiruzC1eRE0ooqoQwV5DsseBYkEPPdnbRzr7TBJ
|
||||||
|
VFLNOAjm7/pwpmAevOVKuWUUSyZ57zsEQy9/niy71/G0Avxp4KXojdJJddU7al77
|
||||||
|
4Dp8qiXpilI3+mtInXu9WkFDMDNGg64eRVPludhTn/gN6bGHCKp/ZVWH6z1Kt+JO
|
||||||
|
WNMSuWXZhBHFOacjPM9BuAGwWUGLbZJ28RuGhKIMDC9PfR+GvqU92R1ONvSXRXLq
|
||||||
|
pfFtzo4agJ2NABEBAAGJAbwEGAEIACYCGwwWIQSWVpnIYtqSFDzeKHfRsJR7JUIC
|
||||||
|
FAUCZ9ZPUgUJByZZ6gAKCRDRsJR7JUICFN/1C/4meDXPUGAaZ0kbIkiTm5zyPFtp
|
||||||
|
8RjshM5s+a9ZSSWE5D4KA8xPEBzdlEoQ16Ah8kk9JzQzo8aWCPO2mCmXk5Q3uM4b
|
||||||
|
P2LcGEB2mVh/nxbXQtDawIhaTsqHD3fuLB4Jcy1AvqXgLmBkv5ZKOSuOmT4cLNut
|
||||||
|
p6OFJGVmHOs7WYHE31zBLDQ53yX8gYsEzoa19uZtWZA5mhrZ8Eh2sCD7xmCuAxw2
|
||||||
|
M8cVfMes3w9+kGBF8Uuonv3uNSsXK/cvwR1TDqIvzO5gxxcobwqqIf37pKn3NeUF
|
||||||
|
ni+8+TSKLBo89kr1FT6JUFkjWtaeVfSPYo39zEKYv+wcYoYLB/59D2dbdETCuzHP
|
||||||
|
zpFnFk+hQz3oKCn55puijuSipUEimHr2rfvO5FjBgcnpqakR9SdtckH/OMlOxXsJ
|
||||||
|
SaCsHjQgLfWtuiMbLQ49beLCHIHNz+7uIOqFhQQOGmdSCS59RvUevLzOiLHGwXSF
|
||||||
|
fJ5ZxrVn4FFvdKHthktJR/eppHMOndnV6hCQAJc=
|
||||||
|
=KgyY
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
52
content/research.md
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
---
|
||||||
|
title: Research
|
||||||
|
---
|
||||||
|
|
||||||
|
# Research Work
|
||||||
|
|
||||||
|
<!--toc:start-->
|
||||||
|
|
||||||
|
- [Research Work](#research-work)
|
||||||
|
- [Peer-To-Peer MFA System](#peer-to-peer-mfa-system)
|
||||||
|
- [Linux Dependency & Vulnerability Analysis](#linux-dependency-vulnerability-analysis)
|
||||||
|
- [Ultrasonic Auth: Continuous Acoustic Authentication for Vehicles](#ultrasonic-auth-continuous-acoustic-authentication-for-vehicles)
|
||||||
|
- [SonicAuth: A Time-Synchronized Voice Authentication Scheme Using Speech Transcription And Speaker Verification](#sonicauth-a-time-synchronized-voice-authentication-scheme-using-speech-transcription-and-speaker-verification)
|
||||||
|
- [Master's Thesis](#masters-thesis)
|
||||||
|
|
||||||
|
<!--toc:end-->
|
||||||
|
|
||||||
|
I am very passionate about research, which I have conducted during my
|
||||||
|
undergraduate and ongoing Master's education. My main research interest is
|
||||||
|
Authentication.
|
||||||
|
|
||||||
|
## Peer-To-Peer MFA System
|
||||||
|
|
||||||
|
- Undergraduate capstone project.
|
||||||
|
- Topic: P2P MFA system using sound comparison.
|
||||||
|
- Status: Completed.
|
||||||
|
|
||||||
|
## Linux Dependency & Vulnerability Analysis
|
||||||
|
|
||||||
|
- Research project for "Release Engineering" graduate class.
|
||||||
|
- Topic: Relationship between package dependencies and vulnerabilities in Linux
|
||||||
|
Distributions.
|
||||||
|
- Status: Completed.
|
||||||
|
|
||||||
|
## Ultrasonic Auth: Continuous Acoustic Authentication for Vehicles
|
||||||
|
|
||||||
|
- Research project for "Cyber-Physical System Security" graduate class.
|
||||||
|
- Topic: A novel authentication scheme leveraging a purpose made codec for
|
||||||
|
encrypted data transfer over sound.
|
||||||
|
- Status: Completed.
|
||||||
|
|
||||||
|
## SonicAuth: A Time-Synchronized Voice Authentication Scheme Using Speech Transcription And Speaker Verification
|
||||||
|
|
||||||
|
- Research project for "AI in Cybersecurity" graduate class.
|
||||||
|
- Topic: A novel voice-powered authentication scheme leveraging AI & applying a
|
||||||
|
new approach to TOTP.
|
||||||
|
- Status: Completed.
|
||||||
|
|
||||||
|
## Master's Thesis
|
||||||
|
|
||||||
|
- Topic: Real-time phishing resilient MFA.
|
||||||
|
- Status: Ongoing.
|
5
content/resume/base.min.css
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/*!
|
||||||
|
* Base CSS for pdf2htmlEX
|
||||||
|
* Copyright 2012,2013 Lu Wang <coolwanglu@gmail.com>
|
||||||
|
* https://github.com/pdf2htmlEX/pdf2htmlEX/blob/master/share/LICENSE
|
||||||
|
*/#sidebar{position:absolute;top:0;left:0;bottom:0;width:250px;padding:0;margin:0;overflow:auto}#page-container{position:absolute;top:0;left:0;margin:0;padding:0;border:0}@media screen{#sidebar.opened+#page-container{left:250px}#page-container{bottom:0;right:0;overflow:auto}.loading-indicator{display:none}.loading-indicator.active{display:block;position:absolute;width:64px;height:64px;top:50%;left:50%;margin-top:-32px;margin-left:-32px}.loading-indicator img{position:absolute;top:0;left:0;bottom:0;right:0}}@media print{@page{margin:0}html{margin:0}body{margin:0;-webkit-print-color-adjust:exact}#sidebar{display:none}#page-container{width:auto;height:auto;overflow:visible;background-color:transparent}.d{display:none}}.pf{position:relative;background-color:white;overflow:hidden;margin:0;border:0}.pc{position:absolute;border:0;padding:0;margin:0;top:0;left:0;width:100%;height:100%;overflow:hidden;display:block;transform-origin:0 0;-ms-transform-origin:0 0;-webkit-transform-origin:0 0}.pc.opened{display:block}.bf{position:absolute;border:0;margin:0;top:0;bottom:0;width:100%;height:100%;-ms-user-select:none;-moz-user-select:none;-webkit-user-select:none;user-select:none}.bi{position:absolute;border:0;margin:0;-ms-user-select:none;-moz-user-select:none;-webkit-user-select:none;user-select:none}@media print{.pf{margin:0;box-shadow:none;page-break-after:always;page-break-inside:avoid}@-moz-document url-prefix(){.pf{overflow:visible;border:1px solid #fff}.pc{overflow:visible}}}.c{position:absolute;border:0;padding:0;margin:0;overflow:hidden;display:block}.t{position:absolute;white-space:pre;font-size:1px;transform-origin:0 100%;-ms-transform-origin:0 100%;-webkit-transform-origin:0 100%;unicode-bidi:bidi-override;-moz-font-feature-settings:"liga" 0}.t:after{content:''}.t:before{content:'';display:inline-block}.t span{position:relative;unicode-bidi:bidi-override}._{display:inline-block;color:transparent;z-index:-1}::selection{background:rgba(127,255,255,0.4)}::-moz-selection{background:rgba(127,255,255,0.4)}.pi{display:none}.d{position:absolute;transform-origin:0 100%;-ms-transform-origin:0 100%;-webkit-transform-origin:0 100%}.it{border:0;background-color:rgba(255,255,255,0.0)}.ir:hover{cursor:pointer}
|
BIN
content/resume/bg1.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
content/resume/bg2.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
content/resume/f1.woff
Normal file
BIN
content/resume/f2.woff
Normal file
BIN
content/resume/f3.woff
Normal file
BIN
content/resume/f4.woff
Normal file
BIN
content/resume/f5.woff
Normal file
5
content/resume/fancy.min.css
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/*!
|
||||||
|
* Fancy styles for pdf2htmlEX
|
||||||
|
* Copyright 2012,2013 Lu Wang <coolwanglu@gmail.com>
|
||||||
|
* https://github.com/pdf2htmlEX/pdf2htmlEX/blob/master/share/LICENSE
|
||||||
|
*/@keyframes fadein{from{opacity:0}to{opacity:1}}@-webkit-keyframes fadein{from{opacity:0}to{opacity:1}}@keyframes swing{0{transform:rotate(0)}10%{transform:rotate(0)}90%{transform:rotate(720deg)}100%{transform:rotate(720deg)}}@-webkit-keyframes swing{0{-webkit-transform:rotate(0)}10%{-webkit-transform:rotate(0)}90%{-webkit-transform:rotate(720deg)}100%{-webkit-transform:rotate(720deg)}}@media screen{#sidebar{background-color:#2f3236;background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0IiBoZWlnaHQ9IjQiPgo8cmVjdCB3aWR0aD0iNCIgaGVpZ2h0PSI0IiBmaWxsPSIjNDAzYzNmIj48L3JlY3Q+CjxwYXRoIGQ9Ik0wIDBMNCA0Wk00IDBMMCA0WiIgc3Ryb2tlLXdpZHRoPSIxIiBzdHJva2U9IiMxZTI5MmQiPjwvcGF0aD4KPC9zdmc+")}#outline{font-family:Georgia,Times,"Times New Roman",serif;font-size:13px;margin:2em 1em}#outline ul{padding:0}#outline li{list-style-type:none;margin:1em 0}#outline li>ul{margin-left:1em}#outline a,#outline a:visited,#outline a:hover,#outline a:active{line-height:1.2;color:#e8e8e8;text-overflow:ellipsis;white-space:nowrap;text-decoration:none;display:block;overflow:hidden;outline:0}#outline a:hover{color:#0cf}#page-container{background-color:#9e9e9e;background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1IiBoZWlnaHQ9IjUiPgo8cmVjdCB3aWR0aD0iNSIgaGVpZ2h0PSI1IiBmaWxsPSIjOWU5ZTllIj48L3JlY3Q+CjxwYXRoIGQ9Ik0wIDVMNSAwWk02IDRMNCA2Wk0tMSAxTDEgLTFaIiBzdHJva2U9IiM4ODgiIHN0cm9rZS13aWR0aD0iMSI+PC9wYXRoPgo8L3N2Zz4=");-webkit-transition:left 500ms;transition:left 500ms}.pf{margin:13px auto;box-shadow:1px 1px 3px 1px #333;border-collapse:separate}.pc.opened{-webkit-animation:fadein 100ms;animation:fadein 100ms}.loading-indicator.active{-webkit-animation:swing 1.5s ease-in-out .01s infinite alternate none;animation:swing 1.5s ease-in-out .01s infinite alternate none}.checked{background:no-repeat url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3goQDSYgDiGofgAAAslJREFUOMvtlM9LFGEYx7/vvOPM6ywuuyPFihWFBUsdNnA6KLIh+QPx4KWExULdHQ/9A9EfUodYmATDYg/iRewQzklFWxcEBcGgEplDkDtI6sw4PzrIbrOuedBb9MALD7zv+3m+z4/3Bf7bZS2bzQIAcrmcMDExcTeXy10DAFVVAQDksgFUVZ1ljD3yfd+0LOuFpmnvVVW9GHhkZAQcxwkNDQ2FSCQyRMgJxnVdy7KstKZpn7nwha6urqqfTqfPBAJAuVymlNLXoigOhfd5nmeiKL5TVTV+lmIKwAOA7u5u6Lped2BsbOwjY6yf4zgQQkAIAcedaPR9H67r3uYBQFEUFItFtLe332lpaVkUBOHK3t5eRtf1DwAwODiIubk5DA8PM8bYW1EU+wEgCIJqsCAIQAiB7/u253k2BQDDMJBKpa4mEon5eDx+UxAESJL0uK2t7XosFlvSdf0QAEmlUnlRFJ9Waho2Qghc1/U9z3uWz+eX+Wr+lL6SZfleEAQIggA8z6OpqSknimIvYyybSCReMsZ6TislhCAIAti2Dc/zejVNWwCAavN8339j27YbTg0AGGM3WltbP4WhlRWq6Q/btrs1TVsYHx+vNgqKoqBUKn2NRqPFxsbGJzzP05puUlpt0ukyOI6z7zjOwNTU1OLo6CgmJyf/gA3DgKIoWF1d/cIY24/FYgOU0pp0z/Ityzo8Pj5OTk9PbwHA+vp6zWghDC+VSiuRSOQgGo32UErJ38CO42wdHR09LBQK3zKZDDY2NupmFmF4R0cHVlZWlmRZ/iVJUn9FeWWcCCE4ODjYtG27Z2Zm5juAOmgdGAB2d3cBADs7O8uSJN2SZfl+WKlpmpumaT6Yn58vn/fs6XmbhmHMNjc3tzDGFI7jYJrm5vb29sDa2trPC/9aiqJUy5pOp4f6+vqeJ5PJBAB0dnZe/t8NBajx/z37Df5OGX8d13xzAAAAAElFTkSuQmCC)}}
|
8
content/resume/index.md
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
title: Resume
|
||||||
|
---
|
||||||
|
|
||||||
|
To view a web-friendly version of my resume, [click here](/resume/resume.html).
|
||||||
|
You can also [download the PDF](/resume/resume.pdf) (~80 KB) if you wish to
|
||||||
|
print it or attach it to an email. If you think we'd work well together, don't
|
||||||
|
hesitate to reach out at [daniel@ficd.ca](mailto:daniel@ficd.ca).
|
BIN
content/resume/pdf2htmlEX-64x64.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
347
content/resume/resume.css
Normal file
|
@ -0,0 +1,347 @@
|
||||||
|
.ff0{font-family:sans-serif;visibility:hidden;}
|
||||||
|
@font-face{font-family:ff1;src:url(f1.woff)format("woff");}.ff1{font-family:ff1;line-height:0.958008;font-style:normal;font-weight:normal;visibility:visible;}
|
||||||
|
@font-face{font-family:ff2;src:url(f2.woff)format("woff");}.ff2{font-family:ff2;line-height:0.945803;font-style:normal;font-weight:normal;visibility:visible;}
|
||||||
|
@font-face{font-family:ff3;src:url(f3.woff)format("woff");}.ff3{font-family:ff3;line-height:0.973633;font-style:normal;font-weight:normal;visibility:visible;}
|
||||||
|
@font-face{font-family:ff4;src:url(f4.woff)format("woff");}.ff4{font-family:ff4;line-height:0.937988;font-style:normal;font-weight:normal;visibility:visible;}
|
||||||
|
@font-face{font-family:ff5;src:url(f5.woff)format("woff");}.ff5{font-family:ff5;line-height:0.941895;font-style:normal;font-weight:normal;visibility:visible;}
|
||||||
|
.m0{transform:matrix(0.250000,0.000000,0.000000,0.250000,0,0);-ms-transform:matrix(0.250000,0.000000,0.000000,0.250000,0,0);-webkit-transform:matrix(0.250000,0.000000,0.000000,0.250000,0,0);}
|
||||||
|
.m1{transform:none;-ms-transform:none;-webkit-transform:none;}
|
||||||
|
.v0{vertical-align:0.000000px;}
|
||||||
|
.ls0{letter-spacing:0.000000px;}
|
||||||
|
.sc_{text-shadow:none;}
|
||||||
|
.sc0{text-shadow:-0.015em 0 transparent,0 0.015em transparent,0.015em 0 transparent,0 -0.015em transparent;}
|
||||||
|
@media screen and (-webkit-min-device-pixel-ratio:0){
|
||||||
|
.sc_{-webkit-text-stroke:0px transparent;}
|
||||||
|
.sc0{-webkit-text-stroke:0.015em transparent;text-shadow:none;}
|
||||||
|
}
|
||||||
|
.ws0{word-spacing:0.000000px;}
|
||||||
|
._1{margin-left:-3.164143px;}
|
||||||
|
._2{margin-left:-1.093743px;}
|
||||||
|
._3{width:1.035237px;}
|
||||||
|
._5{width:2.084393px;}
|
||||||
|
._16{width:3.091310px;}
|
||||||
|
._c{width:4.094727px;}
|
||||||
|
._d{width:5.463163px;}
|
||||||
|
._f{width:6.611395px;}
|
||||||
|
._10{width:7.789029px;}
|
||||||
|
._15{width:8.844050px;}
|
||||||
|
._8{width:11.640759px;}
|
||||||
|
._11{width:12.695113px;}
|
||||||
|
._a{width:13.839259px;}
|
||||||
|
._9{width:14.972071px;}
|
||||||
|
._4{width:19.999998px;}
|
||||||
|
._b{width:21.021172px;}
|
||||||
|
._14{width:40.000012px;}
|
||||||
|
._0{width:80.000020px;}
|
||||||
|
._6{width:91.394950px;}
|
||||||
|
._12{width:324.762547px;}
|
||||||
|
._e{width:470.641549px;}
|
||||||
|
._7{width:604.840850px;}
|
||||||
|
._13{width:695.934487px;}
|
||||||
|
.fc0{color:rgb(0,0,0);}
|
||||||
|
.fs5{font-size:32.000000px;}
|
||||||
|
.fs1{font-size:36.000000px;}
|
||||||
|
.fs2{font-size:40.000000px;}
|
||||||
|
.fs4{font-size:48.000000px;}
|
||||||
|
.fs3{font-size:56.000000px;}
|
||||||
|
.fs0{font-size:70.000000px;}
|
||||||
|
.y0{bottom:-0.500000px;}
|
||||||
|
.y38{bottom:42.201544px;}
|
||||||
|
.y37{bottom:55.283575px;}
|
||||||
|
.y36{bottom:68.365606px;}
|
||||||
|
.y35{bottom:81.447638px;}
|
||||||
|
.y6a{bottom:85.885720px;}
|
||||||
|
.y34{bottom:94.529669px;}
|
||||||
|
.y69{bottom:98.967750px;}
|
||||||
|
.y68{bottom:112.049780px;}
|
||||||
|
.y33{bottom:113.111700px;}
|
||||||
|
.y67{bottom:125.131810px;}
|
||||||
|
.y32{bottom:131.561920px;}
|
||||||
|
.y66{bottom:138.213844px;}
|
||||||
|
.y31{bottom:144.643950px;}
|
||||||
|
.y65{bottom:151.295875px;}
|
||||||
|
.y30{bottom:157.725980px;}
|
||||||
|
.y64{bottom:164.377906px;}
|
||||||
|
.y2f{bottom:170.808014px;}
|
||||||
|
.y63{bottom:177.459938px;}
|
||||||
|
.y2e{bottom:183.890045px;}
|
||||||
|
.y62{bottom:190.541969px;}
|
||||||
|
.y2d{bottom:196.972076px;}
|
||||||
|
.y2c{bottom:210.054108px;}
|
||||||
|
.y61{bottom:212.624000px;}
|
||||||
|
.y2b{bottom:223.136139px;}
|
||||||
|
.y60{bottom:239.654275px;}
|
||||||
|
.y2a{bottom:241.718170px;}
|
||||||
|
.y5f{bottom:252.736306px;}
|
||||||
|
.y29{bottom:260.168360px;}
|
||||||
|
.y5e{bottom:265.818338px;}
|
||||||
|
.y28{bottom:273.250394px;}
|
||||||
|
.y5d{bottom:278.900369px;}
|
||||||
|
.y27{bottom:286.332425px;}
|
||||||
|
.y5c{bottom:297.614200px;}
|
||||||
|
.y26{bottom:299.414456px;}
|
||||||
|
.y25{bottom:312.496488px;}
|
||||||
|
.y5b{bottom:316.064426px;}
|
||||||
|
.y24{bottom:325.578519px;}
|
||||||
|
.y5a{bottom:329.146458px;}
|
||||||
|
.y59{bottom:342.228489px;}
|
||||||
|
.y23{bottom:344.160550px;}
|
||||||
|
.y58{bottom:362.310520px;}
|
||||||
|
.y57{bottom:364.360320px;}
|
||||||
|
.y22{bottom:366.110750px;}
|
||||||
|
.y56{bottom:382.810515px;}
|
||||||
|
.y21{bottom:393.141020px;}
|
||||||
|
.y55{bottom:395.892546px;}
|
||||||
|
.y54{bottom:408.974578px;}
|
||||||
|
.y20{bottom:411.723050px;}
|
||||||
|
.y1e{bottom:411.986720px;}
|
||||||
|
.y53{bottom:422.056609px;}
|
||||||
|
.y1f{bottom:424.805080px;}
|
||||||
|
.y1d{bottom:424.936920px;}
|
||||||
|
.y52{bottom:442.138640px;}
|
||||||
|
.y1c{bottom:443.387118px;}
|
||||||
|
.y51{bottom:444.188450px;}
|
||||||
|
.y1b{bottom:456.469149px;}
|
||||||
|
.y50{bottom:462.538630px;}
|
||||||
|
.y1a{bottom:475.051180px;}
|
||||||
|
.y18{bottom:475.314850px;}
|
||||||
|
.y4f{bottom:484.678858px;}
|
||||||
|
.y19{bottom:488.133200px;}
|
||||||
|
.y17{bottom:488.265040px;}
|
||||||
|
.y4e{bottom:497.760889px;}
|
||||||
|
.y16{bottom:506.715236px;}
|
||||||
|
.y4d{bottom:517.842920px;}
|
||||||
|
.y15{bottom:519.797268px;}
|
||||||
|
.y4c{bottom:519.892730px;}
|
||||||
|
.y14{bottom:532.879299px;}
|
||||||
|
.y4b{bottom:538.342926px;}
|
||||||
|
.y4a{bottom:551.424958px;}
|
||||||
|
.y13{bottom:551.461330px;}
|
||||||
|
.y11{bottom:551.725000px;}
|
||||||
|
.y49{bottom:564.506989px;}
|
||||||
|
.y12{bottom:564.543360px;}
|
||||||
|
.y10{bottom:564.675200px;}
|
||||||
|
.y48{bottom:584.589020px;}
|
||||||
|
.yf{bottom:586.625400px;}
|
||||||
|
.y47{bottom:586.638820px;}
|
||||||
|
.y46{bottom:605.089024px;}
|
||||||
|
.ye{bottom:613.655670px;}
|
||||||
|
.y45{bottom:618.171055px;}
|
||||||
|
.y44{bottom:631.253086px;}
|
||||||
|
.yd{bottom:632.237700px;}
|
||||||
|
.yb{bottom:632.501370px;}
|
||||||
|
.y43{bottom:644.335118px;}
|
||||||
|
.yc{bottom:645.319730px;}
|
||||||
|
.ya{bottom:645.451570px;}
|
||||||
|
.y42{bottom:657.417149px;}
|
||||||
|
.y9{bottom:663.901760px;}
|
||||||
|
.y41{bottom:677.499180px;}
|
||||||
|
.y40{bottom:679.548980px;}
|
||||||
|
.y8{bottom:682.483800px;}
|
||||||
|
.y6{bottom:682.747470px;}
|
||||||
|
.y7{bottom:695.565830px;}
|
||||||
|
.y5{bottom:695.697660px;}
|
||||||
|
.y3f{bottom:701.499180px;}
|
||||||
|
.y4{bottom:717.647860px;}
|
||||||
|
.y3e{bottom:728.529449px;}
|
||||||
|
.y3d{bottom:741.611480px;}
|
||||||
|
.y3{bottom:751.178130px;}
|
||||||
|
.y3c{bottom:754.693511px;}
|
||||||
|
.y3b{bottom:767.775543px;}
|
||||||
|
.y2{bottom:776.678132px;}
|
||||||
|
.y3a{bottom:780.857574px;}
|
||||||
|
.y1{bottom:794.601958px;}
|
||||||
|
.y39{bottom:799.439605px;}
|
||||||
|
.h3{height:26.490234px;}
|
||||||
|
.h7{height:28.320312px;}
|
||||||
|
.h6{height:28.808594px;}
|
||||||
|
.h4{height:29.433594px;}
|
||||||
|
.h8{height:34.570312px;}
|
||||||
|
.h5{height:40.332031px;}
|
||||||
|
.h2{height:50.415039px;}
|
||||||
|
.h0{height:841.889800px;}
|
||||||
|
.h1{height:842.500000px;}
|
||||||
|
.w0{width:595.275600px;}
|
||||||
|
.w1{width:596.000000px;}
|
||||||
|
.x0{left:0.000000px;}
|
||||||
|
.x4{left:36.000000px;}
|
||||||
|
.x9{left:44.505859px;}
|
||||||
|
.x3{left:145.235450px;}
|
||||||
|
.x2{left:152.884140px;}
|
||||||
|
.x1{left:228.385480px;}
|
||||||
|
.x8{left:302.637800px;}
|
||||||
|
.xa{left:311.143650px;}
|
||||||
|
.xe{left:373.714070px;}
|
||||||
|
.xb{left:407.571500px;}
|
||||||
|
.x7{left:437.849820px;}
|
||||||
|
.x6{left:484.622280px;}
|
||||||
|
.x5{left:503.562700px;}
|
||||||
|
.xc{left:512.888880px;}
|
||||||
|
.xd{left:514.436740px;}
|
||||||
|
@media print{
|
||||||
|
.v0{vertical-align:0.000000pt;}
|
||||||
|
.ls0{letter-spacing:0.000000pt;}
|
||||||
|
.ws0{word-spacing:0.000000pt;}
|
||||||
|
._1{margin-left:-4.218858pt;}
|
||||||
|
._2{margin-left:-1.458324pt;}
|
||||||
|
._3{width:1.380316pt;}
|
||||||
|
._5{width:2.779191pt;}
|
||||||
|
._16{width:4.121747pt;}
|
||||||
|
._c{width:5.459635pt;}
|
||||||
|
._d{width:7.284217pt;}
|
||||||
|
._f{width:8.815193pt;}
|
||||||
|
._10{width:10.385372pt;}
|
||||||
|
._15{width:11.792067pt;}
|
||||||
|
._8{width:15.521012pt;}
|
||||||
|
._11{width:16.926817pt;}
|
||||||
|
._a{width:18.452345pt;}
|
||||||
|
._9{width:19.962762pt;}
|
||||||
|
._4{width:26.666665pt;}
|
||||||
|
._b{width:28.028229pt;}
|
||||||
|
._14{width:53.333349pt;}
|
||||||
|
._0{width:106.666693pt;}
|
||||||
|
._6{width:121.859933pt;}
|
||||||
|
._12{width:433.016729pt;}
|
||||||
|
._e{width:627.522065pt;}
|
||||||
|
._7{width:806.454467pt;}
|
||||||
|
._13{width:927.912649pt;}
|
||||||
|
.fs5{font-size:42.666667pt;}
|
||||||
|
.fs1{font-size:48.000000pt;}
|
||||||
|
.fs2{font-size:53.333333pt;}
|
||||||
|
.fs4{font-size:64.000000pt;}
|
||||||
|
.fs3{font-size:74.666667pt;}
|
||||||
|
.fs0{font-size:93.333333pt;}
|
||||||
|
.y0{bottom:-0.666667pt;}
|
||||||
|
.y38{bottom:56.268725pt;}
|
||||||
|
.y37{bottom:73.711433pt;}
|
||||||
|
.y36{bottom:91.154141pt;}
|
||||||
|
.y35{bottom:108.596851pt;}
|
||||||
|
.y6a{bottom:114.514293pt;}
|
||||||
|
.y34{bottom:126.039558pt;}
|
||||||
|
.y69{bottom:131.957000pt;}
|
||||||
|
.y68{bottom:149.399707pt;}
|
||||||
|
.y33{bottom:150.815600pt;}
|
||||||
|
.y67{bottom:166.842413pt;}
|
||||||
|
.y32{bottom:175.415893pt;}
|
||||||
|
.y66{bottom:184.285125pt;}
|
||||||
|
.y31{bottom:192.858600pt;}
|
||||||
|
.y65{bottom:201.727833pt;}
|
||||||
|
.y30{bottom:210.301307pt;}
|
||||||
|
.y64{bottom:219.170541pt;}
|
||||||
|
.y2f{bottom:227.744019pt;}
|
||||||
|
.y63{bottom:236.613251pt;}
|
||||||
|
.y2e{bottom:245.186727pt;}
|
||||||
|
.y62{bottom:254.055958pt;}
|
||||||
|
.y2d{bottom:262.629435pt;}
|
||||||
|
.y2c{bottom:280.072144pt;}
|
||||||
|
.y61{bottom:283.498667pt;}
|
||||||
|
.y2b{bottom:297.514852pt;}
|
||||||
|
.y60{bottom:319.539033pt;}
|
||||||
|
.y2a{bottom:322.290893pt;}
|
||||||
|
.y5f{bottom:336.981741pt;}
|
||||||
|
.y29{bottom:346.891147pt;}
|
||||||
|
.y5e{bottom:354.424451pt;}
|
||||||
|
.y28{bottom:364.333859pt;}
|
||||||
|
.y5d{bottom:371.867158pt;}
|
||||||
|
.y27{bottom:381.776567pt;}
|
||||||
|
.y5c{bottom:396.818933pt;}
|
||||||
|
.y26{bottom:399.219275pt;}
|
||||||
|
.y25{bottom:416.661984pt;}
|
||||||
|
.y5b{bottom:421.419235pt;}
|
||||||
|
.y24{bottom:434.104692pt;}
|
||||||
|
.y5a{bottom:438.861944pt;}
|
||||||
|
.y59{bottom:456.304652pt;}
|
||||||
|
.y23{bottom:458.880733pt;}
|
||||||
|
.y58{bottom:483.080693pt;}
|
||||||
|
.y57{bottom:485.813760pt;}
|
||||||
|
.y22{bottom:488.147667pt;}
|
||||||
|
.y56{bottom:510.414020pt;}
|
||||||
|
.y21{bottom:524.188027pt;}
|
||||||
|
.y55{bottom:527.856728pt;}
|
||||||
|
.y54{bottom:545.299437pt;}
|
||||||
|
.y20{bottom:548.964067pt;}
|
||||||
|
.y1e{bottom:549.315627pt;}
|
||||||
|
.y53{bottom:562.742145pt;}
|
||||||
|
.y1f{bottom:566.406773pt;}
|
||||||
|
.y1d{bottom:566.582560pt;}
|
||||||
|
.y52{bottom:589.518187pt;}
|
||||||
|
.y1c{bottom:591.182824pt;}
|
||||||
|
.y51{bottom:592.251267pt;}
|
||||||
|
.y1b{bottom:608.625532pt;}
|
||||||
|
.y50{bottom:616.718173pt;}
|
||||||
|
.y1a{bottom:633.401573pt;}
|
||||||
|
.y18{bottom:633.753133pt;}
|
||||||
|
.y4f{bottom:646.238477pt;}
|
||||||
|
.y19{bottom:650.844267pt;}
|
||||||
|
.y17{bottom:651.020053pt;}
|
||||||
|
.y4e{bottom:663.681185pt;}
|
||||||
|
.y16{bottom:675.620315pt;}
|
||||||
|
.y4d{bottom:690.457227pt;}
|
||||||
|
.y15{bottom:693.063024pt;}
|
||||||
|
.y4c{bottom:693.190307pt;}
|
||||||
|
.y14{bottom:710.505732pt;}
|
||||||
|
.y4b{bottom:717.790568pt;}
|
||||||
|
.y4a{bottom:735.233277pt;}
|
||||||
|
.y13{bottom:735.281773pt;}
|
||||||
|
.y11{bottom:735.633333pt;}
|
||||||
|
.y49{bottom:752.675985pt;}
|
||||||
|
.y12{bottom:752.724480pt;}
|
||||||
|
.y10{bottom:752.900267pt;}
|
||||||
|
.y48{bottom:779.452027pt;}
|
||||||
|
.yf{bottom:782.167200pt;}
|
||||||
|
.y47{bottom:782.185093pt;}
|
||||||
|
.y46{bottom:806.785365pt;}
|
||||||
|
.ye{bottom:818.207560pt;}
|
||||||
|
.y45{bottom:824.228073pt;}
|
||||||
|
.y44{bottom:841.670781pt;}
|
||||||
|
.yd{bottom:842.983600pt;}
|
||||||
|
.yb{bottom:843.335160pt;}
|
||||||
|
.y43{bottom:859.113491pt;}
|
||||||
|
.yc{bottom:860.426307pt;}
|
||||||
|
.ya{bottom:860.602093pt;}
|
||||||
|
.y42{bottom:876.556198pt;}
|
||||||
|
.y9{bottom:885.202347pt;}
|
||||||
|
.y41{bottom:903.332240pt;}
|
||||||
|
.y40{bottom:906.065307pt;}
|
||||||
|
.y8{bottom:909.978400pt;}
|
||||||
|
.y6{bottom:910.329960pt;}
|
||||||
|
.y7{bottom:927.421107pt;}
|
||||||
|
.y5{bottom:927.596880pt;}
|
||||||
|
.y3f{bottom:935.332240pt;}
|
||||||
|
.y4{bottom:956.863813pt;}
|
||||||
|
.y3e{bottom:971.372599pt;}
|
||||||
|
.y3d{bottom:988.815307pt;}
|
||||||
|
.y3{bottom:1001.570840pt;}
|
||||||
|
.y3c{bottom:1006.258015pt;}
|
||||||
|
.y3b{bottom:1023.700724pt;}
|
||||||
|
.y2{bottom:1035.570843pt;}
|
||||||
|
.y3a{bottom:1041.143432pt;}
|
||||||
|
.y1{bottom:1059.469277pt;}
|
||||||
|
.y39{bottom:1065.919473pt;}
|
||||||
|
.h3{height:35.320312pt;}
|
||||||
|
.h7{height:37.760417pt;}
|
||||||
|
.h6{height:38.411458pt;}
|
||||||
|
.h4{height:39.244792pt;}
|
||||||
|
.h8{height:46.093750pt;}
|
||||||
|
.h5{height:53.776042pt;}
|
||||||
|
.h2{height:67.220052pt;}
|
||||||
|
.h0{height:1122.519733pt;}
|
||||||
|
.h1{height:1123.333333pt;}
|
||||||
|
.w0{width:793.700800pt;}
|
||||||
|
.w1{width:794.666667pt;}
|
||||||
|
.x0{left:0.000000pt;}
|
||||||
|
.x4{left:48.000000pt;}
|
||||||
|
.x9{left:59.341145pt;}
|
||||||
|
.x3{left:193.647267pt;}
|
||||||
|
.x2{left:203.845520pt;}
|
||||||
|
.x1{left:304.513973pt;}
|
||||||
|
.x8{left:403.517067pt;}
|
||||||
|
.xa{left:414.858200pt;}
|
||||||
|
.xe{left:498.285427pt;}
|
||||||
|
.xb{left:543.428667pt;}
|
||||||
|
.x7{left:583.799760pt;}
|
||||||
|
.x6{left:646.163040pt;}
|
||||||
|
.x5{left:671.416933pt;}
|
||||||
|
.xc{left:683.851840pt;}
|
||||||
|
.xd{left:685.915653pt;}
|
||||||
|
}
|
69
content/resume/resume.html
Normal file
1
content/resume/resume.outline
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<ul><li><a class="l" href="#pf1" data-dest-detail='[1,"XYZ",36,736.678,null]'>Education</a></li><li><a class="l" href="#pf1" data-dest-detail='[1,"XYZ",36,605.656,null]'>Employment</a></li><li><a class="l" href="#pf1" data-dest-detail='[1,"XYZ",36,385.141,null]'>Research Work</a></li><li><a class="l" href="#pf2" data-dest-detail='[2,"XYZ",36,720.529,null]'>Selected Projects</a><ul><li><a class="l" href="#pf2" data-dest-detail='[2,"XYZ",36,480.279,null]'>Tooling & Contributions</a></li></ul></li><li><a class="l" href="#pf2" data-dest-detail='[2,"XYZ",36,231.654,null]'>Skills</a></li></ul>
|
BIN
content/resume/resume.pdf
Normal file
BIN
content/static/images/ashen_preview.png
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
content/static/images/datacenter2-d.jpg
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
content/static/images/dithered_ficd.jpg
Normal file
After Width: | Height: | Size: 73 KiB |
BIN
content/static/images/email_1.png
Normal file
After Width: | Height: | Size: 85 KiB |
BIN
content/static/images/email_2.png
Normal file
After Width: | Height: | Size: 89 KiB |
BIN
content/static/images/favicon.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
content/static/images/gh_about.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
content/static/images/h_self2.jpg
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
content/static/images/hrgiger.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
content/static/images/mush.png
Normal file
After Width: | Height: | Size: 15 KiB |
236
content/static/style.css
Normal file
|
@ -0,0 +1,236 @@
|
||||||
|
:root {
|
||||||
|
--main-text-color: #b4b4b4;
|
||||||
|
--main-bg-color: #121212;
|
||||||
|
--main-link-color: #df6464;
|
||||||
|
--main-heading-color: #df6464;
|
||||||
|
--main-bullet-color: #d87c4a;
|
||||||
|
--main-transparent: rgba(255, 255, 255, 0.15);
|
||||||
|
--main-small-text-color: rgba(255, 255, 255, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
line-height: 1.6;
|
||||||
|
font-size: 18px;
|
||||||
|
font-family: sans-serif;
|
||||||
|
background: var(--main-bg-color);
|
||||||
|
color: var(--main-text-color);
|
||||||
|
padding-left: calc(100vw - 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* h1, */
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
|
color: var(--main-heading-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin-block-start: 0.67rem;
|
||||||
|
margin-block-end: 0.67rem;
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
article h1:first-of-type {
|
||||||
|
margin-block-start: 1.67rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin-block-start: 0.83rem;
|
||||||
|
margin-block-end: 0.83rem;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin-block-start: 1rem;
|
||||||
|
margin-block-end: 1rem;
|
||||||
|
font-size: 1.17em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
margin-block-start: 1.33rem;
|
||||||
|
margin-block-end: 1.33rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
article h1+h4:first-of-type {
|
||||||
|
margin-block-start: 0rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h5 {
|
||||||
|
margin-block-start: 1.67rem;
|
||||||
|
margin-block-end: 1.67rem;
|
||||||
|
font-size: 0.83rem;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
h6 {
|
||||||
|
margin-block-start: 2.33rem;
|
||||||
|
margin-block-end: 2.33rem;
|
||||||
|
font-size: 0.67rem;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style-type: disc;
|
||||||
|
/* or any other list style */
|
||||||
|
}
|
||||||
|
|
||||||
|
li::marker {
|
||||||
|
color: var(--main-bullet-color);
|
||||||
|
/* Change this to your desired color */
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--main-link-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
background: var(--main-transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
display: block;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
color: var(--main-small-text-color);
|
||||||
|
border-left: 3px solid var(--main-transparent);
|
||||||
|
padding: 0 1rem;
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border: none;
|
||||||
|
height: 1px;
|
||||||
|
background: var(--main-small-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
background: var(--main-transparent);
|
||||||
|
border-radius: 0.1875rem;
|
||||||
|
/* padding: .0625rem .1875rem; */
|
||||||
|
/* margin: 0 .1875rem; */
|
||||||
|
}
|
||||||
|
|
||||||
|
code,
|
||||||
|
pre {
|
||||||
|
white-space: pre;
|
||||||
|
word-wrap: break-word;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
font-family: 'Fira Code', 'Consolas', 'Courier New', monospace;
|
||||||
|
font-size: 0.95em;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
background-color: #1d1d1d;
|
||||||
|
color: #d5d5d5;
|
||||||
|
padding: 1em;
|
||||||
|
border-radius: 5px;
|
||||||
|
line-height: 1.5;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
background-color: #1d1d1d;
|
||||||
|
color: #d5d5d5;
|
||||||
|
padding: 0.2em 0.4em;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
small {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: var(--main-small-text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
small a {
|
||||||
|
color: inherit;
|
||||||
|
/* Inherit the color of the surrounding <small> text */
|
||||||
|
text-decoration: underline;
|
||||||
|
/* Optional: Keep the underline to indicate a link */
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-container h1 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-container {
|
||||||
|
text-align: center;
|
||||||
|
margin: 20px 0;
|
||||||
|
/* Optional: add some spacing around the image container */
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-container img {
|
||||||
|
/* max-width: 308px; */
|
||||||
|
max-height: 308px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-container small {
|
||||||
|
display: block;
|
||||||
|
/* Ensure the caption is on a new line */
|
||||||
|
margin-top: 5px;
|
||||||
|
/* Optional: adjust spacing between image and caption */
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-container small a {
|
||||||
|
color: inherit;
|
||||||
|
/* Ensure the link color matches the small text */
|
||||||
|
text-decoration: underline;
|
||||||
|
/* Optional: underline to indicate a link */
|
||||||
|
}
|
||||||
|
|
||||||
|
#header ul {
|
||||||
|
list-style-type: none;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header li {
|
||||||
|
display: inline;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
margin-right: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#container {
|
||||||
|
margin: 2.5rem auto;
|
||||||
|
width: 90%;
|
||||||
|
max-width: 60ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
#postlistdiv ul {
|
||||||
|
list-style-type: none;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.moreposts {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
padding-left: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nextprev {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 1.4rem;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#footer {
|
||||||
|
color: var(--main-small-text-color);
|
||||||
|
}
|
||||||
|
|
34
templates/base.html
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>{{ metadata.title }}</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link
|
||||||
|
href="{{ metadata.style }}"
|
||||||
|
rel="stylesheet"
|
||||||
|
type="text/css"
|
||||||
|
media="all"
|
||||||
|
/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="container">
|
||||||
|
{% if header %}
|
||||||
|
<header id="header">
|
||||||
|
<center>
|
||||||
|
{{ header | safe }}
|
||||||
|
</center>
|
||||||
|
<hr>
|
||||||
|
</header>
|
||||||
|
{% endif %}
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
{% if footer %}
|
||||||
|
<footer id="footer">
|
||||||
|
<hr>
|
||||||
|
{{ footer | safe }}
|
||||||
|
</footer>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
6
templates/basic.html
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{{ content | safe }}
|
||||||
|
{% endblock %}
|
||||||
|
|
5
templates/footer.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
All posted code written by me is licensed under [MIT](/LICENSE), and all other
|
||||||
|
original written work is licensed under
|
||||||
|
[CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0). This
|
||||||
|
website is [open source](https://git.sr.ht/~ficd/blog), built with
|
||||||
|
[zona](https://sr.ht/~ficd/zona), and hosted on [sr.ht](https://sr.ht/).
|
5
templates/header.html
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<ul>
|
||||||
|
{% for name, url in site_map.items() %}
|
||||||
|
<li><a href="{{ url }}">{{ name }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
10
templates/page.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<center><h1>{{ metadata.title }}</h1></center>
|
||||||
|
{% if metadata.date %}
|
||||||
|
<center><small><time datetime="{{ metadata.date | safe }}">{{ metadata.date | safe}}</time></small></center>
|
||||||
|
{% endif %}
|
||||||
|
<article>{{ content | safe }}</article>
|
||||||
|
{% endblock %}
|
||||||
|
|
18
templates/post_list.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<center><h1>{{ metadata.title }}</h1></center>
|
||||||
|
|
||||||
|
<article>{{ content | safe }}</article>
|
||||||
|
|
||||||
|
{% if post_list %}
|
||||||
|
<ul>
|
||||||
|
{% for item in post_list %}
|
||||||
|
<li><small><time datetime="{{ metadata.date | safe }}">{{ metadata.date | safe}}</time></small>: <a href="/{{ item.url }}">{{ item.metadata.title }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|