Quick and dirty adding pages from old wiki. Cleanup imminent

This commit is contained in:
David Thurstenson 2024-03-07 17:21:05 -06:00
parent b2677db819
commit 9124e4f98b
45 changed files with 2011 additions and 0 deletions

6
about/_index.md Normal file
View File

@ -0,0 +1,6 @@
---
title: "About"
description: "Contact info, portfolio, etc"
draft: false
hide: true
---

28
about/contact.md Normal file
View File

@ -0,0 +1,28 @@
---
title: "Contact Info"
description: "How to get in touch with me"
date: 2021-9-25
draft: false
---
Listed in order of reliability
| Service | Address |
| ---: | --- |
| Email | thurstylark@gmail.com |
| | thurstylark@thurstylark.com |
| ----- | ----- |
| Matrix | @thurstylark:thurstylark.com |
| ----- | ----- |
| IRC[^1] | thurstylark@libera.chat |
| | thurstylark@oftc.net |
| ----- | ----- |
| Discord | thurstylark |
| ----- | ----- |
| Signal | (ask for number via Matrix) |
| ----- | ----- |
| Twitter | @thurstylark |
[^1]: ~~Since the formation of libera.chat, my presence on freenode.net is purely to squat on my account and nicks so they may not be misused.~~ Never mind, [Freenode decided to shit the bed even harder](https://www.reddit.com/r/irc/comments/o01tmv/freenode_wipes_old_database_and_starts_over/), so I no longer have a presence there. Please use libera.chat or oftc.net instead.

20
about/portfolio.md Normal file
View File

@ -0,0 +1,20 @@
---
title: "Portfolio"
description: "The things I do"
date: 2021-9-25
draft: false
---
## Where can I find your work?
- [wiki.thurstylark.com](https://wiki.thurstylark.com)
- [git.thurstylark.com](https://git.thurstylark.com)
- [Github](https://github.com/thurstylark)
- [Twitch](https://twitch.tv/thurstylark)
- [YouTube](https://www.youtube.com/channel/UCJwFowK8HKYcgD7GVYiz8jA)
## Anything Else?
Probably not, but I go by Thurstylark everywhere, so get to googlin'!

19
about/resume.md Normal file
View File

@ -0,0 +1,19 @@
---
title: "Resume"
description: "How to get me to do stuff for money"
date: 2021-9-25
draft: false
---
## Resume 403: Forbidden
Hi,
Thanks for visiting, but I have decided against providing a traditional resume at this time.
For examples of my work, feel free to take a look at my [Portfolio](../portfolio/). Of special note is my [Twitch channel](https://twitch.tv/thurstylark), where you can watch me work out loud, in real-time. These resources will do a much better job of communicating my abilities than any work history document ever could.
Another factor worth consideration is my perspective on the post-pandemic labor market. I will eventually write a longer post on this subject, but until then, [this video](https://youtu.be/ieStO3JqWJ0) will have to suffice. If you are unable to accept this interpretation, I will not consider working with you.
If you require additional information that isn't covered by the above resources, please reach out to me using one of the methods listed on the [Contact Info](../contact/) page.

4
dotfiles/_index.md Normal file
View File

@ -0,0 +1,4 @@
---
title: Dotfiles
weight: 2
---

226
dotfiles/bashrc.md Normal file
View File

@ -0,0 +1,226 @@
---
title: "Bashrc"
description: "Details about how I configure my shell"
author: "Thurstylark"
date: 2021-9-25
draft: false
---
Source: https://git.thurstylark.com/vcsh/bashrc.git
## Profile
https://git.thurstylark.com/vcsh/bashrc.git/tree/.bash_profile
Bash chooses which dotfile to source based on how it gets run. If starting from a login shell, `~/.bash_profile` will get sourced, but if there's not a command in there to source your `~/.bashrc`, you may find yourself having to `exec bash` after starting bash. This can be fixed by adding the following line to your `~/.bash_profile`:
```
[ -f ~/.bashrc ]( -f ~/.bashrc .md) && . ~/.bashrc
```
I also use `~/.bash_profile` for setting numlock while in a tty:
```
case $(tty) in /dev/tty[0-9]*)
setleds -D +num * (numlock for X is set in ~/.xinitrc)
;;
esac
```
----
## Main bashrc
https://git.thurstylark.com/vcsh/bashrc.git/tree/.bashrc
Things started getting a little too expansive for a single file, so I split off relevant sections into their own files. Now all my individual utilities have their own file, making troubleshooting and adding functionality much easier. You can find info for each file and what it does in its own section on this page.
### General config
I'm not going in to detail about every line, but I'll hilight the important parts. The rest should be documented in the script itself.
First off, if we're not running bash interactively, there's no use for any of the rest of this, so just skip it.
```
- If not running interactively, don't do anything
[ $- != *i* ]( $- != *i* .md) && return
```
Another cool option is actually built in to bash: If you call for a directory without any command before it, just `cd` into that directory.
```
- If a directory is given without any command, CD into it.
shopt -s autocd
```
This is where all the other utilities, aliases, and functions get pulled in. Anything in `~/.bashrc.d/` ending in `.bash` will get pulled in.
```
for f in ~/.bashrc.d/*.bash; do source "$f"; done
```
This also removes the need for the local bashrc sourcing that I [had in this file previously](https://git.thurstylark.com/vcsh/bashrc.git/tree/.bashrc?id=30c53ca7224b583ed5068038b697653810e3b94b#n45). If that functionality is needed, simply make a new script in `~/.bashrc.d/` and don't track it with `vcsh`.
Ordering can be done by adding numbers to the beginning of filenames. For example: `10-prompt.sh`. Currently, nothing that I use requires that kind of functionality.
----
## Prompt
https://git.thurstylark.com/vcsh/bashrc.git/tree/.bashrc.d/12-prompt.bash
I originally built my prompt using http://bashrcgenerator.com and, while it's a nice tool for visually building a prompt, it has several limitations on what you're able to create with it. But more importantly to me, it generates a rediculously long string, defines and resets color for every single character, uses both a color and bold escape sequence to use light/bright colors, mixes raw escape sequences and subshells running tput, and as a result is utterly unreadable and unmaintainable.
So, I replaced it with my own setup that generates the needed color codes on the fly to improve readability. I intentionally put everything in a function and call it immediately so I may use local vars for the color definitions. I didn't really want to leave them around just in case.
I'm not completely happy with this solution because it causes each of the tput subshells to execute each time the prompt is printed. I would like to change this to quash the extra output this causes when using `bash -x`, but I would also like to find a solution that minimizes so many subshells just for a prompt, but avoid hard-coding colors so it can be general enough to support any env in which it may be used.
----
## Environment
https://git.thurstylark.com/vcsh/bashrc.git/tree/.bashrc.d/11-env.bash
Here is where I set a few environment variables that are useful in one way or another, such as `HISTCONTROL`, `EDITOR`, `LS_COLORS`, and `LIBVIRT_DEFAULT_URI`.
----
## Aliases
https://git.thurstylark.com/vcsh/bashrc.git/tree/.bashrc.d/10-alias.bash
Most of these are simple creature comforts and are commented with sufficient explanation.
----
## Pkgfile as `command_not_found_handle()`
https://git.thurstylark.com/vcsh/bashrc.git/tree/.bashrc.d/pkgfile.bash
This sets up `bash`'s `command_not_found_handle()` functionality so that when a command cannot be found in `PATH`, it will use `pkgfile` to check for that command in its databases, which are derived from the [same databases](https://wiki.archlinux.org/title/Pacman#Search_for_a_package_that_contains_a_specific_file) that `pacman -F` uses.
To keep these databases updated, `pkgfile` ships [a systemd timer](https://wiki.archlinux.org/title/Pkgfile#Automatic_updates) that runs the update command daily.
----
## Colored man Pages
https://git.thurstylark.com/vcsh/bashrc.git/tree/.bashrc.d/colored-man-pages.bash
Some color changes in `man` are almost essential for readability for me, so I define my own.
This can be replicated for any similar program that uses `less` as its pager.
----
## Screenshot
https://git.thurstylark.com/vcsh/bashrc.git/tree/.bashrc.d/shot.bash
`shot()` used to be much more complicated, but after moving to sway, I found that I couldn't be arsed to reimplement all of its former functionality. It turned out that the majority of the time, I want to select a region, and put it on stdout to be dealt with how I please. If I find that full-screen or all-screen screenshots are more useful to me in the future, I'll cross that bridge when I come to it.
----
## Countdown
https://git.thurstylark.com/vcsh/bashrc.git/tree/.bashrc.d/countdown.bash
Found this little function when I wanted to add functionality to `shot()`. It takes an integer as an argument, then counts down that number of seconds visually.
I no longer use `countdown()` from `shot()` directly, but sometimes will in some sort of pipeline in tandem with it. I found that I want that flexibility out in the open for me to use instead of packed behind a bespoke ui for little benefit.
----
## cmdcopy
https://git.thurstylark.com/vcsh/bashrc.git/tree/.bashrc.d/cmdcopy.bash
This tool runs the specified command, capturing `stdout` and `stderr`, adds the specified command to the beginning of the output, and sends the result to stdout. The output of this command should be suitable to pipe directly into a paste service such as [ix.io](http://ix.io) when seeking support via IRC or other text-based method.
----
## fbc
https://git.thurstylark.com/vcsh/bashrc.git/tree/.bashrc.d/fbc.bash
In a similar vein to `cmdcopy()`, this tool runs the specified command, pipes `stdout` and `stderr` directly to [fb-client](https://git.server-speed.net/users/flo/fb/), and sets the specified command as the name of the paste using `-n`.
----
## Vactivate
https://git.thurstylark.com/vcsh/bashrc.git/tree/.bashrc.d/vactivate.bash
I started needing more than one python virtualenv, and I wanted easy access to my own specific file structure. Additionally, I wanted the ability to deactivate the venv like I would exit a child shell. This is the solution that I came up with.
A caveat to this is that the prompt modification that venv usually applies is not available using this method. If a prompt modification is desired, it needs to be taken care of elsewhere. I take care of it in my prompt setup detailed [here](https://wiki.thurstylark.com/Bashrc.html#Bashrc-Prompt).
----
## FontFind
https://git.thurstylark.com/vcsh/bashrc.git/tree/.bashrc.d/fontfind.bash
Sometimes you just need to figure out what font provides a specific character. This function provides that solution.
----
## Resolve IP Addresses to MAC Addresses with `arping`
https://git.thurstylark.com/vcsh/bashrc.git/tree/.bashrc.d/arpresolve.bash
This utility comes in handy when I just want a MAC address as a string without having to dig through `nmap` output for it.
Unfortunately not all devices are cooperative to this method, so ymmv.
----
## Get Dell Service Tag
https://git.thurstylark.com/vcsh/bashrc.git/tree/.bashrc.d/getdst.bash
I work with Dell machines a lot, and when dealing with hardware problems, it's nice to have the service tag handy. Lucky for me, the service tag is easily retrieveable using `dmidecode(1)`, so I made a function for it.
As an added bonus, the `-l` option will print the url for that product's support page.
----
## `sing()` and `note2freq()`
https://git.thurstylark.com/vcsh/bashrc.git/tree/.bashrc.d/sing.bash
I was having trouble writing music scripts for the pcspkr because all the examples that I could find only used frequency numbers as arguments to `beep`, and it was difficult to map frequency numbers to musical note letters in the process of making my own tunes. `note2freq()` solves this issue by taking a musical note in the form of `<letter>[accidental]<octave>`, where:
- `<letter>` is one of `A` through `G`
- `[accidental]` is one of:
- `b` for flat
- `s` for sharp
- omitted for a natural note
- `<octave>` is `1` through `7`
`sing()` takes a list of notes in this same form along with note length in ms, uses `note2freq()` to translate each one to a frequency number and constructs a string of arguments that `beep` can use to play the entire tune in one go.
Both of these in tandem make beep tune writing way easier.
----
## Triumph
https://git.thurstylark.com/vcsh/bashrc.git/tree/.bashrc.d/triumph.bash
This function is both an example of how `sing()` is used, as well as a tool in its own right.
I wanted a script that played a tune after a long-running script, but play different tunes based on the exit code of the preceding command. This was my cute Portal-themed implementation of that idea.
Proper tune selection depends on `triumph()` being able to read the exit code from the previous command. For example, for usage in a one-liner script, use something similar to `<targetcmd>; triumph`. Avoid using `||` or `&&` in place of the `;`.
----
## Weechat
https://git.thurstylark.com/vcsh/bashrc.git/tree/.bashrc.d/weechat.bash
See: [Weechat](eechat.md).

View File

@ -0,0 +1,20 @@
---
title: "Browser search bar shortcuts"
description: "Macros for the speedy searching"
author: "Thurstylark"
date: 2021-9-25
draft: false
---
| Service | Trigger | URL | Description |
|-----------------------------|---------|-----------------------------------------------------------------------------|-------------------------------------------------------|
| Arch Wiki Search | aw | https://wiki.archlinux.org/index.php?title=Special%3ASearch&search=%s&go=Go | |
| Arch Package Search | ap | https://www.archlinux.org/packages/?sort=&q=%s&maintainer=&flagged= | |
| Arch User Repository Search | aur | https://aur.archlinux.org/packages?O=0&K=%s&SeB=nd&SB=n&SO=a | |
| Arch Linux Bug Lookup | fs | https://bugs.archlinux.org/task/%s | Go directly to bug number |
| Arch Manpage Lookup | man | https://man.archlinux.org/man/%s | Go directly to manpage |
| Arch Manpage Search | mans | https://man.archlinux.org/search?q=%s&lang=en | Search manpage db |
| Dell Service Tag Lookup | dell | http://www.dell.com/support/home/us/en/04/product-support/servicetag/%s | Go directly to the Dell Support page of a service tag |
| ShellCheck Code Search | sc | https://github.com/koalaman/shellcheck/wiki/SC%s | Look up ShellCheck code. (sc<tab><number>) |

72
dotfiles/ssh.md Normal file
View File

@ -0,0 +1,72 @@
---
title: "OpenSSH"
description: "Creature comfort configs for SSH"
author: "Thurstylark"
date: 2021-9-25
draft: false
---
## User-Specific Client Config
Most directives that can be set in the system-wide client configuration can be set by each user in `~/.ssh/config`. This snippit contains a collection of my most used options:
```
SendEnv LC_* # Send all LC env vars to the host
AddKeysToAgent yes # If asked to unlock a password-protected private
# key, automatically add that key to the ssh-agent
# so you no longer need to reenter the password
# again this session
# Example Host Definition
Host foo # Arbitrary String. Use this definition by running `ssh foo`
HostName foo.bar.com # Actual DNS Hostname or IP address of the server
Port 12345 # Port number to connect to
User thurstylark # Username on the server to connect as
IdentityFile ~/.ssh/id_rsa # Private key to use for authentication
ServerAliveInterval 300 # Interval in seconds before a keepalive packet is sent to the server
ServerAliveCountMax 3 # Declare the connection dead after no response to this many keepalive packets
HostKeyAlgorithms ssh-dss # Use ssh-dss for host-key algorithm checking (ssh-dss is insecure. Use something else)
KexAlgorithms +kex # Add 'kex' to the list of Key Exchange Algorithms available for use.
StrictHostKeyChecking no # Turn off Strict Host Key Checking for only this host (insecure)
UserKnownHostsFile /dev/null # Discard this hosts host key instead of storing in ~/.ssh/known_hosts (not recommended)
VisualHostKey yes # Always use randomart in place of host key sums
```
### Directive Notes
- `Host`
- Can also refer to an actual hostname. See "Host-Specific Keys" below.
- `ServerAliveInterval` and `ServerAliveCountMax`
- It's common for a firewall to cause problems keeping connections open, so tweaking these settings can help. See "Broken Pipe Remedy" below.
- `HostKeyAlgorithms`
- ssh-dss is less secure than the alternatives/defaults. Only use this if necessary.
- `KexAlgorithms`
- I use this to add `diffie-hellman-group1-sha1` to the available Key Exchange Algorithms for connecting to older hardware that doesn't accept any currently allowed kex algorithms. Diffie Hellman is quite insecure, so please use caution.
- `StrictHostKeyChecking`
- Several servers I connect to are descrete servers, but they all are accessed through a single IP Address with a randomized port number. This allows me to continue connecting to the host without stopping to delete a line from `~/.ssh/known_hosts` before connecting.
### Host-Specific Keys
User-specific ssh configs make it stupid easy to create several keys for several different uses. For instance, this allows you to have a separate key for each service that you use, and allows you less headache should one key be compromised.
For example: Github allows you to push to your remote repositories over ssh by adding a public key to your account. Ideally, you should create a keypair for this specific purpose, and name it something like 'github'. Then you can add something like this to your `~/.ssh/config`:
```
host github.com
IdentityFile ~/.ssh/github
```
Now, when your repo's origin url is set to something like `git@github.com:username/reponame.git`, ssh will automatically use your github key instead of needing to specify it in the command, or using your username and password with HTTPS every time.
### Broken Pipe Remedy
Often times a firewall or inconsistent connection can cause an ssh connection to be closed prematurely and give a "Write Failed: broken pipe" error message. Some firewalls are configured to close connections that have sent no data after a certain interval, thus causing a broken pipe error when the connection was otherwise healthy. This can usually be solved by sending data through the connection before that interval is up, thus resetting the firewall's timer.
The `ServerAliveInterval` option sends a keepalive packet if no data has been received within the interval specified. All the keepalive packet does is request a response from the server to verify the connection is still good. By default, this option is disabled.
Additionally, the `ServerAliveCountMax` option specifies the number of keepalive packets that may be sent without a response before ssh terminates the connection. By default this is set to `3`, but if your connection is unreliable, you can set this higher to give your server a better chance at responding the next time a keepalive packet is sent.
It is important to note that messages sent by the `TTYKeepAlive` option are not sent through the encrypted channel and can be spoofed, but the "server alive" messages are sent through the encrypted channel and cannot be spoofed. Do not use `TTYKeepAlive` messages for determining the quality or security of a connection! See `ssh-config(5)` for more info.

5
misc/_index.md Normal file
View File

@ -0,0 +1,5 @@
---
title: Miscellaneous
description: "Various detritus deposited here"
weight: 98
---

5
misc/archive/_index.md Normal file
View File

@ -0,0 +1,5 @@
---
title: Archive
description: "Pages that aren't of much active use, but worth keeping around"
weight: 99
---

144
misc/archive/dotfiles/i3.md Normal file
View File

@ -0,0 +1,144 @@
---
title: "i3 configuration"
description: "Moved to Sway"
author: "Thurstylark"
date: 2021-9-25
draft: false
---
Source: https://git.thurstylark.com/vcsh/i3.git
## j4-make-config
The final config that actually is read by i3 is created using j4-make-config. This is done in the [Xinitrc](Xinitrc.md).
Simple usage:
```
j4-make-config -a $(hostname).config archlinux
```
This creates `~/.config/i3/config` by merging `~/.config/i3/config.base` and `~/.config/i3/$HOSTNAME.config`, and adds the 'archlinux' theme (included with j4-make-config). Optionally, you can add `-r` to tell i3 to reload the config after `j4-make-config` has completed.
Since using `j4-make-config`, the command for reloading the config has been changed to the following:
```
# rebuild and reload the configuration file
bindsym $mod+Shift+c exec "j4-make-config -r -a $HOSTNAME.config archlinux"
```
### Reference
https://github.com/okraits/j4-make-config
----
## Media Keys
### Volume
This differs depending on if you're using ALSA or Pulseaudio. Thus, I include these instructions in the host-specific configs instead of the base config
ALSA:
```
# Alsa Volume controls
bindsym XF86AudioRaiseVolume exec --no-startup-id amixer set Master 5%+ #increase sound volume
bindsym XF86AudioLowerVolume exec --no-startup-id amixer set Master 5%- #decrease sound volume
bindsym XF86AudioMute exec --no-startup-id amixer set Master toggle * mute sound
```
PulseAudio:
```
# PulseAudio Volume controls
bindsym XF86AudioRaiseVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ +5% #increase sound volume
bindsym XF86AudioLowerVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ -5% #decrease sound volume
bindsym XF86AudioMute exec --no-startup-id pactl set-sink-mute @DEFAULT_SINK@ toggle * mute sound
```
### Brightness
Brightness can be universal unless the utility for changing brightness differs between machines, so this snippit lives in the base config.
```
# Sreen brightness controls (requires light(1) from the AUR)
bindsym XF86MonBrightnessUp exec light -A 10 * increase screen brightness
bindsym XF86MonBrightnessDown exec light -U 10 * decrease screen brightness
```
### Playhead Control
This also is universal if the same tool is being used across hosts. I use `playerctl` mainly for its compatibility with Spotify's Linux client.
```
# Music Player controls
bindsym XF86AudioPlay exec --no-startup-id playerctl play-pause
bindsym XF86AudioNext exec --no-startup-id playerctl next
bindsym XF86AudioPrev exec --no-startup-id playerctl previous
```
### References
https://wiki.archlinux.org/index.php/Extra_keyboard_keys
https://wiki.archlinux.org/index.php/Advanced_Linux_Sound_Architecture#Keyboard_volume_control
https://wiki.archlinux.org/index.php/PulseAudio#Keyboard_volume_control
https://wiki.archlinux.org/index.php/Backlight
https://wiki.archlinux.org/index.php/Spotify#Global_media_hotkeys
----
## Screen Locker
The screen locker is already set up in [Xinitrc](Xinitrc.md), so all that is necessary in the i3 config is to set the key combination that should spawn `xautolock -locknow`.
```
# Ctrl+Alt+L to lock the screen
# Locker is set in ~/.xinitrc
bindsym Mod1+Control+l exec "xautolock -locknow"
```
----
## i3Bar
This is another host-specific configuration, since `bar {}` has host-specific options apart from just the i3status config. It also includes the `j4-make-config` theme placeholder, since the theme definitions for the bar are separate from the main config.
I'll only demonstrate the most complicated of my current i3bar configuration. The rest can be viewed on the git repo.
```
bar {
status_command i3status -c ~/.config/i3/status/$HOSTNAME.config
tray_output primary
output eDP1 * Which display should i3bar be bound to?
# $i3-theme-bar
}
```
----
## i3Status
Most of the i3Status configuration is pretty standard, and is well documented by [the upstream docs](https://i3wm.org/i3status/manpage.html), so I'll only document the specific directives I crafted/modified myself
### Volume
This directive chooses ALSA by default, PulseAudio can be specified by adding `device = "pulse"` to the end of this directive.
```
volume master {
format = "🔈%volume" * U+1F508
format_muted = "🔇" * U+1F507
}
```
### SPVPN
This is a simple pidfile watcher used with one of my [VPN](VPN.md) configurations that gets started with systemd.
```
run_watch SPVPN {
pidfile = "/var/run/spvpn@*.pid"
}
```

View File

@ -0,0 +1,83 @@
---
title: "Pkglist backups"
description: "Abandoned due to lack of usefulness"
author: "Thurstylark"
date: 2021-9-25
draft: false
---
Sources:
- https://git.thurstylark.com/vcsh/pkglists.git/
- https://git.thurstylark.com/vcsh/systemd-user.git/
- https://github.com/gs93/pakbak
These used to be actual lists created by [an admittedly terrible script](https://git.thurstylark.com/vcsh/pkglists.git/tree/.pkglists/pkglistbu.sh?id=62cc7e34c1354900cf7cc58480d9b4db2cd7309a) that was run nightly by a systemd --user timer, but now I backup `pacman`'s whole local database whenever there's a change using pakbak and `systemd.path` units.
## Pakbak
Pakbak is pretty straightforward: You configure where you want the backups stored, the ammount of backups you want to keep, and then enable `pakbak.path`. This will trigger `pacbak.service` whenever there is a change to `/var/lib/pacman/local` in the filesystem, `pakbak.path` triggers `pakbak.service`, which runs `/usr/lib/systemd/scripts/pakbak`. The pakbak script checks for pacman's lock file before continuing, then creates a tar archive of `/var/lib/pacman/local`.
If later access is needed, untar the archive, and point pacman at that dir (e.g.: to get the package lists from an unrecoverable system). The archive includes the dirs leading up to the actual database, so if simple recovery is the goal, just untar at `/`. For accessing the database in other situations, it might be prudent to add `--strip-components=3` in order to get just the `local` subdir.
### Config
```
- Backup the database to this folder
target_folder=/home/thurstylark/.pkglists/$(hostname)/
- Define how long backups should be kept
- Can be a number of days or empty to disable
keep_days=
- Define how many backups should be kept
- If more backup are found, the oldest are deleted
- Can be a number of file or empty to disable
keep_number=1
```
This will keep only one copy of the database around, and delete all the others. Since they are being committed to a git repo, there's no need to keep several copies to have access to the history.
## Backing up
Once pakbak has created the archive, it is added, committed, and pushed to a vcsh git repo by a couple of systemd --user services. This is triggered by any change to the directory that pakbak writes its output to for that host. Activation of this process is handled by `pkglists-commit.path`:
```
[Unit]
Description=Path activation for pkglists-commit.service
[Path]
PathChanged=%h/.pkglists/%H
MakeDirectory=true
[Install]
WantedBy=default.target
```
This unit watches `$HOME/.pkglists/$HOSTNAME` for changes, and on any activity, activates `pkglists-commit.service`:
```
[Unit]
Description=Add, commit, and push pacman db backups
[Service]
Type=oneshot
RemainAfterExit=no
ExecStartPre=/usr/bin/bash -c 'wait $(pgrep pakbak)'
ExecStartPre=/usr/bin/vcsh pkglists pull
ExecStartPre=/usr/bin/vcsh pkglists add -A %h/.pkglists/%H/*
ExecStartPre=/usr/bin/vcsh pkglists commit -m "Auto-commiting %H pacman db"
ExecStart=/usr/bin/vcsh pkglists push
```
This service waits for pakbak to complete, pulls the pkglists repo, adds any changes to `$HOME/.pkglists/$HOSTNAME`, commits to the repo, then pushes. Thanks to `git-add`'s `-A` option, the add step also includes removal, so that git will remove the old database from the branch, which avoids the possibility of having multiple databases exist when pulling from or cloning the repo.
This is where the main magic happens that allows automatic distributed backups. For each host that has this set up, they also are housing the backups. The origin branch is _technically_ the canonical master, but since this is git, recovery is very easy to access from any machine. Also, since the trigger is literally any time pacman's local database changes (read: installation or removal of a package), the chances of all the clients having the latest revision of the repo becomes much higher.
## Caveats
- I'm not a big fan of using my own `systemd.path` unit since one is already provided by pakbak, but since A) this process deals with files in a home folder, and B) there isn't any forseeable situation where a `systemd --user` instance _won't_ be running when the database gets updated, I opted for `systemd --user` units to manage this part of the solution, and `--user` units can't depend on `--system` units. This could easily be fixed by installing a copy of pakbak's units to `/usr/lib/systemd/user/` in the `PKGBUILD` and running it from there.
- All of this could probably be replaced with my own `systemd --user` units or a pacman hook, but for the moment, I'm more concerned with getting it working.

View File

@ -0,0 +1,120 @@
---
title: "Xinitrc configuration"
description: "Moved to Sway"
author: "Thurstylark"
date: 2021-9-25
draft: false
---
Source: https://git.thurstylark.com/vcsh/xinitrc.git
----
## Preamble
The first few lines of my Xinitrc are from `/etc/X11/xinit/xinitrc`. They pull in different X configuration, and also run any scripts from `/etc/X11/xinit/xinitrc.d/`.
----
## Screen Locker
> *WARNING:* [Screen lockers on X11 are absolutely not secure!!](http://blog.martin-graesslin.com/blog/2015/01/why-screen-lockers-on-x11-cannot-be-secure/) Do not use a screen locker on X11 if you require high security!! [(in fact, you might want to reconsider even using x11 in the first place...)](http://theinvisiblethings.blogspot.com/2011/04/linux-security-circus-on-gui-isolation.html)
I lock my desktop using a combination of `i3lock(1)` and `xautolock(1)` with some help from `xset(1)` to change dpms timeout before and after locking:
```
screen_locker="xset dpms 0 0 10 dpms force off; i3lock --nofork -befc 000000; xset dpms 0 0 0"
locktime=30 # Default screen lock timeout in minutes
...
# Automatically lock after $locktime minutes using i3lock
xautolock -time $locktime -locker "$screen_locker" -detectsleep &
```
The locker is defined in `$screen_locker`, then used later along with `$locktime` to start `xautolock(1)`. When `$screen_locker` is run, the following happens:
1. DPMS timeout is set to 10 seconds
2. DPMS forces the display off now
3. i3lock is run with these options:
- `--nofork`: Don't fork to the background
- `-b`: Beep on incorrect password attempt
- `-e`: Ignore empty password
- `-f`: Show number of failed attempts, if any
- `-c 000000`: Background color should be `#000000`
4. When i3lock exits, DPMS timeout is set to 0 for never
Whenever I wish to lock the screen, I need only run `xautolock -locknow` making sure that `$DISPLAY` is set correctly. For example, my [i3](/misc/archive/i3/) config is set up to run that command for `Ctrl+Alt+l`.
Also note that the definition of `$screen_locker` and `$locktime` are separated from the invocation of `xautolock(1)` by all the host-specific configuration. This is to allow setting `$locktime` on a host-by-host basis. Given the first step of the locker is to use DPMS to turn the display off, this effectively sets the display sleep timeout to `$locktime`.
As far as power saving options go, `$screen_locker` _could_ be a little more general by using a variable for the last invocation of `xset(1)`, but I don't have a need for it.
----
## Srandrd
All display output configuration, touchscreen configuration, or any other configuration that should change based on display connectivity takes place in the `srandrd(1)` configuration. In fact, `~/.xinitrc` will completely abort if srandrd isn't installed. This makes display layouts and touchscreen easier to maintain in the long run.
The "configuration" can be any executable file which will be run with the environment variable `$SRANDRD_ACTION` set to a string formatted as `<output> <connected|disconnected|unknown>`, where `<output>` is the name of the output according to `xrandr(1)`. I use a bash script for this purpose.
### Script Summary
This script is set up to be one monolithic "configuration" for multiple hosts by using a case statement that tests against `$(hostname)` before attempting to handle `$SRANDRD_ACTION`. If multiple configuration files become necessary at some point, it would be trivial to break out each host's configurations into their own files and do something similar to `source ~/.config/srandrd/$(hostname).conf`, but it's not necessary for the time being.
Once the hostname is determined, I begin by setting a few variables with host-specific information. Setting these variables before handling `$SRANDRD_ACTION` is beneficial for situations where a software or hardware change might change any one of these values, in which case, the information will only need to be updated in one place instead of several places throughout the script.
Finally, `$SRANDRD_ACTION` is handled with a case statement. This section of the script can be arbitrarily complicated, but for my simple usage, every output that needs to be handled needs both a connected and disconnected case defined. In the most complicated case, I do 3 things: Run `xrandr(1)` to configure outputs, configure the touchscreen with `xinput(1)`, and set PulseAudio's default sink with `pacmd(1)`.
### Touchscreen Configuration
When using a touchscreen with multiple monitors, it is possible that the touchscreen will be mapped to cover the entire canvas instead of only the display to which it is attached. This results in situations where touch events on one side of the display will be close to accurate, but touch events on the other side of the display begin to manipulate the cursor on the 2nd display.
This is fairly easy to rectify using `xinput --map-to-output <device id> <output name>` where `<device id>` is the id number of the touchscreen as reported by `xinput list`, and `<output name>` is the xrandr name of the output you wish to map the touchscreen to.
This may seem easy enough to script by finding the device id once, then adding an appropriate line in `~/.xinitrc`, but the device id is not static, and may change between boots.
For this reason, it is more appropriate to match against an attribute of the device that will not change. In the case of `xinput(1)`, the best option for this situation is the device name. The device id can easily be found by running `xinput list --id-only <device name>`. This can easily be strung together with a subshell to do everything on one line. For instance, if you wish to map a device named `ELAN Touchscreen` to an output named `eDP-1`, the resulting line might look like the following:
```
xinput --map-to-output $(xinput list --id-only "ELAN Touchscreen") eDP-1
```
This command must be run after every time the display configuration changes, so it is possible that the command will need to exist several times in the `srandrd(1)` configuration. Since the only unique pieces of information between hosts will be the device name and the output name, it is easier to use a function instead of duplicating the same line over and over:
```
maptouchscreen() {
# maptouchscreen <name> <output>
local name="$1" # <name> should be a full name from the output of `xinput list`
local output="$2" # <output> should be an xrandr output name
xinput --map-to-output $(xinput list --id-only "$name") "$output"
}
```
This allows you to replace any instance of the full `xinput(1)` command with `maptouchscreen <device name> <output>`.
*Note:* If there are spaces in the device name, bash will glob the crap out of it, so be sure to double quote the device name when calling `maptouchscreen()`.
### PulseAudio Default Sink
I want the default PulseAudio sink to change to HDMI when HDMI is plugged in, and back to analog when disconnected.
Changing the default sink in pulse is as easy as running `pacmd set-default-sink <sink id>` where `<sink id>` is the id of the desired sink. Unfortunately, this is another situation where the id might change unexpectedly. We also don't have an easy interface to determine the id number from a name like we did with `xinput(1)`, so we're forced to parse the output of `pactl list sinks short` like so:
```
pacmd set-default-sink $(pactl list sinks short | grep "hdmi" | grep -o "^\S\+")
```
This command lists all sinks in short form, then greps for a line containing "hdmi", uses grep to only print the first character (the sink id), then sets the default sink with `pacmd(1)`. Since this will also need to be run any time the display configuration changes, a function is, again, appropriate:
```
setpasink() {
# setpasink <name>
# Find a unique string in the output of `pacmd list short` to use for <name>
pacmd set-default-sink $(pactl list sinks short | grep "$1" | grep -o "^\S\+")
}
```
This allows you to change the default PulseAudio sink with `setpasink <name>` where `<name>` is any arbitrary string that is unique to the line that corresponds to the desired sink in the output of `pactl list sinks short`.

View File

@ -0,0 +1,14 @@
---
title: "Audiobook RSS Feed"
description: "When you want to serve audiobooks like podcasts"
author: "Thurstylark"
date: 2021-9-25
draft: true
---
I want to serve my library of audiobooks as an RSS feed so that I can use my favorite podcast app as the player.
Packages used:
- python-pyrss2gen: RSS generation
- python-mutagen: metadata extraction

View File

@ -0,0 +1,194 @@
---
title: "Automating Android App Builds"
description: "Back when I thought I'd be using AsteroidOS all the time"
author: "Thurstylark"
date: 2021-9-25
draft: false
---
Goal: Get a compiled apk of [AsteroidOS Sync](https://github.com/asteroidos/AsteroidOSSync) from the latest git commit.
I wanted to do this without untracked software clutter on my main machine, so I decided to do it in a systemd-nspawn container on my home server. The container and build turned out better than I expected, so I went ahead with automating the whole setup to check daily for new commits, building the app if there is a new commit, and dumping it in a folder outside of the container.
## Setting up systemd-nspawn
Arch makes this step super easy with the `arch-install-scripts` package:
```prettyprint
- pacstrap -icd container/ base --ignore linux base-devel
```
- `-i`: Avoid auto-confirmation of package selections
- `-c`: Use the package cache on the host rather than the target
- `-d`: Allow installation to a non-mountpoint directory
- `container/`: Path to your desired container location
- `base --ignore linux base-devel`: Install the base and base-devel groups, ignoring the `linux` package. The kernel is not necessary inside this container, so might as well save the bandwidth
This will get you a container with the latest packages ready to spin up. After that, all you need to do is:
```prettyprint
- systemd-nspawn -bD container/
```
This will boot the container and leave you at a login prompt. For Arch, root will be passwordless. Start here, and configure your new container for what you need. For my setup, I created an unprivileged user, added my `~/.bashrc` and `~/.vimrc`, and installed the android-sdk package from the AUR.
Next, we need to automate bringing the new container up with a systemd service. Easiest way to get a service ready for a systemd-nspawn is to use the existing systemd-nspawn@.service, and tweak it for this specific use. To get a copy of this unit and start editing it right away, run `systemctl edit --full systemd-nspawn@containername.service`. This is the end product of my unit:
```
# /etc/systemd/system/systemd-nspawn@asteroid.service
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Container %i
Documentation=man:systemd-nspawn(1)
PartOf=machines.target
Before=machines.target
After=network.target
[Service]
ExecStart=/usr/bin/systemd-nspawn --quiet --keep-unit --boot --link-journal=try-guest -U --settings=override --machine=%i -D /storage/containers/asteroid/sync-app/ --bind=/storage/containers/asteroid/output:/home/thurstylark/output
KillMode=mixed
Type=notify
RestartForceExitStatus=133
SuccessExitStatus=133
Slice=machine.slice
Delegate=yes
TasksMax=16384
# Enforce a strict device policy, similar to the one nspawn configures
# when it allocates its own scope unit. Make sure to keep these
# policies in sync if you change them!
DevicePolicy=closed
DeviceAllow=/dev/net/tun rwm
DeviceAllow=char-pts rw
# nspawn itself needs access to /dev/loop-control and /dev/loop, to
# implement the --image= option. Add these here, too.
DeviceAllow=/dev/loop-control rw
DeviceAllow=block-loop rw
DeviceAllow=block-blkext rw
[Install]
WantedBy=machines.target
```
The only things changed from the original are all in `ExecStart=`:
- `-D /storage/containers/asteroid/sync-app/`: Boot the nspawn from a directory instead of from an image, and the path to that directory
- `--bind=/storage/containers/asteroid/output:/home/thurstylark/output`: Create a bind mount between the host and the container. The format is `/host/dir:/container/dir` where `/container/dir` is specified with `/` at the root of the container, not of the host.
- Removed `--network-veth` to use the networking from the host instead of creating a virtual ethernet link.
Check the systemd-nspawn manpage for more info.
To start your container, run `systemctl start systemd-nspawn@containername.service`. Confirm it's running with `machinectl list` and `systemctl status systemd-nspawn@containername.service`.
### Reference
- https://wiki.archlinux.org/index.php/Systemd-nspawn
----
## Interacting With Your New Container
When your systemd-nspawn is booted, most interaction is done using `machinectl(1)`. I will only be covering what's necessary for this setup. Check machinectl's manpage for more detailed info.
To get a shell:
```
# machinectl shell user@containername
```
This will bypass the login prompt, and start user's shell. If no user is specified, you will be logged in as root.
The actual building is done by a script in the container. This means we need either a) a way to execute that script from outside the container, or b) put the script on a timer within the container. Since I don't want the container running the whole time, I opted for option A. This allows the machine to be started and stopped as necessary.
To execute the script from outside the container:
```
# machinectl shell user@containername /path/to/script
```
Note: This path is relative to the root of the container, not of the host.
All that's left is to make a service unit for this command. Here's how my unit stands at the time of writing:
```
# /etc/systemd/system/build-aos-sync.service
[Unit]
Description=Build latest commit of AsteroidOS Sync
Requires=systemd-nspawn@asteroid.service
After=systemd-nspawn@asteroid.service
[Service]
Type=oneshot
ExecStart=/usr/bin/machinectl shell thurstylark@asteroid /home/thurstylark/buildapp.sh
```
This unit is set up to boot our container automatically by using `Requires=` and `After=`. This way, we don't have to manage how our container is started. This also enables us to manually trigger a build by starting this unit.
The last part of the actual automation is done with a timer for our new service. It doesn't have to be super complicated, but you can tweak it how you like it:
```
# /etc/systemd/system/build-aos-sync.timer
[Unit]
Description=Timer for automated AsteroidOS Sync build
[Timer]
OnCalendar=daily
[Install]
WantedBy=timers.target
```
This timer is set for `OnCalendar=daily`, which will trigger every day at midnight. When the timer triggers, it will start our service, which will start our container if it's not already started, then it will run our build script. More options for this timer can be found in the `systemd.timer` manpage.
----
## Build Script
The last peice of the puzzle for this is to actually compile the app in question. Before any of this can be done or tested, your Android build environment should be set up. Check the Android Building page for more info.
Here's the script I ended up with:
```
#!/bin/bash
pkgname=asteroid-os-sync
project_root=/home/thurstylark/AsteroidOSSync
bind_mount=/home/thurstylark/output
output=$project_root/app/build/outputs/apk/app-debug.apk
build_app() {
# Reference: https://developer.android.com/studio/build/building-cmdline.html
cd $project_root
git remote update
if [[ "$(git rev-parse @)" == "$(git rev-parse @{u})" ]]; then
echo "App up to date." >&2
exit 0
else
git pull origin master
rm -r app/src/main/res/values-ca-rES@valencia/
ANDROID_HOME=/opt/android-sdk ./gradlew assembleDebug
fi
copy_output
}
pkgver() {
cd $project_root
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
}
copy_output() {
cp ${output} ${bind_mount}/${pkgname}-$(pkgver).apk
}
build_app
```
This script is not incredibly intelligent, but it gets the job done. One thing to point out is the test on line 11. This if statement checks whether our local copy of the git repo is up to date. If it's up to date, the script exits with a little message. This way we are only building if there are changes to be built.
I also use `copy_output()` to rename the resulting apk with the revision number and short commit id (compiled using `pkgver()`) for clarity.

View File

@ -0,0 +1,4 @@
---
title: "Thurstylark-VPS"
description: "Just a little Linode VPS running Arch, but it's a powerful little sucker."
---

View File

@ -0,0 +1,79 @@
---
title: "Cgit"
description: "And automatic config deployment on git push"
author: "Thurstylark"
date: 2021-9-25
draft: false
---
Current configuration can always be found at https://git.thurstylark.com/cgit.git/tree
### Push To Deploy
The remote repo is set up to deploy the entire contents of the repo to `/srv/cgit` by using the `post-receive` hook in the git repo.
```
#!/bin/bash
GIT_WORK_TREE=/srv/cgit git checkout -f
```
This allows configuration changes to be edited on a local repo, committed, then pushed to the remote to apply changes.
### About Page
Had a problem with the about page not showing when the appropriate file names are definied as readme files. Here was the problematic config:
```Cprettyprint linenums
#css=/cgit-css/cgit.css
#logo=/cgit-css/cgit.png
root-title=Thurstylark
root-desc=Projects and Dotfiles
source-filter=/srv/cgit/syntax-highlighting.py
about-filter=/usr/lib/cgit/filters/about-formatting.sh
enable-git-config=1
scan-path=/srv/git
enable-http-clone=1
clone-url=https://git.thurstylark.com/$CGIT_REPO_URL
#
# Search for these files in the root of the default branch of repositories
# for coming up with the about page:
#
readme=:README.md
readme=:readme.md
readme=:README.mkd
readme=:readme.mkd
readme=:README.rst
readme=:readme.rst
readme=:README.html
readme=:readme.html
readme=:README.htm
readme=:readme.htm
readme=:README.txt
readme=:readme.txt
readme=:README
readme=:readme
readme=:INSTALL.md
readme=:install.md
readme=:INSTALL.mkd
readme=:install.mkd
readme=:INSTALL.rst
readme=:install.rst
readme=:INSTALL.html
readme=:install.html
readme=:INSTALL.htm
readme=:install.htm
readme=:INSTALL.txt
readme=:install.txt
readme=:INSTALL
readme=:install
```
The solution was to move the `scan-path` directive to the end of my cgitrc. See the [cgitrc manpage](https://git.zx2c4.com/cgit/tree/cgitrc.5.txt#n392) for details.

View File

@ -0,0 +1,100 @@
---
title: "LetsEncrypt"
description: "Usage of certbot, and relevant info for Apache configuration"
author: "Thurstylark"
date: 2021-9-25
draft: false
---
## Certbot Usage
Create a cert using the interactive menu:
```
# certbot certonly
```
## Automating Renewal
LetsEncrypt Certs are good for a max of 90 days, so automating renewal is a must.
Do a dry-run renewal with certbot:
```
# certbot renew --dry-run
```
This will test, and possibly renew all certs that certbot knows about
Now you can use `certbot renew --quiet` for scripting this renewal. I do mine with a simple systemd script:
```
# /etc/systemd/system/certbot.service
[Unit]
Description=Let's Encrypt renewal
[Service]
Type=oneshot
ExecStart=/usr/bin/certbot renew --quiet --agree-tos
ExecStartPost=/bin/systemctl reload httpd.service
```
## Apache Configuration
There's a couple of considerations when using ssl certs with Apache. The first is to enable the appropriate modules in httpd.conf:
```
LoadModule ssl_module modules/mod_ssl.so
LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
```
Also, make sure to configure apache to listen on port 443:
```
Listen 443
```
That will get the basic framework ready for your virtualhost definition. Here is a very simple virtualhost configuration:
```
<VirtualHost wiki.thurstylark.com:80>
ServerName wiki.thurstylark.com
DocumentRoot "/srv/wiki/"
<Directory "/srv/wiki/">
AllowOverride None
Options None
Require all granted
</Directory>
# Redirect all except the '.wellk-known' path to https.
# This allows automated renewal of ssl certs by certbot
RedirectMatch permanent ^/(?!\.well-known)(.*) https://wiki.thurstylark.com/$1
</VirtualHost>
<VirtualHost wiki.thurstylark.com:443>
ServerName wiki.thurstylark.com
ServerAdmin thurstylark@gmail.com
DocumentRoot "/srv/wiki/"
<Directory "/srv/wiki/">
AllowOverride None
Options None
Require all granted
</Directory>
SSLEngine on
SSLCertificateChainFile "/etc/letsencrypt/live/wiki.thurstylark.com/fullchain.pem"
SSLCertificateKeyFile "/etc/letsencrypt/live/wiki.thurstylark.com/privkey.pem"
</VirtualHost>
```
A couple things to note here: First, this defines two virtualhosts, one for port 80 and one for port 443. This is in order to redirect _all_ traffic to HTTPS except for a very small exception.
This exception is what you see on line 12 in the code above. Only `*/.well-known/*` is not redirected because this is the dir that certbot uses for domain validation. Certbot will only validate over http, and will fail if given a 301 redirect. This allows validation to complete successfuly without a configuration change, thus aiding our automation efforts. Everything else gets a 301 redirect to HTTPS. Be sure to define `DocumentRoot` with the correct location for *both* VirtualHosts, or certbot will fail to renew things correctly. (found this one out the hard way)
Lines 28-29 configure Apache to look for the necessary files in the right places. The locations listed here are actually symlinks to the real files, which are kept in an archive. These links are maintained by certbot automagically.
To obtain new certs for a subdomain, copy this config to `/etc/httpd/conf/extra/`, update the config with the appropriate subdomain name, comment out lines 5-29 to disable the redirect and ssl configuration, and add an include in the main httpd.conf. Once that is all set up, you can run certbot to obtain new certs. Once certbot is finished, you can remove the comments, restart httpd, and begin testing.

View File

@ -0,0 +1,142 @@
---
title: "Vimwiki"
description: "Using vimwiki to generate a static html site"
author: "Thurstylark"
date: 2021-9-25
draft: true
---
Source: https://git.thurstylark.com/vimwiki.git/
## Features
- All content is stored in a git repo as vimwiki content (to avoid having to sync HTML content as well)
- All content automatically converted to HTML and moved to the appropriate directory when the git repo is pushed
- [Template](https://git.thurstylark.com/vimwiki.git/tree/html-template/index.html) based on bootstrap, so theming/building the template is easy peasy
## Table tweaks
Tables without any styles are gross, so let's use the styles from Bootstrap. Problem is that Vimwiki doesn't provide a way to add a class to a table element, so we'll do it with JQuery:
```prettyprint
<head>
...
<script>
$(document).ready(function(){
$("table").addClass("table table-condensed table-hover");
});
</script>
...
</head>
```
This adds `.table`, `.table-condensed`, and `.table-hover` classes to every table element in the whole document. Don't see why it should be any other way for the moment.
### References
- http://stackoverflow.com/a/39897883
- http://www.w3schools.com/jquery/jquery_syntax.asp
## HTML Checkboxes
By default, there is no difference between how a non-checkbox list item, unchecked list item, and a checked list item are displayed when exported to HTML.
There are 5 states of a checkbox, 0-4, and they each represent a different level of completeness. This is mainly for checklist items with children.
Checkbox states:
| State * | % Complete | li class | Unicode character | Escape sequence | HTML code |
|---------|------------|----------|-------------------|-----------------|------------|
| 0 | 0% | `done0` | ◯ | `\u25EF` | `&#9711;` |
| 1 | 1-33% | `done1` | ◔ | `\u25D4` | `&#9684;` |
| 2 | 34-66% | `done2` | ◑ | `\u25D1` | `&#9681;` |
| 3 | 67-99% | `done3` | ◕ | `\u25D5` | `&#9685;` |
| 4 | 100% | `done4` | ✔ | `\u2714` | `&#10004;` |
Now, in order to use these in our HTML, we just have to write a style for `ul li.doneX:before` in our header like so:
```
<style>
ul li.done0:before {content: '\25EF';}
ul li.done1:before {content: '\25D4';}
ul li.done2:before {content: '\25D1';}
ul li.done3:before {content: '\25D5';}
ul li.done4:before {content: '\2714';}
</style>
```
Now here's a few test lists:
- [ ] Unfinished item
- [X] Finished item
- [ ] Parent item 1
- [X] Child item 1
- [ ] Child item 2
- [ ] Child item 3
- [ ] Child item 4
- [ ] Parent item 2
- [X] Child item 1
- [X] Child item 2
- [ ] Child item 3
- [ ] Child item 4
- [ ] Parent item 3
- [X] Child item 1
- [X] Child item 2
- [X] Child item 3
- [ ] Child item 4
- [X] Parent item 4
- [X] Child item 1
- [X] Child item 2
- [X] Child item 3
- [X] Child item 4
- [ ] Parent item 5
- [ ] Child item 1
- [ ] Child item 2
- [ ] Child item 3
- [ ] Child item 4
## Push to Deploy
The easiest way to manage this wiki, and also allow it to be hosted, is to commit all the wiki documents to a repo, and script the deployment to the wiki's webroot using git's post-receive hook. The origin remote repo also hosts the http server, so it makes things simple. Less simple because it requires a vim plugin to compile the HTML files, but it's still doable.
First part of this solution is the vimrc for the remote machine. This sets the destination for the final html files, the origin wiki files, and the html template page.
```
set nocompatible
filetype plugin on
syntax on
let g:vimwiki_list = [{
\ 'path': '/tmp/vimwiki/',
\ 'path_html': '/srv/wiki/',
\ 'template_path': '/tmp/vimwiki/html-template',
\ 'template_default': 'index',
\ 'template_ext': '.html'}]
```
Note: lines 1-3 are required for vimwiki to work correctly with the post-receive hook. The rest of the config are options for vimwiki directly.
The post-receive hook is a fairly simple bash script. This script is located at `~/git/vimwiki.git/hooks/post-receive`, and is run every time the repo receives a push from downstream.
```
#!/bin/bash
mkdir /tmp/vimwiki
export GIT_WORK_TREE=/tmp/vimwiki
export GIT_DIR=/home/thurstylark/git/vimwiki.git
git checkout -f
vim -u /tmp/vimwiki/html-template/srv-vimrc -c VimwikiAll2HTML -c q /tmp/vimwiki/index.wiki
cp /tmp/vimwiki/html-template/slate.bootstrap.css /srv/wiki/
rm -rf /tmp/vimwiki
```
It first makes a directory under /tmp for the contents of the repo, sets `$GIT_WORK_TREE` and `$GIT_DIR`, and does a `git checkout` for all the files in the repo.
Line 9 is where the magic happens. This line runs vim with the vimrc from above, and runs the `:VimwikiAll2HTML` command.
Next, the script copies over the one CSS file that I need to host myself, and lastly, it cleans up the temp dir.

View File

@ -0,0 +1,211 @@
---
title: "Weechat"
description: "Because lurking is the best"
author: "Thurstylark"
date: 2021-9-25
draft: false
---
Current configuration can always be found at https://git.thurstylark.com/vcsh/weechat.git
##Requirements:
- Not dependent on graphical session (terminal-based client)
- Use only one nick during normal operation
- Use multiple computers interchangeably at random
- Do not require a close/quit process to move between workstations
- Reduce the ammount of join/part messages caused by me
- Be reachable through IRC as much as possible (stay online)
- Have the ability to use a mobile app at will
The best option so far is weechat run in a multiplexer like tmux.
----
## Starting Weechat
Easiest way to get this done is to start weechat at boot with a systemd system service:
```
[Unit]
Description=Start Weechat as relay and client
[Service]
Type=forking
User=thurstylark
Group=thurstylark
ExecStart=/usr/bin/tmux -f /home/thurstylark/.config/srv-tmux.conf new-session -ds weechat weechat
[Install]
WantedBy=multi-user.target
```
### Notes
- When starting tmux with `new-session -d` as its command, tmux forks to the background, thus requiring `Type=forking` in order to let systemd keep track of the process.
- I run this service as my user and group, because I use the default locations for weechat config: `~/.weechat/`. This greatly simplifies weechat configuration.
- tmux configuration needs to be passed to tmux by using `-t /path/to/config`. Full path is used just to be thorough.
----
## Configuring tmux
tmux needs a configuration to disable the status bar, visual bell, and other things that won't be useful in this setup.
```
set -g default-terminal "screen-256color"
set-option -g assume-paste-time 1
set-option -g base-index 1
set-option -g pane-base-index 1
set-option -g default-command ""
set-option -g default-shell "/bin/bash"
set-option -g destroy-unattached off
set-option -g detach-on-destroy on
set-option -g display-panes-active-colour red
set-option -g display-panes-colour blue
set-option -g display-panes-time 1000
set-option -g display-time 750
set-option -g history-limit 10000
set-option -g word-separators " -_@"
set-option -g renumber-windows off
set-option -g repeat-time 500
set-option -g set-remain-on-exit off
set-option -g set-titles off
set-option -g set-titles-string "#S:#I:#W - "#T" #{session_alerts}"
set-option -g status off
- Change prefix to C-a
set-option -g prefix C-a
set-option -g status-style fg=black,bg=cyan
set-option -g message-command-style fg=green,bg=black
set-option -g message-style fg=white,bg=red
set-option -g update-environment "DISPLAY SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID SSH_CONNECTION WINDOWID XAUTHORITY"
- Set audible bell on, and visual bell off because it is slooooowwwww
set-option -g bell-action any
set-option -g bell-on-alert on
set-option -g visual-bell off
set-option -g visual-silence off
set-option -g visual-activity off
- Pane active colors
set-option -g pane-active-border-style fg=cyan,bright
- Pane inactive colors
set-option -g pane-border-style fg=colour8
- Use C-a,Shift-R to reload configuration
bind R source-file ~/.tmux.conf \; display-message "Config reloaded..."
- Use C-a,a to send prefix to nested session
bind-key a send-prefix
- Use Alt-arrow keys without prefix key to switch panes
bind -n M-Left select-pane -L
bind -n M-Right select-pane -R
bind -n M-Up select-pane -U
bind -n M-Down select-pane -D
- Do the same for HJKL
bind -n M-h select-pane -L
bind -n M-l select-pane -R
bind -n M-k select-pane -U
bind -n M-j select-pane -D
- No delay for escape key press
set -sg escape-time 0
- Various copy mode tweaks
bind-key -t vi-copy Home start-of-line
bind-key -t vi-copy End end-of-line
- Sync copy mode and PRIMARY selection
bind-key -t vi-copy MouseDragEnd1Pane copy-pipe "xsel -i -p -b"
bind-key -t vi-copy Enter copy-pipe "xsel -i -p -b"
bind-key -t vi-copy y copy-pipe "xsel -i -p -b"
```
### Usage
I will usually use this within yet another tmux session, so I end up needing to set up some key bindings to control the differrent sessions
- `C-a a`: Send prefix to the terminal
- `C-a a d`: Disconnect the nested session from this client.
- `C-a a :`: Get command prompt on nested session
----
## Weechat Relay
Here are all the options related to weechat relay:
```
[cmd] (alias.conf)
alias.cmd.norelay = "/buffer set localvar_set_relay hard-hide"
[look] (relay.conf)
relay.look.auto_open_buffer = off (default: on)
relay.look.raw_messages = 256
[color] (relay.conf)
relay.color.client = cyan
relay.color.status_active = lightblue
relay.color.status_auth_failed = lightred
relay.color.status_connecting = yellow
relay.color.status_disconnected = lightred
relay.color.status_waiting_auth = brown
relay.color.text = default
relay.color.text_bg = default
relay.color.text_selected = white
[network] (relay.conf)
relay.network.allow_empty_password = off
relay.network.allowed_ips = ""
relay.network.bind_address = "127.0.0.1" (default: "")
relay.network.clients_purge_delay = 0
relay.network.compression_level = 6
relay.network.ipv6 = off (default: on)
relay.network.max_clients = 5
relay.network.password = "letmein" (default: "")
relay.network.ssl_cert_key = "%h/ssl/relay.pem"
relay.network.ssl_priorities = "NORMAL:-VERS-SSL3.0"
relay.network.websocket_allowed_origins = ""
[irc] (relay.conf)
relay.irc.backlog_max_minutes = 1440
relay.irc.backlog_max_number = 256
relay.irc.backlog_since_last_disconnect = on
relay.irc.backlog_since_last_message = off
relay.irc.backlog_tags = "irc_privmsg"
relay.irc.backlog_time_format = "[%H:%M] "
[port] (relay.conf)
relay.port.weechat = 9001 (default: 0)
```
### Notes
- `alias.cmd.norelay = "/buffer set localvar_set_relay hard-hide`
- Creates the `/norelay` command which is used to hide a buffer from being relayed to any relay client. This is mainly for stopping a buffer from alerting me on mobile.
- `relay.look.auto_open_buffer = off`
- Keeps weechat from opening a buffer with superfluous information every time a client connects or disconnects
- `relay.network.bind_address = "127.0.0.1"`
- Weechat will only accept relay connections from localhost. This means any relay client that wishes to connect will need to tunnel over ssh first, then connect to the relay. Luckily for me, weechat-android does this natively.
- `relay.port.weechat = 9001`
- The relay client will want to know this.
### Reference
- https://weechat.org/files/doc/stable/weechat_user.en.html#relay_plugin
----
## Workstation Client
By far, the most use of weechat will be from a workstation. With this setup, the only requirements of the client is ssh or mosh. I prefer mosh in this case because of it's reconnect capabilities, making it much less painful to keep a session running on a mobile workstation.
Also, the easiest way to launch this connection is to run literally `weechat`, so I set up a couple aliases for this in my `~/.bashrc` (found [here](https://git.thurstylark.com/vcsh/bashrc.git/tree/.bashrc)):
```
# If you don't have weechat installed, connect to the existing tmux session through mosh
[[ ! -s /usr/bin/weechat ]] && alias weechat='mosh vps -- tmux attach -dt weechat'
# If you are thurstylark-vps, connect to the existing tmux session locally
[[ "$HOSTNAME" = "thurstylark-vps" ]] && alias weechat='tmux attach -dt weechat'
```
This gets run when bash starts, so this allows me to use the same `~/.bashrc` on the client and the server. More details on the Bash page.
The only thing not noted is that if the client has weechat installed (to /usr/bin/weechat) and `$HOSTNAME` is not "thurstylark-vps", an alias for 'weechat' will not be created, and weechat will launch normally.

20
misc/links-of-infamy.md Normal file
View File

@ -0,0 +1,20 @@
---
title: "Links of Infamy"
description: "A link dump of things I find truly amazing"
author: "Thurstylark"
date: 2021-9-25
draft: false
---
- [How to properly run a community.](https://wiki.archlinux.org/index.php/Code_of_conduct)
- [How to properly automate yourself out of a job.](https://github.com/NARKOZ/hacker-scripts)
- [How to properly file a bug report.](https://github.com/chrislgarry/Apollo-11/issues/3)
- [How to properly troubleshoot networking equipment.](https://tools.ietf.org/html/rfc2321)
- [How to properly manage your distro's infrastructure.](http://web.archive.org/web/20150409040851/https://manjaro.github.io/expired_SSL_certificate/)
- [How to properly learn from your mistakes.](https://web.archive.org/web/20160811103932/https://manjaro.github.io/SSL-Certificate-Expired/)
- [How to properly install Gentoo](http://www.bash.org/?464385)
- [How to properly answer useless questions that get asked repeatedly.](http://stackoverflow.com/a/1732454)
- [How to properly appreciate the number five.](https://github.com/jackdcrawford/five)

5
projects/_index.md Normal file
View File

@ -0,0 +1,5 @@
---
title: Projects
draft: false
hide: true
---

View File

@ -0,0 +1,5 @@
---
title: Stream
draft: false
hide: false
---

View File

@ -0,0 +1,57 @@
---
title: "Stream Ideas"
description: "Ideas for stream content"
author: "Thurstylark"
date: 2021-11-21
draft: false
hide: false
---
## Continual
- Lurk in chatrooms
- libera.chat
- #archlinux
- ##linux
- Matrix
- #archlinux:archlinux.org
- [Troll the forums](https://bbs.archlinux.org/)
- [Unanswered posts](https://bbs.archlinux.org/search.php?action=show_unanswered)
- Argue on reddit
- [/r/archlinux](https://reddit.com/r/archlinux)
- [Keep AUR packages updated](https://aur.archlinux.org/)
- Find more to adopt (suggestions welcome!)
## Projects
- Teach myself Ansible
- https://www.ansible.com/resources/get-started
- Easy learner targets:
- tlwiki
- weechat+tmux setup
- aurutils repo
- archinstall remote profile
- Create OBS remote webapp
- Teach myself Websockets
- To replace StreamControl app
- Tweak wiki theme
- Change ul bullet characters
- Also figure out why YNH hosting mangles current ul characters?
- Headings
- larger text size based on H level
- more spacing between previous block and header
- Larger content container
- #page grid?
- Colors
- #0088cc Blue highlight
- #333333 Dark Grey
- #cccccc Max white (text?)
- mostly light text on greys with #08c highlights
- Tweak vim config
- tab stop
- use spaces
- clean the fuck up

View File

@ -0,0 +1,5 @@
---
title: Videos
draft: false
hide: false
---

5
ramblings/_index.md Normal file
View File

@ -0,0 +1,5 @@
---
title: Ramblings
description: "Non-technical musings, rants, or other such tomfoolery"
weight: 80
---

View File

@ -0,0 +1,16 @@
---
title: "If I was wrong, click here"
description: "Criticism Required"
author: "Thurstylark"
date: 2021-9-25
draft: true
---
# Criticism Required
## Notes
> The billionaire wants to explain to us that what might look like the steady hoarding of wealth and a feudalistic imbalance of power is, in fact, the product of defensible moral choices and a fair system. As Max Weber noted, “the fortunate is seldom satisfied with the fact of being fortunate” but wants to know that “he has a right to his good fortune,” and that it is “legitimate fortune.”
> - https://www.currentaffairs.org/2021/01/how-billionaires-see-themselves

5
ramblings/lgbt/_index.md Normal file
View File

@ -0,0 +1,5 @@
---
title: "LGBTQ+"
description: "On sexuality, gender, and other queer shit"
draft: false
---

View File

@ -0,0 +1,73 @@
---
title: "Should I come out while still questioning?"
description: "Adolescence, fluidity, and communicating your truth"
author: "Thurstylark"
date: 2021-9-25
draft: false
---
This began life as a reply to someone on /r/questioning, but decided to archive it for myself.
## Prompt
(Paraphrasing to anonymize)
OP (17, she/her) had been questioning her sexuality for a while, and has privately used a few different labels along the way, but still remained kind of confused about her identity. She had planned on coming out to her family once sure of her labels, but she's slowly coming to the realization that this might take some many years to fully flesh out. She wants to be open about her sexuality to friends and family, but even though they are generally supportive of the LGBTQ+ community, she feels it may still be complicated to explain certain concepts to some individuals.
OP's main question: "Is it a possibility to come out although I'm not sure of my labels yet? At the moment, I would most likely come out as simply "not heterosexual" and questioning. Also, since I'm fairly nervous about this, would it be ok to do this in writing, or should I only do this face-to-face? Should I wait until I've stopped questioning?"
## Response
IMO, identifying as questioning is such a power move.
"Good luck trying to shove me in one of your stupid boxes while even *I* don't know what the hell is going on in here!"
Labels can be tricky when the landscape seems to keep shifting like this, but I have two main ideas on this front:
### 1. On Adolescence
Teen years suck in countless ways, but they also come with a neat perk: ***Nobody expects you to have your shit together yet.*** Those younger than you will look up to you by default, those older than you have been through it and understand, and your peers are busy dealing with their own shit. You have the benefit of a few years of life with bumpers where you're ~~allowed~~ *expected* to figure out who you are, often via trial-and-error.
Salty adults can complain all they want about a teenager going through a "phase," but we only call it that because when we try to remember our *own* teenage years, it reminds us of all the ways that our teenage selves needed improvement in order to become who we are today. It's human nature to change and adapt, and teen/early adult years are often one's first and most substantial opportunity to make those changes based on *internal* motivation as opposed to *external* motivation like a parent, guardian, teacher, etc.
Guess what: When a human with little life experience and a newly-discovered personal agency is given the opportunity to make changes to themselves, they make uninformed decisions. Every single adult on this planet has made a bad decision in their teenage years, and learned from it. C'est la vie. The important part of this process is that when we make a misstep like this, we come out of it with lessons about what not to do next time. This is how adults are forged from the pressure-cooker of puberty, and we all go through it, whether we want to acknowledge that reality or not.
The only reason that adults label this as a "phase" is because when adults cast their mind back to their own lessons, they come to the incorrect conclusion that they *shouldn't have made that decision in the first place.* This makes a little sense when considering that this conclusion *is* the lesson they took from the experience, but how else were they to learn that lesson if not for experience? Life doesn't come with a manual or textbook to learn from, so how else are teenagers supposed to figure out how they want to dress or who they want to hang out with, or what they want to do with their life??
We *all* learn via experience during puberty, and your parents are no exception.
### 2. On Labels and Questioning
*A label is not a template for behavior. It's a tool used to communicate your particular brand of awesome to others.* You are you, pick a label that fits. (or don't, whatever)
This isn't to say that labels are unimportant, though. At the very least labels provide a useful shorthand for things that are complicated or abstract (see: bisexuality vs pansexuality), so there's definitely an argument for their practicality. The point is that *your you-ness* should inform your label choice, and not the other way around.
This is why I think identifying as questioning is so cool. You can't get any more honest than openly admitting that you don't know shit and are still figuring it out :D
Alright, out of my soliloquy, and back to your thing :P
### Communicating Your Truth
Is it a possibility to come out although I am not sure of my labels yet?
As each person on earth is wholely unique, I would argue that there's currently around 7 billion different possible sexualities out there. Who you are, who you like, and the reasoning/motivation for any of these things are fully unique to you alone, which means that you happen to be *literally the only human on the face of the planet* with enough information to determine what label fits you best.
This goes both ways, too. You are the only one who can determine which labels *do* fit, but the same goes for labels that *don't* fit. If heterosexuality no longer fits you, that conclusion is equally entirely valid.
On that same coin, choosing to use no labels is just as valid, and so is picking a label but choosing to keep it private.
should I wait until I stopped questioning?
No. All humans change, and sexuality is not exempt. If you're feeling strongly about letting people know your labels, then that's a good enough reason in itself. If your attraction happens to change later on, that change is also valid, as is your choice of new labels
do you think that I should use a letter to come out?
IMO, whether you end up using it or not, write the letter anyways. When I have tangled, shifting, or abstract thoughts that don't lend themselves to easy explanation, I find that the process of taking hold of them and translating them into words helps *my own* understanding. Even if nobody reads what I write, I come away with a better idea of what I'm feeling, which parts are the most important to communicate, and how they can be worded.
If you end up with a letter you're happy with, I think it's a great way to deal with the nerves involved with face-to-face convos. A letter involves a great deal more time and effort than just words on a page, and I think your parents will definitely understand that :)
Above all else, remember that the way others respond to this information is ultimately filtered through *their* emotions, and is more of a reflection of *their* perspective. Whether the result is positive or negative, you are simply putting the information out there (as is your prerogative), and it is *their* responsibility to deal with it. There can be wider practical concerns (cases where parental withdrawal is likely, for instance), but on the general social front: you are not responsible for how other people handle the information you provide.
However you choose to come out, I wish you all the best :)

View File

@ -0,0 +1,3 @@
---
title: "On Gender"
---

View File

@ -0,0 +1,46 @@
---
title: "Am I faking being trans?"
description: "And who is the authority on my identity anyways?"
author: "Thurstylark"
date: 2021-9-25
draft: false
---
This began life as a reply to someone on /r/questioning, but I later came to realize that I was actually writing to myself.
## Prompt
(paraphrasing to anonymize)
OP expressed that they had recently begun feeling like he/him didn't quite fit, and had started talking to their non-binary friends about their feelings. Unfortunately, OP received some pushback from those friends because, they had felt NB all their life, and the process of discovery for them was mainly focussed on finding the language to express as much, so these friends began assuming that OP was faking it.
OP's main question was: Is it possible that I'm just faking how I feel? That they're right and I'm just making it up in my mind to fit in with my friends?
## Response
Labels aren't a template for behavior. They're a tool used to communicate your particular flavor of awesome to others. You are you, pick a label that fits (or don't, whatever).
There are 7 billion unique people on this earth, and we haven't developed mind-reading tech yet, so that leaves *you* as the only person who is physically capable of living your life, feeling your emotions, and experiencing your gender. Nobody else knows exactly what's going on in your head, and the only way we can learn is if you tell us.
That doesn't always happen perfectly, though. Sometimes the right words don't exist, sometimes the words come out wrong, sometimes both of those go exactly right, and the other party ends up misinterpreting what was said... This can affect what others understand about what you're trying to communicate, but none of that changes this one simple fact:
### *You* are the ultimate source of information about *yourself*
So, are you cis? How the fuck should I know? I don't live your life. You're cis if you say so. You're bi if you say so. You are who you say you are, because nobody else has a better source of information about you than you do.
Put another way: What if you're faking being *cis?* What if you were never cis from the get-go, but you've been "faking it" as your assigned gender for your whole life because that's all that you've been allowed to think until now? What if this means that, since you have no experience with a label that accurately reflects your gender identity (internal), you therefore don't know what it's like to *not* fake your gender expression (external)? What if it feels like or sounds like "faking it" because you've been faking an *incorrect* gender this whole time, and simply don't know what it feels like to truly identify with your label because it was given to you at birth based on your genitals instead of you choosing your label based on how accurately it reflects your reality?
### Change is life
Additionally: Human nature is to change, and neither sexuality or gender are exempt from that by any means. Knowing for certain that one label fits you for any amount of time does not mean that you're stuck with it until you die. Changing your label is just as valid as changing your haircut or your clothes. Both of these are also external expressions of internal taste in style, why would the rules for your taste in romance or sex be any different?
If your gender changes, and you decide to change your labels to match, that's it. Any resistance you receive for communicating this information to others is laughably pointless. What are they gonna do, try to *persuade* your experience into compliance??
### Communicating your truth
Remember, You aren't responsible for how others react to information that you provide. You are simply putting it out there, and any reaction to that news is ultimately a reflection of *their* thoughts and emotions through the lens of *their* experience and bias. Your life and experience isn't affected by whether they choose to respect you by accepting information from the primary source (you) as truth, or if they choose to live in their own reality by denying it. You continue to be you, they continue to be them, and the planet continues to spin.
I realize that you may not be in a place to directly confront your friends about how they discuss sexuality and gender, but I would encourage you to push back on the idea that you're "faking" something. You are welcome to accept others' perspective, but *they* are as much of an authority on *your* gender as *you* are on *theirs.* Just because they know what it's like to experience *their* gender doesn't mean that they know what it's like to experience *your* gender.
The short version of this story is this: Your friends have shared information about their experience that they expect *you* to respect, but they did not to afford *you* the same respect when you decided to express similar information. That's rude and inconsiderate, and it's perfectly appropriate for you to ~~ask~~ ~~expect~~ *demand* them to respect your gender expression (however fluid or unresolved it might be), just the same as *they* have asked of *you*.

View File

@ -0,0 +1,19 @@
---
title: "On Labels"
author: "Thurstylark"
date: 2021-9-25
draft: false
---
### A label is not a template for behavior. It is a tool used for describing your specific brand of awesome to others. You are you, pick a label that fits (or don't, whatever)
That is to say: I am secure in the label that I've chosen, not because *I* can fit within *the label*, but because *the label* fits *me.* I am the only one in the world qualified to make any judgments about my sexuality, because I am the only one in the world who lives my life, feels my emotions, and experiences my attraction The *only* reason I have chosen to use a one-word label for such a large, complicated part of my person, is because it provides a useful short-hand.
However, this absolutely doesn't mean labels have no usefulness beyond communicating complicated concepts in a succinct way. In an external sense, labels provide some semblance of community in a world where people are often denied the opportunity to internalize these concepts from a young age; Finding this community provides legitimacy, validation, and support where otherwise one would be left to deal with their identity completely alone.
But, for the purposes of one's *internal* struggle: You are who you are, and whatever that ends up looking like for you, it can be explored and discovered with or without the participation of others. For some people, it helps to have some experience to consider, but there are just as many who have come to their conclusions completely on their own.
### IMO: Begin by finding the truth about yourself, and then you can figure out how to communicate that to others.
Or don't. I don't live your life :)

View File

@ -0,0 +1,3 @@
---
title: "On Sexuality"
---

View File

@ -0,0 +1,57 @@
---
title: "Do people actually desire physical affection?"
description: "Asexuality, relationships, and wtf is normalcy anyways?"
author: "Thurstylark"
date: 2021-9-25
draft: false
---
This began life as a reply to someone on /r/questioning, but decided to archive it for myself.
## Prompt
(paraphrasing to anonymize)
OP has just started their first romantic relationship with someone that shares many intrests and commonalities. OP enjoys spending time with their partner, but didn't feel anything special during their first kiss. OP would be fine with kissing them again if requested, but it's not something they felt that they would specifically desire or seek out.
OP recognizes that they generally don't quite understand romance or attraction, so being in a relationship is somewhat difficult already, but in an effort to understand their partner better, they wanted other perspectives.
OP's main question: "Do 'regular' people actually desire physical affection? Like, do they look at their partner and feel a physical urge to touch/kiss them, or does it originate in some concious 'I want to touch/kiss them' thought that then begets an action?"
## Response
Do people actually desire physical affection?
For me, 'yes' isn't strong enough.
I don't just desire physical affection, I *need it*. In fact, I sometimes don't feel as if my feelings are properly expressed *without* employing physical affection. Past that, I can get irritable, depressed, and lonely during prolonged periods without it. It affects my mood on a deep level, and it's something I need in order to function properly. I don't think I could stay in a monogamous relationship that lacked physical affection.
### "Regular" people
BUT, if that's something you don't desire or need, then that isn't weird, it's just a part of your particular flavor of awesome. "Normal" or "regular" people aren't a thing, and I discourage anyone from trying to compare themselves to a baseline human configuration of wants and needs. Evolution-based life doesn't operate like that. Evolution is dependent on randomness, uniqueness, and mutations, then it keeps the useful ones around over time.
To this end, I encourage you to ask yourself: Where does your idea of "normal" come from? From your parents? Peers? Media? A combination?
Also, what is to be gained by people who reinforce this notion of "normal"? Do they earn money from it? Do they feel accepted or powerful by being (or claiming to be) a part of the "normal" group? Do they use it to otherize those who don't fit in the "normalcy" they so enjoy?
There's deep introspection down that path, so here's a lighter take: I don't have to understand you to respect you, but more importantly, *I don't have to understand you for you to deserve my respect.* You don't deserve respect because you fit in my definition of "respectable person", you deserve my respect because you are a human.
For example: I don't understand what it is to live in an existence where physical affection does nothing for me, but that's ok. My inability to empathize fully with your situation is not a failing on my part, and especially not on yours. I have to accept that yours is a perspective that I will never fully grasp, but also that ***you are still valid***. If someone is unable to *respect* you, that's a them thing, not a you thing.
### The nature of relationships
Above all, don't feel like you have to push yourself to do things that you're not comfortable with. In our current society, there is definitely a tendency to push for obtaining romantic relationships and putting them on an ever-escalating path towards monogamous marriage (most commonly referred to as the [Relationship Escalator](https://medium.com/@agahran/why-step-off-the-relationship-escalator-d5b033b1ccb2)).
There's a societal expectation that you date to marry forever and that's the best path for everyone, but it doesn't have to be that way. You are a unique person, your partner is a unique person, but also, the relationship between you and your partner is a unique entity of its own. Just as you don't have any responsibility to look or act or be a certain way, your relationships with others don't have to look a certain way.
All that to say: If physical affection is something that you don't want or need to be included in your relationship with another person, then by all means, you shouldn't feel obligated to shoehorn it in. Human relationships are best when they're mutually beneficial, and beneficial relationships tend to be stifled when one forces themselves to be someone they're not for the sake of the relationship.
That is my perspective, but don't take my word for everything. Try things out, figure out what works best for *you*. I greatly appreciate that you specifically expressed your desire for other perspectives. That is a valuable and [seemingly] rare trait, and you should be proud of that. Keep following that curiosity and openness.
If you would like more perspective, I would take a look at /r/asexuality, /r/demisexuality, and any other subs that may interest you from their sidebars and wikis. Follow your nose, ask questions, and read about the experience of others.
### Learning from the Polyamorous community
Also, while I am not directly recommending polyamory for your situation, a lot of understanding can be gained from that community about the nature of relationships. It was certainly a catalyst for shifting my own perspectives when it came to relationships. /r/polyamory, and the resources documented there is a good place to start. Decide whether it's for you or not, but I would recommend checking it out, if only in the interest of gaining new outside perspectives.

View File

@ -0,0 +1,19 @@
---
title: "Does experimenting make you any less straight?"
author: "Thurstylark"
date: 2021-9-25
draft: false
---
## No.
End of story. Full stop. Thanks for playing!
### Wait, Really?
Yes, really.
*You* are the only one who can define your sexuality. Sometimes people just know, sometimes they have to try things out before they are sure. Both are valid methods, and their results are genuine. Just because you experimented doesn't make the results any less valid. It doesn't matter if you kissed someone, or slept with someone and enjoyed it. If you say you're straight, then you're straight.
Labels aren't a template for behavior. Labels are a tool used to communicate your specific flavor of awesome to others. Likewise, behavior doesn't define your labels either. You do.

View File

@ -0,0 +1,34 @@
---
title: "Origin of Thursdaylark"
description: "When thurstylark isn't thurstylark on libera.chat"
author: "Thurstylark"
date: 2023-7-20
draft: false
---
## Huh?
Yeah, well... It's kind of insular, so bear with me...
Years before the implosion of freenode.net, I spent a lot of time in #archlinux. First to get support as I explored the distro, then to also give support as my own experience grew. Many builds were riced, and all was good.
I was generally more active during work hours, as I had found myself on a small dev team, and used Arch for my work machine. From my employer's perspective, this was fine as long as I continued to be interoperable with the rest of my team which were running Debian. To them, it was free as in beer, and I took it upon myself to give back to the community by donating some of my time on the clock to supporting others who used tools that I used for my job (which included Debian along with other projects). Whether I had permission to do so is another conversation entirely ;)
During this time, #archlinux had an activity tracker running, which was fun to glance at every once in a while. It kept stats on things like which words or phrases were most commonly used by which user, and stuff like that. For instance, one could craft a query that would tell them how often the wiki was linked, which, unsurprisingly, was *extremely* often.
One day, someone (I believe it was teraflops) noticed that my stats were somewhat anomalous: I had been consistantly writing the most lines on Thursdays. They immediately then dubbed me as "thursdaylark", and I found this amusing enough to let it stick around.
So, ever since then, I have had weechat set up to automatically change my nick to thursdaylark at midnight on Thursday local time, and then change it back to thurstylark the following midnight. Thus my stats were wrecked, but the legacy stayed around.
For some reason, I still find myself interacting with #archlinux the most on thursdays, and I'm not entirely sure why. Several things about my life, employment, and even sleep patterns have changed dramatically since then, but for some reason, I happen to be more active as thursdaylark instead of as thurstylark.
## Okay... But that was on Freenode...
Sure, but then Freenode was taken over by some trust fund kiddie who summarily shit all over the only thing that made Freenode worthwhile in the first place: the users and the communities they curated for decades prior. The support staff either were ousted or left of their own accord to form a new network from its ashes: libera.chat.
Everyone basically moved directly over, and I was no different. All my configs stayed the same, and just pointed to libera.chat instead.
## But, why?
Meh, I still find it funny

View File

@ -0,0 +1,34 @@
---
title: "Patches Welcome"
description: "Perfection is an asymptotic, but collective goal."
draft: false
---
If I ever claimed to be flawless, slap me with a fish.
----
"Patches Welcome" is a common phrase in the FOSS (Free and Open Sourse Software) community, and it exemplifies my approach to every project that I publish under my name.
# What does it mean?
**"Patches Welcome" is an explicit invitation to help me improve the things that I do.**
A 'patch' traditionally refers to a description of a fix or modification that can be made to a project. For software, this could mean bug fixes, feature additions, tooling changes, or even a major overhaul to the project structure.
In this context, I'm referring not only to my software projects, but (almost) any aspect of any project that I put out for consumption, including streams, videos, websites, and even my own methodologies.
## What does it *not* mean?
**This is *not* an open invitation to harass, troll, or otherwise cause unwelcome disruption to any community space.**
If you have a problem with me, take it up with me. *I will take good-faith criticism under consideration, but I always reserve the right to ignore your bullshit.*
# How to contribute
The best way to get in touch about any specific change will most likely depend on the medium of the content that should be changed. If I left a link to this page, I will usually also leave the preferred contact method nearby, so check there first.
For software projects, my first choice is to use the Issues or Pull Requests feature of the applicable git forge (Github, Gitlab, Gitea, etc). Otherwise, you may email patches, or discus via any other method listed on the [Contact Info](/about/contact/) page. I will usually prefer a publicly-readable medium in most cases.
For anything not covered here, or if you're unsure, feel free to use any method listed on the [Contact Info](/about/contact/) page. If another method is more appropriate, I will be happy to redirect as need be.

10
ramblings/rtfm-or-gtfo.md Normal file
View File

@ -0,0 +1,10 @@
---
title: "RTFM or GTFO"
description: "Approachability in the Arch Linux Community"
author: "Thurstylark"
date: 2021-9-25
draft: true
---
In the Linux distro corner of the FOSS world, the [Arch Linux Wiki](https://wiki.archlinux.org/) has achieved near-legendary status as the best repository of 3rd party documentation on the internet, but it's also the achilles' heel of the Arch Linux Community

View File

@ -0,0 +1,28 @@
---
title: "Stupid Crestron Quirks"
description: "Crestron can be stupid sometimes. These are the undocumented ways."
author: "Thurstylark"
date: 2021-9-25
draft: true
---
## When creating a SIMPL Windows program for a 2 Series DMPS, DO NOT select the control system at program creation
When you create a new SIMPL Windows program, you get the option to select which control system this program is being created for. Without selecting this option, you won't be able to connect any of your logic to any of the hardware, and your program won't do anything useful. You *can* create a program without a control system, but this is usually to create a SIMPL Macro, which is then completed and added to a different SIMPL program. All this to say, a SIMPL Windows program without a control system at the top of the hardware tree is not useful on its own.
So, when I create a program that's supposed to run on a 2 Series DMPS (model `DMPS-*`, not `DMPS3-*`), and I understand all the above, naturally I select the model number of the control system I'm writing a program for.
The program gets created, and I get started creating the program. I get hung up on the part of the program that deals with switching video and audio sources, so I naturally look at the help file for the device that I'm trying to control. It's probably the most unhelpful help file in the history of helping people.
Here's where it's valuable to understand a little about the hardware. Crestron has a long history of design-recycling masquerading as backwards-compatibility. Basically, whenever they create a new product, they take an existing product and its tech, modify it to do what they want to market, and throw it out there. In this case, they took a 2 Series processor and a paired-down DM chassis, shoehorned them into the same case, and rushed it to market. The result is a disjointed attempt at providing the advertized functionality. Instead of providing the programmer with the appropriate controls for input switching in the hardware tree (you know, where you control the hardware), they instead had a whole bunch of undocumented nonsense nodes in a jumble of confusing unreadable card-based slot structure, and then a macro (yes, quite literally like the macro that I alluded to earlier), which connects itself to all the right spots in the hardware tree, and provides a littany of **actually useful** controls in the logic tree.
The perceptive reader might ask how such a macro does the attaching by itself (as the attaching of signals is usually the exclusive job of the Crestron programmer/dealer). Well, the answer came to me after 45 minutes of troubleshooting on my own and with my manager, and then after an hour-long phone call with Crestron True Blue support: I created the program wrong.
See, if you select a 2 Series DMPS at program creation, this macro doesn't get automatically added and connected to the appropriate places in order to be useful. Instead you have to create the program with no control system, then add the control system in configure mode. Apparently there is some sort of script that bootstraps the module to the hardware, and if you add the control system to the project at program creation, this script doesn't get to run, and your program is SOL. And since I had put the switching problem aside and finished creating the rest of the program, the tech on the phone had to tell me that I had to create a new program from scratch, and copy/pase my code into my new project to get it to work.
Now, I'm hesitant to rag solely on Crestron's developers for this convoluted mess of what-the-fuckery, but this situation does make it obvious that there is definitely a cultural reluctance to modernize and refactor their systems for the good of the programmers that have to put these systems together for *their* customers. Further, I'm sure that the decision to base their control systems on Windows CE and .NET Compact Framework 3.5 was not made by the developers, and they are certainly making the best of the hand they're dealt (especially now that their current control systems are running on these discontinued products). I think the blame for this particular circuis goes to their exec team who didn't give enough time to make this project the right way. It's a classic case of a product being rushed to market, but here's the important part: It seems that way only from the perspective of the *programmer*.
See, if there's anything that I would commend Crestron's Dev team for, it would be stability. It takes a lot to get a big system with hundreds of finicky pieces to work together just right, but by god, once you get it right, it will do the exact same thing in the exact same way every freakin time until the hardware gives out. This is no small feat, and I recognize that for what it is. I take issue with all the other cruft and bullshittery that collects after years and years of the "Backwards Compatibility and Stability above all" doctrine. It's a doctrine that creates a focus on marketing and sales above product quality. From the end-user's perspective, the product works as desired, but this is at the cost of programming time due to the complexity of these systems and the necessity of a programmer with the appropriate experience. All part of the bill that the customer has to pay.
And this is one of the many reasons Crestron can be stupid.

4
reference/_index.md Normal file
View File

@ -0,0 +1,4 @@
---
title: Reference
description: "Because sometimes the memory just needs a joggin'"
---

View File

@ -0,0 +1,40 @@
---
title: "Balanced and Unbalanced Analog Audio"
description: "How the pros do it"
author: "Thurstylark"
date: 2021-9-25
draft: true
---
This document is meant to serve as a cursory overview of the concepts necessary to understand balanced audio, and as a reference for myself.
If you'd like to skip the narrative, feel free to browse through the [#References](#References.md) I used while writing this document.
## What is sound anyways?
At its most base physical level, sound is simply a vibration in some sort of physical medium. The job of the human ear is to capture these vibrations out of the air, and translate them into neurological impulses. The brain's interpretation of thes impulses is what we commonly call sound.
A "vibration" is a mechanical phenomenon whereby oscillations occur about an equilibrium point. In the context of sound, the transmission medium is the thing that is vibrating.
### Example: Human Speech
To illustrate how these parts fit together, let's consider an exceedingly common case: Two humans in conversation. The speaker is the source of sound, and the listener is the destination. In this case, the medium is [atmospheric air](https://en.wikipedia.org/wiki/Atmosphere_of_Earth), which is to say: the collection of gasses that fills all the *seemingly* empty space between objects on planet Earth.
The speaker creates sound by squeezing the right muscles, which causes two special skin folds to be pushed together inside their throat. As the speaker pushes air out of their lungs, these folds block the path of air until the air pressure is great enough to push the folds apart, which releases a small amount of air from their lungs, causing the air pressure to drop, which allows the folds to rebound and meet again. The [Wikipedia page on vocal cords](https://en.wikipedia.org/wiki/Vocal_cords#Function) summarizes this better than I ever could: "In essence, sound is generated in the larynx by chopping up a steady flow of air into little puffs of sound waves."
This stream of air pressure variations is what travels through the air from source to destination.
- Equilibrium (aka: 0dB,
## References
- https://en.wikipedia.org/wiki/Sound
- https://en.wikipedia.org/wiki/Analog_signal
- https://en.wikipedia.org/wiki/Audio_signal
- https://en.wikipedia.org/wiki/Balanced_audio

View File

@ -0,0 +1,6 @@
---
title: "Thurstylark.com"
date: 2021-10-05T22:00:36-05:00
draft: true
---

View File

@ -0,0 +1,7 @@
---
title: "Gitea"
description: "An upgrade from cgit, but easier to host than GitLab"
date: 2021-10-05T22:05:14-05:00
draft: true
---

View File

@ -0,0 +1,7 @@
---
title: "Matrix Homeserver"
description: "Vive la décentralisation!"
date: 2021-10-05T22:07:45-05:00
draft: true
---

View File

@ -0,0 +1,7 @@
---
title: "Thurstylark Wiki"
description: "A Hugo static site with simple hosting"
date: 2021-10-05T22:02:12-05:00
draft: true
---