2025-01-27

Live reloading for any generated website

When generating a website (typically HTML and CSS files), it is often useful to have a live reload feature. This means that your browser will automatically reload the page when you make changes to the files via code. For example, say you write some code that generates a plot on a webpage, or that generates some WebAssembly module that is embedded in the page. In the past, I would use tools like webpack or try to manually establish a socket on the server and inject JavaScript in the page.

I recently found a much simpler solution. Just use Bash together with any server that can serve static files and injects live-reloading like live-server.

Show more

2025-01-25

Running code in blog posts is probably a bad idea

One of my favorite things to do is to automate as much as possible. So when I started writing blog posts, I thought it would be a good idea to run the code in my blog posts automatically. For example, I would add blogs with cool code and visualizations and then run this code upon each push to the repository via CI. I even made a package for it called PlutoStaticHTML.jl.

What PlutoStaticHTML.jl allows you to do is to write your blog posts in Pluto notebooks (Pluto.jl is like Jupyter notebooks but for the Julia language). Then, you can setup CI such that the code will be executed each time you push to the repository and the output will be embedded in the blog post.

Show more

2024-05-30

Battery Learning Curves

A few months ago, I spent some time on trying to predict the changes in batteries over time. My aim was to estimate when electric cars would finally be as cheap or cheaper than internal combustion engine cars. However, my approach in that blog post was extremely naive since I didn't know about learning curves. Simply put, learning curves are a real world phenomenon where a good or service becomes consistently cheaper over time. As shown in the learning curve link, solar modules have gotten 99.6% cheaper since 1976. From $100 to about $0.3, that's almost 4 orders of magnitude!

Show more

2024-05-29

Summary of Same as Ever by Morgan Housel

One of my favorite books this year has been Same as Ever: A Guide to What Never Changes by Morgan Housel. I've read some of his blog posts at Collab Fund before, so I already knew the book would be good. His writing style is simple on the surface, but at the same time surprisingly insightful. (Which is quite a feat, I wouldn't disagree if you say my academic writing has been the opposite.) Morgan also often comes up with new ideas that I've never heard before. For example, he has argued that the German army in the 1930s got so strong because they had their weapons taken away from them by the Treaty of Versailles. Thanks to the lack of old weapons, they built new and more advanced equipment from scratch.

Show more

2024-04-29

Some SaaS banned me, again

A few years ago, a good friend of mine happily moved to Microsoft Office 365. It was great, he said, because his files were synced across all his devices and he felt it was making him more productive. He even stored many gigabytes of personal pictures on OneDrive because the storage pricing was fair and it was easy to do. Then, he shared his picture collection with one person and got banned almost immediately. No OneDrive, no Word, no opportunity for backup, no nothing. Contacting customer support didn't help. If I remember correctly, Microsoft claimed he was possibly involved in terrorist activities. In truth, Microsoft probably had a problem with sharing pictures of children. But, he shared the pictures with his own wife. He shared pictures of his children with his wife. The Dutch tech site Tweakers wrote a long article about similar events with software as a service (SaaS) platforms in 2021, so this was not an one-off occurrence.

Show more

2024-04-25

The history of the ROC curve

The Receiver Operating Characteristic (ROC) curve is a well-known tool used to evaluate the performance of binary classifiers. Its history is clear. According to Wikipedia, it

"was first developed by electrical engineers and radar engineers during World War II for detecting enemy objects in battlefields, starting in 1941, which led to its name ('receiver operating characteristic')"

Another source also states that the ROC curve was first used during the second world war to distinguish between enemy targets, or just noise by radar receiver operators (utah.edu, 2007).

Show more

2024-04-17

Updating my notes via email

Charles Darwin made it a habit to immediately write down anything that conflicted with his own ideas, so his brain would not forget or ignore it. In his own words:

"I had also, during many years, followed a golden rule, namely that whenever published fact, a new observation of thought came across me, which was opposed to my general results, to make a memorandum of it without fail and at once; for I had found by experience that such facts and thoughts were far more apt to escape from the memory than favourable ones."

Based on this, I've also made it a habit to quickly write down new ideas or thoughts. Unlike Darwin, however, I don't carry a notebook with me. Instead, I prefer to store my notes in a Git repository. Unlike a notebook, a Git repository is more fireproof, can more easily be searched and edited, and can scale to much larger sizes. Jeff Huang, for example, wrote that he has a single text file with all his notes from 2008 to 2022. At the time of his writing, the file contained 51,690 handwritten lines of text. He wrote that the file been his "secret weapon".

Show more

2024-03-08

Installing Forgejo with a separate runner

On the 15th of February 2024, Forgejo announced that they will be decoupling (hard forking) their project further from Gitea. I think this is great since Forgejo is the only European Git forge that I know of, and a hard fork means that the project can now grow more independently. With Forgejo, it is now possible to easily self-host host a forge. This is great because it allows decoupling it from American Big Tech.

This post will go through a full step by step guide on how to set things up. This guide is based on my Gitea configuration that I ran for a year, so it works. During the year, I paid about 10 euros per month for two Hetzner servers. The two servers allow separating Forgejo from the runners. This ensures that a heavy job on the runner will not slow down the Forgejo server.

Show more

2024-02-19

How much have batteries changed over time?

From time to time, batteries make the headlines because they store too little energy, because they are too expensive, or because the costs have dropped dramatically in the last year. These things could indeed be true at the same time. Or, as Hans Rosling would say, "things can be bad, and getting better." I was curious by how much. To figure out where things are heading, let's not focus on headlines and instead look at data for multiple years.

Phone Batteries

As a first investigation, I wonder whether much is happening in the area of small batteries. Thanks to the rise of smartphones, these batteries may have improved dramatically over time. We could checkout the raw battery prices, but consumers would not buy at these prices. So instead let's look at consumer smartphone prices. Smartphones are a mass produced product, so they should be able to incorporate state-of-the-art battery technology. Let's therefore look at iPhone battery capacity over time.

Show more

2024-02-03

Encrypting and decrypting a secret with wasm_bindgen

Doing a round trip of encrypting and decrypting a secret should be pretty easy, right? Well, it turned out to be a bit more involved than I thought. But, in the end it worked here is the code for anyone who wants to do the same.

I'll be going through the functions step by step first. The full example with imports is shown at the end.

First, we need to generate a key. Here, I've set extractable to false. This aims to prevent the key from being read by other scripts.

fn crypto() -> web_sys::Crypto {
    let window = web_sys::window().expect("no global `window` exists");
    window.crypto().expect("no global `crypto` exists")
}

pub fn generate_key() -> Promise {
    let sc = crypto().subtle();
    // Symmetric encryption is used, so the same key is used for both operations.
    // GCM has good performance and security according to Wikipedia.
    let algo = AesKeyGenParams::new("AES-GCM", 256);
    let extractable = false;
    let usages = js_array(&["encrypt", "decrypt"]);
    sc.generate_key_with_object(
        &algo,
        extractable,
        &usages
    ).expect("failed to generate key")
}

Show more

◀ prev

▶ next