A collection of short notes from my cross-disciplinary studies, shared as I learn in public.
The status indicator reflects the maturity of the content: • rough — Initial thoughts, unstructured • growing — Being actively developed • evergreen — Stable, well-developed content • withered — No longer being maintained This helps readers understand the completeness of the content.
The confidence tag expresses how well-supported the content is, or how likely its overall ideas are right. This uses a scale from "impossible" to "certain", based on the Kesselman List of Estimative Words: 1. "certain" 2. "highly likely" 3. "likely" 4. "possible" 5. "unlikely" 6. "highly unlikely" 7. "remote" 8. "impossible" Even ideas that seem unlikely may be worth exploring if their potential impact is significant enough.
The importance rating distinguishes between trivial topics and those which might change your life. Using a scale from 0-10, content is ranked based on its potential impact on: - the reader - the intended audience - the world at large For example, topics about fundamental research or transformative technologies would rank 9-10, while personal reflections or minor experiments might rank 0-1.
The IndieWeb specification formally distinguishes two written post types based on structure, not length:
name (title) property. Usually has multiple paragraphs, subheadings, blockquotes. What most people call a "blog post."name property or an empty string name. Short, unstructured plain text. The equivalent of a tweet or toot.The distinction matters for Post Type Discovery, the algorithm IndieWeb clients use to determine how to render a post:
if post has "name" property:
if name != content (first N chars):
→ article
else:
→ note
else:
→ note
This means a titled, categorized, tagged post with multiple paragraphs is an article by IndieWeb definition, even if you call it a "note" on your site. The IndieWeb "note" is specifically the titleless micro-post.
Other recognized post types: photo, video, audio, bookmark, reply, repost, like, checkin, rsvp, event. All defined by which microformat properties are present, not by an explicit "type" field.
Pages with export const dynamic = 'force-static' and export const revalidate = false are fully pre-rendered at build time via generateStaticParams(). In development mode, this means:
export const dynamic = 'force-static'
export const revalidate = false
export async function generateStaticParams() {
// This runs ONCE at server start in dev mode
const posts = getContentByType("news")
return posts.map(p => ({ slug: p.slug }))
}
The generateStaticParams() function executes once when the dev server starts. Adding a new row to the database or a new .mdx file does not re-trigger it.
To see new content in dev: kill the server (fuser -k 3000/tcp), remove the lock file if needed (rm .next/dev/lock), and restart. There is no hot-reload workaround without changing the page to force-dynamic (which sacrifices static generation).
In production builds (npm run build), this is not an issue because generateStaticParams() runs during the build and all pages are pre-rendered at that point.
Mixture-of-Experts (MoE) is an architecture where a model is divided into smaller "expert" sub-networks instead of one monolithic neural network. For any given input, a gating mechanism routes tokens to only the most relevant experts.
Input → Gating Network → selects top-k experts → Expert outputs → Combined output
Key properties:
Google pioneered this in deep learning through a lineage of papers:
The tradeoff: MoE models have large total parameter counts (need more memory to load), but use fewer FLOPs per token (faster inference). This is why Gemini 1.5 Pro can match 1.0 Ultra quality while being cheaper to run.
fuser identifies processes using files or sockets. Combined with -k, it kills whatever is holding a port open. Essential for freeing up ports when a dev server crashes without cleaning up.
# Kill whatever is on port 3000
fuser -k 3000/tcp
# Just identify the process (no kill)
fuser 3000/tcp
# Output: 3000/tcp: 12345
# Kill with a specific signal
fuser -k -SIGTERM 3000/tcp
Comparison with alternatives:
# lsof approach (more verbose, more info)
lsof -ti:3000 | xargs kill
# ss + grep approach (most portable)
ss -tlnp | grep :3000
fuser is part of psmisc on most Linux distributions. It is simpler than lsof for the common case of "kill whatever is on this port." The output format (PID/protocol) is also easier to parse in scripts.
On macOS, fuser exists but behaves differently. Use lsof -ti:PORT | xargs kill instead.
In Next.js, setting dynamicParams = false on a page with generateStaticParams() tells the framework to return a hard error for any path not pre-generated at build time. This is not a 404. It is an unhandled NoFallbackError that spams server logs.
// This CRASHES on unknown slugs — even from bots/crawlers
export const dynamicParams = false
export async function generateStaticParams() {
return posts.map(p => ({ slug: p.slug }))
}
// This gracefully falls through to notFound()
export const dynamicParams = true
export default async function Page({ params }) {
const post = posts.find(p => p.slug === params.slug)
if (!post) notFound() // proper 404
}
With dynamicParams = false, every crawler hitting /blog/nonexistent-slug throws NoFallbackError in the server logs. In production with Docker Swarm, this can make the service appear unhealthy if the error rate is high enough.
The fix is dynamicParams = true combined with explicit notFound() calls in the page component. You still get static generation for known slugs via generateStaticParams(), but unknown slugs get a clean 404 instead of a crash.
In HTML, <button> cannot be a descendant of another <button>. Browsers silently restructure the DOM when they encounter this, but React's server-rendered HTML does not match the browser's restructured DOM, causing a hydration mismatch.
// BAD: nested button causes hydration error
<button onClick={openMenu}>
<Icon />
{isOpen && (
<div className="submenu">
<button onClick={selectOption}>Option A</button> {/* nested! */}
</div>
)}
</button>
// GOOD: move submenu outside the button, wrap both in a div
<div onMouseEnter={showMenu} onMouseLeave={hideMenu}>
<button onClick={openMenu}>
<Icon />
</button>
{isOpen && (
<div className="submenu">
<button onClick={selectOption}>Option A</button>
</div>
)}
</div>
The error message in Next.js dev mode is: In HTML, <button> cannot be a descendant of <button>. This will cause a hydration error.
This also applies to <a> inside <a>, <form> inside <form>, and other elements with restrictions defined in the HTML spec's content model.
When a Dockerfile copies source with COPY . ., git submodules appear as empty directories. Git submodules are tracked by reference (a commit SHA in .gitmodules), not by content. Docker's build context does not include .git/ metadata, so there is nothing to resolve the submodule from.
# Submodule directory will be EMPTY after this
COPY . .
# Fix: clone the submodule content directly if missing
RUN if [ ! "$(ls src/content/blog/*.mdx 2>/dev/null)" ]; then \
echo "Fetching content..." && \
apk add --no-cache git && \
git clone --depth 1 \
"https://x-access-token:${GITHUB_TOKEN}@github.com/user/content.git" \
src/content && \
rm -rf src/content/.git; \
fi
The pattern: check if the submodule directory has the expected files. If not, clone it with --depth 1 (shallow, fast) using a GitHub token passed as a build arg. Remove .git/ after cloning to keep the image small.
This applies to every submodule independently. If you have three submodules (content, prompts, til), you need three separate clone fallback blocks.
Alternative: use git clone --recursive in CI before docker build, so the build context already has submodule contents. But this requires CI to have git access, which is not always the case with managed platforms like Dokploy.
When building a force-directed knowledge graph with D3.js, the default force settings cluster everything into an unreadable blob. The key parameters to tune for readable cluster separation:
const simulation = d3.forceSimulation(nodes)
.force("link", d3.forceLink(links).id(d => d.id).distance(60).strength(0.3))
.force("charge", d3.forceManyBody().strength(-120).distanceMax(400))
.force("center", d3.forceCenter(width / 2, height / 2).strength(0.05))
.force("collision", d3.forceCollide().radius(d => nodeRadius[d.type] + 4).strength(0.7))
.force("x", d3.forceX(width / 2).strength(0.03))
.force("y", d3.forceY(height / 2).strength(0.03))
.alphaDecay(0.02)
What each does:
-120): Repulsive force between all nodes. More negative = more spacing. distanceMax(400) caps the influence range so distant clusters do not push each other to infinity.60) + strength (0.3): How far apart linked nodes want to be. Lower strength makes the links springier, letting clusters breathe.0.05): Very weak pull toward center. Prevents drift without collapsing the graph.+4 padding): Physical collision boundary. strength(0.7) means nodes push each other away firmly but not rigidly.0.03): Gentle gravity toward center on each axis independently. Works with center force to keep things on screen.0.02): Slower cooldown. Default is 0.0228. Lower values let the simulation settle longer, producing better final positions.The defaults (charge: -30, linkDistance: 30, no forceX/Y) are designed for small graphs. For 500+ nodes with multiple types, you need 3-4x stronger repulsion and explicit centering forces.
Deriving an array with .map() inside a component body creates a new array reference on every render, even if the contents are identical. If that array is in a useEffect dependency list, it triggers an infinite loop.
// BAD: entries is a new array every render, useEffect fires forever
const entries = entriesWithContent.map(e => e.entry)
useEffect(() => {
fetchReactions(entries)
}, [entries]) // new reference every render = infinite loop
// GOOD: useMemo stabilizes the reference
const entries = useMemo(
() => entriesWithContent.map(e => e.entry),
[entriesWithContent]
)
useEffect(() => {
fetchReactions(entries)
}, [entries]) // only fires when entriesWithContent actually changes
This applies to any derived value in a dependency array: .filter(), .reduce(), Object.keys(), spread into new object, etc. If it creates a new reference, wrap it in useMemo.
React's comparison is referential (Object.is), not structural. Two arrays with identical contents are still different objects.
"Diary" comes from Latin diarium, meaning "daily allowance" or "daily record," from dies ("day"). At its root, a diary is just a thing organized by days. Historically it was practical: logs, expenses, travel notes, weather, religious observance. The emotional confessional angle came later, once people decided their inner turbulence deserved timestamps.
I collect and use vintage Macs, so the A1502 was on my radar. The pre-2016 MacBook Pros are the last ones with keyboards that don't self-destruct.
The MacBook Pro model A1502 is a 13-inch Retina MacBook Pro from the 2013-2015 era. It uses the older scissor-switch keyboard, not the butterfly keyboard that Apple introduced in 2016 and later abandoned after years of reliability complaints. The butterfly keyboards had shallow key travel and were notorious for getting stuck from dust. The A1502's keyboard is from the generation people actually liked.
I was trying to place a bassline stuck in my head and initially confused it with the Cosby Show intro. Took me a minute to realize it was the George Lopez theme.
The theme song for the George Lopez sitcom (2002-2007) is "Low Rider" by War, released in 1975. It's not a cover or a remix; it's the original funk track, licensed directly for the show. The song already had deep cultural associations with Chicano car culture and Southern California, which made it a natural fit for the show's setting and tone. Easy to mix up similar funk basslines if they're living in the same corner of memory.
This came up while I was building a tier list of collector's editions and studying binding quality differences across publishers.
The International Collectors Library (ICL) was published by the Doubleday Book & Music Club starting in the 1940s. The books have faux leather or leatherette covers with gold embossing and look nice on a shelf, but they're not in the same tier as Easton Press or Franklin Library in terms of collectibility or resale value. Easton Press uses genuine leather and Smyth-sewn bindings. ICL books are more like a dressed-up book club edition. Still pleasant to own, but don't pay collector prices for them.
"Sleigh Ride" was originally a purely instrumental orchestral piece composed by Leroy Anderson in 1948, with no lyrics at all. Mitchell Parish added the words ("Just hear those sleigh bells jingling...") two years later in 1950. The lyrics don't mention Christmas even once. They describe a general winter scene: snow, sleigh bells, a fire at the end of the ride. It became a holiday staple purely through cultural association, not because the song has anything to do with Christmas.
Haruki Murakami's memoir about long-distance running is called What I Talk About When I Talk About Running (2007). The title is a deliberate nod to Raymond Carver's short story collection What We Talk About When We Talk About Love. Murakami actually translated Carver's work into Japanese. The memoir covers his parallel life as a novelist and marathon runner, and the discipline both require.
The Japanese title is Hashiru Koto ni Tsuite Kataru Toki ni Boku no Kataru Koto. It mirrors Carver's title structure almost word for word, which shows how literally Murakami mapped the reference across languages.
The use of "baby" as a romantic pet name for women became popular in the 1900s-1920s Jazz Age. African American jazz and blues culture drove the adoption, with artists using "baby" in lyrics as a term of affection. Before that, the word just meant an actual infant. The romantic usage spread through popular music into mainstream American English. By the 1950s and 60s, rock and roll had cemented it as a default term of endearment. "Babe" followed a similar path. Both terms originated in Black vernacular and became controversial as they crossed into mainstream white usage, stripped of their original cultural context.
Christopher Nolan's Memento (2000) follows Leonard Shelby, who has anterograde amnesia and can't form new memories. He tracks information through Polaroid photos, notes, and tattoos on his body. The film's structure alternates between color sequences shown in reverse chronological order and black-and-white sequences shown chronologically, with both timelines converging at the end. It was Nolan's breakthrough film, made for about $4.5 million.
The dual-timeline structure looks like this:
Color scenes (reverse): ... C4 → C3 → C2 → C1
\
→ converge at ending
/
B&W scenes (forward): B1 → B2 → B3 → B4 ...
The color scenes show the "present" moving backward in time. The black-and-white scenes show an earlier period moving forward. Both threads meet at the chronological middle of the story, which is the film's final scene.
I was reading about the Crooked Man from The Conjuring 2 (2016), one of Valak's manifestations, and got curious about the nursery rhyme behind it.
The nursery rhyme "There Was a Crooked Man" first appeared in print in James Orchard Halliwell's The Nursery Rhymes of England in 1842, though the rhyme itself is probably older. Some historians believe the "crooked man" refers to the Scottish General Sir Alexander Leslie, who signed a covenant securing religious and political freedom for Scotland. The "crooked stile" supposedly refers to the border between England and Scotland.
I was going down a nursery rhyme rabbit hole, looking up the origins of "There Was a Crooked Man" and other classic English rhymes, and the Opies kept getting cited as the authority.
Iona and Peter Opie published The Oxford Dictionary of Nursery Rhymes in 1951, with a revised edition in 1997. It covers over 500 rhymes with historical context and folk origins. The Opies spent decades collecting and documenting children's folklore and are considered the foremost scholars of English nursery rhymes. Their work traces many rhymes back to political satire, street cries, and medieval songs that had nothing to do with children originally.
I was watching Girl Interrupted and noticed Lisa (Angelina Jolie) calls Susanna (Winona Ryder) "Susie Q." I wanted to know where that nickname came from.
It traces back to a 1930s jazz dance step from the Lindy Hop and tap scenes. Lil Hardin Armstrong (Louis Armstrong's wife) popularized it with her 1936 novelty tune "Doin' the Suzie-Q." One story says the dance's name came from a mishearing of "Syracuse," where a couple from Georgia first introduced the step. Dale Hawkins picked up the name for his 1957 rockabilly hit "Susie Q," which Creedence Clearwater Revival covered in 1968.
Upon browsing r/mathematics I came across this post.
The inquiry of this post was to find "books that would give a layperson introduction into a mathematical way of thought.
There were numerous responses to this of which I have left below with a link to each message.
here the numerous resources are listed with links to the original posters.
You can use Zod's instanceof validator to validate file inputs:
const MAX_UPLOAD_SIZE = 1024 * 1024 * 3; // 3MB
const ACCEPTED_FILE_TYPES = ['image/png'];
const Schema = z
.instanceof(File)
.optional()
.refine((file) => {
return !file || file.size <= MAX_UPLOAD_SIZE;
}, 'File size must be less than 3MB')
.refine((file) => {
return ACCEPTED_FILE_TYPES.includes(file.type);
}, 'File must be a PNG');
Above example validates the file is the correct max file size and file type.
The HTTP Header X-Robots-Tag is used to instruct search engines on how it should handle indexing the page. It takes in any rule that can be specified in the robots meta tag (<meta name="robots" content="noindex">).
There is a whole list of values that can be used: https://http.dev/x-robots-tag.
I noticed it being used on Netlify preview URLs (example):
X-Robots-Tag: noindex
Which makes sense because these are draft URLs that should not be indexed.
We can use esbuild's drop option to remove console APIs and debugger statements from our code when we build our application.
export default defineConfig({
esbuild: {
drop: ['console', 'debugger']
}
});
You can delete a single or multiple lines in normal mode:
dd[n]dd (n = number of lines)You can delete a range of lines in command mode:
:[from],[to]dThere is special characters you can use in the range:
.: The current line.$: The last line.%: All lines.Examples on using the range:
:5,10d: Delete lines from 5 to 10.:.,$d: Delete from the current line to the end of file.:.,1d: Delete from the current line to the beginning of file.:5,$d: Delete from line 5 to end of file.:%d: Delete all lines.Vite uses esbuild to transpile Typescript into Javascript and esbuild does not do any type checking.
To generate type declarations, you can use tsc:
tsc --declaration --emitDeclarationOnly
If you are building an application and want to check types only:
tsc --noEmit
Example package.json:
{
"name": "vite-app",
"version": "0.0.0",
"scripts": {
"build:types": "tsc --declaration --emitDeclarationOnly"
"check-types": "tsc --noEmit"
},
"devDependencies": {
"vite": "^2.7.2",
"typescript": "^4.0.3"
}
}
It's nice to seperate the type checking from the build because:
Types can be narrowed down by using the is keyword:
const isString = (value: unknown): value is string => {
return typeof value === 'string';
}
function myFunction(value: string | number) {
if (isString(value)) {
value
// ^? (parameter) value: string
} else {
value
// ^? (parameter) value: number
}
}
When isString is called, TypeScript will narrow the type to string if the function returns true. TypeScript will also handle the else branch and narrows the type to number as it now knows that it is not a string.
Another example:
type Color = 'red' | 'blue' | 'green';
function isRed(color: string): color is 'red' {
return color === 'red'
}
function paint(color: Color) {
if (isRed(color)) {
color
// ^? (parameter) color: "red"
} else {
color
// ^? (parameter) color: "blue" | "green"
}
}
In the example above, isRed narrows color to red if the function returns true, otherwise the type is narrowed to "blue" | "green".
I was studying creepypasta as a writing form, reading guides on crafting them alongside Greek tragedies. The structural parallels are real: both rely on dramatic irony, dread, and an audience that knows something the protagonist doesn't.
"Creepypasta" is a portmanteau of "creepy" and "copypasta" (internet slang for copied-and-pasted text). The term refers to short horror stories or urban legends shared across the internet, often presented as if they were real accounts or found documents. The form took off in the late 2000s on forums like 4chan and Something Awful. Famous examples include Slender Man, Jeff the Killer, and the SCP Foundation.
TypeScript has the ability to add string types using template literal strings:
type EventType = "Click" | "Change";
type OnEventType = `on${EventType}`
// ^? type OnEventType = "onClick" | "onChange"
It also returns every possible combination of the unions:
type CssAttr = "margin" | "padding";
type Position = "left" | "right" | "top" | "bottom";
type CssKeys = `${CssAttr}-${Position}`
// ^? type CssKeys = "margin-left"
// | "margin-right"
// | "margin-top"
// | "margin-bottom"
// | "padding-left"
// | "padding-right"
// | "padding-top"
// | "padding-bottom"
Can be used on object keys:
type Events = {
[key in `on${string}`]: () => void;
}
const events: Events = {
onClick: () => {},
onChange: () => {}
// ^? ✅ (property) onChange: () => void
brokenFn: () => {}
// ^? ❌ Object literal may only specify known properties, and 'brokenFn' does not exist in type 'Events'
}
Can be used with the other string manipulation types:
type Action = 'query' | 'mutation';
type Hook = `use${Capitalize<Actions>}`;
// ^? type Hook = "useQuery" | "useMutation"
Can be used with generics:
type EventType = "click" | "change";
type OnEventType<T extends string> = {
[key in T as `on${Capitalize<key>}`]: () => void
}
const events: OnEventType<EventType> = {
onClick: () => {},
onChange: () => {},
// ^? ✅ (property) onChange: () => void
brokenFn: () => {}
// ^? ❌ Object literal may only specify known properties, and 'brokenFn' does not exist in type 'OnEventType<EventType>'
}
There is also a curated list of Awesome Template Literal Types on GitHub that is worth checking out for more examples.
DARPA (Defense Advanced Research Projects Agency) was founded in 1958, originally as ARPA, in response to the Soviet launch of Sputnik. Its mission was to prevent technological surprise. ARPANET, the precursor to the modern internet, was one of its projects. The "D" for "Defense" was added in 1972, removed in 1993, then added back again in 1996.
ARPANET was created during the ARPA era, which is why it's called ARPANET and not DARPANET. The name stuck even after the agency got its D back.
Taylor Swift lost ownership of her original master recordings when her former label, Big Machine Records, was sold to Scooter Braun's Ithaca Holdings in 2019. Rather than buy them back, she began re-recording her first six albums starting in 2021, labeling each one "(Taylor's Version)" so fans could stream the versions she owns. It's one of the few times an artist has re-recorded an entire catalog to reclaim ownership.
As of 2025, four have been released: Fearless (April 2021), Red (November 2021), Speak Now (July 2023), and 1989 (October 2023). Reputation and her self-titled debut still don't have Taylor's Version releases.
Typescript 4.9 introduced the new satisfies operator.
Steve explains it best using this example:
type Route = { path: string; children?: Routes };
type Routes = Record<string, Route>;
const routes = {
AUTH: {
path: "/auth",
children: {
LOGIN: {
path: "/login",
},
},
},
HOME: {
path: "/",
},
} satisfies Routes;
routes.AUTH.path; // works
routes.AUTH.children.LOGIN.path; // works
routes.HOME.children.LOGIN.path; // error
// ^? Property 'children' does not exist on type '{ path: string; }'.
Matt Pocock has a great example of a use-case in his TypeScript 4.9 deep dive video.
The loader function in Remix can be inferred automatically using:
type LoaderData = Awaited<ReturnType<typeof loader>>;
Awaited: Extracts the value returned from a Promise.ReturnType: Constructs a type consisting of the return type of a function.Putting it together:
import { json } from "@remix-run/node";
type LoaderData = Awaited<ReturnType<typeof loader>>;
// ^? LoaderData: Response
export const loader = async () => {
return json({ ok: true });
};
The return and initial value of the reduce() method can be typed using a generic.
In the example below, the array of products is converted to an object keyed by productId. This was safely typed with ProductsById being passed as a generic.
const products = [
{
productId: '12345',
name: 'Product A'
},
{
productId: '67890',
name: 'Product B'
}
];
type Product = { productId: string; name: string };
type ProductsById = Record<string, Product>;
// Transforms the array `products` into an object keyed by `productId`
const productsById = products.reduce<ProductsById>(
(previousValue, currentValue) => {
return {
...previousValue,
[currentValue.productId]: currentValue
};
},
{}
);
productsById;
// ^? const productsById: ProductsById
The result of productsById returns the below object which matches the ProductsById type:
{
"12345": {
"productId": "12345",
"name": "Product A"
},
"67890": {
"productId": "67890",
"name": "Product B"
}
}
You can extract the type from a useRef hook using ElementRef:
import { useRef, ElementRef } from "react";
const Component = () => {
const audioRef = useRef<ElementRef<"audio">>(null);
// ^? React.RefObject<HTMLAudioElement>
return <audio ref={audioRef}>Hello</audio>;
};
TypeScript can enforce explicit type imports and exports using the importsNotUsedAsValues configuration.
{
"compilerOptions": {
"importsNotUsedAsValues": "error",
}
}
Setting this to error will report an error if there is a type being imported without import type syntax.
import type { MyType } from './types';
export type { MyType };
Bundlers prefer this to help avoid potiential problems with types being incorrectly bundled.
React 18 removed the children prop from React.FC and must be defined explicitly in your component's type.
When creating new React components that extend HTML elements (eg Button), you will need to specify the children prop in React 18:
type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
children: React.ReactNode;
};
const Button: React.FC<ButtonProps> = ({
children,
disabled,
name,
type,
value
}) => {
return (
<button disabled={disabled} name={name} type={type} value={value}>
{children}
</button>
);
};
First extend the native HTML attributes:
interface MyInputProps extends React.HTMLProps<HTMLInputElement> {
size: "sm" | "md" | "lg";
}
A typescript will appear because TS knows that HTMLInputElement already has a size attribute and it does not match the one we added:
interface MyInputProps extends React.HTMLProps<HTMLInputElement> {
size: "sm" | "md" | "lg";
// ^? Type 'string' is not assignable to type 'number'
}
We need to omit the native size attribute:
interface MyInputProps extends Omit<React.HTMLProps<HTMLInputElement>, 'size'> {
size: "sm" | "md" | "lg";
}
And now we can type our new component. Spread the props so our new size prop is not set as the value to the native HTML attribute.
const MyInput: React.FC<MyInputProps> = (props) => {
const { size, ...rest } = props;
return <input {...rest} className="my-input" />;
};
If we want to continue using the native size, Chakra UI has a clever technique of using a new prop htmlSize that can be used instead:
interface MyInputProps extends Omit<React.HTMLProps<HTMLInputElement>, 'size'> {
size: "sm" | "md" | "lg";
htmlSize?: number;
}
const MyInput: React.FC<MyInputProps> = (props) => {
const { size, htmlSize, ...rest } = props;
return <input {...rest} size={htmlSize} className="my-input" />;
};
TypeScript allows you to suppress errors on a line by using the @ts-ignore directive right before the erroring line:
// @ts-ignore
const myString: string = 1;
The downside to using @ts-ignore is that there is no indication if it is really suppressing any errors unless the directive is removed. This can lead to forgotten @ts-ignore once the errors has been fixed.
Using @ts-expect-error will behave the same way but if there is no error in the code, TypeScript will report an error that the @ts-expect-error was not necessary:
// @ts-expect-error
const myString: string = 1;
This is a great alternative to @ts-ignore if you intend to fix the code at a later stage. When the error is fixed, TypeScript will remind you to remove the directive.
The never data type in TypeScript can be used to check that all cases in a switch are considered.
type Day =
| "Monday"
| "Tuesday"
| "Wednesday"
| "Thursday"
| "Friday"
| "Saturday"
| "Sunday";
function getDayIndex(day: Day) {
switch (day) {
case "Monday": {
return 1;
}
default: {
// `Type 'string' is not assignable to type 'never'.`
const _exhaustiveCheck: never = day;
return _exhaustiveCheck;
}
}
}
_exhaustiveCheck will have an error because TypeScript is attempting to assign the rest of the Day union to never which cannot happen.
This can be found in the TypeScript documentation.
TypeScript will not show an error if additional keys are added to an object literal:
type User = {
name: string;
};
const userData = {
name: "Peter",
email: "peter@email.com",
};
function printUser(user: User) {
console.log(user);
}
printUser({ name: "Peter", email: "peter@email.com" });
// Error: Object literal may only specify known properties, and 'email' does not exist in type 'AllowedType'.
printUser(userData);
// No error on this line
This is because it is intentional. See microsoft/TypeScript#12936.
A workaround is available on https://stackoverflow.com/a/61960616 by using a custom utility Exact:
type Exact<A, B> = A extends B ? (B extends A ? A : never) : never;
type User = {
name: string;
};
const userData = {
name: "Peter",
email: "peter@email.com",
};
function printUser<T>(user: Exact<T, User>) {
console.log(user);
}
printUser({ name: "Peter", email: "peter@email.com" });
// Error: Object literal may only specify known properties, and 'email' does not exist in type 'AllowedType'.
printUser(userData);
// Error: Argument of type '{ name: string; email: string; }' is not assignable to parameter of type 'never'
TypeScript handles optional and undefined differently - exactOptionalPropertyTypes will help catch scenarios where undefined should be typed explicitly.
When turned off:
type User = {
email?: string;
}
const user: User = { email: undefined }
// Valid
When turned on:
type User = {
email?: string;
}
const user: User = { email: undefined }
// Type '{ email: undefined; }' is not assignable to type 'User' with 'exactOptionalPropertyTypes: true'.
// Consider adding 'undefined' to the types of the target's properties.
Read optional vs undefined | TkDodo's blog to learn the difference and how this can help.
noUnCheckedIndexAccess adds undefined to any un-declared fields in a type. This is useful if you have an index signature and want to check if a property exists before accessing it.
Take this example:
const myObject: Record<string, string[]> = {};
myObject["myKey"].push("myString");
This satisfies TypeScript because myKey is typed as string in the index signature of myObject. What we do not know yet is if myObject["myKey"] is defined for us to use.
With noUnCheckedIndexAccess enabled, TypeScript will warn us that the object is possibly undefined and that we should check it exists:
const myObject: Record<string, string[]> = {};
if (myObject["myKey"]) {
myObject["myKey"].push("myString");
}
I was examining a physical book with the "New York: Macmillan; London: Collier Macmillan" imprint and wanted to understand why two names appeared. Bibliographic research for the collection.
When old books list "New York: Macmillan; London: Collier Macmillan," those were two separate publishing entities. The American Macmillan Company was founded in New York in 1869 and sold to the Brett family in 1896. It merged with Crowell-Collier in 1960. The British Macmillan Publishers (founded 1843 by Daniel and Alexander Macmillan) remained independent. They shared a name and some history but operated as distinct companies in different markets for most of the 20th century.
Adding an interface for callable objects:
interface Callable {
(): string;
}
const myCallable: Callable = function () {
return "I was called";
};
const myFunction = myCallable;
const value = myFunction();
// ^? const value: string
Another example with parameters:
interface Callable {
(numOne: number, numTwo: number): number;
}
const addNumbers: Callable = function (numOne, numTwo) {
return numOne + numTwo;
};
const myFunction = addNumbers;
const value = myFunction(1, 2);
// ^? const value: number
Assertion functions throw an error if a certain condition is not met.
assert(name === "Peter");
The assertion function will throw an error name is not "Peter".
With assertion functions, there is "assertion signatures" which are used to narrow the type of values to be more specific.
Consider the below example: We are not sure of the type of maybeNumber. We can assert it is a number before continuing with the code flow.
function assert(condition: unknown): asserts condition {
if (!condition) {
throw new Error("Assertion failed.");
}
}
let maybeNumber: any;
assert(typeof maybeNumber === "number");
maybeNumber;
// ^? let maybeNumber: number
We now know that maybeNumber is a number because the assertion did not fail, so TypeScript narrowed the type down to `number.
We can be more specific with the condition. Below example has an assertion signature asserts value is number:
function assertIsNumber(value: unknown): asserts value is number {
if (typeof value !== "number") {
throw new Error("Not a number");
}
}
let maybeNumber: any;
assert(typeof maybeNumber === "number");
maybeNumber;
// ^? let maybeNumber: number
We can also include a custom message to be used as the error message when the assertion fails:
function assert(condition: unknown, message?: string): asserts condition {
if (!condition) {
throw new Error(message || 'Assertion failed.');
}
}
let myVariable: { myKey: string } | undefined;
myVariable.myKey;
// ^? 'myVariable' is possibly 'undefined'.
assert(myVariable, "myVariable is undefined");
myVariable
// ^? let myVariable: { myKey: string }
A common problem faced with using Array.includes() in TypeScript:
const environments = ["DEV", "UAT", "PROD"] as const;
function isSupported(env: string) {
if (environments.includes(env)) {
// Error: Argument of type 'string' is not
// assignable to parameter of type '"DEV" | "UAT" | "PROD"'.
}
}
The definition of Array.includes():
interface Array<T> {
includes(searchElement: T, fromIndex?: number): boolean;
}
The function wants both the searchElement and the array to be of the same type.
This can be solved by narrowing the type using a helper function:
function includes<T extends U, U>(arr: ReadonlyArray<T>, searchElement: U): searchElement is T {
return arr.includes(searchElement as T);
}
ReadonlyArray<T> and search for element of type U.T extends U: T is a subset of U.searchElement is T.function isSupported(env: string) {
if (includes(environments, env)) {
console.log(env);
// ^? env: "DEV" | "UAT" | "PROD"
}
}
The HTML i element is named the Idiomatic Text element on MDN Web Docs.
The HTML specifications defines the i element as:
The
ielement represents a span of text in an alternate voice or mood, or otherwise offset from the normal prose in a manner indicating a different quality of text, such as a taxonomic designation, a technical term, an idiomatic phrase from another language, transliteration, a thought, or a ship name in Western texts.
Historically, the i element was used for presentation and browsers display it in italics. However, even though some browsers continue to display it in italics as a fallback, the i element should not be used for presentational purposes as it does not necessarily mean the text will be in italics.
The i element has semantic meaning and the usage depends on the situation and the surrounding text. MDN Web Docs has a great example:
An example for
<i>could be: "The Queen Mary sailed last night". Here, there is no added emphasis or importance on the word "Queen Mary". It is merely indicated that the object in question is not a queen named Mary, but a ship named Queen Mary.
The <details> HTML element creates an accordion-like element that the user can toggle open and close.
The W3C HTML specification describes the element:
The details element represents a disclosure widget from which the user can obtain additional information or controls.
<details>
<summary>Show/Hide</summary>
<p>Today I learnt about the `details` element</p>
</details>
The open attribute is a boolean that can be used to indicate if the content is visible or not.
<details open="true">
<summary>Show/Hide</summary>
<p>Today I learnt about the `details` element</p>
</details>
I was looking into Jeff from The Donna Reed Show and ended up reading about Reed's whole career.
Donna Reed is best known for playing Mary Hatch Bailey in It's a Wonderful Life (1946), but she actually won her Academy Award for From Here to Eternity (1953). She then moved to television, starring as Donna Stone in The Donna Reed Show from 1958 to 1966. Her career spanned over four decades, but those three roles are the ones people remember.
tar command$ tar -czvf archive.tar.gz ./directory
-c: Create archive.-z: Compress using gzip algorithm.-f: Specify filename of archive.-v: Verbose (show progress).$ tar -xvf archive.tar.gz
-x: Extract from archive.-f: Specify filename of archive.-v: Verbose (show progress).$ tar -xvf archive.tar.gz -C ./another-directory
-C: Changes the directory.$ tar -xvf archive.tar.gz file1 file2 file3
$ tar -xvf archive.tar.gz --wildcards '*.js'
$ tar -tf archive.tar.gz
-t: List the content.I was sorting out the difference between the Emmys and the Oscars while reading about Angelina Jolie's Best Supporting Actress win for Girl, Interrupted (1999). That led me to the broadcast history of the ceremony itself.
The 25th Academy Awards ceremony on March 19, 1953, was the first to be televised. Bob Hope hosted. From that ceremony through the 97th in March 2025, there have been 73 televised ceremonies. The average ceremony runs about 3.5 hours, which means if you watched every single televised Oscars back to back, it would take roughly 10.6 days.
structuredClone() is a native API in JavaScript that can do deep cloning of objects:
const original = {
name: "Peter",
properties: {
age: new Date()
}
};
const copy = structuredClone(original);
copy.properties.action = "Jump";
original.properties.action; // undefined
It can handle circular references and other JS built-in types such as Date, Set, Map.
Learn more on MDN.
The object spread operator actually does a shallow copy. If you modify a deeply nested property, both objects are affected:
const original = {
name: "Peter",
properties: {
age: new Date()
}
};
const copy = { ...original };
copy.properties.action = "Jump";
original.properties.action; // "Jump"
I never got involved in spaces vs tabs debates throughout my career. But the topic has popped up recently and I took notice of something that I have missed for many years: spaces have been an accessibility issue for many developers. For the visually impaired, spaces are hard to read. Tabs give developers the control and flexibility of the spacing to suit their needs.
2.?ts= query.timeoutID).Both return values are passed to clearTimeout() to cancel the timeout.
In RTK Query, services are created like this example:
export const myApi = createApi({
reducerPath: 'myApi',
baseQuery: fetchBaseQuery({ baseUrl: '/api' }),
endpoints: (builder) => ({
getUserById: builder.query({
query: (id) => `user/${id}`,
}),
}),
})
The baseQuery can be a custom utility that can wrap the default fetchBaseQuery.
Below is use-case that provides meta along with each request:
const myBaseQuery = async (args, api, extraOptions) => {
const requestId = uuid();
const baseResult = await fetchBaseQuery({ baseUrl: "/api" })(
args,
api,
extraOptions
);
return {
...baseResult,
meta: baseResult.meta && { ...baseResult.meta, requestId },
};
};
export const myApi = createApi({
reducerPath: "myApi",
baseQuery: myBaseQuery,
endpoints: (builder) => ({
getUserById: builder.query({
query: (id) => `user/${id}`,
}),
}),
});
baseResult can return an error if an error occured and we can use that to track which endpoint had an error. api parameter has an endpoint value that has the name of the endpoint (eg getUserById from the above example).
const baseResult = await fetchBaseQuery({ baseUrl: "/api" })(
args,
api,
extraOptions
);
if (baseResult.error) {
const error = baseResult.error;
if ("status" in error) {
const errMsg = "error" in error ? error.error : JSON.stringify(error.data);
console.error(`Error with ${api.endpoint}: ${error}`);
}
}
AWS Lightsail does not have an option to rename instances. However, you can create a new instance from a snapshot and give it the desired name.
After verifying the new instance is running as expected, you may now re-attach the existing static IP.
Use ReactDOM.unmountComponentAtNode() (React < 18) or root.unmount() to remove a React app from the DOM.
import ReactDOM from 'react-dom';
const domNode = document.getElementById('root');
ReactDOM.render(<App />, domNode);
ReactDOM.unmountComponentAtNode(domNode);
import { createRoot } from 'react-dom/client';
const domNode = document.getElementById('root');
const root = createRoot(domNode);
root.render(<App />);
root.unmount();
updated_at columnmoddatetime() is a trigger that stores the current time into a timestamp field. This can be useful for tracking the last modification time of a particular row within a table.
To use, create a BEFORE UPDATE trigger using this function. Specify a single trigger argument: the name of the column to be modified. The column must be of type timestamp or timestamp with time zone.
create extension if not exists moddatetime schema extensions;
-- assuming the table name is "todos", and a timestamp column "updated_at"
-- this trigger will set the "updated_at" column to the current timestamp for every update
create trigger handle_updated_at before update on todos
for each row execute procedure moddatetime (updated_at);
pnpm can do cross-platform scripting when shell-emulator is enabled.
# .npmrc
shell-emulator=true
It means scripts like this will work across all platforms:
"scripts": {
"serve": "NODE_ENV=production node server"
}
It is powered by @yarnpkg/shell and it replaces the need to use libraries like cross-env.
pnpm patch allows you to make changes to a dependency package without having to wait for the package maintainers to release the changes.
It first extracts the package into a temporarily directory and asks you to make the changes.
$ pnpm patch my-pkg@1.0.0
You can now edit the following folder: /tmp/5ea276f0eeb3585ea64ddf4b3b7ef377
Once you've made the changes, you patch up the changes using pnpm patch-commit:
$ pnpm patch-commit /tmp/5ea276f0eeb3585ea64ddf4b3b7ef377
This will create a patchfile in your project and pnpm will use this each time you do an pnpm install.
pnpm will reference patches in package.json:
"pnpm": {
"patchedDependencies": {
"my-pkg@1.0.0": "patches/my-pkg@1.0.0.patch"
}
}
Pierre-Louis Moreau de Maupertuis (1698-1759) was the first to formally state the principle of least action in 1744. The principle says that the path a physical system takes between two states is the one that minimizes (or makes stationary) a quantity called the action. Euler and Lagrange later gave it rigorous mathematical form. In modern notation, the action S is defined as:
S = ∫ L dt
where L is the Lagrangian (kinetic energy minus potential energy). The principle states that the physical path makes S stationary: δS = 0. This one equation underlies classical mechanics, general relativity, and quantum field theory. Feynman's path integral formulation of quantum mechanics is built directly on it.
I had the opportunity to work on some PHP this week and picked up a few new tricks that are very different from JavaScript:
$array1 = array("a" => "green", "red", "blue", "red");
$array2 = array("b" => "green", "yellow", "red");
$result = array_diff($array1, $array2);
$array1 = array("a" => "green", "red", "blue");
$array2 = array("b" => "green", "yellow", "red");
$result = array_intersect($array1, $array2);
$message = 'world';
$example = function () use ($message) {
return "hello $message";
};
class MyClass {
public static function getDifference() {
$array1 = array("a" => "green", "red", "blue");
$array2 = array("b" => "green", "yellow", "red");
$result = array_udiff($array1, $array2, array($this, 'filterById'));
}
private function filterById($a, $b) {}
}
selfclass MyClass {
public static $url = "https://petermekhaeil.com/";
public static function getUrl() {
return self::$url;
}
}
I was thinking about why songs grow on me after repeat listens. The brain begins to anticipate beats, motifs, and specific moments, and that anticipation heightens the emotional payoff. Turns out there's a name for the underlying mechanism.
The mere exposure effect was first identified by psychologist Robert Zajonc in the 1960s. The finding is simple: the more often we're exposed to a stimulus (a face, a song, a word, an idea), the more we tend to like it. Repeated exposure increases familiarity, and familiarity breeds preference. This applies to advertising, music, interpersonal attraction, and just about everything else.
In 2009, Tony Hoare describes his invention as a "billion-dollar mistake":
I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.
npm view outputs data about an npm package:
$ npm view zod
Output:
zod@3.20.6 | MIT | deps: none | versions: 254
TypeScript-first schema declaration and validation library with static type inference
https://zod.dev
keywords: typescript, schema, validation, type, inference
dist
.tarball: https://registry.npmjs.org/zod/-/zod-3.20.6.tgz
.shasum: 2f2f08ff81291d47d99e86140fedb4e0db08361a
.integrity: sha512-oyu0m54SGCtzh6EClBVqDDlAYRz4jrVtKwQ7ZnsEmMI9HnzuZFj8QFwAY1M5uniIYACdGvv0PBWPF2kO0aNofA==
.unpackedSize: 567.1 kB
maintainers:
- colinmcd94 <colin@colinhacks.com>
- vriad <colin@vriad.com>
dist-tags:
alpha: 3.0.0-alpha.29 beta: 3.20.4-beta.0 canary: 1.10.2-canary latest: 3.20.6 next: 3.8.2-alpha.6
published 4 days ago by colinmcd94 <colin@colinhacks.com>
If you want to use the latest version of a package when using npm create, you need to specify latest as the package version.
It's why most tools will have instructions like below. It's to force npm to install the latest version of the package:
$ npx create-remix@latest
$ npm create svelte@latest
$ npx create-next-app@latest
The above will fetch the latest versions from the registry and execute the script.
If you do not specify a version and have previously installed the package, npm will use that previously installed version.
The same goes with the other npm commands like npm init, npm exec, npx.
npm can get noisy during installs with the audit report:
1 vulnerabilities (0 moderate, 1 high)
To address issues that do not require attention, run:
npm audit fix
To address all issues (including breaking changes), run:
npm audit fix --force
Dan Abramov has a great write-up on why npm audit is broken by design - it is worth the read.
You can disable the audit for all npm commands using .npmrc:
audit=false
loglevel=silent
In Node.js, you can access stdin using file descriptor 0 to take input stream:
const fs = require("fs");
const data = fs.readFileSync(0, "utf-8");
This can be used on the Node.js CLI:
echo Peter Mekhaeil | node -p "fs.readFileSync(0, 'utf8').toLowerCase().replaceAll(' ','-')"
Nginx supports nested locations:
server {
location /app {
location /app/assets {
# ...
}
location /app/pages {
# ...
}
}
}
Note that nested locations are not relative to the parent location.
In the above example:
location /app parent location block that matches requests starting with /app.location/app/assets nested location that matches /app/assets.location/app/pages nested location that matches /app/pages.Next.js statically types links to avoid errors when using next/link. The type declarations are generated by the dev/build process and includes information of all valid routes in the application.
import type { Route } from 'next';
import Link from 'next/link'
// ✅
<Link href="/about" />
// ✅
<Link href="/blog/nextjs" />
// ✅
<Link href={`/blog/${slug}`} />
// ✅
<Link href={('/blog' + slug) as Route} />
// ❌ TypeScript errors if href is not a valid route
<Link href="/aboot" />
Module Federation is a microfrontend pattern that involves 2 components:
Delete all .DS_Store found within a directory recursively:
find . -name '.DS_Store' -type f -delete -print
-print will also print the path of the file when deleting.
logpoints in Chrome DevTools allow you insert logging statements without adding breakpoints.
Right-click on the line you want to log:

Add the statement you would like to output to the console:

Everytime the code runs on this logpoint, it will output to the console:

This allows for quick console logging without having you to touch your source code and without having to add breakpoints.
JSON.stringify has an optional second parameter replacer that can recursively transform properties during the stringify process.
The replacer parameter can be a function or an array:
JSON.stringify({ name: 'Peter', til: true }, ['name']);
// '{"name":"Peter"}'
function replacer(key, value) {
if (key === 'name') {
return 'Mekhaeil';
}
return value;
}
JSON.stringify({ name: 'Peter', til: true }, replacer);
// '{"name":"Mekhaeil","til":true}'
JSON.parse() has an optional reviver parameter that can transform the value being parsed.
This is useful for deserialization:
const jsonString = '{"date":"Sun, 12 Feb 2023 06:45:00 GMT"}';
function reviver(key, value) {
if (key === "date") {
return new Date(value);
}
return value;
}
const data = JSON.parse(jsonString, reviver);
// ^? { date: Date }
JSON.parse's reviver and JSON.stringify's replacer can be combined together to build a JSON serialization and deserialization utility.
WeakMap have "weak" reference to its keys. When the references to the key is lost and there are more references to the value, the value can be garbage collected.
const pokemon = { name: "Pikachu" };
const myPokemons = new WeakMap();
myPokemons.set(pokemon, 1);
// reference removed
pokemon = null;
// pokemon is removed from memory
myPokemons.has(pokemon); // false
keys(), values(), entries()).Tag templates (or tag functions) parse template literals with a function:
function log(strings, ...args) {
console.log(strings, args[0])
}
const person = "Peter";
log`My name is ${person}`;
// ['My name is ', ''] 'Peter'
First parameter is an array of strings, the following parameters are the variables that were passed in the expression. Think of them as substitutes. The string parts of the template have an index that matches the associated substitute that followed.
In the above example, ['My name is ', ''] was the string, Peter was the first substitute.
Tag templates can come useful in formatting strings:
function introduce(strings, ...args) {
let formattedString = '';
strings.forEach((string, i) => {
formattedString += string + (args[i] ? args[i].toUpperCase() : '');
});
return formattedString;
}
var person = "Peter";
introduce`My name is ${person}`
// 'My name is PETER'
const GET_DOGS = gql`
query GetDogs {
dogs {
id
breed
}
}
`;
const query = gql`
{
user(id: 5) {
firstName
lastName
}
}
`
const users = await sql`
select
name,
age
from users
`
const userId = 42
const result = await prisma.$queryRaw`SELECT * FROM User WHERE id = ${userId};`
const Button = styled.a`
background: white;
color: black;
`
const Input = tw.input`border hover:border-black`
Symbol.iterator defines the default iterator for an object. Applying it to an object to enable iteration:
const myObject = { a: 1, b: 2, c: 3 };
myObject[Symbol.iterator] = function* () {
for (const key of Object.keys(this)) {
yield [key, this[key]];
}
};
for (const [key, value] of myObject) {
console.log(key, value);
}
Spread operator does a shallow clone of only enumerable properties. Non-enumerable properties such as prototype will not be cloned.
Cunningham's Law states: "The best way to get the right answer on the Internet is not to ask a question; it's to post the wrong answer." It's attributed to Ward Cunningham, the developer of the first wiki. The irony is that Cunningham himself has said he didn't coin this law. It was named after him by a colleague, Steven McGeady, who observed the pattern in Cunningham's behavior on early internet forums.
Signals are reactive primitives for managing application state.
Signals are reactive. They keep track of the subscriptions and notify subscribers when state has changed. Calling the getter creates a subscription, telling the signal of the location that requires the value.
useSignal() => getter + setteruseState() => value + setteruseState() is not reactive. React does not know of the location that requires the value, therefore must re-renders the whole component when calling the setter.
import { createSignal } from "solid-js";
function Counter() {
const [count, setCount] = createSignal(0);
setInterval(() => setCount(count() + 1), 1000);
return <div>Count: {count()}</div>;
}
export default component$(() => {
const count = useSignal(0);
return (
<>
<button onClick$={() => count.value++}>Increment</button>
Count: {count.value}
</>
);
});
import { signal } from "@preact/signals";
const count = signal(0);
function Counter() {
return (
<div>
<p>Count: {count}</p>
<button onClick={() => count.value++}>click me</button>
</div>
);
}
Angular has announced some prototyping work around adding signals as a reactive primitive in Angular.
The new scrollend event fires when scrolling has ended.
addEventListener("scrollend", (event) => {});
onscrollend = (event) => {};
Previously before this event, there was no straightforward way to detect when scrolling has ended. We would have had to use the onscroll and a timer to detect if scrolling has ended.
Read the full write-up on developer.chrome.com.
Promise.race() takes a list of promises and returns the first promise that settles (regardless if fulfilled or rejected).
Good use to implement a request timeout. It resolves the first promise that settles which will either be the fetch request or the timeout promise.
const fetchApi = async () => {
const res = await fetch("/api");
return await res.json();
};
const requestTimeout = (delay: number) => {
return new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("Timeout")), delay);
});
};
const data = Promise.race([fetchApi, requestTimeout(5000)]);
In JavaScript, negative zero -0 is not the same as a positive zero +0.
This is because numbers in JavaScript are represented using the IEEE 754 floating-point standard which requires zeros to have an associated sign. Floating point numbers include a sign bit (0 for positive, 1 for negative). In the case of +0, the sign bit is 0 while in the case of -0 the sign bit is 1.
+0 === -0 // true
-0 === +0 // true
This is because of ECMAScript's Strict Equality Comparison Algorithm:
If Type(x) is Number, then
a. If x is NaN, return false.
b. If y is NaN, return false.
c. If x is the same Number value as y, return true.
d. If x is +0 and y is −0, return true.
e. If x is −0 and y is +0, return true.
f. Return false.
Object.is() can be used:
Object.is(+0, -0); // false
Object.is(-0, +0); // false
Both +0 and -0 will return "0".
const negativeZero = -0;
negativeZero.toString() // "0"
const positiveZero = +0;
positiveZero.toString() // "0"
JSON.stringify({"negativeZero": -0}); // '{"negativeZero":0}'
Math.random() is implemented using a pseudo-random number generator (PRNG) - the random number is derived from an internal state, which is altered by a fixed algorithm for every new random number. The sequence of random numbers is deterministic.
Crypto.getRandomValues() use a pseudo-random number generator seeded with a value with enough entropy. Implementations do not use a truly random number generator to guarantee enough performance but the output is suitable for cryptographic purposes.
crypto.getRandomValues(new Uint8Array(10))
// Uint8Array(10) [85, 215, 117, 156, 114, 11, 222, 34, 65, 119]
A much cleaner and performant alternative to objects.
const myPokemons = new Map();
const bulbasaur = { id: 1, name: "Bulbasaur" };
myPokemons.set(bulbasaur.id, bulbasaur);
myPokemons.delete(bulbasaur.id);
for (const [key, value] of myPokemons) {
// ...
}
// Iterator of all map keys
myPokemons.keys();
// Iterator of all map values
myPokemons.values();
const clonedPokemons = new Map(myPokemons);
// deep cloning
const deepClone = structuredClone(myPokemons);
const myObj = Object.fromEntries(myMap);
const myMap = new Map(Object.entries(myObj));
myMap.set(document.body, value);
myMap.set(function() {}, value);
myMap.set(myPokemon, value);
An import map is JSON that browsers use to resolve the path of JS modules when used in import and import() statements.
An example can be found on three.js:
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@0.149.0/build/three.module.js"
}
}
</script>
<script type="module">
import * as THREE from 'three';
const scene = new THREE.Scene();
</script>
Another example commonly seen in micro-frontends:
<script type="importmap">
{
"imports": {
"react": "https://unpkg.com/react@18.2.0/umd/react.production.min.js",
"react-dom": "https://unpkg.com/react-dom@18.2.0/umd/react-dom.production.min.js"
}
}
</script>
<script type="module">
import * as React from 'react';
import * as ReactDOM from 'react-dom';
</script>
Ever wondered why Response.statusText returns an empty string? It's because it is not part of the HTTP/2 spec.
HTTP/2 does not define a way to carry the version or reason phrase that is included in an HTTP/1.1 status line.
Otherwise, in HTTP/1 it will return status message such as OK, Continue and Not Found.
Reference:
A fugue is a composition built on a short melody (the "subject") that enters in one voice and is then imitated by other voices at different pitches, layering on top of each other. The word comes from Latin fuga ("flight"), because the melody seems to flee from one voice to the next. Bach's The Art of Fugue (Die Kunst der Fuge) is considered the pinnacle of the form. He was still working on it when he died in 1750, leaving the final fugue unfinished. The last piece, Contrapunctus XIV, breaks off mid-phrase. The manuscript just stops. Some printed editions include a note at that point: "At this point the composer died." A movement built on interweaving voices, cut short in the middle of a sentence.
const newFunction = oldFunction.bind({});
this set to the value passed in the argument.The navigator.sendBeacon() method is intended to be used for sending analytics data to a server.
navigator.sendBeacon("/log", analyticsData);
See documentation on usage.
The claim that humans only use 5% or 10% of their brains is a neuromyth. Brain imaging studies show that virtually all parts of the brain are active at some point over a 24-hour period. Different regions activate for different tasks. The myth has been around since at least the early 1900s and keeps getting recycled in pop culture (the films Lucy and Limitless both used it as a premise). No neuroscientist has ever endorsed it.
The likely origin is a misquotation of William James, who wrote in The Energies of Men (1907) that people only meet "a small part" of their mental potential. Early neuroscience findings about glial cells (which outnumber neurons and were initially thought to be inert) may have reinforced the confusion. The leap from "we don't use our full potential" to "we only use 10% of our brain" is the kind of distortion that sticks because it sounds empowering.
A barrel file is a module that re-exports from other modules:
// ./components/index.js
export { Button } from './Button.js';
export { Anchor } from './Anchor.js';
export { Text } from './Text.js'
Usage:
import { Button, Anchor, Text } from './components';
Barrel files have an impact on your bundler performance (this is how I came across the term Barrel Files).
# Optional: Create new JSON file `feed.json` with empy array.
jq -n '[]' > feed.json
# Append an object to the array from `feed.json`
# and store the new JSON in `feed.json.tmp`
jq \
--arg date "$date" \
--arg title "$title" \
'. += [{"date": $date, "title": $title}]' \
feed.json > feed.json.tmp
# Replace temp file with original file.
mv feed.json.tmp feed.json
--arg content "$content" creates a variable $content to be used within the jq tool.'. += [{...}]' feed.json appends a new object to the array from feed.json.> feed.json.tmp is redirecting the output of jq into a temporarily file.mv feed.json.tmp feed.json is replacing original file with the new temporarily file. Basically updating the original file with the new content.The banners on top of web apps that promote the native version of the app is controlled using a <meta> tag in the HTML:
<meta name="apple-itunes-app" content="app-id=1477376905, app-argument=https://github.com/" />
See the documentation on Promoting Apps with Smart App Banners . This only works for iOS Safari.
Example from GitHub:
import.meta is an object that is available within Javascript ES modules. It contains metadata about the module and is extensible.
It contains import.meta.url that returns the full URL of the module.
<script type="module" src="module.mjs"></script>
// module.mjs
let img = document.createElement('img');
img.src = new URL('image.jpg', import.meta.url);
document.body.appendChild(img);
process.env is specific to Node and cannot be used in the browser.
interface ImportMeta {
myVariable: string
}
import.meta.myVariable; // string
Vite extend import.meta to add things like:
import.meta.env.import.meta.globI was reading about Gege Akutami, the Jujutsu Kaisen creator, and kept seeing the word "mangaka" used without explanation.
A mangaka is a manga artist in Japanese. The word combines manga (comics/whimsical pictures) with -ka (a suffix meaning "person who does"). Unlike American comics, where writing, penciling, inking, and coloring are often split between specialists, a mangaka typically handles both story and art. Some have assistants for backgrounds and inking, but the mangaka is the central creative force.
The <mark> HTML element represents marked or highlighted text.
<span><mark>Peter</mark> Mekhaeil</span>
Can be styled:
mark {
background-color: yellow;
color: black;
}
The hex color notation can be described as #RGB[A] or #RRGGBB[AA] - it accepts an alpha channel that can be used to represent the transparency.
When using it as #RRGGBB[AA], the alpha channel is a hexadecimal number where 00 is full transparent and FF full opaque. If using the shorter #RGB[A] notation, it is a hexadecimal number ranging from 0 and F.
#FF7f00 /* orange */
#FF7f0000 /* orange 0% opaque */
#FF7f0080 /* orange 50% opaque */
#FF7f00FF /* orange 100% opaque */
#01E /* blue */
#01E0 /* blue 0% opaque */
#01E8 /* blue 53% opaque */
#01EF /* blue 100% opaque */
You can find out more on MDN.
GitHub supports web form fields in issue templates:
name: Feature request
description: Suggest an idea for this project
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this feature report!
- type: textarea
id: feature-description
attributes:
label: Description
description: "A clear and concise description of what the problem is."
placeholder: Ex. I'm always frustrated when [...].
validations:
required: true
This will render the below form:
There are 3 ways to create a release using the GitHub API.
tag_name: The name of the tag.name: The name of the release.body: The description of the release.There are more parameters in the documentation.
Sample repository with releases: git-tag-release.
curl \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer <YOUR-TOKEN>"\
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/OWNER/REPO/releases \
-d '{"tag_name":"v0.0.0","name":"v0.0.0","body":"Full Changelog: https://github.com/OWNER/REPO/commits/v0.0.0"}'
Using Octokit:
const octokit = new Octokit({
auth: 'YOUR-TOKEN'
});
await octokit.request('POST /repos/{owner}/{repo}/releases', {
owner: 'OWNER',
repo: 'REPO',
tag_name: 'v0.0.0',
name: 'v0.0.0',
body: 'Full Changelog: https://github.com/OWNER/REPO/commits/v0.0.0'
});
gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
/repos/OWNER/REPO/releases \
-f tag_name='v0.0.0' \
-f name='v0.0.0' \
-f body='Full Changelog: https://github.com/OWNER/REPO/commits/v0.0.0'
To show list of files in the most recent Git stash:
git stash show
To show the diff:
git stash show -p
To show content of nth most recent stash:
git stash show -p stash@{n}
Find the commits that contain the file. Take note of the last commit that deleted the file:
git log --all --full-history --oneline -- <file-path>
--all: Show commits in all branches, tags and refs.--full-history: Show full history of commits.--oneline: Pretty format because we only need the commit hash.Restore the file by checking out the commit that happened before it was deleted:
git checkout <deleting-commit>^ -- <file-path>
The ^ means "parent of" - in the above example, it means checkout the parent commit of the deleting commit. This would contain the file and its content before it was deleted.
Sometimes you need to reset a remote Git repository while keeping your local history intact. Here's how:
1. Add the Remote:
git remote add origin <remote-url>
Links your local repo to the remote.
2. Force Push to Overwrite Remote History:
git push --force --set-upstream origin main
Replaces the remote history with your local history.
Clean up history from a repository by removing the git commits and replacing it with a new single commit.
git checkout --orphan temp_branch
git add -A
git commit -am "First commit"
git branch -D master
git branch -m master
git push -f origin master
# ~/.ssh/config
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_rsa
Host github.com-work
HostName github.com
User git
IdentityFile ~/.ssh/id_rsa_work
.gitconfig path based on working directory:# ~/.gitconfig
[user]
name = Default Name
email = default.name@example.com
[includeIf "gitdir:~/work/"]
path = ~/work/.gitconfig
# ~/work/.gitconfig
[user]
name = Work Name
email = work.email@example.com
git remote add origin git@github.com-work:username/repo.git
git commit --reuse-message HEAD
--reuse-message takes an existing commit and reuse the log message.
Add --edit to bring up the editor if you wish to edit the message before committing.
git checkout - is a shorthand for git checkout @{-1}. It will checkout the last previous branch.@{-1} refers to the last branch that was checked. It can be used with git checkout @{-1} to checkout the previous branch.git checkout @{-N}.git add my-file
git commit --amend --no-edit
--amend: Amends previous commit.--no-edit: Use previous commit message.Query the first item in the history of that path and return the committedDate:
query CommittedDate($name: String!, $owner: String!, $path: String!) {
repository(owner: $owner, name: $name) {
ref(qualifiedName: "refs/heads/master") {
target {
... on Commit {
history(first: 1, path: $path) {
edges {
node {
committedDate
}
}
}
}
}
}
}
}
2>&1 is used to redirect standard error (stderr) to standard output (stdout). It allows you to capture and handle both types of output in the same way.
There are 3 file descriptors, represented by numbers:
> is used to redirect the output of a command to something else.
& indicates that what follows is a file descriptor (in the context of a redirection). It is required otherwise it will interpret the 1 as a filename (eg 2>1 would mean "redirect stderr to a file named 1").
2>&1 indicates that file descriptor 2 (stderr) should be redirected to file descriptor 1 (stdout).
command > /dev/null 2>&1
The stdout of command is redirected to /dev/null and stderr is redirected to stdout. Meaning everything is redirected to /dev/null.
cat file.txt > output.txt 2>&1
Send the content of file.txt to output.txt. If any errors (eg. file does not exist), send it to stdout which is also output.txt.
ls -l ./apps/ ./packages 2> /dev/null
List the content of ./apps and ./packages. If there was any errors (eg. directory does not exist), send stderr to /dev/null.
no-restricted-syntax ruleESLint's no-restricted-syntax uses selectors to query an AST and this can be used to restrict certain syntax from being used.
Use a AST Explorer to view the resulting AST of the JavaScript code you want to query.
This rule disallows the use of MyLibrary.myFunction():
{
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "MemberExpression[property.name='myFunction'][object.name='MyLibrary']",
"message": "'MyLibrary.myFunction()' is depreciated. Please use MyOtherLibrary.myNewFunction()"
}
]
}
}
This rule disallows the use of MyLibrary().myFunction():
{
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "[property.name='myFunction'] CallExpression[callee.name='MyLibrary']",
"message": "'MyLibrary().myFunction()' is depreciated. Please use MyOtherLibrary.myNewFunction()"
}
]
}
}
Take advantage of HTTP/2 in Vite Dev Server by enabling server.https in your vite.config.js.
{
server: {
https: true
}
}
Browsers limit the number of active connections per domain when using HTTP/1.1 and this can be avoided by enabling HTTP/2 which supports unlimited concurrent requests.
Vite's Dev server takes advantage of modern browser's support for ES Modules and instead of bundling your site, the dev server will serve the modules via network requests in your browser. Enabling HTTP/2 can come handy in large applications that need to serve a lot of these modules.
The sections in .editorconfig are filepath globs. They can be used to define config for certain files and directories:
root = true
[*]
indent_style = tab
indent_size = 2
insert_final_newline = true
# Match exact file package.json
[package.json]
indent_style = space
# Match .css files under test directory
[test/**/*.css]
insert_final_newline = false
docker kill $(docker ps -q)
docker ps: Lists all running containers. -q only return the container IDs.docker kill: Stops the continers by container ID.docker rm $(docker ps -a -q)
docker ps -a -q: Lists all containers (including non-running) and only return their IDs.docker rm: Remove containers by their ID.docker rmi $(docker images -q)
docker images -q: Lists all images by their IDs.docker rmi: Removes docker images by their ID.Steps on building a Docker image and pushing it to a self-hosted registry:
docker build.docker login to log in to the registry.docker tag.docker push.Putting it together in an example:
# Build the image
docker build -t app:1.0.0 .
# Log into the registry
docker login example.com
# Tag the image to the registry
docker tag app:1.0.0 example.com/app:1.0.0
# Push the image to the registry
docker push example.com/app:1.0.0
This will create an image with the name example.com/app:1.0.0 being pushed to the registry.
COPY --from is used for mulit-stage builds and it is used to copy from another image, either by referencing a local image name or a tag available on a Docker registry.
COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf
It can also be used for copying from stages created earlier in the Dockerfile:
# stage 1
FROM alpine as git
RUN apk add git
# stage 2
FROM git as fetch
WORKDIR /repo
RUN git clone https://github.com/your/repository.git .
# stage 3
FROM nginx as site
COPY --from=fetch /repo/docs/ /usr/share/nginx/html
du -h [DIRECTORY] | sort -hr | head -n 10
The du command returns the estimated disk usage used.
-h: Show sizes in human readable format (eg. 2K, 1G).Use sort to organise the output:
-h: Sort by human readable numbers (eg. 2K, 1G).-r: Reverse the output (so it is in descending order).Show the top 10 items using head:
-[NUMBER]: Number of lines to output (Default is 10).Chrome DevTools allows you to override API responses and HTTP headers directly in the browser - this is a great feature for testing, debugging, and prototyping without modifying the backend.
You can:
You just need to enable "Local Overrides" in DevTools and edit the response or headers for the network requests you want to tweak.
More details here: Chrome DevTools Overrides
If you switch focus from the current page to the Chrome DevTools, some overlay elements automatically hide if they are triggered by focus. For example, dropdown menus.
The Chrome DevTools have a feature to emulate page focus. Press Ctrl+Shift+P (or Cmd+Shift+P on macOS) and search for "Emulate a focused page". You won't lose focus of the page while inspecting the elements.
find ./my-folder -mtime +10 -type f -delete
-mtime +10: Filter files that have a last modified date 10 days ago.-type f: Filter files only.-delete: Delete files matching the filters.In Dart (starting from version 3.6.0), you can use underscores (_) as digit separators in number literals to make them more readable. This is especially handy for large numbers or when grouping digits for higher-level clarity.
Here are some examples:
var n1 = 1_000_000;
var n2 = 0.000_000_000_01;
var n3 = 0x00_14_22_01_23_45; // MAC address
var n4 = 65_1234_5678; // SG Phone number
var n5 = 100__000_000__000_000; // one hundred million million!
This feature makes it easier to read long numeric values and organize digits meaningfully.
Dart isn’t alone in supporting this - other languages like JavaScript, Java, Python, and Kotlin also allow underscore digit separators. It's a great example of a feature that crosses language boundaries to make code cleaner and more human-readable.
cy.clock() allows you to control time in your Cypress test:
cy.clock();
cy.intercept('GET', '/pokemon').as('pokemon');
// 1st call
cy.wait('@pokemon');
// forward 10 seconds and wait for next `/pokemon` request
cy.tick(10_000);
cy.wait('@pokemon');
Pseudo-classes are states applied to the selected elements. They have a single colon (:).
button:hover {
background: red;
}
Pseudo-elements selects specific parts of the selected elements. They have double colons (::).
p::first-line {
text-transform: uppercase;
}
The :is pseudo-class takes a list of selectors and selects any elements that matches the selectors in that list. Its useful to compact large selectors.
Take this example:
header h2,
nav h2,
article h2 {
color: black;
}
Can be written as:
is:(header, nav, article) h2 {
color: black;
}
It's worth noting there is a difference between :is and :where() when it comes to specificity value. Detailed explanations:
The :has(<selector>) pseudo-class selects elements that contain certain child elements that match the <selector> selectors.
Open the CodeSandbox demo. The :has() selector is being used to select the pricing card that contains a .popular element:
.pricing-card:has(.popular) {
border-color: blue;
}
/* section that contain an image */
section:has(img) {
color: red;
}
/* section that contain a .sale element */
section:has(.sale) {
border-color: red;
}
/* section that does NOT contain a .sale element */
section:not(:has(.sale)) {
border-color: red;
}
/* paragraph that contains an anchor */
p:has(a) {
color: blue;
}
/* paragraph that contains a an image as first sibling */
p:has(> img) {
color: blue;
}
/* paragraph that contains a an image as first sibling */
p:has(> img) {
color: blue;
}
/* h1 that is followed by a paragraph */
h1:has(+ p) {
margin-bottom: 0;
}
See caniuse.com for browser support.
Can also use CSS to detect if the feature is supported:
@supports(selector(:has(img))) {}
Some OpenType fonts support alternate numeric glyphs that can be styled using font-variant-numeric.
Here is a CodeSandbox that demonstrate each value. This demo uses the "Source Sans Pro" font which supports these features.
Take a look at the tabular-nums feature - it can make the design of tabular data very satisfying.
/* normal: Disable using alternate glyphs */
font-variant-numeric: normal;
/* ordinal: Use letters to represent numeric order */
font-variant-numeric: ordinal;
/* slashed-zero: Use a 0 with a diagonal slash */
font-variant-numeric: slashed-zero;
/* lining-nums: Use glyphs that are all aligned by their baseline. */
font-variant-numeric: lining-nums;
/* oldstyle-nums: Use glyphs where some numbers have descenders */
font-variant-numeric: oldstyle-nums;
/* proportional-nums: Use glyphs where numbers are not all of the same size */
font-variant-numeric: proportional-nums;
/* tabular-nums: Use glyphs where numbers all have the same width */
font-variant-numeric: tabular-nums;
/* diagonal-fractions: Use diagonal fractions (numbers are made smaller and separated by a slash) */
font-variant-numeric: diagonal-fractions;
/* stacked-fractions: Numbers are made smaller, stacked and separated by a horizontal line */
font-variant-numeric: stacked-fractions;
Values can be combined together:
font-variant-numeric: slashed-zero tabular-nums;
Not all fonts support these features. The values will have no effect if the font family does not have support.
CSS can be applied to the first letter of an element:
p::first-letter {
text-transform: uppercase;
}
CSS.escape() returns an string that conforms to the CSS selector specs. Useful when generating dynamic CSS selectors based on an input.
CSS.escape("app:@org/name");
// 'app\\:\\@org\\/name'
If there is a certificate error, Chromium based browsers will not cache responses and will treat a self-signed certificate as a certificate error.
See https://bugs.chromium.org/p/chromium/issues/detail?id=110649#c8.
Mkcert can create a locally-trusted development certificate for your dev servers to prevent this from happening.
The <button> element can have a value like <input> and this value can also be passed to the server when the form is submitted:
<form action="#" method="POST">
<input type="text" name="name" value="Peter" />
<button type="submit" name="_action" value="add">Add</button>
<button type="submit" name="_action" value="delete">Delete</button>
</form>
The form can be submitted with this data without the need of JavaScript. On the server, you can check the value of _action to decide what to do next based on which button the user clicked to submit the form.
If you are submitting the form programmatically using JavaScript, FormData needs to know which button was used to submit the form:
document.querySelector("form").addEventListener("submit", (event) => {
event.preventDefault();
const formData = new FormData(event.target);
// The FormData does not know how the form was submitted.
// There could be more than one submit button on the form and
// we want to include the one that was used to submit the form.
// We append the button (also known as the submitter) to FormData.
// See more: https://developer.mozilla.org/en-US/docs/Web/API/SubmitEvent/submitter
if (event.submitter) {
formData.append(event.submitter.name, event.submitter.value);
}
const data = Object.fromEntries(formData.entries());
console.log(data); // {name: "Peter", _action: "add"}
// When ready, submit the form programmatically
});
Remix does a great job at using this technique - they demonstrate it in their video Remix Single: Multiple Forms and Single Button Mutations. The Remix implementation can be found here.
Axios supports adding custom config to requests that can be used later throughout the request.
Here is an example adding a custom config called endpointName:
const instance = axios.create();
const { data } = await instance.get("/api", {
endpointName: "myApi"
});
It can be used in interceptors:
instance.interceptors.request.use(function (config) {
console.log(config.endpointName);
return config;
});
instance.interceptors.response.use(function (response) {
console.log(response.config.endpointName);
return response;
});
It is also included in Axios errors:
instance.interceptors.response.use(null, function (error) {
if (isAxiosError(error)) {
console.log(error.config.endpointName);
}
return Promise.reject(error);
});
Create an axios.d.ts and add the custom config under AxiosRequestConfig:
import "axios";
declare module "axios" {
export interface AxiosRequestConfig {
endpointName?: string;
}
}
OpenAI's web crawler has a user-agent:
User agent token: GPTBot
Full user-agent string: Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; GPTBot/1.0; +https://openai.com/gptbot)
Which means it can be restricted to crawl your site using robots.txt:
User-agent: GPTBot
Disallow: /
Found in OpenAI's documentation.
Node.js supports the FORCE_COLOR environment variable to force color in the terminal output.
FORCE_COLOR=0 // 2 colors (no color)
FORCE_COLOR=1 // 16 colors
FORCE_COLOR=2 // 256 colors
FORCE_COLOR=3 // 16,777,216 colors
Color is automatically disabled when a process is piping output into another process. Use FORCE_COLOR to force color in the piped output.
Adam Argyle has written a Codepen that lists the different units.
To learn more about what each unit means:
| Unit | Definition |
|---|---|
| % | Percentage of the parent element's font size |
| em | Font size of the element |
| ex | Height of the element's font |
| ch | Width of the "0" (zero) character of the element's font |
| cap | Hight of the capital letters of the element's font |
| ic | Advance measure of the 水 CJK (Chinese/Japanese/Korean) character of the element's font |
| lh | Height of the element's line height |
| Unit | Definition |
|---|---|
| rem | Font size of the root element |
| rex | Height of the root element's font |
| rch | Width of the "0" (zero) character of the root element's font |
| rlh | Height of the root element's line height |
| ric | Advance measure of the 水 CJK (Chinese/Japanese/Korean) character of the root element's font |
| rcap | Height of the capital letters of the root element's font |
| Unit | Definition |
|---|---|
| px | Pixels |
| pt | Points |
| pc | Picas |
| in | Inches |
| cm | Centimeters |
| mm | Millimeters |
| Q | Quarter-millimeters |
| Unit | Definition |
|---|---|
| vw | Viewport width |
| vh | Viewport height |
| vi | Viewport inches |
| vb | Viewport breadths |
| dvw | Dynamic viewport width |
| dvh | Dynamic viewport height |
| dvi | Dynamic viewport inches |
| dvb | Dynamic viewport breadths |
| svw | Smallest possible viewport width |
| svh | Smallest possible viewport height |
| svi | Smallest possible viewport inches |
| svb | Smallest possible viewport breadths |
| lvw | Largest possible viewport width |
| lvh | Largest possible viewport height |
| lvi | Largest possible viewport inches |
| lvb | Largest possible viewport breadths |
| vmin | Smallest value between the viewport's width and height |
| vmax | Largest value between the viewport's width and height |
| Unit | Definition |
|---|---|
| cqw | Container width |
| cqh | Container height |
| cqi | Container inches |
| cqb | Container breadths |
| cqmin | Smallest value between the element's parent container's width and height |
| cqmax | Largests value between the element's parent container's width and height |
G.H. Hardy once visited Ramanujan in the hospital and mentioned he'd arrived in a taxi numbered 1729, calling it a rather dull number. Ramanujan immediately replied that it wasn't dull at all: 1729 is the smallest number expressible as the sum of two cubes in two different ways. It's now called the Hardy-Ramanujan number, and "taxicab numbers" are named after this story.
The two decompositions:
1^3 + 12^3 = 1 + 1728 = 1729
9^3 + 10^3 = 729 + 1000 = 1729
As I wrap up site development, I finally have time to dive into the deep lit world my friend Vivien introduced me to. Below is a complete tabled overview of the Chinese classics and poetry she recommended, complete with her thoughts and why they matter.
| Title / Poet | Pinyin | What it is | Vivien’s take / why start here |
|---|---|---|---|
| 苏轼 | Sū Shì | Song-dynasty master of cí lyric poetry | “My idol!!! His poems and essays are all gems; his upbeat view of life is worth learning.” |
| 定风波 | Dìng Fēng Bō | lyric written in exile | See how Su turns hardship into calm humour. |
| 念奴娇·赤壁怀古 | Niàn Nú Jiāo · Chì Bì Huái Gǔ | lyric on the Red Cliff | Grand historical sweep + personal feeling. |
| 水调歌头 | Shuǐ Diào Gē Tóu | Mid-Autumn lyric to his brother | The famous “May we share the moon” line. |
| 辛弃疾 | Xīn Qì Jí | Late-Song patriot-poet | His bold military imagery balances Su’s cosmopolitan ease. |
| 李白 | Lǐ Bái | Tang “Immortal of Wine” | For exuberant free-spirited verse; try 《将进酒》. |
| 曹操 | Cáo Cāo | Statesman-poet of the Three Kingdoms | Read 《短歌行》 for the heroic Jian’an style. |
| 楚辞 | Chǔ Cí | Warring–States anthology of lyrical verse | On Vivien’s shortlist; good gateway to earlier poetic diction. |
| 人间词话 | Rén Jiān Cí Huà | Wang Guowei’s notes on cí aesthetics | Dip in once you’ve sampled Song lyrics – sharp, elegant criticism. |
Vivien’s note:
Classic Chinese can feel tough at first; don’t hesitate to read modern annotated editions or bilingual versions. Learning by doing beats endless theory, so write your own verses alongside the reading!
| Title | Pinyin | Genre & era | Quick orientation |
|---|---|---|---|
| 《道德经》 | Dào Dé Jīng | Daoist philosophy, c. 4ᵗʰ BCE | 81 laconic chapters on dao & governance. |
| 《庄子》 | Zhuāng Zǐ | Daoist philosophy & tales | Playful paradoxes that loosen rigid thinking. |
| 《孟子》 | Mèng Zǐ | Confucian dialogues | Moral psychology & “benevolent government.” |
| 《荀子》 | Xún Zǐ | Confucian realism | Argues human nature is “bad” → need for ritual. |
| 《韩非子》 | Hán Fēi Zǐ | Legalist essays | Ruthless statecraft; counter-weights Mencius. |
| 《大学》 + 《原本大学微言》 | Dà Xué | Confucian primer + modern commentary | Path from self-cultivation to good rule. |
| 《周易》 ★ | Zhōu Yì | Classic of Changes | Vivien’s pick; read both text & commentaries. |
| 《吕氏春秋》 | Lǚ Shì Chūn Qiū | Encyclopedic Qin-era synthesis | Early attempt to blend the Hundred Schools. |
| 《鬼谷子》 | Guǐ Gǔ Zǐ | Strategy & persuasion | Rhetoric for diplomats and spies. |
| 《了凡四训》 | Liǎo Fán Sì Xùn | Ming self-cultivation manual | Karma, virtue, and practical life advice. |
| 《增广贤文》 ★ | Zēng Guǎng Xián Wén | Ming proverb anthology | Compact wisdom; great for aphoristic style. |
| 《战国策》 | Zhàn Guó Cè | “Warring-States Strategems” | Anecdotes & persuasion tactics of envoys. |
| 《左传》 | Zuǒ Zhuàn | Spring-&-Autumn history | Narrative history + moral judgment. |
| 《史记》 | Shǐ Jì | Grand Scribe’s Records | Foundation of Chinese historiography. |
| 《孙子兵法》 | Sūn Zǐ Bīng Fǎ | The Art of War | Timeless strategy in 13 terse chapters. |
| 《三国演义》 | Sān Guó Yǎn Yì | Ming epic novel | “70 % history, 30 % fiction” – gripping, vast cast. |
| 《古文观止》 | Gǔ Wén Guān Zhǐ | Anthology of exemplary prose | Use for prose-style imitation drills. |
| 《郁离子》 | Yù Lí Zǐ | Yuan-dynasty fables | Philosophical allegories in terse prose. |
| 《警世通言》, 《醒世恒言》, 《喻世明言》 | Féng Mènglóng | Ming vernacular story collections | Morality tales; vivid characters and dialogue. |
★ = Vivien explicitly recommended
Thanks to Vivien for curating this treasure trove. I’m going to post reflections, translations, and analyses here as I go. If you’re reading any of these too, feel free to reach out or tag me in your own write-ups.
Next up: writing my own ci after Su Shi
I was going through AoPS material for competition prep, looking at their calculus coverage and geometry/stereometry resources, and using Alcumus for integration bee practice. It's one of the better free tools for drilling at the AMC/AIME level.
Alcumus is a free adaptive math practice tool built by Art of Problem Solving (AoPS). It adjusts difficulty based on the student's performance and covers algebra, number theory, combinatorics, and geometry. It's primarily used by students preparing for math competitions like AMC, AIME, and MATHCOUNTS. The name is a play on "calculus" (or possibly a reference to Alcuin of York, the medieval scholar who posed famous math puzzles).
I was researching the unified field theory timeline and found that Schrodinger also spent years on the same problem. Both men working in parallel on the same dead end is a striking detail.
The last major project Einstein worked on before his death in 1955 was a Unified Field Theory, an attempt to combine gravity and electromagnetism into a single mathematical framework. He spent roughly the last 30 years of his life on it. He never succeeded, and most physicists at the time considered the effort misguided. The problem he was trying to solve, unifying all fundamental forces, remains unsolved.
Alfred North Whitehead and Bertrand Russell published Principia Mathematica in three volumes from 1910 to 1913. The project attempted to derive all mathematical truths from a set of axioms using symbolic logic. The proof that 1+1=2 doesn't appear until Volume II, around page 362. Russell later said the work took them ten years of grinding labor and nearly broke both of them intellectually.
This is a completely different book from Isaac Newton's Philosophiae Naturalis Principia Mathematica (1687), which laid out the laws of motion and universal gravitation. They share a name and nothing else. Newton's is physics; Whitehead and Russell's is pure logic.
I was deep into Lockhart's work when I found this. I'd already read Arithmetic and Measurement and was tracking down the books Lockhart himself cites. This essay was the starting point for all of it.
"A Mathematician's Lament" is a 2002 essay by Paul Lockhart, a K-12 math teacher who previously worked in research mathematics at Brown and UC Santa Cruz. The essay argues that math education has been reduced to rote procedures and has lost all contact with the creative, exploratory nature of actual mathematics. Lockhart compares it to teaching music by having students fill out sheet music notation worksheets without ever hearing a song. Keith Devlin helped popularize it by sharing it on his MAA column in 2008.
I was mapping my own study areas against the trivium and quadrivium to see what classical education covers and where the gaps are. I also looked into classical education publishers and the role of printing presses in spreading the model. This was curriculum design research.
In classical education, the Trivium consists of three disciplines: Grammar (the mechanics of language), Logic (the art of reasoning), and Rhetoric (the art of persuasion). Together with the Quadrivium (arithmetic, geometry, music, astronomy), they formed the seven liberal arts that structured medieval European education. The word "trivium" literally means "three ways" or "three roads" in Latin. "Trivial" originally meant "of the trivium," something basic that any educated person should know.
I was building a list of names for a project, things like Edith, Erudite, Verity, and Minerva kept surfacing. I ended up using "Minerva Remington" as a character name. But I wanted to know what it actually meant.
The name Minerva comes from the Latin word mens, meaning "mind" or "intellect." She was the Roman goddess of wisdom, arts, trade, and strategic warfare, the equivalent of the Greek Athena. The etymological root is the same one that gives us "mental" and "mentor."
I was combining Pomodoro with time blocking and ultradian rhythms, trying to build a daily structure that actually held. That's when I looked up whether anyone had patented the technique.
The Pomodoro Technique can't be patented because it's a method, not a tangible invention. Francesco Cirillo developed it in the late 1980s: work in 25-minute intervals separated by short breaks, using a timer. But patent law doesn't cover abstract ideas or methods of organizing human activity. The technique is named after the tomato-shaped kitchen timer Cirillo used as a university student.
I was studying Pareto as a productivity principle, not just as economics history. I'd been mapping competence pyramids and looking for frameworks that actually predict where effort pays off.
The Pareto Principle (the 80/20 rule) is named after Italian economist Vilfredo Pareto, who observed around 1896 that roughly 80% of the land in Italy was owned by 20% of the population. He also noticed that 20% of the pea pods in his garden produced 80% of the peas. The principle was later generalized by Joseph Juran in the 1940s, who named it after Pareto and applied it to quality control and business management.
The writing technique of placing short, blunt sentences side by side without conjunctions is called parataxis. Hemingway used it constantly:
He sat down. He drank his coffee. He looked at the rain.
The opposite is hypotaxis, which uses subordinate clauses to create complex, nested sentences. Parataxis creates a feeling of immediacy and flatness, like the narrator is just reporting what happened without interpreting it.
I spent a while on this one. I was looking for simpler ways to explain cognitive load, studying Sweller's empirical outcomes, and trying to frame cognitive load as a finite yet renewable resource. Self-directed pedagogy research, not homework.
Cognitive Load Theory was developed by John Sweller, an Australian educational psychologist, in the late 1980s. The core idea is that working memory has limited capacity, and instructional design should minimize unnecessary cognitive load. Sweller identified three types: intrinsic (inherent difficulty of the material), extraneous (caused by poor instruction), and germane (effort devoted to building schemas). It's one of the most empirically supported theories in educational psychology.
I came across semiotics while studying how occult and esoteric symbols function in institutional contexts, how a symbol gets loaded with meaning and then used to reinforce ideological structures.
The study of signs and symbols, how they create meaning, and how they're interpreted is called semiotics. Ferdinand de Saussure and Charles Sanders Peirce developed the field independently in the early 20th century. Saussure called it "semiology" and approached it from linguistics; Peirce called it "semiotics" and came at it from logic and philosophy. Peirce's term won out.
The English word "April" comes from Latin Aprilis, which is believed to derive from the verb aperire, meaning "to open." The connection is to buds and blossoms opening in spring. There's no consensus on this etymology, but it's the most widely accepted one. The month was the second month in the early Roman calendar before January and February were added.
The legal field governing activities on the world's oceans is called admiralty law (or maritime law). It covers navigation, commerce, marine pollution, fisheries, territorial waters, and jurisdiction over ships. The name comes from the "Admiral," originally an Arabic term (amir al-bahr, "commander of the sea") that entered European languages during the Crusades. In England, admiralty courts operated separately from common law courts until the 19th century.
"Lacrimosa" is Latin for "weeping" or "tearful." In music, it refers to a specific section of the Dies Irae sequence in the Catholic Requiem Mass. Mozart's version, from his Requiem in D minor (K. 626), is the most famous setting. It's the last section Mozart worked on before his death in December 1791; the rest of the Requiem was completed by his student Franz Xaver Sussmayr. There's a bitter symmetry to it: the movement about weeping was the last thing Mozart ever composed. His pen stopped in the middle of the Lacrimosa, eight bars in.
The Litany Against Fear is a fictional incantation from Frank Herbert's Dune, published in 1965. Characters in the novel use it as a mantra to calm themselves and push through terror. It's spoken by the Bene Gesserit, the secretive order that trains its members in mental and physical discipline.
The full text:
I must not fear. Fear is the mind-killer. Fear is the little-death that brings total obliteration. I will face my fear. I will permit it to pass over me and through me. And when it has gone past I will turn the inner eye to see its path. Where the fear has gone there will be nothing. Only I will remain.
Descartes' "I think, therefore I am" comes from his 1637 work Discourse on the Method. The idea is that the act of doubting or thinking is itself proof of one's existence. It's the starting point of his entire philosophical system: the one thing that can't be doubted is that there's a mind doing the doubting.
A commonly missed detail: Descartes wrote it in French, not Latin. The original line is "je pense, donc je suis." The famous Latin version, "Cogito, ergo sum," came from a later translation. The Discourse was written in French precisely because Descartes wanted it to be accessible beyond the Latin-reading academic world.
Indila is a French singer-songwriter whose music blends pop and R&B with North African and Middle Eastern influences. Her songs use instruments like the oud and accordion alongside electronic beats. Her 2014 debut album Mini World produced the hit "Derniere Danse," which charted in over 20 countries. She's notably private and rarely does interviews or public appearances.
I was looking up the name after seeing it attached to a film character, probably Mildred Pierce, and wanted to know what the name carried before Hollywood got to it.
The name Mildred comes from Old English elements: milde ("gentle, mild") and thryth ("strength, power"). So it literally means "gentle strength" or "gentle ruler." It was a popular medieval English name that went through several revivals, most recently in the early 20th century.
In Turkish, "Aga" historically referred to a feudal lord or person of authority, but it doesn't mean "king." The Turkish word for king is "kral" (borrowed from Slavic languages). "Aga" functioned more like "sir" or "lord" and was used as a title of respect, especially in the Ottoman period. The Aga Khan title uses the same root but in a different cultural context.
"Ein Sof" (Hebrew: אין סוף) is a Kabbalistic term meaning "The Infinite," "The Endless," or "The Boundless." It refers to the unknowable, transcendent aspect of God that exists beyond any human description or comprehension. In Kabbalistic cosmology, Ein Sof is the source from which all creation emanates, but it itself is wholly beyond form, attribute, or limitation.
Paul Morphy, the 19th-century American chess prodigy, didn't follow a rigid opening repertoire but frequently played the Italian Game. He preferred open, tactical positions that let him develop pieces quickly and attack. He also played the Evans Gambit and the King's Gambit. Morphy's approach was ahead of his time: rapid development, open lines, and king-side attacks. He dominated European masters during a brief tour in 1858-59, then essentially retired from chess at 22. Bobby Fischer called him "perhaps the most accurate player who ever lived."
The Italian Game in algebraic notation:
1. e4 e5
2. Nf3 Nc6
3. Bc4
The word "baptism" comes from Greek baptizo (baptizo), meaning "to dip," "to immerse," or "to submerge." Before its religious use, the word was used for ordinary acts of dipping or washing, like dyeing cloth. The religious sense of ritual purification by immersion in water was a later development.
The Hebrew word for heaven is shamayim (shamaiyim). It's a dual-form noun, which is unusual. It refers both to the physical sky and to the spiritual realm where God dwells. In Jewish tradition, there are seven levels of heaven, each with distinct characteristics. The word appears in the very first verse of the Torah: Bereshit bara Elohim et ha-shamayim ve'et ha-aretz ("In the beginning God created the heavens and the earth").
The name Mary comes from Hebrew Miriam (Miryam), derived from the root marah, meaning "bitterness" or "rebelliousness." In the Hebrew Bible, Miriam is Moses and Aaron's older sister. The same name was later carried by Mary the mother of Jesus. It's one of the most common names in Western history, and most people who bear it have no idea it means "bitter."
The Hebrew word "tehillim" (תְּהִלִּים) is the title of the biblical Book of Psalms. It means "praises" or "songs of praise." Not all of the 150 psalms are praise poems; many are laments, confessions, or cries for help. But the overall collection is categorized under the umbrella of praise, which is why the Hebrew title stuck.
The English word "cure" comes from the Latin "cura," which meant "care, concern, attention." In its earliest English usage, "cure" referred to the care and attention given to a person, not a specific remedy for illness. Over time the meaning narrowed to mean treatment or remedy. The older sense survives in phrases like "cure of souls," where a parish priest has the "cure" (care) of his congregation.
I was naming something, a chapter or a project, and "chronomancy" was a candidate. I ended up not liking it. But I kept the etymology.
"Chronomancy" combines "chrono-" (time) and "-mancy" (divination or magic). It means predicting the future through the interpretation of time and natural cycles. The "-mancy" suffix shows up all over the place: necromancy (the dead), pyromancy (fire), bibliomancy (books). Chronomancy is one of the rarer ones, but it follows the same Greek construction.
The word "lord" comes from Old English hlafweard, which literally meant "loaf-keeper" or "bread-guardian." The master of a household was defined by his role as the one who provided bread. The related Old High German form is hlaf-wart. Over time the pronunciation collapsed from hlafweard to lord, but the original meaning tells you exactly what medieval authority was built on: whoever controlled the food.
I was studying Camus broadly at the time, collecting his quotes and trying to describe him in one sentence. The Rebel came up as the most divisive thing he wrote.
Albert Camus's famous line "The only way to deal with an unfree world is to become so absolutely free that your very existence is an act of rebellion" comes from his 1951 essay The Rebel (L'Homme revolte). He was 37 when it was published. The book caused a bitter falling-out with Jean-Paul Sartre, who disagreed with Camus's rejection of revolutionary violence. Their friendship never recovered.
Bare Repository Attacks in Git
A bare repository is a Git repo with no working tree, just the
.gitinternals. Git will recognize one anywhere it finds the right directory structure. An attacker can exploit this by embedding a bare repo inside a normal repository, tucked into a subdirectory or smuggled in via submodules.When you clone the outer repo and
cdinto it, Git may auto-discover the embedded bare repo. If that bare repo has hooks configured (say, apost-checkoutorpre-commit), they run on your machine. Arbitrary code, no prompt.The fix landed in Git 2.38 with
safe.bareRepository:With
explicitset, Git refuses to operate in any bare repository unless its path has been added tosafe.directory. It won't auto-discover bare repos nested inside cloned projects.Without this, cloning a repo someone hands you could silently execute whatever they put in a hook. The attack surface is small but the impact is full code execution.