One pattern I like a lot is a bin/service wrapper. In each of your services (I like to call them Macro Service instead of Microservice).
The idea is to provide a few key things:

Using the new ChatGPT GPT-4o Image Generation to incrementally generate a photo of Hoda! (A "Chipin" is a 50-50 Chuhuahua and Mini-Pincer. Hoda is 70-20, so is a ChuhuaPin!)
Previously if you asked ChatGPT to generate you an image it would switch over to DALL-E, a separate image generation model. Each time it generated a new image it would more or less start from the beginning, maybe, and it was a challenge to get small incremental changes to an image.

Agency (a more useful concept of Free Will), has two important ingredients -- the ability to predict outcomes and the ability to influence outcomes -- both of which come in a spectrum of possible degrees. We can lay these out into a visualization that breaks down naturally into a four-square grid.
My friend Brad asked about what I've been reading lately in the AI/LLM space to keep up. Here's my link roundup! Things that have been on my rotation lately.

cat some_file.txt | llm -s 'Turn this into a CSV of street, city, state, zip' > data.csv
Figured out how to make opening a CSV in firefox pop open a terminal running VisiData (vd)
I like VisiData! If you are working with tabular data, like a CSV file, it is a lovely slicer and dicer. It's a pretty terminal-keyboard-heavy program, like a vim family thing. Like many of these power tools, I find that you can get into it best by finding ONE use-case and then gradually introducing new tricks from there. So the simple use-case for VisiData is simply viewing CSV files.

Drawing Xes in Boxes is harder than you might think! Teaching Ghostwriter a bit about space by pre-segmenting the input image gets us closer.
You may recall from TLT - 2024.11.23 - A Ghostly Game that Ghostwriter is ... not good with spatial awareness. For example, we can ask it to draw an X in a box and see how close it gets...

Working on Ghostwriter, making some incremental progress on playing tic-tac-toe.
I've been trying to play tic-tac-toe with Ghostwriter, but it is quite bad. Reading the LLM transcript, it sees that we are playing, has a good idea of what it wants to do, but can't aim its output very well at all.

Each token is one choice from many forking paths. Let's see some of the other possibilities. Also try the Live LLM Token Tree Visualization Tool!
Mostly we talk about LLMs (Large Language Models) as generating one token (roughly a syllable, it depends) at a time. But that's not really the whole picture. Given the context, all of the text that has led up to this point, the model will rank all of the possible tokens and assign each a weight (a probability).
This is the website and wiki of me, Brock Wilcox a.k.a. awwaiid. Please see the Home page if you would like a less philosophical introduction to this site. Otherwise, read on!
I love living in the future -- we have so many neat things. One of my favorites is the internet. For me the internet is a powerful communication tool, and this website is one of the ways I utilize the internet to communicate. By placing my thoughts, papers, and projects on this site for the world to view I hope to communicate a little about myself to whomever is interested in knowing me.
In-Hub, LLM + Sonic Pi, dash of docker-compose
In-Hub, LLM Club, Mediapipe, Coffee Project, docker-compose
Assistants conceptWebsite updates to break insulation, bit of Human Essentials
#!/usr/bin/env ts-node and contains Typescriptblog command really lives, but vim $(which blog) works great :).data format directly into JSON so you could do the extract even after the upgrade .... but my data is migrated now and works fine so I lost momentumA week spent coughing, writing Java, and watching Andor. First World Problems hah. Not bad in the scheme of things! :)
Lunch table with Humans!
week indicator on this checkin is already upsettingLlamas, Pythons, Coffee, and Sway
Fuzzy brained, but starting to figure this thing out.
Pairing, Merging
layout.css.devPixelsPerPx to something bigger. I go in there... and it is set to 0.75!!! I changed it to the default and everything is already much better hahaFirst day of RC!
I'm trying to solidify my understanding of the schema organization for Human Essentials. The goal is to build up some documentation to make contribution even easier for new folks. Also I like to play with PlantUML and GraphViz.
First I ran rails erd filetype=dot attributes=false and got a beast of a diagram. This includes all of the models and some indirect relationships.
Notes from the Changelog interview with Cory Doctorow on Chokepoint Capitalism
Lemonade stand operated (or perhaps supervised?) by a robot. Image by Bing Image Creator.
While driving to and waiting for Millie (the car) to get maintenanced, I listened to Examining capitalism's chokepoints, an interview with Cory Doctorow discussing his book Chokepoint Capitalism. This touched on all sorts of things, but right up at the front was an off-topic question - How is Cory so prolific?
Jam with Theo -- banging drums, strumming bass, and making up nonsense about Wanda Vision!
(download)
Theo and I went over to 7DrumCity and jammed for a while. He and Sacha were telling me about Wanda Vision, which I haven't seen at all, so I started to make up a song. A delightful time was had by all!
Song inspired by Hoda The Dog lounging about in the living room sun!
Voice note (download)
Revision 1 (download)
Revision 2 (download)
Revision 3 (download)
G
My little dog
C
laying in my living room
G
she's laying in
D
a patch of sun
G
My little dog
C
laying in my living room
G
And I think her day
D G
is gonna be a good one
G
My little dog
C
laying in my living room
G
she's laying in
D
a patch of sun
G
My little dog
C
laying in my living room
G
And I think her day
D G
is gonna be a good one
C
She's laying there
G
all through the day
C
Just seeing her
G
takes my cares away
C
What she's dreaming of
G
I couldn't say
D
But I bet it's something
G
real fun
G
My little dog
C
laying in my living room
G
she's laying in
D
a patch of sun
G
My little dog
C
laying in my living room
G
And I think her day
D G
is gonna be a good one
START HERE! This page is an overview; much of the music I've written or been involved with in one lovely place. Also check out my Music Gear and Setup!
These works are licensed under a Creative Commons Attribution-ShareAlike (CC BY-SA) License (or maybe CC BY-NC... feel free to ask).
Here are a bunch of songs! Some of these are more proof-of-concept than anything :) . These include both solo efforts and collaborations, follow the links to learn more and maybe get some lyrics, variations, and background.
I had ChatGPT write me a poem .... but first some somewhat irrelevant background information!
I've purchased and chained a few Neopixel-like LED fairy-light strands (these ones on Amazon) as a fun winter/Christmasy project. I have them hooked up to an Arduino-like, right now this M4 Feather Express, but I'm planning on switching to an ESP32-S2 TFT Feather. Each LED is individually controllable using Arduino/C++. The idea is to make some holiday light displays with different colors and twinkling and all that. While learning how to use it I made a few toy animations, such as this simple snake:
Pair a keyboard with the Norns and Grid. Then you record commands like a set of timed and sequenced macros visible and triggered on the grid. Like a guitar-looper mashed up with a REPL mashed up with a sequencer!

See https://github.com/awwaiid/repl-looper for the code, documentation, and a journal of development.
In today's sugary exploration, let's take a look at a shorthand for object key expansion in Javascript (ECMAScript 2015+, es6+). For an overview of the TON of delicious sugar that was added to Javascript at around es6, check out es6-features.org.
Most of the "scripting" languages (Python, Ruby) have "dictionaries" or "hashes", a datastructure of key-value pairs. In JS these are called "objects", and they do a lot of other things beyond this basic data-storage behavior. In JSON -- JavaScript Object Notation -- you can see the basic literal declaration syntax. Let's build an addressbook, keyed (indexed) by name.
let addressBook = {
"alice": {
"street": "123 Elsewhere Lane",
"zip": "32341"
},
"bob": {
"street": "221 Baker Street",
"zip": "00234"
},
"clarence": {
"street": "P.O. Box 17",
"zip": "88877"
}
};
console.log("Bob's info", addressBook["bob"]);
We're using Firebase as the hosting service for https://covidcanidoit.com and the experience has been kinda weird, coming from a more traditional server-database world.
First, I didn't even realize that Firebase was more than a cloud-JSON-blob! Our initial use of it was only for static asset hosting. This is a VueJS application that so far mostly lives in the browser, so static hosting is perfect. I generally use Github Pages for this purpose, but another team member had already set up Firebase for us.
Once I learned that it was even a thing, all was good. I wrapped the CLI that Firebase provides into yarn land, and now you can do yarn deploy and it'll build up the local assets and push them up. Works quite well! The auth is stored somewhere else on my computer. If a new dev wants to deploy, you add their google account to the Firebase project and presto!
I got a Pocket Operator PO-33 a while back, and find it super fun -- it is minimalist and usable. It inspires me to play around with beats and tunes ... and it also inspires me to work on my own samplers, sequencers, and synths.
Let's see what we can do with Web Audio these days! Starting with a basic VueJS app, I googled lots of stuff. Somewhat randomly, I wanted a Wicki-Hayden hexagon style keyboard, so had to find some CSS that makes hex-buttons. I'll probably switch to this Hexi-Flexi-Grid at some point, to make dynamically sized hexagons easier, but these work.
Combine that with a simple synth, and now we have a playable thing. I had to make some tweaks to get it to work tolerably on my phone -- fix the layout size, use touch events. Unfortunately it isn't very usable at this point due to a sizeable delay between pushing a button and the sound. I'm going to write a pure-JS snippet to eliminate any overhead from VueJS, and if that is also slow then I'm not sure what I'll do. It's kinda cool that I can use Web Audio ... and I'd sure like to keep using it. We'll see!
The Pocket Operator PO-33 Knock-Out is a super fun sampler and step-sequencer made by Teenage Engineering! I got one in August 2019, and am using it to play around with sample-based music.
See also Music Gear and Setup
In 2019 I got a Pocket Operator PO-33, part of the "Metal" series of devices from Teenage Engineering. This is a sampler and step-sequencer in a pocket-calculator-esq form factor. Very fun! These are some notes.
The graph module uses GraphViz to draw graphs. Here are some examples I've put together, but much fancier thinges are possible. See http://www.research.att.com/sw/tools/graphviz/refs.html for GraphViz documentation, and see http://www.research.att.com/sw/tools/graphviz/examples/ for some examples.
<graph abc>
digraph {
a -> b - > c;
}
</graph>
<graph>
digraph {
rankdir=LR;
node [ shape=plaintext fontsize=10 ];
struct1 [
label=<<TABLE border="0" cellborder="1" cellspacing="0" cellpadding="0" width="75">
<TR><TD bgcolor="lightgrey">foo</TD></TR>
<TR><TD>columnx</TD></TR>
<TR><TD>id</TD></TR>
<TR><TD port="barid1">bar_id</TD></TR>
<TR><TD>baz</TD></TR>
</TABLE>
>
];
struct0 [
label=<<TABLE border="0" cellborder="1" cellspacing="0">
<TR><TD bgcolor="lightgrey">bar</TD></TR>
<TR><TD port="barid0">id</TD></TR>
<TR><TD>name</TD></TR>
<TR><TD>date</TD></TR>
</TABLE>
>
];
struct1:barid1 -> struct0:barid0;
}
</graph>
<graph>
digraph {
n1 -> n2;
n2 -> n3;
n3 -> n1;
}
</graph>
<graph>
digraph {
node [shape=box];
rankdir=LR;
n1 -> n2;
n2 -> n3;
n3 -> n1;
}
</graph>
<graph>
digraph G {
subgraph cluster_0 {
style=filled;
color=lightgrey;
node [style=filled,color=white];
a0 -> a1 -> a2 -> a3;
label = "process #1";
}
subgraph cluster_1 {
node [style=filled];
b0 -> b1 -> b2 -> b3;
label = "process #2";
color=blue
}
start -> a0;
start -> b0;
a1 -> b3;
b2 -> a3;
a3 -> a0;
a3 -> end;
b3 -> end;
start [shape=Mdiamond];
end [shape=Msquare];
}
</graph>
(Cats Dominate Our Lives Too Much)
(download)
Wake up
Feed me
Don't wait
I need
You've got your own world
But you brought me here
Suck it up you worthless whore
I feel like you
Don't care
Be kind
Shut up
Leave me
I know that you think
I am here to entertain
My attention is not free
Sometimes you can be
So vain
Tease me
Be touched
Give me
Wake up
Feed me
Don't wait
I need
You
I've been doing a spot of accounting at work over the last few months. This is clearly a failure of delegation and management on my part, but it has led to at least one deep observation that I mightn't have had otherwise.
Perhaps that is a slight exaggeration. They don't ACTUALLY travel through time. But if you hang out with them a bit and observe their twisted time and verb conjugation ... well it's obvious that they would be right at home hopping around a branching multiverse.
I Dockerized this website yesterday! I had already built a cpanfile that declares the Perl5 dependencies of OddMuse, which made it easy. I'm also going to run this with the data directory directly bind-mounted.
First the Dockerfile:
FROM perl:latest
# Set up the deploy user
ARG uid=1000
ARG gid=1000
RUN echo groupadd -g $gid deploy
RUN groupadd -g $gid deploy
RUN useradd --create-home -u $uid -g $gid -ms /bin/bash deploy
WORKDIR /app
COPY cpanfile .
RUN cpanm -qn --installdeps .
USER deploy
I've been having lots of fun with https://github.com/vimwiki/vimwiki lately! I've mixed in a bit of encryptfs to have a private directory of notes. Sometime during boot, I set it up with:
sudo mount -t ecryptfs \
-o key=passphrase,ecryptfs_cipher=aes,ecryptfs_key_bytes=16,ecryptfs_passthrough=no,ecryptfs_enable_filename_crypto=yes,ecryptfs_fnek_sig=1a9380706fdf5bce \
~/docs/private/vimwiki ~/notes
I haven't done much customization yet. But one thing I'm playing with now is making it easy to post notes from VimWiki directly onto my website.
Last night at the DC Perl Mongers meetup we collaboratively built a proof-of-concept for storing key/value pairs as messages in a slack channel, https://github.com/plicease/globalhash. This was made straightforward by great Slack API docs and cpan:WebService::Slack::WebApi. Example usage:
# writes "hello=world" into the #globalhash channel
$ globalhash set hello world
# reads the #globalhash channel for the most
# recent value of hello and prints it
$ globalhash get hello
world
There are of course a TON of things you could do from here. Some ideas:
A fun thing to do is to explore things using introspection/reflection. In Ruby and Perl6, for example, we can get a list of methods for a given object instance pretty easily:
# Ruby
"hello good people!".methods.each { |method| puts method.to_s }
# Perl6
for "hello good people!".^methods -> $method { say $method }
On the REPL (irb/pry or perl6) this is even shorter since it prints out lists of things by default, so you can do:
One of the codebases I work on regularly has a large and slow test suite. So slow that it typically only runs in totality in a continuous-integration (ci) environment, and there it uses the parallel_tests gem to slice it into pieces and run in parallel. This gets it to run in like 30 minutes instead of 2.5 hours.
But I want to run the whole thing linearly sometimes, especially so I can make sure tests aren't conflicting with each other. So I created a new ci job that runs it linearly ... and got a fail that I didn't get otherwise. Took forever to figure it out!
This was about a worker that I call a "sweeper" -- it's job is to run once a day and make sure nothing was missed by other realtime jobs during the day. Here is a simplified version.