GitHub Stars

GitHub stars posts

1859 posts latest post 2026-05-24
Publishing rhythm
May 2026 | 23 posts
In my adventure to put more homelab [1] in docker, I moved our modded minecraft setup to docker. Getting Mods # [2] So far I have found all of our mods from curse forge [3]. modpacks make getting multiple mods working together much easier, someone else has already vetted a pack of often times 100+ mods that all play well together. I have yet to get these working in docker, I will, but for not I just have individual mods. download file # [4] under the hood docker is using wget to get the mod. The link you click on from curseforge will block wget. What I do is pop open the devtools (f12 in chrome), click on the network tab, click the download link on the web page, and watch the real link show up. [5] Docker-compose # [6] I am using docker compose, it makes the command much easier to start, and all the things needed stored in a file. I am not using compose to run multiple things, just for the simple start command. Create a directory for your server and add the following to a docker-compose.yml file. version: "3.8" services: mc: container_name: walkercraft image: itzg/minecraft-server ports: - 25565:25565 environment: EULA: "TRUE" TYPE: "FORGE" VERSION: 1.16.5 M...
Reading eventbridge rules from the command line can be a total drag, pipe it into visidata to make it a breeze. I just love when I start thinking through how to parse a bunch of json at the command line, maybe building out my own custom cli, then the solution is as simple as piping it into visidata. Which is a fantastic tui application that had a ton of vim-like keybindings and data features. alias awsevents = aws events list-rules | visidata -f json
Anyone just starting out their vim customization journey is bound to run into this error. E5520: <Cmd> mapping must end with <CR> I did not get it # [1] I’ll admit, in hindsight it’s very clear what this is trying to tell me, but for whatever reason I still did not understand it and I just used a : everywhere. From the docs # [2] If you run :h <cmd> you will see a lot of reasons why you should do it, from performance, to hygene, to ergonomics. You will also see another clear statement about how to use <cmd>. E5520 <Cmd> commands must terminate, that is, they must be followed by <CR> in the {rhs} of the mapping definition. Command-line mode is never entered. When to map with a : # [3] You still need to map your remaps with a : if you do not close it with a <cr>. This might be something like prefilling a command with a search term. nnoremap <leader><leader>f :s/search/ Otherwise use # [4] If you can close the <cmd> with a <cr> the command do so. Your map will automatically be silent, more ergonomic, performant, and all that good stuff. nnoremap <leader><leader>f <cmd>s/search/Search/g<cr> References: [1]: #i-did-not-get-it [2]: #from-the-docs [3]: #when-to-map-with-a-...
The default keybinding for copy-mode <prefix>-[ is one that is just so awkward for me to hit that I end up not using it at all. I was on a call with my buddy Nic this week and saw him just fluidly jump into copy-mode in an effortless fashion, so I had to ask him for his keybinding and it just made sense. Enter, that’s it. So I have addedt his to my ~/.tmux.conf along with one for alt-enter and have found myself using it way more so far. Setting copy-mode to enter # [1] To do this I just popped open my ~/.tmux.conf and added the following. Now I can get to copy-mode with <prefix>-Enter which is control-b Enter, or alt-enter. bind Enter copy-mode bind -n M-Enter copy-mode More on copy-mode # [2] I have a full video on copy-mode you can find here. tmux copy-mode [3] References: [1]: #setting-copy-mode-to-enter [2]: #more-on-copy-mode [3]: /tmux-copy-mode/
In python, a string is a string until you add special characters. In browsing twitter this morning I came accross this tweet, that showed that you can use is accross two strings if they do not contain special characters. https://twitter.com/bascodes/status/1492147596688871424 I popped open ipython to play with this. I could confirm on 3.9.7, short strings that I typed in worked as expected. waylonwalker ↪main v3.9.7 ipython ❯ a = "asdf" waylonwalker ↪main v3.9.7 ipython ❯ b = "asdf" waylonwalker ↪main v3.9.7 ipython ❯ a is b True Using the upper() method on these strings does break down. waylonwalker ↪main v3.9.7 ipython ❯ a.upper() is b.upper() False waylonwalker ↪main v3.9.7 ipython ❯ a = "ASDF" waylonwalker ↪main v3.9.7 ipython ❯ b = "ASDF" waylonwalker ↪main v3.9.7 ipython ❯ a is b True If You can also see this in the id of the objects as well, which is the memmory address in CPython. waylonwalker ↪main v3.9.7 ipython ❯ id(a) 140717359289568 waylonwalker ↪main v3.9.7 ipython ❯ id(b) 140717359289568 waylonwalker ↪main v3.9.7 ipython ❯ id(a.upper()) 140717359581824 waylonwalker ↪main v3.9.7 ipython ❯ id(b.upper()) 140717360337824 Finally just as the post shows if...
Just starred nvim-terminal.lua [1] by norcalli [2]. It’s an exciting project with a lot to offer. A high performance filetype mode for Neovim which leverages conceal and highlights your buffer with the correct color codes. References: [1]: https://github.com/norcalli/nvim-terminal.lua [2]: https://github.com/norcalli
One thing about moving to a tiling window manager like awesome wm or i3 is that they are so lightweight they are all missing things like bluetooth gui’s out of the box, and you generally bring your own. Today I just needed to connet a new set of headphones, so I decided to just give the bluetoothctl cli a try. It seems to come with Ubuntu, I don’t think I did anything to get it. bluetoothctl Running bluetoothctl pops you into a repl/shell like bah, python, or ipython. From here you can execute bluetoothctl commands. Here is what I had to do to connect my headphones. # list out the commands available help # scan for new devices and stop when you see your device show up scan on scan off # list devices devices paired-devices # pair the device pair XX:XX:XX:XX:XX:XX # now your device should show up in the paired list paired-devices # connet the device connect XX:XX:XX:XX:XX:XX help # [1] Here is the output of the help menu on my machine, it seems pretty straight forward to block, and remove devices from here. note ctrl revers to the bluetooth controller on the machine you are on, and dev refers to a device id. Menu main: Available commands: ------------------- advertise A...
The work on xsv [1] by BurntSushi [2]. A fast CSV command line toolkit written in Rust. References: [1]: https://github.com/BurntSushi/xsv [2]: https://github.com/BurntSushi
I often run shell commands from python with Popen, but not often enough do I set up error handline for these subprocesses. It’s not too hard, but it can be a bit awkward if you don’t do it enough. Using Popen # [1] import subprocess from subprocess import Popen # this will run the shell command `cat me` and capture stdout and stderr proc = Popen(["cat", "me"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) # this will wait for the process to finish. proc.wait() reading from stderr # [2] To get the stderr we must get it from the proc, read it, and decode the bystring. Note that we can only get the stderr object once, so if you want to do more than just read it you will need to store a copy of it. proc.stderr.read().decode() Better Exception # [3] Now that we can read the stderr we can make better error tracking for the user so they can see what to do to resolve the issue rather than blindly failing. err_message = proc.stderr.read().decode() if proc.returncode != 0: # the process was not successful if "No such file" in err_message: raise FileNotFoundError('No such file "me"') References: [1]: #using-popen [2]: #reading-from-stderr [3]: #better-exception
Samba is an implementation of the smb protocol that allows me to setup network shares on my linux machine that I can open on a variety of devices. I think the homelab [1] is starting to intrigue me enought to dive into the path of experimenting with different things that I might want setup in my own home. One key piece of this is network storage. As I looked into nas, I realized that it takes a dedicated machine, or one virtualized at a lower level than I have capability for right now. Humble Beginnings # [2] To get goind I am going to make a directory /srv/samba/public open to anyone on my network. I am not going to worry too much about it, I just want something up and running so that I can learn. Install samba, open the firewall, and edit the smb.conf sudo apt install samba samba-common-bin sudo ufw allow samba sudo nvim /etc/samba/smb.conf I added this to the end of my smb.conf [public] comment = public share, no need to enter username and password path = /srv/samba/public/ browseable = yes writable = yes guest ok = yes Then I made the /srv/samba/public directory and made it writable by anyone. sudo mkdir -p /srv/samba/public sudo setfacl -R -m "u:nobody:rwx" /srv/s...
A super useful tool when doing PR’s or checking your own work during a big refactor is the silver searcher. Its a super fast command line based searching tool. You just run ag "<search term>" to search for your search term. This will list out every line of every file in any directory under your current working directory that contains a match. Ahead/Behind # [1] It’s often useful to need some extra context around the change. I recently reviewed a bunch of PR’s that moved schema from save_args to the root of the dataset in all yaml configs. To ensure they all made it to the top level DataSet configuraion, and not underneath save_args. I can do a search for all the schemas, and ensure that none of them are under save_args anymore. ag "schema: " -A 12 -B 12 References: [1]: #aheadbehind
I’m really excited about kondo [1], an amazing project by tbillington [2]. It’s worth exploring! Cleans dependencies and build artifacts from your projects. References: [1]: https://github.com/tbillington/kondo [2]: https://github.com/tbillington
Check out snapdrop [1] by SnapDrop [2]. It’s a well-crafted project with great potential. A Progressive Web App for local file sharing References: [1]: https://github.com/SnapDrop/snapdrop [2]: https://github.com/SnapDrop
The work on Heimdall [1] by linuxserver [2]. An Application dashboard and launcher References: [1]: https://github.com/linuxserver/Heimdall [2]: https://github.com/linuxserver
I’ve ran a Minecraft server at home since December 2017 for me and my son to play on. We start a brand new one somewhere between every day and every week. The older he gets the longer the server lasts. In all these years, I’ve been popping open the command line and running the server manually, and even inside of Digital Ocean occasionally to play a more public server with a friend. My buddy Nic has been sharing me some of his homelab [1] setup, and it’s really got me to thinking about what I can run at home, and Dockerizing all the things. Today I found a really sweet github repo that had a minecraft server running in docker with a pretty incredible setup. I ended up running the first thing in the Readme that included a volume mount. If you are going to run this container, I HIGHLY reccomend that you make sure that you have your world volume mounted, otherwise it will die with your docker container. Docker Compose # [2] With the following stored as my docker-compose.yml in a brand new and otherwise empty directory I was ready to start the server for the night. version: "3" services: mc: container_name: walkercraft image: itzg/minecraft-server ports: - 25565:25565 en...
Installing rust in your own ansible playbook will make sure that you can get consistent installs accross all the machines you may use, or replicate your development machine if it ever goes down. Personal philosophy # [1] I try to install everything that I will want to use for more than just a trial inside of my ansible playbook. This way I always get the same setup across my work and home machines, and anytime I might setup a throw away vm. reccommended install # [2] This is how rust reccomends that you install it on Ubuntu. First update your system, then run their installer, and finally check that the install was successful. # system update sudo apt update sudo apt upgrade # download and run the rust installer curl https://sh.rustup.rs -sSf | sh # confirm your installation is successful rustc --version Ansible Install # [3] The first thing I do in my playbooks is to check if the tool is already installed. Here I chose to look for cargo, you could also look for rustc. - name: check if cargo is installed shell: command -v cargo register: cargo_exists ignore_errors: yes I first check for an existing install so I can re-run my playbooks quickly filling in only missing...
The work on tinysearch [1] by tinysearch [2]. 🔍 Tiny, full-text search engine for static websites built with Rust and Wasm References: [1]: https://github.com/tinysearch/tinysearch [2]: https://github.com/tinysearch
Looking for inspiration? templates [1] by zevaverbach [2]. No description available. References: [1]: https://github.com/zevaverbach/templates [2]: https://github.com/zevaverbach
Check out lukas-reineke [1] and their project cmp-rg [2]. ripgrep source for nvim-cmp References: [1]: https://github.com/lukas-reineke [2]: https://github.com/lukas-reineke/cmp-rg
In looking for a way to automatically generate descriptions for pages I stumbled into a markdown ast in python. It allows me to go over the markdown page and get only paragraph text. This will ignore headings, blockquotes, and code fences. import commonmark import frontmatter post = frontmatter.load("post.md") parser = commonmark.Parser() ast = parser.parse(post.content) paragraphs = '' for node in ast.walker(): if node[0].t == "paragraph": paragraphs += " " paragraphs += node[0].first_child.literal It’s also super fast, previously I was rendering to html [1] and using beautifulsoup to get only the paragraphs. Using the commonmark ast was about 5x faster on my site. Duplicate Paragraphs # [2] When I originally wrote this post, I did not realize at the time that commonmark duplicates nodes. I still do not understand why, but I have had success duplicating them based on the source position of the node with the snippet below. from itertools import compress import commonmark import frontmatter post = frontmatter.load("post.md") parser = commonmark.Parser() ast = parser.parse(post.content) # find all paragraph nodes paragraph_nodes = [ n[0] for n in ast.walker() if n[0...