init
This commit is contained in:
commit
c4dae0f4bb
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "themes/no-js-hugo-theme"]
|
||||
path = themes/no-js-hugo-theme
|
||||
url = https://github.com/stevenengler/no-js-hugo-theme.git
|
6
archetypes/default.md
Normal file
6
archetypes/default.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
title: "{{ replace .Name "-" " " | title }}"
|
||||
date: {{ .Date }}
|
||||
draft: true
|
||||
---
|
||||
|
37
config.toml
Normal file
37
config.toml
Normal file
@ -0,0 +1,37 @@
|
||||
baseURL = "https://beckmeyer.us/"
|
||||
languageCode = 'en-us'
|
||||
title = "Joel Beckmeyer's Homepage"
|
||||
theme = "no-js-hugo-theme"
|
||||
|
||||
[author]
|
||||
name = "Joel Beckmeyer"
|
||||
email = "joel@beckmeyer.us"
|
||||
|
||||
[menu]
|
||||
[[menu.main]]
|
||||
name = "Git"
|
||||
identifier = "Gitea"
|
||||
url = "https://git.beckmeyer.us/TnSb"
|
||||
weight = 400
|
||||
[[menu.main]]
|
||||
name = "GitHub"
|
||||
identifier = "GitHub"
|
||||
url = "https://github.com/TinfoilSubmarine"
|
||||
weight = 500
|
||||
|
||||
[markup]
|
||||
[markup.highlight]
|
||||
codeFences = true
|
||||
noClasses = false
|
||||
|
||||
[markup.tableOfContents]
|
||||
startLevel = 1
|
||||
endLevel = 6
|
||||
|
||||
[params]
|
||||
# footer text at the bottom of every page
|
||||
footerText = "Have any questions? Let me know on [Matrix](https://matrix.to/#/@joel:thebeckmeyers.xyz), or start a discussion on [Fediverse](https://social.beckmeyer.us/TinfoilSubmarine)!"
|
||||
# enable the table of content on pages with more than this many words
|
||||
# (negative to disable)
|
||||
# (can be overridden per-page by setting the 'toc' front matter parameter)
|
||||
#tocWordThreshold = 1000 # default <unset>
|
12
content/_index.md
Normal file
12
content/_index.md
Normal file
@ -0,0 +1,12 @@
|
||||
---
|
||||
title: Home
|
||||
menu:
|
||||
main:
|
||||
weight: 100
|
||||
---
|
||||
|
||||
# Welcome!
|
||||
|
||||
You can find me on the [Fediverse](https://social.beckmeyer.us/TinfoilSubmarine) and [Matrix](https://matrix.to/#/@joel:thebeckmeyers.xyz).
|
||||
|
||||
[What is the Fediverse?](https://pleroma.social/blog/2021/01/13/the-big-pleroma-and-fediverse-faq/)
|
11
content/contact.md
Normal file
11
content/contact.md
Normal file
@ -0,0 +1,11 @@
|
||||
---
|
||||
title: Contact
|
||||
draft: false
|
||||
menu:
|
||||
main:
|
||||
weight: 200
|
||||
---
|
||||
|
||||
Joel Beckmeyer\
|
||||
Matrix: [@joel:thebeckmeyers.xyz](https://matrix.to/#/@joel:thebeckmeyers.xyz)\
|
||||
Fediverse: [@TinfoilSubmarine@social.beckmeyer.us](https://social.beckmeyer.us/TinfoilSubmarine)
|
6
content/posts/_index.md
Normal file
6
content/posts/_index.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
title: Blog
|
||||
menu:
|
||||
main:
|
||||
weight: 300
|
||||
---
|
35
content/posts/better.md
Normal file
35
content/posts/better.md
Normal file
@ -0,0 +1,35 @@
|
||||
---
|
||||
title: "Better?"
|
||||
tags: ["poetry"]
|
||||
date: 2021-04-03T22:15:44-04:00
|
||||
draft: false
|
||||
---
|
||||
There are many that say
|
||||
(and I tend to agree)
|
||||
that free software is the best there could be.
|
||||
|
||||
But please don't mistake
|
||||
using software that's free
|
||||
as a right to superiority.
|
||||
|
||||
There are many that go
|
||||
from day to day living
|
||||
and don't give a thought to what they are using.
|
||||
|
||||
Are they worse for this?
|
||||
Are you better for caring?
|
||||
Sometimes the truth can be quite baring.
|
||||
|
||||
That not every human
|
||||
in present circumstance
|
||||
is able or willing to take a chance.
|
||||
|
||||
'Cause that's what it is,
|
||||
taking a chance and going
|
||||
into the unknown with fear, and knowing
|
||||
|
||||
that what you might find,
|
||||
may not truly be better.
|
||||
|
||||
But instead simply different;
|
||||
and still made by a stranger.
|
33
content/posts/consistency.md
Normal file
33
content/posts/consistency.md
Normal file
@ -0,0 +1,33 @@
|
||||
---
|
||||
title: "Consistency"
|
||||
tags: ["FOSS"]
|
||||
date: 2021-04-04T00:00:00-05:00
|
||||
draft: false
|
||||
---
|
||||
I've seen a lot of talk about this stuff:
|
||||
|
||||
- "Check out my FOSS project (hosted on Github)"
|
||||
- "Wayland is a great innovation and boon to the community! Also, there are very few tools/alternatives available yet for your favorite X11 tool!"
|
||||
- "We love open source! Also, we develop the most popular proprietary operating system!"
|
||||
- "Do as I say, not as I do."
|
||||
|
||||
We love to poke fun at and expose this kind of stuff, which is all fine and
|
||||
dandy. I think it's an interesting (and important) part of our humanity that
|
||||
this kind of thing bugs us so much. Think about that last point, which at least
|
||||
in my experience, is something I *loved* to fault authorities for.
|
||||
|
||||
Hypocrisy is fun and also infuriating to uncover in others, but how often do
|
||||
we do a "consistency check" on ourselves? Is what we are saying evidenced by
|
||||
the rest of our actions?
|
||||
|
||||
That's a hard look sometimes. I know it is for me, since I'm **very** quick
|
||||
to judge others, but don't often think about how I fail at my own principles.
|
||||
|
||||
Example: As a FOSS advocate, it's nearly natural to assume that everything will
|
||||
be better and easier with more people using FOSS. When evidence seems to point
|
||||
to the contrary (e.g. fighting with Matrix/Element to get it working for my
|
||||
family and friends), I don't own up to the fact that it isn't easier, and that
|
||||
is an actual problem.
|
||||
|
||||
If we truly want to build a welcoming and wholesome community, let's be careful
|
||||
to do a consistency check to make sure nothing smells foul.
|
6
content/posts/disruptive_technologies.md
Normal file
6
content/posts/disruptive_technologies.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
title: "Disruptive Technologies"
|
||||
date: 2021-01-27T10:01:12-05:00
|
||||
draft: true
|
||||
---
|
||||
|
12
content/posts/federation.md
Normal file
12
content/posts/federation.md
Normal file
@ -0,0 +1,12 @@
|
||||
---
|
||||
title: "Federation"
|
||||
date: 2021-03-24T08:17:39-04:00
|
||||
draft: true
|
||||
---
|
||||
First, federation was non-existent. There was no need for federation with
|
||||
so few computers and no widespread network to support.
|
||||
|
||||
Then, federation was necessary. No one had the resources to run a centralized
|
||||
everything for all users. So we created a way to communicate between computers.
|
||||
|
||||
After that, federation was
|
138
content/posts/hello_doas.md
Normal file
138
content/posts/hello_doas.md
Normal file
@ -0,0 +1,138 @@
|
||||
---
|
||||
title: "Hello doas"
|
||||
tags: ["Linux"]
|
||||
date: 2021-01-30T15:15:55-05:00
|
||||
draft: false
|
||||
---
|
||||
Today, I switched my workstation from `sudo` to `doas`. I'm running Void Linux,
|
||||
and the process was fairly easy.
|
||||
|
||||
First, I needed to figure out how to remove `sudo` (yes, I realize I could have
|
||||
installed `doas` first, then removed `sudo`, but I decided to do it the hard way.)
|
||||
As it turns out, the [advanced usage section of the XBPS manual](https://docs.voidlinux.org/xbps/advanced-usage.html#ignoring-packages) details how to use the `ignorepkg` entry in xbps.d with nothing
|
||||
other than this exact use case! I created the file `/etc/xbps.d/20-ignorepkg-sudo.conf` with contents
|
||||
|
||||
```
|
||||
ignorepkg=sudo
|
||||
```
|
||||
|
||||
and then ran `sudo xbps-remove sudo` (an ironic command).
|
||||
|
||||
After that, because I was stupid and removed `sudo` before I had set up `doas`,
|
||||
I had to use plain-old `su` to change to the root user and run `xi opendoas`. I also
|
||||
configured `doas` in `/etc/doas.conf` with the following:
|
||||
|
||||
```
|
||||
# see doas.conf(5) for configuration details
|
||||
permit nopass keepenv :admin
|
||||
```
|
||||
|
||||
I ran `groupadd admin`, `usermod -aG admin joel`, and then logged out so that my
|
||||
user account would see the new group perms.
|
||||
|
||||
And just like that, I can now run `doas xbps-install ...` and all of my other commands,
|
||||
just substituting `doas` for `sudo`.
|
||||
|
||||
The one thing I immediately missed was `sudoedit`. Before I accidentally tried
|
||||
to use `sudo` for the first time, I had already accidentally tried to run `sudoedit`
|
||||
*at least* 5 times. I had to fix this. I saw a discussion on Reddit where [one user
|
||||
suggested](https://www.reddit.com/r/linux/comments/l6y7nv/is_doas_a_good_alternative_to_sudo/gl4hs42?utm_source=share&utm_medium=web2x&context=3) writing a script to replace the `sudoedit` functionality.
|
||||
I quickly starting hacking together something like that. I started with:
|
||||
|
||||
```
|
||||
#!/bin/sh
|
||||
mkdir -p /tmp/doasedit
|
||||
doas cp $1 /tmp/doasedit/tmp_file
|
||||
$EDITOR /tmp/doasedit/tmp_file
|
||||
```
|
||||
|
||||
And quickly ran into my first road-block. The script is going to have to change
|
||||
the permissions of that file before the user can edit it. But if the script changes
|
||||
the permissions, how can I restore it to the original location with the right
|
||||
permissions? `cp /tmp/doasedit/tmp_file $1` won't work. I thought about just using
|
||||
cat to overwrite the file contents in-place (`cat /tmp/doasedit/tmp_file > $1`).
|
||||
That *could* create some issues if a program has the file open. Instead, a better option
|
||||
is to create two copies of the file--one for editing, and one for preserving file
|
||||
attributes:
|
||||
|
||||
```
|
||||
#!/bin/sh
|
||||
mkdir -p /tmp/doasedit
|
||||
doas cp $1 /tmp/doasedit/edit
|
||||
doas chown -R $USER:$USER /tmp/doasedit/edit
|
||||
doas cp $1 /tmp/doasedit/file
|
||||
$EDITOR /tmp/doasedit/edit
|
||||
cat /tmp/doasedit/edit | doas tee /tmp/doasedit/file 1>/dev/null
|
||||
doas mv -f /tmp/doasedit/file $1
|
||||
rm -rf /tmp/doasedit
|
||||
```
|
||||
|
||||
Of course, the issue with this is that it only works with absolute paths.
|
||||
I want to make it work for relative paths as well. I'm going to take advantage
|
||||
of `realpath`, which is part of the `coreutils` package from Void. As a bonus, this
|
||||
will also take care of the edge case where the given file is a symlink (IIRC,
|
||||
`sudoedit` didn't follow symlinks, so I may be diverging here):
|
||||
|
||||
```
|
||||
#!/bin/sh
|
||||
mkdir -p /tmp/doasedit
|
||||
srcfile="$(realpath $1)"
|
||||
|
||||
doas cp $srcfile /tmp/doasedit/edit
|
||||
doas chown -R $USER:$USER /tmp/doasedit/edit
|
||||
doas cp $srcfile /tmp/doasedit/file
|
||||
|
||||
$EDITOR /tmp/doasedit/edit
|
||||
|
||||
cat /tmp/doasedit/edit | doas tee /tmp/doasedit/file 1>/dev/null
|
||||
doas mv -f /tmp/doasedit/file $srcfile
|
||||
|
||||
rm -rf /tmp/doasedit
|
||||
```
|
||||
|
||||
At this point, it works...okay-ish. It can only be used in one instance currently
|
||||
since I hard-coded `/tmp/doasedit/file` and `/tmp/doasedit/edit`, but that's easily fixed:
|
||||
|
||||
```
|
||||
#!/bin/sh
|
||||
|
||||
destfile_pfx="$(cat /dev/urandom | tr -cd 'a-f0-9' | head -c 32)"
|
||||
|
||||
while [ -d "/tmp/doasedit/$destfile_pfx" ]; do
|
||||
destfile_pfx="$(cat /dev/urandom | tr -cd 'a-f0-9' | head -c 32)"
|
||||
done
|
||||
|
||||
mkdir -p /tmp/doasedit/$destfile_pfx
|
||||
srcfile="$(realpath $1)"
|
||||
|
||||
doas cp $srcfile /tmp/doasedit/$destfile_pfx/edit
|
||||
doas chown -R $USER:$USER /tmp/doasedit/$destfile_pfx/edit
|
||||
doas cp $srcfile /tmp/doasedit/$destfile_pfx/file
|
||||
|
||||
$EDITOR /tmp/doasedit/$destfile_pfx/edit
|
||||
|
||||
cat /tmp/doasedit/$destfile_pfx/edit | doas tee /tmp/doasedit/$destfile_pfx/file 1>/dev/null
|
||||
doas mv -f /tmp/doasedit/$destfile_pfx/file $srcfile
|
||||
|
||||
rm -rf /tmp/doasedit/$destfile_pfx
|
||||
```
|
||||
|
||||
At this point, the only thing missing is the check to see if the file was actually
|
||||
edited:
|
||||
|
||||
```
|
||||
...
|
||||
cat /tmp/doasedit/$destfile_pfx/edit | doas tee /tmp/doasedit/$destfile_pfx/file 1>/dev/null
|
||||
|
||||
if cmp -s "/tmp/doasedit/$destfile_pfx/file" "$srcfile"; then
|
||||
echo "Skipping write; no changes."
|
||||
else
|
||||
doas mv -f /tmp/doasedit/$destfile_pfx/file $srcfile
|
||||
fi
|
||||
...
|
||||
```
|
||||
|
||||
I put this in a [repo on GitHub](https://github.com/AluminumTank/doasedit) if
|
||||
anyone is interested. I know that a major
|
||||
weakness of this script is the number of times it calls `doas`, which could
|
||||
break flows where password is required every time `doas` is run.
|
44
content/posts/moving_back_to_openssl.md
Normal file
44
content/posts/moving_back_to_openssl.md
Normal file
@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Moving Back To OpenSSL"
|
||||
tags: ["Linux"]
|
||||
date: 2021-03-22T11:00:00-04:00
|
||||
draft: false
|
||||
---
|
||||
Void Linux [recently announced](https://voidlinux.org/news/2021/02/OpenSSL.html)
|
||||
that they were going to move back to OpenSSL after originally [switching to
|
||||
LibreSSL in 2014](https://voidlinux.org/news/2014/08/LibreSSL-by-default.html).
|
||||
It seems that there are a lot of things at play here.
|
||||
|
||||
It seems that the main focus of the recent announcement is on the maintainability
|
||||
and other difficulties of not using the *one true SSL/TLS library*. To me,
|
||||
this pragmatically makes sense. However, every time something like this happens
|
||||
I get this lingering feeling of worry...
|
||||
|
||||
Microsoft moving their default browser from their own implementation to
|
||||
Chromium, and other browsers following suit.
|
||||
|
||||
Linux distributions moving *en masse* to **systemd**.
|
||||
|
||||
Distributed email being slowly crushed and killed by Google with GMail.
|
||||
|
||||
And many other examples that aren't immediately coming to mind.
|
||||
|
||||
I think it's great that OpenSSL as a project has made a comeback from the
|
||||
Heartbleed fiasco, and that it is apparently more actively developed nowadays,
|
||||
but the fact that we are even at the point of moving back to OpenSSL due to
|
||||
difficulties with building software is worrying. To me, it looks like a
|
||||
symptom of software becoming too entrenched and dependent on a single piece
|
||||
of software.
|
||||
|
||||
This kind of accusation coming from anyone is going to be hypocritical, since
|
||||
we all depend on Linux, X11, Wayland, systemd, or some common piece of software
|
||||
that we take for granted and don't lose sleep over. However, I think what's
|
||||
categorically different about this one is that an alternative was adopted,
|
||||
worked on, but eventually "failed" (at least for Void, but also possibly for
|
||||
Linux as well).
|
||||
|
||||
I don't know what the fix for this specific issue would be. I'm not nearly
|
||||
familiar enough with SSL/TLS or how you would develop software to be agnostic
|
||||
of dependencies like this. But I think in order to honor principles like
|
||||
the Unix philosophy, the KISS principle, and countless others, we need to
|
||||
figure out a way to be more modular for dependency issues like this.
|
110
content/posts/openwrt_plus_unbound.md
Normal file
110
content/posts/openwrt_plus_unbound.md
Normal file
@ -0,0 +1,110 @@
|
||||
---
|
||||
title: "OpenWRT + Unbound + adblock"
|
||||
tags: ["Linux"]
|
||||
date: 2021-02-05T19:03:15-05:00
|
||||
draft: false
|
||||
---
|
||||
I decided to do some work on my Linksys WRT32X running OpenWRT to make it a
|
||||
little more useful.
|
||||
|
||||
[Unbound](https://nlnetlabs.nl/projects/unbound/about/) is a DNS
|
||||
resolver which I like because it's recursive, meaning it directly queries the
|
||||
root servers instead of relying on existing DNS servers run by Google,
|
||||
Cloudflare, your ISP, or the like. I already have it running on several of my
|
||||
servers and computers, but I figured it would be great if everything on my
|
||||
network can use Unbound and be, well, *unbound* from all of those intermediary
|
||||
DNS servers.
|
||||
|
||||
Luckily, OpenWRT already has Unbound packaged, and also has a useful LuCI app
|
||||
that goes with it (LuCI is the graphical web interface that comes with OpenWRT).
|
||||
All I had to do was install `luci-app-unbound`, which pulls in all of the
|
||||
necessary dependencies to run unbound.
|
||||
|
||||
![LuCI: Software](/luci_software.png)
|
||||
|
||||
![LuCI: Install](/luci_install.png)
|
||||
|
||||
After that finished installing, I
|
||||
refreshed LuCI/OpenWRT and went to "Services" on the top, and there it is!
|
||||
|
||||
![LuCI: Services -> Recursive DNS](/luci_services.png)
|
||||
|
||||
At this point, you'll have to get your hands dirty. You can either dig through
|
||||
some LuCI menus or SSH in and make some edits. For reference, I'm using
|
||||
["Parallel dnsmasq"](https://github.com/openwrt/packages/blob/openwrt-19.07/net/unbound/files/README.md#parallel-dnsmasq) section from the README for unbound in the OpenWRT packages (which
|
||||
has a lot of other useful information as well!). Essentially, I made the edits
|
||||
to `/etc/config/unbound` and `/etc/config/dhcp` after SSH'ing in. However, you
|
||||
can make the same edits through LuCI.
|
||||
|
||||
For the `/etc/config/unbound` edits, you can make the edits to the file in
|
||||
LuCI directly at "Services -> Recursive DNS -> Files -> Edit: UCI":
|
||||
|
||||
![LuCI: Edit /etc/config/unbound](/unbound_config.png)
|
||||
|
||||
For the `/etc/config/dhcp` edits, you can make the edits by finding the same
|
||||
fields under "Network -> DHCP and DNS":
|
||||
|
||||
![LuCI: Edit DHCP and DNS Settings](/dhcp_config.png)
|
||||
|
||||
However, the field names are different from the lines in the config, so they
|
||||
would need to be researched to determine which fields in LuCI map to which
|
||||
lines in `/etc/config/dhcp`.
|
||||
|
||||
At this point (or maybe after restarting unbound and dnsmasq, which is a lot
|
||||
easier using SSH and `/etc/init.d ... restart` as well), OpenWRT should now
|
||||
be using unbound for resolving all DNS lookups, while dnsmasq is only used for
|
||||
DHCP-DNS.
|
||||
|
||||
Bonus: you can also enable a nice status dashboard in LuCI under
|
||||
"Services -> Recursive DNS -> Status", but this requires installing several more
|
||||
software packages: `unbound-control` and `unbound-control-setup`. You will also
|
||||
need to change a line in `/etc/config/unbound`:
|
||||
|
||||
```
|
||||
...
|
||||
option unbound_control '0'
|
||||
...
|
||||
```
|
||||
becomes
|
||||
```
|
||||
...
|
||||
option unbound_control '1'
|
||||
...
|
||||
```
|
||||
|
||||
A word of warning: there is another section on "Unbound and odhcpd" which
|
||||
tries to cut out dnsmasq completely. However, when I tried to set this up,
|
||||
I got myself into a lot of trouble (had to reset OpenWRT, re-install any extra
|
||||
software packages, and restore configuration from backup). It is also possible that if you mess up
|
||||
the configuration for the "Parallel dnsmasq" method, you could end up in a
|
||||
similar error state and have to start over. Please be careful when doing this
|
||||
and don't change anything you're not supposed to.
|
||||
|
||||
Now, moving on to adblock, which should be **much** simpler to setup. First,
|
||||
install `luci-app-adblock` and refresh. Navigate to "Services -> Adblock":
|
||||
|
||||
![Services -> Adblock](/adblock.png)
|
||||
|
||||
Check the settings at the bottom. The only thing you need to get going is
|
||||
to go to the "Blocklist Sources" tab and choose your blocklists.
|
||||
|
||||
![Adblock: Blacklist sources](/adblock_blocklist.png)
|
||||
|
||||
The
|
||||
[adblock readme](https://github.com/openwrt/packages/blob/master/net/adblock/files/README.md)
|
||||
has some more info on what each list is. After that,
|
||||
make sure "Enabled" is checked under the "General Settings" tab:
|
||||
|
||||
![Adblock: enable](/adblock_enable.png)
|
||||
|
||||
and click the "Refresh" button above:
|
||||
|
||||
![Adblock: refresh](/adblock_refresh.png)
|
||||
|
||||
Then you're good to go; adblock should work out of the box with unbound; cheers!
|
||||
|
||||
ADDENDUM: Another word of warning: once you've setup adblock, it will download
|
||||
the blocklists, merge them into a single file at `/var/lib/unbound/adb_list.overall`,
|
||||
and try to restart unbound. I recommend not trying to view/interact with adblock
|
||||
or unbound during this restart, which can take anywhere from 30 seconds - 2 minutes.
|
||||
Just leave them alone in LuCI for a little bit...
|
6
content/posts/repressive_filters.md
Normal file
6
content/posts/repressive_filters.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
title: "Repressive Filters"
|
||||
date: 2021-01-31T17:07:19-05:00
|
||||
draft: true
|
||||
---
|
||||
|
43
content/posts/the_generation_ship_problem.md
Normal file
43
content/posts/the_generation_ship_problem.md
Normal file
@ -0,0 +1,43 @@
|
||||
---
|
||||
title: "The Generation Ship Problem"
|
||||
tags: ["Volatile Mediums"]
|
||||
date: 2021-03-19T15:00:00-04:00
|
||||
draft: false
|
||||
---
|
||||
After talking about the hardware and software problems of
|
||||
digital permanence, I'm struck by a classical Sci-Fi
|
||||
motif with a conundrum: the **Generation Ship**; a ship
|
||||
outfitted with all of the technology, infrastructure, and
|
||||
storage to support lightyear-scale human travel.
|
||||
|
||||
But what about that technology on the ship? If we build
|
||||
one of these ships, we need to accomplish one of several
|
||||
things in regards to information storage:
|
||||
|
||||
### 1. Innovate to the point where the lifetime of the storage devices is able to support lightyear scale travel.
|
||||
That's a tall order, given where we are right now with
|
||||
physical storage devices. As I mentioned in one of my
|
||||
previous posts, the average lifetime of physical storage
|
||||
devices is less than 100 years, no matter if it is a hard
|
||||
drive, solid-state drive, etc.
|
||||
|
||||
### 2. Provide the facility to create new storage devices to replace the failing old ones.
|
||||
Again, in my mind a tall order, since it would require
|
||||
facilities on the ship to create storage devices. The
|
||||
problem of having materials is at least solvable by just
|
||||
sending the ship with all of the materials it needs in
|
||||
advance.
|
||||
|
||||
### 3. Provide the facility to revitalize storage devices.
|
||||
One of the main reasons I'm even thinking about this is
|
||||
because I'm an individual with limited resources.
|
||||
Accordingly, I think about things in terms of
|
||||
broken/working, on/off, etc. With enough resources, there
|
||||
is a much larger chance of being able to repair, re-purpose,
|
||||
and otherwise revitalize storage devices, increasing their
|
||||
lifetime. E.g., if the only failure in the hard drive is the
|
||||
control circuit, that is an "easy enough" repair.
|
||||
|
||||
I like to toy with the idea of a generation ship a lot in
|
||||
my head, but I think it's really fun to think about the
|
||||
technical possibilities and needs of a ship like this.
|
116
content/posts/volatile_formats.md
Normal file
116
content/posts/volatile_formats.md
Normal file
@ -0,0 +1,116 @@
|
||||
---
|
||||
title: "Volatile Formats"
|
||||
tags: ["Volatile Mediums"]
|
||||
date: 2021-03-18T14:24:00-04:00
|
||||
draft: false
|
||||
---
|
||||
*Note: This is a continuation of the thoughts I started
|
||||
thinking about in my [Volatile Mediums](https://beckmeyer.us/posts/volatile_mediums/) blog post.*
|
||||
|
||||
The next level up from physical mediums for data storage
|
||||
is the *way* that the data is stored. In the digital age,
|
||||
we have a plethora of formats for storing information.
|
||||
For me, one of the most interesting areas of information
|
||||
storage is the analog-digital space.
|
||||
|
||||
The fundamental problem of storing audio, video, and other
|
||||
replications of the physical world is that there is so much
|
||||
information that we can collect with sensors
|
||||
(think microphones, video cameras, etc.). It would be great
|
||||
if we could go get the best camera and microphone out there,
|
||||
record whatever people record these days, and have that
|
||||
exact physical experience "played back" for us on a screen
|
||||
and speaker/headphones.
|
||||
|
||||
Unfortunately, there are several problems with this. Among
|
||||
those is the actual design of the sensor. It takes a lot of
|
||||
careful thought, engineering, and the like to create a truly
|
||||
good microphone or camera. And after all of that, this sensor
|
||||
will cost something. Hopefully, that cost will correspond to
|
||||
the actual technical ability of that sensor! In any case,
|
||||
not everyone can have the best camera or microphone due to
|
||||
any number of constraints, not just those listed above.
|
||||
|
||||
The second problem is the sampling issue. The sensor will
|
||||
create some sort of output that can then be measured, or
|
||||
**sampled**, by an ADC (analog-to-digital converter). The
|
||||
very word "sample" belies what this nearly magical box is
|
||||
doing: it is only looking at certain portions or timestamps
|
||||
of the analog signal. Granted, the time between samples
|
||||
can be very small (e.g. 44.1 kHz is a fairly common sample
|
||||
rate for audio), but there is still some loss of signal.
|
||||
Once the ADC creates these samples, it converts them into
|
||||
a digital format (something that can be stored on a
|
||||
CD, hard drive, thumb drive, etc.).
|
||||
|
||||
The third problem is the encoding issue. The ADC creates all
|
||||
of these samples, but we need to start thinking about storage
|
||||
limitations. Storing the raw output of a sensor can take a
|
||||
lot of space: an average album length (40 minutes) could
|
||||
easily take 400MB of space! Now, again, the physical storage
|
||||
space is moving in the upward direction to combat this, but
|
||||
storing isn't the only problem. One prime issue is internet
|
||||
bandwidth.
|
||||
|
||||
The solution to this is compression, like a ZIP file. It
|
||||
makes big files smaller by doing some fancy math tricks
|
||||
that can be reversed by a computer to reconstruct the
|
||||
original file. However, for audio/video files, another level
|
||||
of compression exists which actually gets rid of some of the
|
||||
information in the original file to save more space. This
|
||||
is called "lossy" compression, as opposed to "lossless"
|
||||
compression.
|
||||
|
||||
Great! We've found a way to save more space. The problem
|
||||
with lossy compression is that we have to decide which
|
||||
information to throw away. Usually, this is frequencies
|
||||
that the average human ear/eye can't perceive. But, let's
|
||||
just say that some compression is a bit too "greedy" when it
|
||||
comes to saving space and starts to cut into the band of
|
||||
frequencies that can be perceived. Also note that
|
||||
the design of these compression algorithms is an artform
|
||||
and takes lots of careful consideration.
|
||||
|
||||
The final problem I want to mention is the codec problem.
|
||||
There are many different codecs available today, and for
|
||||
each and every one of them to be useful, you need to have a
|
||||
way to decode each and every one of them. Unfortunately,
|
||||
this is sometimes very difficult.
|
||||
|
||||
It could be a licensing
|
||||
issue, where you don't have the correct software installed
|
||||
or purchased to actually decode that file on your computer.
|
||||
|
||||
Or it could be a physical constraints issue, where your
|
||||
computer isn't powerful enough to decode the file at a fast
|
||||
enough rate for you to view it without stuttering,
|
||||
buffering, etc.
|
||||
|
||||
Third, it could be a personal preference. Some people
|
||||
have much more sensitive eyes/ears and need to have formats
|
||||
that are more **transparent**, meaning that the lossy file
|
||||
is perceptually identical to the source it was encoded from.
|
||||
|
||||
With all of these issues at play, I think there are several
|
||||
key points to make:
|
||||
|
||||
### 1. Codecs need to be freely available for widespread use with no strings attached.
|
||||
Can't stress this one enough: we need to make sure we are
|
||||
doing everything possible to not let our information die
|
||||
when a corporation or individual makes a decision that
|
||||
impacts the "who, what, where, when, and how" of their codec
|
||||
usage.
|
||||
|
||||
### 2. Lossless compression is good, but it is not the only thing we need.
|
||||
We need to remember that not everyone has the ability to use
|
||||
lossless codecs, whether that be because of internet
|
||||
bandwidth limitations, storage limitation, or the like.
|
||||
Instead, we need to continue to innovate in the lossy
|
||||
compression space to narrow the perceptual gap between lossy
|
||||
and lossless more and more.
|
||||
|
||||
### 3. A codec should never become obsolete.
|
||||
This one may sound weird, but the fact is, if we're talking
|
||||
about long-term storage of information, we can't let codecs
|
||||
die, since there may come a day where we need a codec to
|
||||
decode great-grandpa's album that never made it big.
|
46
content/posts/volatile_mediums.md
Normal file
46
content/posts/volatile_mediums.md
Normal file
@ -0,0 +1,46 @@
|
||||
---
|
||||
title: "Volatile Mediums"
|
||||
tags: ["Volatile Mediums"]
|
||||
date: 2021-01-29T23:36:00-05:00
|
||||
draft: false
|
||||
---
|
||||
I've recently been thinking a lot about storage mediums [1] -- especially in the long-term.
|
||||
|
||||
Technology has made a lot of progress. Digital storage mediums started out only being
|
||||
able to store [224KB on a tape drive](https://en.wikipedia.org/wiki/Tape_drive)
|
||||
for an average lifetime of [*up to* 30 years](https://blog.storagecraft.com/data-storage-lifespan/).
|
||||
Now, we can store terrabytes of data on hard drives and solid-state drives. However,
|
||||
no one ever really answered the question about long-term storage.
|
||||
|
||||
(Note: the following is based off an assumption that the storage medium is only
|
||||
being used to make backups or archive data. The device itself could be unplugged and stored
|
||||
when no backup is in progress.)
|
||||
|
||||
Even though *theoretically* hard drives could store data for 20+ years, random bit flips, drive
|
||||
failure, etc. all make hard drives too volatile of an option. As always, of course
|
||||
redundancy takes away some of these issues.
|
||||
|
||||
SSDs are in an even worse position: they cost significantly more than hard drives
|
||||
per TB right now, and last I heard, there were still issues with bit fade when
|
||||
unpowered.
|
||||
|
||||
CD/DVD is sounding a lot better, but there are some serious issues here too.
|
||||
Variable quality directly impacts the storage lifetime. Physically storing the
|
||||
discs is a lot more risky since the disc itself doesn't have as much built-in
|
||||
protection as a hard drive or SSD has. You'll need a much larger quantity to
|
||||
store the terrabytes of data that you can easily dump on one hard drive. And finally, life
|
||||
expectancy is still fairly low -- while manufacturers of recordable discs (the 'R' in CD-R, DVD-R, etc.)
|
||||
claim life expectancies of 100-200 (!) years under optimal conditions, others are *slightly* more conservative,
|
||||
[giving an estimate of 30 years](https://www.clir.org/pubs/reports/pub121/sec4/).
|
||||
Oh, and remember how I mentioned this is for recordable discs? That means they're single write.
|
||||
The random access (RW - CD-RW, DVD-RW, etc.) discs have even lower life expectancies.
|
||||
|
||||
All in all, humanity has not gotten very far with the digital storage medium.
|
||||
All of these life expectancies have an inconsequential variance when we zoom out
|
||||
to the century view of history.
|
||||
|
||||
[1] And no, I'm not talking about the kind you pay to see your dead great-great-aunt to figure out if
|
||||
you're actually related to George Washington.
|
||||
|
||||
*This is intended to be the beginning of a learning series/personal study on the issues surrounding
|
||||
information preservation, digital permanence, and their related issues.*
|
3
deploy
Executable file
3
deploy
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
hugo
|
||||
rsync -avz --delete public/ epoch:/srv/www/
|
BIN
public/adblock.png
Normal file
BIN
public/adblock.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
BIN
public/adblock_blocklist.png
Normal file
BIN
public/adblock_blocklist.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 64 KiB |
BIN
public/adblock_enable.png
Normal file
BIN
public/adblock_enable.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
BIN
public/adblock_refresh.png
Normal file
BIN
public/adblock_refresh.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 69 KiB |
68
public/categories/index.html
Normal file
68
public/categories/index.html
Normal file
@ -0,0 +1,68 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="no-js" lang="en-us" prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb#">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<base href="https://beckmeyer.us/">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>Categories – Joel Beckmeyer's Blog</title>
|
||||
<link rel="stylesheet" href="/css/styles.css">
|
||||
<link id="theme_css" rel="stylesheet" href="/css/themes/light.css">
|
||||
<link rel="alternate" type="application/rss+xml" href="https://beckmeyer.us/categories/index.xml" title="Joel Beckmeyer's Blog" />
|
||||
</head>
|
||||
<body>
|
||||
<input class="show-hide-menu-input" style="display:none;" autocomplete="off" type="checkbox" id="toggle-1">
|
||||
<div class="main">
|
||||
<div class="header">
|
||||
<div class="header-content">
|
||||
<div class="title">
|
||||
<a href="https://beckmeyer.us/">Joel Beckmeyer's Blog</a>
|
||||
</div>
|
||||
<div>
|
||||
<div class="header-right">
|
||||
<label id="show-hide-menu-label" class="clickable-header-label" for="toggle-1">
|
||||
<img class="color-adapting-image" width="30" src="/images/hamburger.svg" alt="menu button">
|
||||
</label>
|
||||
</div>
|
||||
<label class="overlay" for="toggle-1"></label>
|
||||
<div class="dont-show">
|
||||
Links:
|
||||
</div>
|
||||
<ul class="links">
|
||||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/contact/">Contact</a></li>
|
||||
<li><a href="/posts/">Posts</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="body">
|
||||
<div class="body-content">
|
||||
|
||||
<div class="title-header">
|
||||
<h1>Categories</h1>
|
||||
</div>
|
||||
<article class="all-list">
|
||||
<div class="title-list">
|
||||
<h3><a href="/contact/">Contact</a></h3>
|
||||
<div class="title-list-date">
|
||||
</div>
|
||||
</div>
|
||||
<div class="body-list">
|
||||
<p></p>
|
||||
<p>
|
||||
Joel Beckmeyer
|
||||
Matrix: @joel:thebeckmeyers.xyz
|
||||
Fediverse: @TinfoilSubmarine@social.beckmeyer.us
|
||||
</p>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="dont-show">
|
||||
<div class="footer">
|
||||
<p>Have any questions? Let me know on <a href="https://matrix.to/#/@joel:thebeckmeyers.xyz">Matrix</a>, or start a discussion on <a href="https://social.beckmeyer.us/TinfoilSubmarine">Fediverse</a>!</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
12
public/categories/index.xml
Normal file
12
public/categories/index.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<title>Categories on Joel Beckmeyer's Blog</title>
|
||||
<link>https://beckmeyer.us/categories/</link>
|
||||
<description>Recent content in Categories on Joel Beckmeyer's Blog</description>
|
||||
<generator>Hugo -- gohugo.io</generator>
|
||||
<language>en-us</language>
|
||||
<managingEditor>joel@beckmeyer.us (Joel Beckmeyer)</managingEditor>
|
||||
<webMaster>joel@beckmeyer.us (Joel Beckmeyer)</webMaster><atom:link href="https://beckmeyer.us/categories/index.xml" rel="self" type="application/rss+xml" />
|
||||
</channel>
|
||||
</rss>
|
58
public/contact/index.html
Normal file
58
public/contact/index.html
Normal file
@ -0,0 +1,58 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="no-js" lang="en-us" prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb#">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<base href="https://beckmeyer.us/">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>Contact – Joel Beckmeyer's Blog</title>
|
||||
<link rel="stylesheet" href="/css/styles.css">
|
||||
<link id="theme_css" rel="stylesheet" href="/css/themes/light.css">
|
||||
</head>
|
||||
<body>
|
||||
<input class="show-hide-menu-input" style="display:none;" autocomplete="off" type="checkbox" id="toggle-1">
|
||||
<div class="main">
|
||||
<div class="header">
|
||||
<div class="header-content">
|
||||
<div class="title">
|
||||
<a href="https://beckmeyer.us/">Joel Beckmeyer's Blog</a>
|
||||
</div>
|
||||
<div>
|
||||
<div class="header-right">
|
||||
<label id="show-hide-menu-label" class="clickable-header-label" for="toggle-1">
|
||||
<img class="color-adapting-image" width="30" src="/images/hamburger.svg" alt="menu button">
|
||||
</label>
|
||||
</div>
|
||||
<label class="overlay" for="toggle-1"></label>
|
||||
<div class="dont-show">
|
||||
Links:
|
||||
</div>
|
||||
<ul class="links">
|
||||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/contact/">Contact</a></li>
|
||||
<li><a href="/posts/">Posts</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="body">
|
||||
<div class="body-content">
|
||||
<div class="title-header">
|
||||
<h1>Contact</h1>
|
||||
<div class="title-header-date">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>Joel Beckmeyer<br>
|
||||
Matrix: <a href="https://matrix.to/#/@joel:thebeckmeyers.xyz">@joel:thebeckmeyers.xyz</a><br>
|
||||
Fediverse: <a href="https://social.beckmeyer.us/TinfoilSubmarine">@TinfoilSubmarine@social.beckmeyer.us</a></p>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="dont-show">
|
||||
<div class="footer">
|
||||
<p>Have any questions? Let me know on <a href="https://matrix.to/#/@joel:thebeckmeyers.xyz">Matrix</a>, or start a discussion on <a href="https://social.beckmeyer.us/TinfoilSubmarine">Fediverse</a>!</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
604
public/css/styles.css
Normal file
604
public/css/styles.css
Normal file
@ -0,0 +1,604 @@
|
||||
h1 { font-size: 1.50em; }
|
||||
h2 { font-size: 1.40em; }
|
||||
h3 { font-size: 1.20em; }
|
||||
h4 { font-size: 1.00em; }
|
||||
h5 { font-size: 0.85em; }
|
||||
h6 { font-size: 0.75em; }
|
||||
|
||||
h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
/* For devices which support hover, hide the heading URL fragment
|
||||
link/icon until the mouse hovers over the heading */
|
||||
|
||||
h1:hover .heading-anchor,
|
||||
h2:hover .heading-anchor,
|
||||
h3:hover .heading-anchor,
|
||||
h4:hover .heading-anchor,
|
||||
h5:hover .heading-anchor,
|
||||
h6:hover .heading-anchor {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
h1 .heading-anchor,
|
||||
h2 .heading-anchor,
|
||||
h3 .heading-anchor,
|
||||
h4 .heading-anchor,
|
||||
h5 .heading-anchor,
|
||||
h6 .heading-anchor {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.heading-anchor {
|
||||
color: grey;
|
||||
margin-left: 0.5em;
|
||||
font-size: 0.75em;
|
||||
}
|
||||
|
||||
.heading-anchor:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.heading-anchor img {
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.dont-show {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Improvements to Hugo Chroma syntax highlighting */
|
||||
|
||||
.highlight {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
/* set the tab size for browsers that support it */
|
||||
tab-size: 4;
|
||||
-moz-tab-size: 4;
|
||||
/* needed for the iPhone so that the two columns (line numbers and code) don't have different font sizes */
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
.highlight > * {
|
||||
padding: 0.5em;
|
||||
border-width: 2px;
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
.highlight pre {
|
||||
margin: 0px;
|
||||
overflow-x: auto;
|
||||
word-wrap: normal;
|
||||
}
|
||||
|
||||
.highlight td.lntd pre {
|
||||
/* needed to fix an iPhone scrolling bug */
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.highlight td.lntd:last-child {
|
||||
/* needed until this bug is fixed: https://github.com/alecthomas/chroma/issues/225 */
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Improvements to inline code blocks */
|
||||
|
||||
code {
|
||||
font-size: 98%;
|
||||
}
|
||||
|
||||
:not(pre) > code {
|
||||
/* inline code elements */
|
||||
background-color: rgba(25, 25, 25, 0.05);
|
||||
border-radius: 5px;
|
||||
font-size: 80%;
|
||||
padding-top: 0.2em;
|
||||
padding-bottom: 0.2em;
|
||||
padding-left: 0.4em;
|
||||
padding-right: 0.4em;
|
||||
}
|
||||
|
||||
/* Formatting for "notice" shortcodes */
|
||||
|
||||
.notice {
|
||||
margin: 1.5em 0;
|
||||
width: 70%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
background-color: #E9E9E9;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 500pt) {
|
||||
.notice {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.notice > hr {
|
||||
display: none; /* only want the child hr elements to appear if css is disabled */
|
||||
}
|
||||
|
||||
.notice .notice-title {
|
||||
margin: 0;
|
||||
padding: 0.4em;
|
||||
line-height: 1em;
|
||||
background-color: #D5D5D5;
|
||||
}
|
||||
|
||||
.notice .notice-title span {
|
||||
vertical-align: -10%; /* we don't want the font descender space to be centered as well */
|
||||
}
|
||||
|
||||
.notice .notice-title .notice-title-icon {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-left: 0.15em;
|
||||
margin-right: 0.25em;
|
||||
height: 0.85em;
|
||||
}
|
||||
|
||||
.notice .notice-body {
|
||||
padding: 0.6em;
|
||||
}
|
||||
|
||||
.notice .notice-body p:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.notice .notice-body p {
|
||||
margin: 0.8em 0;
|
||||
}
|
||||
|
||||
/* ************************ */
|
||||
|
||||
blockquote {
|
||||
color: #404040;
|
||||
border-left: 0.25em solid #CCC;
|
||||
padding-left: 0.5em;
|
||||
margin-left: 1.5em;
|
||||
}
|
||||
|
||||
.title-header {
|
||||
margin-top: 1.5em;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.title-header > h1{
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.3em;
|
||||
}
|
||||
|
||||
.title-header-date {
|
||||
color: rgb(90, 90, 90);
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
.title-list > h2, .title-list > h3, .title-list > h4, .title-list > h5, .title-list > h6{
|
||||
margin-bottom: 0.1em;
|
||||
}
|
||||
|
||||
.body-list p {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.title-list-date {
|
||||
color: rgb(90, 90, 90);
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
.table-of-contents {
|
||||
border-width: 2px;
|
||||
border-style: solid;
|
||||
padding: 1em;
|
||||
margin-bottom: 2em;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.table-of-contents nav > ul {
|
||||
/* only the most-parent ul element */
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.table-of-contents ul {
|
||||
list-style: none;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.table-of-contents li {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
.table-of-contents ul ul {
|
||||
list-style: none;
|
||||
padding-left: 1.0em;
|
||||
}
|
||||
|
||||
.table-of-contents-title {
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.section-list {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.section-list li {
|
||||
display: inline-block;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
.section-list li:last-child {
|
||||
margin-right: 0em;
|
||||
}
|
||||
|
||||
.section-list li > * {
|
||||
background-color: rgba(25, 25, 25, 0.05);
|
||||
border-radius: 5px;
|
||||
font-size: 90%;
|
||||
padding-top: 0.2em;
|
||||
padding-bottom: 0.2em;
|
||||
padding-left: 0.4em;
|
||||
padding-right: 0.4em;
|
||||
}
|
||||
|
||||
.links {
|
||||
font-size: 120%;
|
||||
list-style-type: none;
|
||||
line-height: 1;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
margin-top: 9pt;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
overflow: hidden;
|
||||
-webkit-overflow-scrolling: touch; /* this needs to go here for some reason */
|
||||
}
|
||||
|
||||
.links li {
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.links li > * {
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
.links li:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.links a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.links a:hover {
|
||||
color: #505050;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
position: fixed;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.header-right {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.header-right * {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.header-right *:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.clickable-header-label {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.clickable-header-label * {
|
||||
height: 1em;
|
||||
width: auto; /* to override the <img width="__"> attribute when css is supported */
|
||||
}
|
||||
|
||||
#show-hide-menu-label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 13pt;
|
||||
font-family: Lato, Arial, Helvetica, "Liberation Sans", sans-serif;
|
||||
line-height: 1.45;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: bold;
|
||||
font-size: 140%;
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
.title a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: lightgray;
|
||||
background-size: 100%;
|
||||
background-position: bottom;
|
||||
display: inline-block;
|
||||
z-index: 1; /* this prevents images with css filters from appearing above the header when in portrait mode */
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
margin: 15pt;
|
||||
position: relative; /* so that "position:absolute" works for the menu label */
|
||||
}
|
||||
|
||||
.body {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.body-content {
|
||||
margin: 15pt;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
/* Image/Figure formatting */
|
||||
|
||||
.body-content :not(figure) img {
|
||||
/* regular image elements should be inline elements */
|
||||
max-width: 100%;
|
||||
max-height: 60vw; /* if the image is really tall, we don't want the width to be 100% */
|
||||
}
|
||||
|
||||
.body-content figure {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 70%;
|
||||
}
|
||||
|
||||
.body-content figure img {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: 0.5em;
|
||||
max-width: 100%;
|
||||
max-height: 40vw; /* if the image is really tall, we don't want the width to be 70% */
|
||||
}
|
||||
|
||||
.body-content figure:not(.color-adapting-image) img {
|
||||
/* if the image is designed to adapt to the theme, then don't use a background */
|
||||
background-color: rgb(255, 255, 255); /* images with transparent backgrounds typically assume a light background */
|
||||
}
|
||||
|
||||
.body-content figure figcaption {
|
||||
font-size: 90%;
|
||||
line-height: 1.5em;
|
||||
padding-bottom: 0.3em;
|
||||
border-bottom: 2px solid lightgray;
|
||||
}
|
||||
|
||||
.body-content figure figcaption * {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@media only screen and (orientation: portrait) {
|
||||
.body-content :not(figure) img,
|
||||
.body-content figure img {
|
||||
/* need to target both so that they're more specific */
|
||||
max-height: 100vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 400pt) {
|
||||
.body-content figure {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.body-content figure figcaption {
|
||||
margin-left: 5%;
|
||||
margin-right: 5%;
|
||||
}
|
||||
}
|
||||
|
||||
/* ************************ */
|
||||
|
||||
.main {
|
||||
width: 700pt; /* make sure to also change this in the media query */
|
||||
margin: 0 auto;
|
||||
margin-top: 10pt;
|
||||
margin-bottom: 10pt;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0 0 10px rgba(50, 50, 50, .17);
|
||||
}
|
||||
|
||||
.footer {
|
||||
text-align: center;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (orientation: portrait) {
|
||||
.header {
|
||||
top: 0;
|
||||
position: sticky;
|
||||
position: -webkit-sticky; /* needed for iOS */
|
||||
box-shadow: 0 0 1em rgba(30, 30, 30, .3);
|
||||
}
|
||||
|
||||
.body-content :target::before {
|
||||
/* When linking to tags with 'id's (example:
|
||||
'website.com/post/#heading'), make them
|
||||
appear lower down the page so that they
|
||||
don't appear under the sticky header set
|
||||
above.
|
||||
See: https://stackoverflow.com/a/24298427
|
||||
Note that this causes the cursor text
|
||||
selection of the target to behave
|
||||
undesirably.
|
||||
*/
|
||||
content: '';
|
||||
display: block;
|
||||
height: 3em;
|
||||
margin-top: -3em;
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (max-width: 700pt) {
|
||||
.main {
|
||||
width: 100%;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 12pt;
|
||||
background-color: white;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 400pt) {
|
||||
.header-right {
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.clickable-header-label {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.clickable-header-label * {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#show-hide-menu-label {
|
||||
display: inherit;
|
||||
}
|
||||
|
||||
.show-hide-menu-input:checked ~ .main .links {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
right: 0;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.show-hide-menu-input:checked ~ .main .overlay {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
.links {
|
||||
display: block;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
overflow-y: scroll;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: -100px; /* start to the right for the transition */
|
||||
min-width: 75%;
|
||||
z-index: 3;
|
||||
background-color: rgb(247, 247, 247);
|
||||
padding: 10pt;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.links li {
|
||||
margin-right: 0;
|
||||
border-bottom: solid 1px gray;
|
||||
}
|
||||
|
||||
.links li > * {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 13px;
|
||||
}
|
||||
|
||||
.links li:first-child {
|
||||
border-top: solid 1px gray;
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
margin: 8pt 10pt;
|
||||
}
|
||||
|
||||
.body-content {
|
||||
margin: 10pt;
|
||||
}
|
||||
|
||||
.title a {
|
||||
vertical-align: -10%; /* we don't want the font descender space to be centered as well */
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
body {
|
||||
background-color: initial !important;
|
||||
}
|
||||
|
||||
.main {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
width: 100%;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: initial !important;
|
||||
background-image: none !important;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.body-content {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.header-right {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.links {
|
||||
display: none;
|
||||
}
|
||||
}
|
64
public/css/themes/dark-chroma.css
Normal file
64
public/css/themes/dark-chroma.css
Normal file
@ -0,0 +1,64 @@
|
||||
/* Background */ .chroma { color: #d0d0d0; background-color: #1a1a1a }
|
||||
/* Error */ .chroma .err { color: #a61717; background-color: #e3d2d2 }
|
||||
/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
|
||||
/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; width: auto; overflow: auto; display: block; }
|
||||
/* LineHighlight */ .chroma .hl { display: block; width: 100%; background-color: #404040 }
|
||||
/* LineNumbersTable */ .chroma .lnt { margin-right: 0.4em; padding: 0 0.4em 0 0.4em; }
|
||||
/* LineNumbers */ .chroma .ln { margin-right: 0.4em; padding: 0 0.4em 0 0.4em; }
|
||||
/* Keyword */ .chroma .k { color: #6ab825; font-weight: bold }
|
||||
/* KeywordConstant */ .chroma .kc { color: #6ab825; font-weight: bold }
|
||||
/* KeywordDeclaration */ .chroma .kd { color: #6ab825; font-weight: bold }
|
||||
/* KeywordNamespace */ .chroma .kn { color: #6ab825; font-weight: bold }
|
||||
/* KeywordPseudo */ .chroma .kp { color: #6ab825 }
|
||||
/* KeywordReserved */ .chroma .kr { color: #6ab825; font-weight: bold }
|
||||
/* KeywordType */ .chroma .kt { color: #6ab825; font-weight: bold }
|
||||
/* NameAttribute */ .chroma .na { color: #bbbbbb }
|
||||
/* NameBuiltin */ .chroma .nb { color: #24909d }
|
||||
/* NameClass */ .chroma .nc { color: #447fcf }
|
||||
/* NameConstant */ .chroma .no { color: #447fcf }
|
||||
/* NameDecorator */ .chroma .nd { color: #ffa500 }
|
||||
/* NameException */ .chroma .ne { color: #bbbbbb }
|
||||
/* NameFunction */ .chroma .nf { color: #447fcf }
|
||||
/* NameNamespace */ .chroma .nn { color: #447fcf }
|
||||
/* NameTag */ .chroma .nt { color: #6ab825; font-weight: bold }
|
||||
/* NameVariable */ .chroma .nv { color: #447fcf }
|
||||
/* LiteralString */ .chroma .s { color: #ed9d13 }
|
||||
/* LiteralStringAffix */ .chroma .sa { color: #ed9d13 }
|
||||
/* LiteralStringBacktick */ .chroma .sb { color: #ed9d13 }
|
||||
/* LiteralStringChar */ .chroma .sc { color: #ed9d13 }
|
||||
/* LiteralStringDelimiter */ .chroma .dl { color: #ed9d13 }
|
||||
/* LiteralStringDoc */ .chroma .sd { color: #ed9d13 }
|
||||
/* LiteralStringDouble */ .chroma .s2 { color: #ed9d13 }
|
||||
/* LiteralStringEscape */ .chroma .se { color: #ed9d13 }
|
||||
/* LiteralStringHeredoc */ .chroma .sh { color: #ed9d13 }
|
||||
/* LiteralStringInterpol */ .chroma .si { color: #ed9d13 }
|
||||
/* LiteralStringOther */ .chroma .sx { color: #ffa500 }
|
||||
/* LiteralStringRegex */ .chroma .sr { color: #ed9d13 }
|
||||
/* LiteralStringSingle */ .chroma .s1 { color: #ed9d13 }
|
||||
/* LiteralStringSymbol */ .chroma .ss { color: #ed9d13 }
|
||||
/* LiteralNumber */ .chroma .m { color: #3677a9 }
|
||||
/* LiteralNumberBin */ .chroma .mb { color: #3677a9 }
|
||||
/* LiteralNumberFloat */ .chroma .mf { color: #3677a9 }
|
||||
/* LiteralNumberHex */ .chroma .mh { color: #3677a9 }
|
||||
/* LiteralNumberInteger */ .chroma .mi { color: #3677a9 }
|
||||
/* LiteralNumberIntegerLong */ .chroma .il { color: #3677a9 }
|
||||
/* LiteralNumberOct */ .chroma .mo { color: #3677a9 }
|
||||
/* OperatorWord */ .chroma .ow { color: #6ab825; font-weight: bold }
|
||||
/* Comment */ .chroma .c { color: #999999; font-style: italic }
|
||||
/* CommentHashbang */ .chroma .ch { color: #999999; font-style: italic }
|
||||
/* CommentMultiline */ .chroma .cm { color: #999999; font-style: italic }
|
||||
/* CommentSingle */ .chroma .c1 { color: #999999; font-style: italic }
|
||||
/* CommentSpecial */ .chroma .cs { color: #e50808; background-color: #520000; font-weight: bold }
|
||||
/* CommentPreproc */ .chroma .cp { color: #cd2828; font-weight: bold }
|
||||
/* CommentPreprocFile */ .chroma .cpf { color: #cd2828; font-weight: bold }
|
||||
/* GenericDeleted */ .chroma .gd { color: #d22323 }
|
||||
/* GenericEmph */ .chroma .ge { font-style: italic }
|
||||
/* GenericError */ .chroma .gr { color: #d22323 }
|
||||
/* GenericHeading */ .chroma .gh { color: #ffffff; font-weight: bold }
|
||||
/* GenericInserted */ .chroma .gi { color: #589819 }
|
||||
/* GenericOutput */ .chroma .go { color: #cccccc }
|
||||
/* GenericPrompt */ .chroma .gp { color: #aaaaaa }
|
||||
/* GenericStrong */ .chroma .gs { font-weight: bold }
|
||||
/* GenericSubheading */ .chroma .gu { color: #ffffff }
|
||||
/* GenericTraceback */ .chroma .gt { color: #d22323 }
|
||||
/* TextWhitespace */ .chroma .w { color: #666666 }
|
112
public/css/themes/dark.css
Normal file
112
public/css/themes/dark.css
Normal file
@ -0,0 +1,112 @@
|
||||
@import url("dark-chroma.css");
|
||||
|
||||
a {
|
||||
color: #A1A1EA;
|
||||
}
|
||||
|
||||
.highlight > * {
|
||||
border-color: #505050;
|
||||
}
|
||||
|
||||
:not(pre) > code {
|
||||
/* inline code elements */
|
||||
background-color: rgba(90, 90, 90, 0.25);
|
||||
}
|
||||
|
||||
a > code {
|
||||
background-color: rgba(65, 65, 170, 0.3);
|
||||
}
|
||||
|
||||