June 21, 2025 @ 02:50 AM UTC
A function that _should_ work to get the full extension of a file, with sanitization: // GetFullExtensionSanitized returns the full extension of a file (such as .tar.gz), as compared to // filepath.Ext, which only returns the last part of the extension (such as .gz). func GetFullExtensionSanitized(filename string) string { filename = filepath.Base(filename) extension := "" for { ext := filepath.Ext(filename) if ext == "" { break } extension = ext + extension filename = strings.TrimSuffix(filename, ext) } if len(extension) > 15 { // no extension is likely to be >15 characters, so we reject these return "" } var builder strings.Builder builder.Grow(len(extension)) var prev rune for _, r := range extension { if r == '.' && prev == '.' { continue } if !slices.Contains([]rune(".abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"), r) { continue } builder.WriteRune(r) prev = r } extension = builder.String() return extension }
June 18, 2025 @ 09:51 PM UTC
git archive `git stash create` to create an archive with the current working directory
June 17, 2025 @ 12:52 AM UTC
Inspect the platform of a Docker image on a remote registry: docker manifest inspect [IMAGE_REFERENCE] --verbose | jq .Descriptor.platform
May 29, 2025 @ 07:34 PM UTC
In case you're wondering why your registry auth isn't working when doing Docker operations using the Docker Go SDK, even though the Docker CLI works: You might need to use the Docker CLI library to authenticate with the registry. Ran into this issue with ECR + a Docker config that uses the OSX Keychain credential helper. See https://github.com/moby/moby/issues/34503 and https://github.com/moby/moby/issues/39377#issuecomment-1119914406.
April 25, 2025 @ 09:49 PM UTC
Prediction: People will be defining voice agent behavior using React-esque semantics sooner or later. I don't mean as part of a web app, I mean that voice-only agents will have conversational flows defined using React/JSX. Something like this, essentially (this will seem familiar if you've built a voice agent flow with Pipecat Flows or another orchestration tool): export function ConversationFlow({ patientName, patientBirthday }) { const [authStatus, setAuthStatus] = useState('unauthenticated'); return ( <Conversation> <Node> <System>You are a friendly voice assistant.</System> <System>Ask the user to confirm their name and their birthday.</System> <Tool name="verify" properties={{ name: ..., birthday: ... }} execute={(props) => { if (props.name === patientName && props.birthday === patientBirthday) { setAuthStatus('authenticated'); } else { setAuthStatus('forbidden'); } }} /> </Node> {authStatus === 'authenticated' ? <AuthenticatedFlow /> : <UnauthorizedFlow />} </Conversation> ); } This probably won't be the exact form, since you need to keep in mind that: 1. You can't "re-render" because you're laying things out in time instead of space. 2. The ordering of elements is meaningful, and state (such as `verified`) can only flow downwards since you can't go back in time. ...and design the affordances accordingly. But this model definitely feels more amenable to building good abstractions than defining conversation flows in code.
April 11, 2025 @ 06:57 PM UTC
Fired off a quick thread about a pet peeve of mine: git diffs. https://x.com/KabirGoel/status/1910768886955614672. This... might need a blog post.
April 09, 2025 @ 08:54 PM UTC
Something I've noticed about my work style: I'll hotfix things where necessary, but I'm uncomfortable with treating hotfixes as solutions. I strongly prefer to ask why something happened and how we can change the system around it to make it impossible--all the way down to the system's core design. (Of course, part of gaining maturity as an engineer is being able to weigh the benefits of changing a system with the cost of wranlging debt.) This is a useful way of thinking about and debugging organizational processes as well, and there you don't have to worry about the cost of paying off debt.
March 14, 2025 @ 08:55 PM UTC
You should never use magic numbers for your z-indexes. Centralize them using CSS variables in a global file. Your future self will thank you.
February 13, 2025 @ 11:09 PM UTC
Hah, this is interesting. Steve Klabnik likes to write tutorials for things as he learns about them, and apparently that's how The Rust Programming Language came about: https://steveklabnik.github.io/jujutsu-tutorial/. He seems to have a nice setup for writing these tutorials that's based on mdBook (https://rust-lang.github.io/mdBook/index.html).
February 12, 2025 @ 10:36 PM UTC
Convert a ReadableStream to whatever format you want (JSON, Uint8Array, text, etc.) using the Response constructor: await new Response(myReadableStream).json()