mirror of
https://github.com/jbranchaud/til
synced 2026-03-03 22:48:45 +00:00
Compare commits
25 Commits
6fdadfa1fb
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55a6691681 | ||
|
|
3632cfbe1b | ||
|
|
e82bc873b9 | ||
|
|
43ade88fab | ||
|
|
8f99085e4b | ||
|
|
f20428b06a | ||
|
|
e41802653d | ||
|
|
2cc52bf8bc | ||
|
|
df418b5718 | ||
|
|
d084e0ffe0 | ||
|
|
72b466a8b3 | ||
|
|
be18f387ed | ||
|
|
efb83050ab | ||
|
|
ec12f7ea80 | ||
|
|
f186d5977d | ||
|
|
f967520fa3 | ||
|
|
1517e1fb7a | ||
|
|
f56d93b49b | ||
|
|
dd6350aa41 | ||
|
|
bdd3adf577 | ||
|
|
f48adc0f05 | ||
|
|
9773f10b84 | ||
|
|
bd58be8fda | ||
|
|
35f1f0b807 | ||
|
|
81afd44913 |
30
README.md
30
README.md
@@ -10,7 +10,7 @@ working across different projects via [VisualMode](https://www.visualmode.dev/).
|
||||
|
||||
For a steady stream of TILs, [sign up for my newsletter](https://visualmode.kit.com/newsletter).
|
||||
|
||||
_1726 TILs and counting..._
|
||||
_1750 TILs and counting..._
|
||||
|
||||
See some of the other learning resources I work on:
|
||||
|
||||
@@ -29,6 +29,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
* [Ansible](#ansible)
|
||||
* [Astro](#astro)
|
||||
* [AWS](#aws)
|
||||
* [Bash](#bash)
|
||||
* [Brew](#brew)
|
||||
* [Chrome](#chrome)
|
||||
* [Claude Code](#claude-code)
|
||||
@@ -126,6 +127,10 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Turn Off Output Pager For A Command](aws/turn-off-output-pager-for-a-command.md)
|
||||
- [Use Specific AWS Profile With CLI](aws/use-specific-aws-profile-with-cli.md)
|
||||
|
||||
### Bash
|
||||
|
||||
- [Edit The Current Command Prompt](bash/edit-the-current-command-prompt.md)
|
||||
|
||||
### Brew
|
||||
|
||||
- [Clean Up Your Brew Installations](brew/clean-up-your-brew-installations.md)
|
||||
@@ -241,6 +246,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Reload The nginx Configuration](devops/reload-the-nginx-configuration.md)
|
||||
- [Resolve The Public IP Of A URL](devops/resolve-the-public-ip-of-a-url.md)
|
||||
- [Running Out Of inode Space](devops/running-out-of-inode-space.md)
|
||||
- [Set, Get, And Unset Env Vars With Dokku](devops/set-get-and-unset-env-vars-with-dokku.md)
|
||||
- [Set Up Domain For Hatchbox Rails App](devops/set-up-domain-for-hatchbox-rails-app.md)
|
||||
- [SSH Into A Docker Container](devops/ssh-into-a-docker-container.md)
|
||||
- [SSL Certificates Can Cover Multiple Domains](devops/ssl-certificates-can-cover-multiple-domains.md)
|
||||
@@ -720,6 +726,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Capture Screenshot To Clipboard From CLI](mac/capture-screenshot-to-clipboard-from-cli.md)
|
||||
- [Check Network Quality Stats From The Command Line](mac/check-network-quality-stats-from-the-command-line.md)
|
||||
- [Clean Up Old Homebrew Files](mac/clean-up-old-homebrew-files.md)
|
||||
- [Control Which Monitor App Switcher Appears On](mac/control-which-monitor-app-switcher-appears-on.md)
|
||||
- [Convert An HEIC Image File To JPG](mac/convert-an-heic-image-file-to-jpg.md)
|
||||
- [Default Screenshot Location](mac/default-screenshot-location.md)
|
||||
- [Detect How Long A User Has Been Idle](mac/detect-how-long-a-user-has-been-idle.md)
|
||||
@@ -754,9 +761,11 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Create Umbrella Task For All Test Tasks](mise/create-umbrella-task-for-all-test-tasks.md)
|
||||
- [List The Files Being Loaded By Mise](mise/list-the-files-being-loaded-by-mise.md)
|
||||
- [Look In Ruby Version Dotfile](mise/look-in-ruby-version-dotfile.md)
|
||||
- [Override Your Project Mise File](mise/override-your-project-mise-file.md)
|
||||
- [Preserve Color Output For Task Command](mise/preserve-color-output-for-task-command.md)
|
||||
- [Read Existing Dot Env File Into Env Vars](mise/read-existing-dot-env-file-into-env-vars.md)
|
||||
- [Run A Command With Specific Tool Version](mise/run-a-command-with-specific-tool-version.md)
|
||||
- [Search Through Bin Paths For Tool Locations](mise/search-through-bin-paths-for-tool-locations.md)
|
||||
|
||||
### MongoDB
|
||||
|
||||
@@ -862,6 +871,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Clear The Screen In psql](postgres/clear-the-screen-in-psql.md)
|
||||
- [Clear The Screen In psql (2)](postgres/clear-the-screen-in-psql-2.md)
|
||||
- [Compute Hashes With pgcrypto](postgres/compute-hashes-with-pgcrypto.md)
|
||||
- [Compute Median Instead Of Average](postgres/compute-median-instead-of-average.md)
|
||||
- [Compute The Levenshtein Distance Of Two Strings](postgres/compute-the-levenshtein-distance-of-two-strings.md)
|
||||
- [Compute The md5 Hash Of A String](postgres/compute-the-md5-hash-of-a-string.md)
|
||||
- [Concatenate Strings With A Separator](postgres/concatenate-strings-with-a-separator.md)
|
||||
@@ -1029,9 +1039,16 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
### Python
|
||||
|
||||
- [Access Instance Variables](python/access-instance-variables.md)
|
||||
- [Access Most Recent Return Value In REPL](python/access-most-recent-return-value-in-repl.md)
|
||||
- [Break Debugger On First Line Of Program](python/break-debugger-on-first-line-of-program.md)
|
||||
- [Check If Package Is Installed With Pip](python/check-if-package-is-installed-with-pip.md)
|
||||
- [Create A Dummy DataFrame In Pandas](python/create-a-dummy-dataframe-in-pandas.md)
|
||||
- [Dunder Methods](python/dunder-methods.md)
|
||||
- [Easy Key-Value Aggregates With defaultdict](python/easy-key-value-aggregates-with-defaultdict.md)
|
||||
- [Install With PIP For Specific Interpreter](python/install-with-pip-for-specific-interpreter.md)
|
||||
- [Iterate First N Items From Enumerable](python/iterate-first-n-items-from-enumerable.md)
|
||||
- [Keep A Tally With collections.Counter](python/keep-a-tally-with-collections-counter.md)
|
||||
- [Load A File Into The Python REPL](python/load-a-file-into-the-python-repl.md)
|
||||
- [Override The Boolean Context Of A Class](python/override-the-boolean-context-of-a-class.md)
|
||||
- [Store And Access Immutable Data In A Tuple](python/store-and-access-immutable-data-in-a-tuple.md)
|
||||
- [Test A Function With Pytest](python/test-a-function-with-pytest.md)
|
||||
@@ -1070,9 +1087,12 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Cast Common Boolean-Like Values To Booleans](rails/cast-common-boolean-like-values-to-booleans.md)
|
||||
- [Change The Nullability Of A Column](rails/change-the-nullability-of-a-column.md)
|
||||
- [Change The Time Zone Offset Of A DateTime Object](rails/change-the-time-zone-offset-of-a-datetime-object.md)
|
||||
- [Check How Database Is Configured](rails/check-how-database-is-configured.md)
|
||||
- [Check If ActiveRecord Update Fails](rails/check-if-activerecord-update-fails.md)
|
||||
- [Check If Any Records Have A Null Value](rails/check-if-any-records-have-a-null-value.md)
|
||||
- [Check Specific Attributes On ActiveRecord Array](rails/check-specific-attributes-on-activerecord-array.md)
|
||||
- [Check The Current Named Log Level](rails/check-the-current-named-log-level.md)
|
||||
- [Clean Up Memory Hungry Rails Console Processes](rails/clean-up-memory-hungry-rails-console-processes.md)
|
||||
- [Code Statistics For An Application](rails/code-statistics-for-an-application.md)
|
||||
- [Columns With Default Values Are Nil On Create](rails/columns-with-default-values-are-nil-on-create.md)
|
||||
- [Comparing DateTimes Down To Second Precision](rails/comparing-datetimes-down-to-second-precision.md)
|
||||
@@ -1426,6 +1446,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Limit Split](ruby/limit-split.md)
|
||||
- [List The Running Ruby Version](ruby/list-the-running-ruby-version.md)
|
||||
- [Listing Local Variables](ruby/listing-local-variables.md)
|
||||
- [Make A Long String Of Text Readable](ruby/make-a-long-string-of-text-readable.md)
|
||||
- [Make An Executable Ruby Script](ruby/make-an-executable-ruby-script.md)
|
||||
- [Make Structs Easier To Use With Keyword Initialization](ruby/make-structs-easier-to-use-with-keyword-initialization.md)
|
||||
- [Map With Index Over An Array](ruby/map-with-index-over-an-array.md)
|
||||
@@ -1479,6 +1500,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Single And Double Quoted String Notation](ruby/single-and-double-quoted-string-notation.md)
|
||||
- [Skip Specific CVEs When Auditing Your Bundle](ruby/skip-specific-cves-when-auditing-your-bundle.md)
|
||||
- [Skip The Front Of An Array With Drop](ruby/skip-the-front-of-an-array-with-drop.md)
|
||||
- [Specify Default For Data Definition](ruby/specify-default-for-data-definition.md)
|
||||
- [Specify Dependencies For A Rake Task](ruby/specify-dependencies-for-a-rake-task.md)
|
||||
- [Specify How Random Array#sample Is](ruby/specify-how-random-array-sample-is.md)
|
||||
- [Split A Float Into Its Integer And Decimal](ruby/split-a-float-into-its-integer-and-decimal.md)
|
||||
@@ -1566,6 +1588,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Kill Other Connections To A Session](tmux/kill-other-connections-to-a-session.md)
|
||||
- [Kill The Current Session](tmux/kill-the-current-session.md)
|
||||
- [List All Key Bindings](tmux/list-all-key-bindings.md)
|
||||
- [List Processes Running Across All Session](tmux/list-processes-running-across-all-sessions.md)
|
||||
- [List Sessions](tmux/list-sessions.md)
|
||||
- [Open New Splits To The Current Directory](tmux/open-new-splits-to-the-current-directory.md)
|
||||
- [Open New Window With A Specific Directory](tmux/open-new-window-with-a-specific-directory.md)
|
||||
@@ -1625,6 +1648,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Check The Current Working Directory](unix/check-the-current-working-directory.md)
|
||||
- [Check The Installed OpenSSL Version](unix/check-the-installed-openssl-version.md)
|
||||
- [Clear The Screen](unix/clear-the-screen.md)
|
||||
- [Combine All My TILs Into A Single File](unix/combine-all-my-tils-into-a-single-file.md)
|
||||
- [Command Line Length Limitations](unix/command-line-length-limitations.md)
|
||||
- [Compare Two Variables In A Bash Script](unix/compare-two-variables-in-a-bash-script.md)
|
||||
- [Configure cd To Behave Like pushd In Zsh](unix/configure-cd-to-behave-like-pushd-in-zsh.md)
|
||||
@@ -1673,6 +1697,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Fix Previous Command With fc](unix/fix-previous-command-with-fc.md)
|
||||
- [Fix Shim Path After asdf Upgrade](unix/fix-shim-path-after-asdf-upgrade.md)
|
||||
- [Fix Unlinked Node Binaries With asdf](unix/fix-unlinked-node-binaries-with-asdf.md)
|
||||
- [Format And Display Small Amounts Of Columnar Data](unix/format-and-display-small-amounts-of-columnar-data.md)
|
||||
- [Forward Multiple Ports Over SSH](unix/forward-multiple-ports-over-ssh.md)
|
||||
- [Generate A SAML Key And Certificate Pair](unix/generate-a-saml-key-and-certificate-pair.md)
|
||||
- [Generate A Sequence Of Numbered Items](unix/generate-a-sequence-of-numbered-items.md)
|
||||
@@ -1695,6 +1720,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Ignore A Directory During ripgrep Search](unix/ignore-a-directory-during-ripgrep-search.md)
|
||||
- [Ignore The Alias When Running A Command](unix/ignore-the-alias-when-running-a-command.md)
|
||||
- [Include Ignore Files In Ripgrep Search](unix/include-ignore-files-in-ripgrep-search.md)
|
||||
- [Inspect EXIF Data For An Image File](unix/inspect-exif-data-for-an-image-file.md)
|
||||
- [Interactively Browse Available Node Versions](unix/interactively-browse-availabile-node-versions.md)
|
||||
- [Interactively Switch asdf Package Versions](unix/interactively-switch-asdf-package-versions.md)
|
||||
- [Interpret Cron Schedule From The CLI](unix/interpret-cron-schedule-from-the-cli.md)
|
||||
@@ -1756,6 +1782,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Show A File Preview When Searching With FZF](unix/show-a-file-preview-when-searching-with-fzf.md)
|
||||
- [Show Disk Usage For The Current Directory](unix/show-disk-usage-for-the-current-directory.md)
|
||||
- [Show The Size Of Everything In A Directory](unix/show-the-size-of-everything-in-a-directory.md)
|
||||
- [Show Tree View Of Processes And Subprocesses](unix/show-tree-view-of-processes-and-subprocesses.md)
|
||||
- [Skip Paging If Output Fits On Screen With Less](unix/skip-paging-if-output-fits-on-screen-with-less.md)
|
||||
- [SSH Escape Sequences](unix/ssh-escape-sequences.md)
|
||||
- [SSH With Port Forwarding](unix/ssh-with-port-forwarding.md)
|
||||
@@ -1771,6 +1798,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Unrestrict Where ripgrep Searches](unix/unrestrict-where-ripgrep-searches.md)
|
||||
- [Update Package Versions Known By asdf Plugin](unix/update-package-versions-known-by-asdf-plugin.md)
|
||||
- [Use fzf To Change Directories](unix/use-fzf-to-change-directories.md)
|
||||
- [Use Negative Lookbehind Matching With ripgrep](unix/use-negative-lookbehind-matching-with-ripgrep.md)
|
||||
- [Use Regex Pattern Matching With Grep](unix/use-regex-pattern-matching-with-grep.md)
|
||||
- [View A Web Page In The Terminal](unix/view-a-web-page-in-the-terminal.md)
|
||||
- [View The Source For A Brew Formula](unix/view-the-source-for-a-brew-formula.md)
|
||||
|
||||
18
bash/edit-the-current-command-prompt.md
Normal file
18
bash/edit-the-current-command-prompt.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# Edit The Current Command Prompt
|
||||
|
||||
A neat feature of `bash` is the ability to open whatever the current state of
|
||||
the command prompt is into your default editor.
|
||||
|
||||
Let's say we have a really long command that we've just tried to run, but it
|
||||
failed and we need to make a small change somewhere in the middle. Instead of
|
||||
holding the left arrow key for 30 seconds, we can instead hit `CTRL-X CTRL-E`.
|
||||
|
||||
This pops us into our `EDITOR` (or maybe `VISUAL`, not sure which). In my case,
|
||||
that is `nvim`. I now have access to all the features I'm used to in `nvim` for
|
||||
quickly navigating to and editing, searching and replacing, or whatever.
|
||||
|
||||
Once I've got the command how I like it, I can save and exit (`:wq`) and the
|
||||
updated command will be executed.
|
||||
|
||||
This is similar to [the `fc` builtin](unix/fix-previous-command-with-fc.md),
|
||||
which also happens to be available for `zsh`.
|
||||
29
devops/set-get-and-unset-env-vars-with-dokku.md
Normal file
29
devops/set-get-and-unset-env-vars-with-dokku.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Set, Get, And Unset Env Vars With Dokku
|
||||
|
||||
The `dokku` CLI provides `config` subcommands for managing environment variables
|
||||
for the target container.
|
||||
|
||||
An env var can be set for an active container with `config:set`:
|
||||
|
||||
```bash
|
||||
$ dokku config:set app-name JEMALLOC_ENABLED=true MALLOC_CONF="stats_print:true"
|
||||
```
|
||||
|
||||
Notice I'm able to set multiple env vars at once if needed.
|
||||
|
||||
If I ever need to check what an env var is currently set to for one of my app
|
||||
containers, I can use `config:get`:
|
||||
|
||||
```bash
|
||||
$ dokku config:get app-name JEMALLOC_ENABLED
|
||||
true
|
||||
```
|
||||
|
||||
I can always override any value with another `config:set`. However, if I need to
|
||||
entirely remove the env var, I can use `config:unset`:
|
||||
|
||||
```bash
|
||||
$ dokku config:unset app-name MALLOC_CONF
|
||||
```
|
||||
|
||||
[source](https://dokku.com/docs/configuration/environment-variables/)
|
||||
21
mac/control-which-monitor-app-switcher-appears-on.md
Normal file
21
mac/control-which-monitor-app-switcher-appears-on.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Control Which Monitor App Switcher Appears On
|
||||
|
||||
For the most part when I hit `cmd+tab` (and `cmd+shift+tab`) to switch between
|
||||
apps, the visual switcher UI (which shows a row of the open apps) appears on my
|
||||
main monitor. However, sometimes I will be hitting `cmd+tab` and nothing shows
|
||||
up on my main monitor. I look to the right at my side monitor and there is the
|
||||
app switcher UI.
|
||||
|
||||
Why is it appearing over there all of a sudden?
|
||||
|
||||
The reason is that the app switcher UI is anchored to the same screen where the
|
||||
doc is located. Though the doc defaults to my main monitor, if I access the doc
|
||||
from the side monitor, now it is anchored there.
|
||||
|
||||
To switch it back, I just have to make the doc slide up on my main monitor by
|
||||
running my mouse down to the bottom of that screen.
|
||||
|
||||
The switch up was because I accidentally accessed the doc on my side monitor
|
||||
without realizing.
|
||||
|
||||
[source](https://superuser.com/a/744680)
|
||||
37
mise/override-your-project-mise-file.md
Normal file
37
mise/override-your-project-mise-file.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# Override Your Project Mise File
|
||||
|
||||
A project I'm working on has a version-controlled `.mise.toml` file in it. Some
|
||||
changes were made to that recently that introduce some env vars that conflict
|
||||
with my setup. If I make edits to that file, then I have a modified version of
|
||||
`.mise.toml` sitting in my Git working copy.
|
||||
|
||||
```
|
||||
# .mise.toml
|
||||
[env]
|
||||
CONFIG_SETTING = "project"
|
||||
```
|
||||
|
||||
Instead, I can rely on the loading precedence rules of `mise` to override those
|
||||
project settings with my individual settings. I can do that with the
|
||||
`.mise.local.toml` file which is played on top of any `mise` configuration from
|
||||
files further down the precedence chain.
|
||||
|
||||
```
|
||||
# .mise.local.toml
|
||||
[env]
|
||||
CONFIG_SETTING = "override"
|
||||
```
|
||||
|
||||
Assuming I have `mise` setup with my shell environment to automatically load in
|
||||
these files, I can now check what takes precedence:
|
||||
|
||||
```bash
|
||||
$ echo $CONFIG_SETTING
|
||||
override
|
||||
```
|
||||
|
||||
Make sure `.mise.local.toml` is included in the `.gitignore` file to avoid
|
||||
checking in your personal environment overrides.
|
||||
|
||||
To be sure about what files are loaded and in what order, give `mise cfg` a try.
|
||||
I discuss that in more detail in [List The Files Being Loaded By Mise](list-the-files-being-loaded-by-mise.md).
|
||||
29
mise/search-through-bin-paths-for-tool-locations.md
Normal file
29
mise/search-through-bin-paths-for-tool-locations.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Search Through Bin Paths For Tool Locations
|
||||
|
||||
The `mise bin-paths` command will list all the bin paths that are managed by
|
||||
`mise`. When you tell `mise` to install a tool, it installs a specific version
|
||||
at a location where its binaries can be made accessible on the system path.
|
||||
|
||||
While `mise ls` is useful for seeing what is installed by `mise` and at what
|
||||
version, the `bin-paths` command can tell you where those tool installations
|
||||
with their binaries are located.
|
||||
|
||||
Combine this with `grep` or `rg` to narrow down the results to tools by a
|
||||
specific name:
|
||||
|
||||
```bash
|
||||
❯ mise bin-paths | rg 'neovim'
|
||||
/Users/lastword/.local/share/mise/installs/npm-neovim/5.4.0/bin
|
||||
/Users/lastword/.local/share/mise/installs/pipx-neovim-remote/2.5.1/bin
|
||||
/Users/lastword/.local/share/mise/installs/neovim/0.11.6/bin
|
||||
```
|
||||
|
||||
I can then look in one of these directories to see the one or more binaries that
|
||||
they include. For instance, here is what is in the `node` bin path:
|
||||
|
||||
```bash
|
||||
❯ ls /Users/lastword/.local/share/mise/installs/node/22.22.0/bin
|
||||
./ ../ claude@ corepack@ node* npm* npx@
|
||||
```
|
||||
|
||||
See `mise bin-paths --help` for more details.
|
||||
44
postgres/compute-median-instead-of-average.md
Normal file
44
postgres/compute-median-instead-of-average.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# Compute Median Instead Of Average
|
||||
|
||||
One of the first aggregate functions we might use in PostgreSQL, besides `sum`,
|
||||
is `avg`.
|
||||
|
||||
```sql
|
||||
select avg(book_count) as average_books_read
|
||||
from (
|
||||
select users.id, count(books.id) as book_count
|
||||
from users
|
||||
left join books
|
||||
on books.user_id = users.id
|
||||
where books.read_in_year = 2025
|
||||
group by users.id
|
||||
) as user_book_counts;
|
||||
```
|
||||
|
||||
This computes the average of the set of values which sums them all up
|
||||
and divides by the count. The average (maybe you've heard this also called the
|
||||
_mean_) is not always the best way to understand data, especially when there are
|
||||
outliers.
|
||||
|
||||
Instead, we might want to compute the _median_ value of our set of data. There
|
||||
is no easily identifiable `median` aggregate function. Instead, we can use
|
||||
`percentile_cont` with a value of `0.5`. This gets us the 50th percentile of our
|
||||
set of data which is the definition of the _median_.
|
||||
|
||||
```sql
|
||||
select percentile_cont(0.5) within group (
|
||||
order by book_count
|
||||
) as median_books_read
|
||||
from (
|
||||
select users.id, count(books.id) as book_count
|
||||
from users
|
||||
left join books on books.user_id = users.id and books.read_in_year = 2025
|
||||
group by users.id
|
||||
) as user_book_counts;
|
||||
```
|
||||
|
||||
The full syntax for `percentile_cont` is `percentile_cong(precision) within
|
||||
group (order by ...)` because this is an aggregiate that has to work with an
|
||||
ordered-set of data.
|
||||
|
||||
[source](https://www.postgresql.org/docs/current/functions-aggregate.html)
|
||||
34
python/access-most-recent-return-value-in-repl.md
Normal file
34
python/access-most-recent-return-value-in-repl.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Access Most Recent Return Value In REPL
|
||||
|
||||
One of my favorite features of Ruby's `irb` and `pry` are that you can use `_`
|
||||
to reference the most recent return value. Often as we use an interpreter or
|
||||
REPL, we end up with _intermediate_ values. That is, we've execute some kind of
|
||||
statement which returned a value and we now want to use that resulting value in
|
||||
our next statement. Python also supports `_`.
|
||||
|
||||
Let's say I've run a statement that took a while to process, but I forgot to
|
||||
assign it to a variable. Instead of re-running the whole thing, I can create a
|
||||
variable that references the previous return value using `_`.
|
||||
|
||||
```python
|
||||
>>> BytePairEncoding.train_bpe(long_text)
|
||||
{'merge_rules': [...], 'vocab': {...}}
|
||||
>>> result = _
|
||||
>>> list(result.keys())
|
||||
['merge_rules', 'vocab']
|
||||
```
|
||||
|
||||
Even if I don't necessarily want to assign it a variable, it can be nice to
|
||||
reference the previous value as I continue with what I'm doing:
|
||||
|
||||
```python
|
||||
>>> result['merge_rules'][0][1]
|
||||
256
|
||||
>>> result['vocab'][_]
|
||||
b'e '
|
||||
```
|
||||
|
||||
Notice how the value from the first statement gets used as part of a `dict`
|
||||
access.
|
||||
|
||||
[source](https://docs.python.org/3/tutorial/introduction.html#numbers)
|
||||
50
python/check-if-package-is-installed-with-pip.md
Normal file
50
python/check-if-package-is-installed-with-pip.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Check If Package Is Installed With Pip
|
||||
|
||||
I recently installed PyTorch, but when I tried using it, I was getting an error
|
||||
about `numpy` not being installed. I was kind of surprised by that because I
|
||||
thought I would have already had that.
|
||||
|
||||
I wanted to check, so I asked with `pip show`:
|
||||
|
||||
```bash
|
||||
❯ python3 -m pip show numpy
|
||||
WARNING: Package(s) not found: numpy
|
||||
```
|
||||
|
||||
I can even list everything that is installed with `pip` using `pip list` like
|
||||
so:
|
||||
|
||||
```bash
|
||||
❯ python3 -m pip list
|
||||
Package Version Build
|
||||
------------------ --------- -----
|
||||
certifi 2026.1.4
|
||||
cffi 2.0.0
|
||||
charset-normalizer 3.4.4
|
||||
click 8.3.1
|
||||
commonmark 0.9.1
|
||||
cryptography 46.0.3
|
||||
docutils 0.22.4
|
||||
filelock 3.24.2
|
||||
fsspec 2026.2.0
|
||||
idna 3.11
|
||||
Jinja2 3.1.6
|
||||
...
|
||||
```
|
||||
|
||||
I then installed `numpy` (`python3 -m pip install numpy`) and how I can use `pip
|
||||
show` again to confirm that.
|
||||
|
||||
```bash
|
||||
❯ python3 -m pip show numpy
|
||||
Name: numpy
|
||||
Version: 2.4.2
|
||||
Summary: Fundamental package for array computing in Python
|
||||
Home-page: https://numpy.org
|
||||
Author: Travis E. Oliphant et al.
|
||||
Author-email:
|
||||
License-Expression: BSD-3-Clause AND 0BSD AND MIT AND Zlib AND CC0-1.0
|
||||
Location: /Users/lastword/.local/share/mise/installs/python/3.12.12/lib/python3.12/site-packages
|
||||
Requires:
|
||||
Required-by:
|
||||
```
|
||||
53
python/easy-key-value-aggregates-with-defaultdict.md
Normal file
53
python/easy-key-value-aggregates-with-defaultdict.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Easy Key-Value Aggregates With defaultdict
|
||||
|
||||
The `collections` module has the `defaultdict` object that can be used to
|
||||
aggregate values tied to a key. What sets this apart from simply using a `dict`
|
||||
is that we get the base value for free. So if our aggregate value is a list,
|
||||
then we get `[]` by default for each new key. In the same way, we'd get `0` if
|
||||
it was constructed with `int`.
|
||||
|
||||
Here is the counter example from [Keep A Tally With
|
||||
collections.Counter](keep-a-tally-with-collections-counter.md)
|
||||
|
||||
```python
|
||||
from collections import defaultdict
|
||||
|
||||
def get_pair_counts(token_ids: list[int]) -> Counter:
|
||||
"""Count how often each adjacent pair appears"""
|
||||
counts = defaultdict(int)
|
||||
for i in range(len(token_ids) - 1):
|
||||
pair = (token_ids[i], token_ids[i + 1])
|
||||
counts[pair] += 1
|
||||
return counts
|
||||
```
|
||||
|
||||
We never have to initially set a key to `0`. If the key is not yet present, then
|
||||
`int()` (the zero-value constructor) is used as the `__missing__` value.
|
||||
|
||||
We can do the same with `list`:
|
||||
|
||||
```python
|
||||
>>> import collections
|
||||
>>> stuff = collections.defaultdict(list)
|
||||
>>> stuff['alpha'].append(1)
|
||||
>>> stuff['alpha']
|
||||
[1]
|
||||
>>> stuff['beta']
|
||||
[]
|
||||
```
|
||||
|
||||
In the same way, this uses `list()` as the `__missing__` value to start of each
|
||||
key with an `[]`.
|
||||
|
||||
I find this so handy because in other languages I've typically had to do
|
||||
something more like this:
|
||||
|
||||
```python
|
||||
words_by_length = {}
|
||||
for item in items:
|
||||
if len(item) not in words_by_length:
|
||||
words_by_length[len(item)] = []
|
||||
words_by_length[len(item)].append(item)
|
||||
```
|
||||
|
||||
This is much clunkier.
|
||||
17
python/install-with-pip-for-specific-interpreter.md
Normal file
17
python/install-with-pip-for-specific-interpreter.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Install With PIP For Specific Interpreter
|
||||
|
||||
The `pip` module can be invoked for any of its commands, such as install, using
|
||||
a specific Python interpreter like so:
|
||||
|
||||
```bash
|
||||
$ python3 -m pip install black
|
||||
```
|
||||
|
||||
This avoid ambiguity between the version of Python I am using and version of the
|
||||
package manager I'm using.
|
||||
|
||||
Similarly if I need to upgrade `pip`, I can do the following:
|
||||
|
||||
```bash
|
||||
$ python3 -m pip install --upgrade pip
|
||||
```
|
||||
27
python/iterate-first-n-items-from-enumerable.md
Normal file
27
python/iterate-first-n-items-from-enumerable.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Iterate First N Items From Enumerable
|
||||
|
||||
As I'm working through the 2nd chapter of [Build a Large Language Model (from
|
||||
scratch)](https://still.visualmode.dev/blogmarks/227), I came across a code
|
||||
example processing a dictionary of words. This example used a for loop to print
|
||||
out each dictionary entry until an index of 50 was reached on then it did a
|
||||
`break`.
|
||||
|
||||
This struck me as an odd way to grab and process N items from a list. I did some
|
||||
searching and found `itertools` which provides
|
||||
[`islice`](https://docs.python.org/3/library/itertools.html#itertools.islice).
|
||||
|
||||
```python
|
||||
from itertools import islice
|
||||
|
||||
# preprocess words from a file into a word list
|
||||
all_words = ... # not shown here
|
||||
|
||||
vocab = {token: integer for integer, token in enumerate(all_words)}
|
||||
for item in islice(enumerate(vocab.items()), 50):
|
||||
print(item)
|
||||
```
|
||||
|
||||
The `islice` function is a better approach because the intention (to grab the
|
||||
first 50 things) is encoded in the function call rather than buried in a loop
|
||||
body. It also has equivalent memory efficiency to the original example because
|
||||
it lazily processes the list of `vocab` items.
|
||||
40
python/keep-a-tally-with-collections-counter.md
Normal file
40
python/keep-a-tally-with-collections-counter.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Keep A Tally With collections.Counter
|
||||
|
||||
Python's `collections` module comes with a
|
||||
[`Counter`](https://docs.python.org/3/library/collections.html#collections.Counter)
|
||||
object which is a specialized dict subclass focussed on tallying counts of keys.
|
||||
|
||||
> It is a collection where elements are stored as dictionary keys and their
|
||||
> counts are stored as dictionary values. Counts are allowed to be any integer
|
||||
> value including zero or negative counts.
|
||||
|
||||
I used it recently while doing an exploratory implementation of a Byte-Pair
|
||||
Encoding (BPE):
|
||||
|
||||
```python
|
||||
from collections import Counter
|
||||
|
||||
def get_pair_counts(token_ids: list[int]) -> Counter:
|
||||
"""Count how often each adjacent pair appears"""
|
||||
counts = Counter()
|
||||
for i in range(len(token_ids) - 1):
|
||||
pair = (token_ids[i], token_ids[i + 1])
|
||||
counts[pair] += 1
|
||||
return counts
|
||||
```
|
||||
|
||||
Here I'm able to count the number of occurrences of each pair of bytes from the
|
||||
input text. A tuple of `int` values is hashable, so they work great as keys for
|
||||
a `Counter`.
|
||||
|
||||
The count value of any key will default to `0`. That makes it straightforward to
|
||||
increment from there as you iterating over occurrences.
|
||||
|
||||
```python
|
||||
>>> counts = Counter()
|
||||
>>> counts['hello']
|
||||
0
|
||||
>>> count['hello'] += 1
|
||||
>>> count['hello']
|
||||
1
|
||||
```
|
||||
35
python/load-a-file-into-the-python-repl.md
Normal file
35
python/load-a-file-into-the-python-repl.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Load A File Into The Python REPL
|
||||
|
||||
I opened up a Python REPL to try some things out.
|
||||
|
||||
```
|
||||
$ python3
|
||||
>>> import math
|
||||
>>> math.floor(5/2)
|
||||
2
|
||||
```
|
||||
|
||||
Now, I want to reference a Python file I've been working on so that I can
|
||||
manually test the behavior of what I'm building. To do this, I can import a file
|
||||
by its name in the same way that I would import any module. Then I can use that
|
||||
namespace for class and method references. Crucially, the file should exist in
|
||||
the same directory the REPL was started from.
|
||||
|
||||
First, here is the file:
|
||||
|
||||
```python
|
||||
# bpe.py
|
||||
class BytePairEncoding:
|
||||
def text_to_bytes(text: str) -> list[int]:
|
||||
"""Convert a string to a list of byte values (0-255)"""
|
||||
return list(text.encode("utf-8"))
|
||||
```
|
||||
|
||||
Now to use it from the REPL:
|
||||
|
||||
```
|
||||
$ python
|
||||
>>> import bpe
|
||||
>>> bpe.BytePairEncoding.text_to_bytes("Gimme some bytes!")
|
||||
[71, 105, 109, 109, 101, 32, 115, 111, 109, 101, 32, 98, 121, 116, 101, 115, 33]
|
||||
```
|
||||
46
rails/check-how-database-is-configured.md
Normal file
46
rails/check-how-database-is-configured.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# Check How Database Is Configured
|
||||
|
||||
While making some adjustments to the database connection string (`DATABASE_URL`)
|
||||
for a pre-production Rails environment, we wanted to check that configuration
|
||||
options like `sslmode` were picked up.
|
||||
|
||||
From a `rails console` session I can check the live database configuration like
|
||||
so:
|
||||
|
||||
```ruby
|
||||
> ActiveRecord::Base.connection_db_config.configuration_hash
|
||||
=> {
|
||||
adapter: "postgresql",
|
||||
encoding: "unicode",
|
||||
pool: 5,
|
||||
database: "my_app_development"
|
||||
}
|
||||
```
|
||||
|
||||
I can look at the
|
||||
[`configuration_hash`](https://api.rubyonrails.org/classes/ActiveRecord/DatabaseConfigurations/HashConfig.html#attribute-i-configuration_hash)
|
||||
from `rails console` of my pre-prod environment to see more configuration
|
||||
settings:
|
||||
|
||||
```ruby
|
||||
> ActiveRecord::Base.connection_db_config.configuration_hash
|
||||
=> {
|
||||
adapter: "postgresql",
|
||||
encoding: "unicode",
|
||||
pool: 5,
|
||||
username: "app_user",
|
||||
password: "super_s3cr3t",
|
||||
port: 15432,
|
||||
database: "pre_prod_database",
|
||||
host: "some-host-123.ondigitalocean.com",
|
||||
sslmode: "verify-full"
|
||||
}
|
||||
```
|
||||
|
||||
Since I was specifically looking for the `sslmode` value, I can access that
|
||||
directly:
|
||||
|
||||
```ruby
|
||||
> ActiveRecord::Base.connection_db_config.configuration_hash[:sslmode]
|
||||
=> "verify-full"
|
||||
```
|
||||
46
rails/check-the-current-named-log-level.md
Normal file
46
rails/check-the-current-named-log-level.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# Check The Current Named Log Level
|
||||
|
||||
I'm connected to a `rails console` session for an active Rails app. I want to
|
||||
check the current log level.
|
||||
|
||||
```ruby
|
||||
> Rails.logger.level
|
||||
=> 1
|
||||
```
|
||||
|
||||
The `1` doesn't mean much to me at a glance. I can translate that to the
|
||||
severity level using the `Logger::SEV_LABLE` constant.
|
||||
|
||||
```ruby
|
||||
[44] pry(main)> Logger::SEV_LABEL[Rails.logger.level]
|
||||
=> "INFO"
|
||||
```
|
||||
|
||||
Ah yes, `INFO`, that makes sense as the default.
|
||||
|
||||
I can see all the severity levels by inspecting the constant itself.
|
||||
|
||||
```ruby
|
||||
[45] pry(main)> Logger::SEV_LABEL
|
||||
=> ["DEBUG", "INFO", "WARN", "ERROR", "FATAL", "ANY"]
|
||||
```
|
||||
|
||||
As I convenience, I can set the label using the index, the string, or even a
|
||||
symbol.
|
||||
|
||||
```ruby
|
||||
> Rails.logger.level
|
||||
=> 1
|
||||
> Rails.logger.level = "WARN"
|
||||
=> "WARN"
|
||||
> Rails.logger.level
|
||||
=> 2
|
||||
> Rails.logger.level = :debug
|
||||
=> :debug
|
||||
> Rails.logger.level
|
||||
=> 0
|
||||
```
|
||||
|
||||
See the [Debugging Rails Applications
|
||||
guide](https://guides.rubyonrails.org/debugging_rails_applications.html#log-levels)
|
||||
for more details.
|
||||
43
rails/clean-up-memory-hungry-rails-console-processes.md
Normal file
43
rails/clean-up-memory-hungry-rails-console-processes.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Clean Up Memory Hungry Rails Console Processes
|
||||
|
||||
I noticed (using `htop`) that a remote server hosting a Rails app had most of
|
||||
its RAM being actively consumed. This was hindering my ability to run a fresh
|
||||
deploy because the deploy processes had to do a ton of memory swapping which
|
||||
drastically slowed the whole thing down.
|
||||
|
||||
With some investigation, I discovered that most of the memory was being consumed
|
||||
by a handful of `rails console` processes. I didn't have any known active `rails console` processes that I was using. That combined with the dates of these
|
||||
processes starting way in the past suggested to me that these were abandoned
|
||||
processes that hadn't been properly cleaned up.
|
||||
|
||||
```bash
|
||||
server:~# ps aux | grep rails
|
||||
32767 878915 0.0 0.0 1227160 936 pts/0 Ssl+ 2025 0:03 /exec rails console
|
||||
32767 878942 0.9 6.5 830996 261748 pts/0 Rl+ 2025 249:51 ruby /app/bin/rails console
|
||||
32767 3004097 0.0 0.0 1227160 692 pts/0 Ssl+ 2025 0:04 /exec rails console
|
||||
32767 3004129 0.9 6.4 834672 257228 pts/0 Dl+ 2025 406:31 ruby /app/bin/rails console
|
||||
32767 3048582 0.0 0.0 1227160 940 pts/0 Ssl+ Jan09 0:00 /exec rails console
|
||||
32767 3048611 1.1 6.3 829936 253484 pts/0 Dl+ Jan09 60:50 ruby /app/bin/rails console
|
||||
32767 3060033 0.0 0.0 1227160 944 pts/0 Ssl+ 2025 0:04 /exec rails console
|
||||
32767 3060063 0.9 6.5 838084 260812 pts/0 Rl+ 2025 405:37 ruby /app/bin/rails console
|
||||
root 3699372 0.0 0.0 7008 1300 pts/0 S+ 15:51 0:00 grep --color=auto rails
|
||||
server:~# ps aux | grep 'rails console' | awk '{sum+=$6} END {print sum/1024 " MB"}'
|
||||
1014.64 MB
|
||||
```
|
||||
|
||||
As we can see by tacking on this `awk` command, these processes are consuming
|
||||
1GB of memory.
|
||||
|
||||
Each of these is a pair of processes. A parent process (`/exec rails console`)
|
||||
that kicks off and supervises the memory-hungry child process (`ruby /app/bin/rails console`).
|
||||
|
||||
To free up this memory, I targeted each of the parent processes with a `kill`
|
||||
command one by one. For example:
|
||||
|
||||
```bash
|
||||
server:~# kill 878915
|
||||
```
|
||||
|
||||
I suspect that I may have left the occasional terminal tab open with one of
|
||||
these `rails console` processes running and the SSH connection was getting
|
||||
killed without the `rails console` getting killed with it.
|
||||
38
ruby/make-a-long-string-of-text-readable.md
Normal file
38
ruby/make-a-long-string-of-text-readable.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# Make A Long String Of Text Readable
|
||||
|
||||
I have a paragraph of text that interpolates a couple user-specific values
|
||||
before being included in an API request. Because it is being passed to an API,
|
||||
it is a single-line string value. However, in the editor it is hard to read like
|
||||
that because it overflows way past the edge of the viewport.
|
||||
|
||||
```ruby
|
||||
description = "This is the description we need to provide for #{user.name} as part of an API request dealing with compliance and registration for a service. If you need to contact them, their email is #{user.email}."
|
||||
```
|
||||
|
||||
I'd rather make this easier on myself and others to read from the editor while
|
||||
still being able to submit a single-line string to the API. That can be
|
||||
accomplished with a heredoc and some combination or `gsub`, `strip`, and
|
||||
`squish`.
|
||||
|
||||
If we are in a strictly Ruby-only context, we can use `gsub` and `strip` to
|
||||
collapse line breaks and remove surrounding white space.
|
||||
|
||||
```ruby
|
||||
description = <<~MSG.gsub(/\s+/, ' ').strip
|
||||
This is the description we need to provide for #{user.name} as part
|
||||
of an API request dealing with compliance and registration for a
|
||||
service. If you need to contact them, their email is #{user.email}.
|
||||
MSG
|
||||
#=> "This is the description we need to provide for #{user.name} as part of an API request dealing with compliance and registration for a service. If you need to contact them, their email is #{user.email}."
|
||||
```
|
||||
|
||||
Or in a Rails context, I can instead just use `squish`:
|
||||
|
||||
```ruby
|
||||
description = <<~MSG.squish
|
||||
This is the description we need to provide for #{user.name} as part
|
||||
of an API request dealing with compliance and registration for a
|
||||
service. If you need to contact them, their email is #{user.email}.
|
||||
MSG
|
||||
#=> "This is the description we need to provide for #{user.name} as part of an API request dealing with compliance and registration for a service. If you need to contact them, their email is #{user.email}."
|
||||
```
|
||||
43
ruby/specify-default-for-data-definition.md
Normal file
43
ruby/specify-default-for-data-definition.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Specify Default For Data Definition
|
||||
|
||||
Here is what a `Data` definition for the concept of a `Permission` might look
|
||||
like:
|
||||
|
||||
```ruby
|
||||
Permission = Data.define(:id, :name, :description, :enabled)
|
||||
|
||||
perm1 = Permission.new(
|
||||
id: 123,
|
||||
name: :can_edit,
|
||||
description: "User is allowed to edit.",
|
||||
enabled: true
|
||||
)
|
||||
```
|
||||
|
||||
However, as we're creating various `Permission` entities, we may find that the
|
||||
vast majority of them are _enabled_ by default and so we'd like to apply `true`
|
||||
as a default value.
|
||||
|
||||
We cannot do this directly in the `Data` definition, but we can open a block to
|
||||
override the `initialize` method.
|
||||
|
||||
```ruby
|
||||
Permission = Data.define(:id, :name, :description, :enabled) do
|
||||
def initialize(:id, :name, :description, enabled: true)
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
perm1 = Permission.new(
|
||||
id: 123,
|
||||
name: :can_edit,
|
||||
description: "User is allowed to edit."
|
||||
)
|
||||
|
||||
perm1.enabled #=> true
|
||||
```
|
||||
|
||||
Now we're able to create a `Permission` without specifying the `enabled`
|
||||
attribute and it takes on the default of `true`.
|
||||
|
||||
[source](https://dev.to/baweaver/new-in-ruby-32-datadefine-2819#comment-254o8)
|
||||
46
tmux/list-processes-running-across-all-sessions.md
Normal file
46
tmux/list-processes-running-across-all-sessions.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# List Processes Running Across All Session
|
||||
|
||||
I wanted an overview of all the processes running across all the tmux sessions
|
||||
that I have running on my machine right now. The `list-panes` command (with the
|
||||
`-a` flag) gives me a listing of all the panes across all session of the current
|
||||
tmux server.
|
||||
|
||||
That output on its own isn't giving me quite the info I'm looking for though.
|
||||
With the `-f` (_format_) flag, I can use variables available in that context
|
||||
like `session_name`, `pane_pid`, and `pane_current_command`.
|
||||
|
||||
I can assemble the details I want into a command like this:
|
||||
|
||||
```bash
|
||||
❯ tmux list-panes -a -F "#{session_name}:#{window_index}.#{pane_index} #{pane_pid} #{pane_current_command}"
|
||||
PLP:1.1 62364 zsh
|
||||
TIL:1.1 62345 nvim
|
||||
TIL:1.2 65838 task
|
||||
TIL:2.1 11428 tmux
|
||||
client-app:1.1 62373 ssh
|
||||
client-app:1.2 10796 zsh
|
||||
client-app:1.3 63081 zsh
|
||||
client-app:2.1 61115 overmind
|
||||
client-app:3.1 82608 zsh
|
||||
visualmode-dev:1.1 52237 zsh
|
||||
```
|
||||
|
||||
This gives me the details I want, but I can take it a step further by piping it
|
||||
to the `column` command to improve the formatting a little:
|
||||
|
||||
```bash
|
||||
❯ tmux list-panes -a -F "#{session_name}:#{window_index}.#{pane_index} #{pane_pid} #{pane_current_command}" \
|
||||
| column -t
|
||||
PLP:1.1 62364 zsh
|
||||
TIL:1.1 62345 nvim
|
||||
TIL:1.2 65838 task
|
||||
TIL:2.1 11428 tmux
|
||||
client-app:1.1 62373 ssh
|
||||
client-app:1.2 10796 zsh
|
||||
client-app:1.3 63081 zsh
|
||||
client-app:2.1 61115 overmind
|
||||
client-app:3.1 82608 zsh
|
||||
visualmode-dev:1.1 52237 zsh
|
||||
```
|
||||
|
||||
See `man tmux` and, in particular, the `FORMATS` section for more details.
|
||||
35
unix/combine-all-my-tils-into-a-single-file.md
Normal file
35
unix/combine-all-my-tils-into-a-single-file.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Combine All My TILs Into A Single File
|
||||
|
||||
In [Build A Small Text-based Training
|
||||
Dataset](https://www.visualmode.dev/build-a-small-text-training-dataset), I went
|
||||
over my need for a sizeable and interesting corpus of text that I could use as a
|
||||
training dataset I could use to run against [my own naive Byte Pair Encoding
|
||||
implementation](https://github.com/jbranchaud/build-an-llm-from-scratch/blob/main/chapter-02/bpe_tokenizer.py).
|
||||
My repo of hand-written TILs is a great candidate, but I need those smashed all
|
||||
into one file.
|
||||
|
||||
Here is a formatted version of the one-liner I ended up with:
|
||||
|
||||
```bash
|
||||
{
|
||||
cat README.md; \
|
||||
find */ -name '*.md' -print0 \
|
||||
| sort -z \
|
||||
| xargs -0 -I{} sh -c 'echo "<|endoftext|>"; cat "$1"' _ {}; \
|
||||
} > combined.md
|
||||
```
|
||||
|
||||
This combines all 1700+ of my TILs into a single file separated by the
|
||||
`<|endoftext|>` delimiter.
|
||||
|
||||
The two things I find most interesting about this command are:
|
||||
|
||||
1. The use of a null byte (`\0`) separator between the filenames in case there
|
||||
is anything weird (like spaces) in those filenames. This starts with
|
||||
`-print0`. The `-z` of `sort` maintains that null byte separator. And then
|
||||
`xargs` knows to handle it by the `-0` flag.
|
||||
|
||||
2. We can coerce `xargs` into running multiple commands by having it spawn a
|
||||
single shell process that runs each of those commands. To reliably pass the
|
||||
filename into that shell process, we have `xargs` constitute it as the second
|
||||
argument (`$1`) by substituting in the filename where `{}` appears.
|
||||
44
unix/format-and-display-small-amounts-of-columnar-data.md
Normal file
44
unix/format-and-display-small-amounts-of-columnar-data.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# Format And Display Small Amounts Of Columnar Data
|
||||
|
||||
In [_List Processes Running Across All (tmux)
|
||||
Sessions](tmux/list-processes-running-across-all-sessions.md), I showed an
|
||||
example of piping some data from `tmux` to the `column -t` command to nicely format
|
||||
and display the columnar data as a table. By default is uses spaces as the
|
||||
delimiter.
|
||||
|
||||
```bash
|
||||
❯ tmux list-panes -a -F "#{session_name}:#{window_index}.#{pane_index} #{pane_pid} #{pane_current_command}" \
|
||||
| column -t
|
||||
|
||||
PLP:1.1 62364 zsh
|
||||
TIL:1.1 62345 nvim
|
||||
TIL:1.2 65838 task
|
||||
TIL:2.1 11428 tmux
|
||||
client-app:1.1 62373 ssh
|
||||
client-app:1.2 10796 zsh
|
||||
client-app:1.3 63081 zsh
|
||||
client-app:2.1 61115 overmind
|
||||
client-app:3.1 82608 zsh
|
||||
visualmode-dev:1.1 52237 zsh
|
||||
```
|
||||
|
||||
This can be useful for formatting data from all kinds of commands and tools.
|
||||
Sometimes the columns of data are separated by something other than spaces. For
|
||||
instance, here is some git branch information (for my [dotfiles
|
||||
repo](https://github.com/jbranchaud/dotfiles)) separated by the `|` character.
|
||||
To format that with `column`, I need to also include the `-s '|'` flag to
|
||||
override the delimiter.
|
||||
|
||||
```bash
|
||||
❯ git for-each-ref --format='%(refname:short)|%(authordate:short)|%(authorname)' refs/heads/ \
|
||||
| column -t -s '|'
|
||||
|
||||
claude/sync-dotfiles-011CUP87cRV6c51eEi3Chg99 2025-10-22 jbranchaud
|
||||
jb/add-rhubarb-for-fugitive-github-browse 2025-11-02 jbranchaud
|
||||
jb/fix-hardcoded-paths 2025-11-02 jbranchaud
|
||||
jb/set-nvim-to-default-manpager 2025-10-19 jbranchaud
|
||||
main 2026-01-10 jbranchaud
|
||||
master 2025-10-30 Dorian Karter
|
||||
my-dotfiles 2025-11-01 jbranchaud
|
||||
upstream-master 2026-01-01 Dorian Karter
|
||||
```
|
||||
47
unix/inspect-exif-data-for-an-image-file.md
Normal file
47
unix/inspect-exif-data-for-an-image-file.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# Inspect EXIF Data For An Image File
|
||||
|
||||
The `exiftool` CLI (which can be downloaded via `brew`) is a useful tool for
|
||||
inspecting all the EXIF data attached to a media file. A media file like an
|
||||
image has a bunch of additional details embedded in it like timestamps, image
|
||||
metadata, and sometimes location information.
|
||||
|
||||
Here is all the data attached to a screenshot I found on my desktop:
|
||||
|
||||
```bash
|
||||
❯ exiftool ~/Desktop/CleanShot\ 2025-11-17\ at\ 11.22.18@2x.png
|
||||
ExifTool Version Number : 13.50
|
||||
File Name : CleanShot 2025-11-17 at 11.22.18@2x.png
|
||||
Directory : /Users/lastword/Desktop
|
||||
File Size : 1194 kB
|
||||
File Modification Date/Time : 2025:11:17 11:22:21-06:00
|
||||
File Access Date/Time : 2025:12:15 10:43:55-06:00
|
||||
File Inode Change Date/Time : 2025:12:05 15:37:48-06:00
|
||||
File Permissions : -rw-r--r--
|
||||
File Type : PNG
|
||||
File Type Extension : png
|
||||
MIME Type : image/png
|
||||
Image Width : 2502
|
||||
Image Height : 1232
|
||||
Bit Depth : 8
|
||||
Color Type : RGB with Alpha
|
||||
Compression : Deflate/Inflate
|
||||
Filter : Adaptive
|
||||
Interlace : Noninterlaced
|
||||
XMP Toolkit : XMP Core 6.0.0
|
||||
Y Resolution : 144
|
||||
Resolution Unit : inches
|
||||
X Resolution : 144
|
||||
Exif Image Width : 2502
|
||||
Color Space : sRGB
|
||||
User Comment : Screenshot
|
||||
Exif Image Height : 1232
|
||||
SRGB Rendering : Perceptual
|
||||
Image Size : 2502x1232
|
||||
Megapixels : 3.1
|
||||
```
|
||||
|
||||
This works with other kinds of media files. For instance, I ran this against an
|
||||
MP4 screen recording file which contained even more metadata.
|
||||
|
||||
In addition to reading data, `exiftool` can also write it. See `man exiftool`
|
||||
for more details on what else it can do.
|
||||
36
unix/show-tree-view-of-processes-and-subprocesses.md
Normal file
36
unix/show-tree-view-of-processes-and-subprocesses.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# Show Tree View Of Processes And Subprocesses
|
||||
|
||||
Though you can cobble together a command on a MacOS Unix system to output a
|
||||
hierarchical tree view of a parent process and its descendent subprocesses, it
|
||||
is easier to [`brew install pstree`](https://github.com/FredHucht/pstree) and
|
||||
use that.
|
||||
|
||||
Here is what I see when I run it for a _pid_ that corresponds to a `tmux`
|
||||
session that I have running locally:
|
||||
|
||||
```bash
|
||||
❯ pstree 61690
|
||||
-+= 61690 lastword tmux new-session -d -s TIL -c /Users/lastword/dev/jbranchaud/til
|
||||
|--= 63081 lastword /bin/zsh
|
||||
|-+= 11428 lastword zsh
|
||||
| \-+= 48511 lastword pstree 61690
|
||||
| \--- 48512 root ps -axwwo user,pid,ppid,pgid,command
|
||||
|-+= 62345 lastword zsh
|
||||
| \--= 06031 lastword claude
|
||||
|--= 62364 lastword /bin/zsh
|
||||
|-+= 62373 lastword zsh
|
||||
| \--= 64407 lastword ssh my-app-staging
|
||||
|-+= 61115 lastword /bin/zsh
|
||||
| \-+= 61579 lastword overmind start -f Procfile.dev
|
||||
| \--- 61586 lastword tmux -C -L overmind-my-app-abc123 new -n web -s my-app -P -F %overmind-process #{pane_id} web #{pane_pid} /var/folders/zc/abc123/T/overmin
|
||||
|--= 52237 lastword /bin/zsh
|
||||
|--= 82608 lastword /bin/zsh
|
||||
\--= 10796 lastword /bin/zsh
|
||||
```
|
||||
|
||||
I was looking for a frozen `claude` process that was part of this session. And I
|
||||
found it about halfway down that list -- `06031`. Now I can run `kill` on that
|
||||
process as needed.
|
||||
|
||||
For some additional context, I initially found the _pid_ for the `tmux` session
|
||||
by running `ps aux | grep tmux` and looking through those results.
|
||||
42
unix/use-negative-lookbehind-matching-with-ripgrep.md
Normal file
42
unix/use-negative-lookbehind-matching-with-ripgrep.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Use Negative Lookbehind Matching With ripgrep
|
||||
|
||||
The most straightforward way to use `ripgrep` is to hand it a pattern. It will
|
||||
take that pattern and move forward through each file trying to find matches.
|
||||
|
||||
```bash
|
||||
$ rg 'TwilioClient\.new'
|
||||
```
|
||||
|
||||
That will find all occurrences of `TwilioClient.new` in available project files.
|
||||
|
||||
What if that pattern is too permissive though? That is going to match on
|
||||
occurrences of `TwilioClient.new` as well as things like
|
||||
`LoggingTwilioClient.new`. If we want to exclude the latter, there are a few
|
||||
ways to do that. One of them being the use of [the _negative lookbehind_ regex
|
||||
feature](https://www.pcre.org/current/doc/html/pcre2syntax.html#SEC23) that is
|
||||
available with PCRE2 (Perl-Compatible Regular Expressions).
|
||||
|
||||
A _negative lookbehind_ is like a standard pattern. We look forward through the
|
||||
document for the base pattern (like `TwilioClient\.new`). However, once we find
|
||||
that match, we then look back at the previous characters and if they match our
|
||||
negative lookbehind pattern, then it is no longer a positive match.
|
||||
|
||||
We can use one of the following to forms to achieve this:
|
||||
|
||||
```
|
||||
(?<!...) )
|
||||
(*nlb:...) ) negative lookbehind
|
||||
(*negative_lookbehind:...) )
|
||||
```
|
||||
|
||||
For instance, here is what this looks like for our example:
|
||||
|
||||
```bash
|
||||
$ rg -P '(?<!Logging)TwilioClient\.new'
|
||||
```
|
||||
|
||||
Note: we have to use the `-P` flag to tell `ripgrep` that we are using PCRE2
|
||||
syntax. Otherwise, it assumes a simpler regex syntax that doesn't support
|
||||
_negative lookbehind_.
|
||||
|
||||
See `man rg` for more details.
|
||||
Reference in New Issue
Block a user