TIL
Faster Binary Search (2025-12-16)
In the regular procedure, the algorithm checks whether the middle element is equal to the target in every iteration. Some implementations leave out this check during each iteration. The algorithm would perform this check only when one element is left (when L equals R). This results in a faster comparison loop, as one comparison is eliminated per iteration, while it requires only one more iteration on average.
def binary_search_alternative(arr, target):
left = 0
right = len(arr) - 1
while left < right:
mid = left + ceil((right - left) / 2)
if arr[mid] > target:
right = mid - 1
else:
left = mid
if arr[left] == target: # move target check out of loop
return left
return None
Hermann Bottenbruch published the first implementation to leave out this check in 1962.
https://en.wikipedia.org/wiki/Binary_search#Alternative_procedure
How To Wrap Christmas Lights (2025-12-06)
- Cut two slits in a piece of cardboard.
- Wrap starting with the female plug.
- Tuck or plug in the male end.
It's the Christmas light video again - 2025 edition by Technology Connections
Add Pre-Wash Soap Your Dishwasher (2025-12-06)
There's a tiny slot next to the soap dispenser with holes in the lid. This is for soap during the pre-wash rinse. Just a little sink soap in this slot makes a huge difference!
I was right about dishwasher pods, and now I can prove it by Technology Connections
i3 config (2025-12-10)
set $mod Mod4 # Windows key
Then press $mod+Shift+R to reload config
ssh key pairs (2025-12-09)
- Check for id_rsa:
ls ~/.ssh(if there, skip to 3.) - Make ssh key
ssh-keygen - Copy to server
ssh-copy-id {YOU}@server - If on Windows or doing for another account:
- copy
id_rsa.pubto/home/{USER}/.ssh/authorized_keys - folder permissions:
chmod 700 .ssh - file permissions:
chmod 600 .ssh/authorized_keys
- copy
lazygit is the best (2025-11-27)
Learned from lazygit
- in files: ctrl+b, t to only show tracked files
- add files to
.git/info/excludefor a private, uncommitted gitignore - you can apply patches from stash
The Performance Inequality Gap, 2026 (2025-11-24)
https://infrequently.org/2025/11/performance-inequality-gap-2026/
| Budget @ P75 | Total | JS (15%) | Total | JS (50%) |
|---|---|---|---|---|
| 3 sec | 2.0 MiB | 0.3 MiB | 1.2 MiB | 0.62 MiB |
| 5 sec | 3.7 MiB | 0.57 MiB | 2.3 MiB | 1.15 MiB |
Updated network test parameters for 2026 are:
- 9 Mbps downlink
- 3 mbps uplink
- 100 millisecond RTT
The goal of these recommendations is to emulate a 75th percentile user experience, meaning a full quarter of devices and networks will perform worse than this baseline.
Per usual, we consider pages built in two styles:
- JS-light, where only 15% of critical-path bytes are JavaScript
- JS-heavy, comprised of 50% JavaScript
Git: Conventional Commits
From Conventional Commits and Angular's convention
Prefix commit messages with meaningful tags. Start with a type, add a (scope), and end with ! if it's a breaking change. i.e., fix(css): saved items not underlined or feat(config)!: switch to YAML.
- build: Changes that affect the build system or external dependencies
- chore: Linting, testing, building.
- ci: Changes to our CI configuration files and scripts
- docs: Documentation only changes
- feat: A new feature
- fix: A bug fix
- perf: A code change that improves performance
- refactor: A code change that neither fixes a bug nor adds a feature
- style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
- test: Adding missing tests or correcting existing tests
JS: Null Coalescence Assignment (??=) (2025-11-30)
function memoize(fn) {
const known = [];
return (num) => (known[num] ??= fn(num));
}
It's beautiful.
Outlook conversations (2025-07-29)
Outlook can only group by conversation when sorted by Date. Sorting by Category completely breaks the grouping.
git bisect (2025-03-28)
If you know a bug was introduced between two releases, you can find it quickly:
git bisect startgit bisect good {tag/commit}git bisect bad {tag/commit}- Test:
git bisect goodorgit bisect bad(orgit bisect skip) git stashandgit stash popif you need test code.
A Great Joke (2025-03-27) #
In the late '90s, the USA was trying to build a super collider in Texas. They needed to get a foreign partner on board, but no countries came forward... until it was suggested that Russia's dirt-cheap manufacturing could be used to produce components at massive discounts, and those discounts could be viewed as their cash contributions. The same labs once used to develop ballistic missiles would now be used to build detector components.
A Russian physicist at the SSC joked by saying "Why, this is nothing new. For many years we made high-precision components for delivery to the United States".
Source: https://www.youtu.be/3xSUwgg1L4g; Part 2 - Bush.
Git undos (2025-02-24)
Undo: created a commit
- Run
git reset --soft HEAD~.
Undo: deleted a commit
- Run
git reflogto display the list of recent head commits. - Copy the first one's hash.
- Run
git reset, thengit stashto set changes aside. - Run
git reset --hard COPIED_HASHto revert to the previous head commit. - Run
git stash popto restore stashed changes.
Undo: rebased a branch (reword, move, delete, fixup)
- See above.
Undo: pulled from a remote
- See above.
Undo: pushed to a remote
- Find the output of the
git pushcommand to undo. - On the last line of the output, copy the first commit hash.
- Run
git push force COPIED_HASH. - If the remote branch was changed since your push, the new changes will silently be overwritten.
Undo: created a branch
- Run
git branch -d BRANCH_NAME.
Undo: deleted a branch
- Find the output of the
git branch -dcommand to undo. - Copy the commit hash.
- Run
git branch BRANCH_NAME COPIED_HASH.
Undo: staged a file
- To unstage the whole file, run
git restore --staged FILE_PATH. - To unstage specific hunks, instead run
git reset -p FILE_PATH, and manually select the hunks.
Undo: unstaged a file
- To stage the whole file, run
git add FILE_PATH. - To stage specific hunks, instead run
git add -p FILE_PATH, and manually select the hunks. - If some of the staged changes were not in the working directory, they cannot be recovered.
Undo: confirmed a conflict resolution
- Abort the current rebase by running
git rebase --abort. - Restart the rebase from scratch. Recreate the same rebase list, perform the same message edits, and redo every conflict resolution yourself.
Zoom (2025-02-13)
You can share multiple windows, which will hide switches and other windows but allow multiple apps!
Excel (2025-01-14)
You can reference the same cell in every sheet with =SUM('*'!A1). It will probably expand to a sheet range: =SUM(Demian:Susan!A1).
cosmopolitan (2024-12-08)
fat binaries, including redbean and greenbean : greenbean might only provide a static page (404 for everything else)
Update: cosmopolitan libc (2025-01-12)
Compile C into a fat binary (run on any platform). https://justine.lol/cosmopolitan/index.html
GIT rebase branch (2024-08-07)
A ── B ── C ┬─ (<- dev)
│
└─ D ─ E ─ (<- branch)
git rebase dev {branch} --onto origin/{base}
A ── B ┬─ C ─ (<- dev)
│
└─ D ── E ─ (<- branch)
HTML/CSS/JS Playground (2024-07-29)
CSS Transparent Variable Colors (2024-07-29)
body {
color: color-mix(in srgb, var(--color) 50%, transparent);
}
Math: chance statistics (2024-06-27)
Odds:
- % = chance of happening
- F = factor to multiply by (840)
- D = GCD(%, F)
- = ((% × F) / D) out of (F / D)
Chance of Happening X times:
- N = X out of N
- % = chance of happening
- Ways = Combinations(N, K)
- = Ways × POW(%, X) × POW(1-%, N-X)
Combinations:
- K out of N
- = N! / (K! × (N-K)!)
- shuffles are considered the same
- divide Permutations by number of shuffles
Permutations:
- K out of N
- = N! / (N-K)!
- shuffles are considered different
Linux: deleting large folders
Using rsync is 3x faster than rm.
mkdir empty
rsync -aP --delete empty/ target/
HTML: <em> vs <i>
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/em#i_vs._em
<em>is for emphasis:He did <em>WHAT</em>??<i>is for titles and other uses that don't denote emphasis:We watched <i>Good Omens</i> last night.
SQLITE: LIMIT 0,30
- 0 is offset
- 30 is number
7z update option
7z u {archive} {paths}
Will:
- keep unmatched (wildcards, exclusions)
- keep deleted
- add new
- update newer
- ignore older
- update same
- no anti-items
7z excluding folders
7z.exe a ./Desktop/Documents.20230612.7z \
./Documents/git/ \
./Documents/GitHub/ \
./Documents/htdocs/ \
./Documents/VILLANOVA/ \
-xr!node_modules \
-xr!.git -xr!fonts
Javascript: variable keys in maps
let x = "apple";
return { [x]: 10 }; // { "apple": 10 }
return { ...state, [x]: 10 };
return { ...state, apples: { [fav]: 10 } };
Python: venv
2023-04-28
Using Python's built in virtual environment means that all libraries are installed locally, allowing you to edit the libraries if understanding or functionality escapes you.
python -m venv ./.venv ## Creates a virtual env in the current folder
source .venv/bin/activate ## Activates the venv
PHP multi-thread
One
// returns the PID of the child to the parent
// the child will receive a 0
$isChildProcess = pcntl_fork() === 0;
if ($isChildProcess) {
doAsyncTask();
}
Many
// A pool of threads
foreach ($urls as $index => $page) {
if (pcntl_fork() === 0) {
doAsyncTask();
break; // no grandchildren!
}
}
Bash Inputs
From Files
$var = (cat file.txt)
Prompts
echo -n "username: "
read -r user
echo -n -s "password: "
read -r pwd
SQL: ordered list of values
2021-04-20
You can quickly get an ordered list of ids or values by joining to a temporary table.
SELECT f.id, dbo.professors.* FROM dbo.professors
JOIN (VALUES (33),(33),(33),(90),(90)) as f(id)
ON f.id = dbo.professors.professor_id;
id professor_id name
33 33 Sir Isaac Newton
33 33 Sir Isaac Newton
33 33 Sir Isaac Newton
90 90 Carl Sagan
90 90 Carl Sagan
Javascript: forward declaration (2019-08-20)
Obsolete! Functions are now hoisted automatically.
Many linters check for functions to exist before they're referenced. With circular calling, you need to declare a function before it's defined. TIL this is called forward declaration.
let bind = function bindForward() {};
function ajax(url) {
load(url).then(bind);
}
bind = function bind() {
$("a").click(ajax);
};
Javascript: Destructuring (2019-08-08)
When destructuring, JS only assigns the deepest nested keys:
const req = { query: { person: { first: "Chris", last: "Hallberg" } } };
const {
query: {
person: { first, last },
},
} = req;
console.log(query); // undefined
console.log(person); // undefined
console.log(first); // "Chris"
console.log(last); // "Hallberg"
You can also assign names that don't match the keys you're grabbing. Just be careful with your brackets.
const req = { query: { data: "apples" } };
// rename query to data
var { query: data } = req;
console.log(data); // { data: "apples" }
// destruct data from query
var {
query: { data },
} = req;
console.log(data); // apples
Warning: In browsers, name seems to be assigned to "[object Object]" somewhere along the line, so be careful.
Javascript: Destructuring as parameters
2019-09-19
I learned today that you can destructure variables as part of a function declaration or as part of a for-of loop:
function getHeight({ height }) {
return height;
}
getHeight({ width: 10, height: 200, depth: 7 }); // 200
const points = [
{ x: 3, y: 4 },
{ x: 5, y: 5 },
];
for (let { x, y } of points) {
console.log(`distSq = ${(x ** 2, y ** 2)}`);
}
// distSq = 25
// distSq = 50
Javascript: Destructuring as default parameters
2019-09-24
It's been a good month for destructuring. Building on the previous revelation, you can set parameter defaults with destructuring.
function showConfig({ tabSize = 2, theme = "Nord" } = {}) {
console.log(`Theme: ${theme}, Tab Size: ${tabSize}`);
}
showConfig({ tabSize: 4, theme: "Monokai" }); // Theme: Monokai, Tab Size: 4
showConfig({ theme: "Monokai" }); // Theme: Monokai, Tab Size: 2
showConfig(); // Theme: Nord, Tab Size: 2
WebVR
Oculus Quest debugging
2019-09-07
I couldn't find any official way to get debugging info from the Oculus Quest since it only connects over Wi-Fi (if at all) and the SteamVR logs don't pick up anything.
So I dropped a text element into the world and used that as my string log. You can put this element inside the camera if you want it to be visible as a UI element, but I didn't do that.
<a-text id="log" value="Hello!" color="#000" align="center" position="0 2 -5"></a-text>
const logEl = document.getElementById("log");
function log(msg) {
logEl.setAttribute("value", msg);
}
// For updating messages
function debug() {
requestAnimationFrame(debug);
log(blueGun.object3D.matrix.toArray().join(","));
}
requestAnimationFrame(debug);
// For everything else
try {
// do a back flip
} catch (e) {
log(e);
}
Move the World, Not the Camera
2019-09-07
I have a few game concepts that involve pulling the player along or changing their view but trying to override the default WebVR camera is a pain.
If you do manage to get control of the camera (either with groups or with rigs) you need to then manually ensure you draw both eye "cameras" anyway. It's just more work that it's worth when you can move the whole world instead!
A hierarchy like this makes this quite easy to do:
- scene
- camera
- world
- hand controllers
- all physical items
Thank you, Stefan Judis for the idea and encouragement.