From eef357ebc10246da0da3c8bce427991eeb3f1dce Mon Sep 17 00:00:00 2001 From: Collin Williams <96917990+bluedragon1221@users.noreply.github.com> Date: Sun, 16 Aug 2026 15:21:39 -0500 Subject: add a logo, changes to css, format older articles --- Logo.svg | 18 ++ article.js | 70 ++++- fib.html | 587 ++++++++++++++++++++------------------- fonts.css | 37 +++ fonts/FiraCode-VF.woff2 | Bin 0 -> 113088 bytes fonts/FiraMath-Regular.woff2 | Bin 0 -> 99332 bytes fonts/gelasio-latin-italic.woff2 | Bin 0 -> 40068 bytes fonts/gelasio-latin.woff2 | Bin 0 -> 34832 bytes forgejno.html | 1 - minimalnetworkinglaptop.html | 234 ++++++++-------- no_ai.html | 1 - prose.css | 169 +++++++---- reversible.html | 36 +-- soplt.html | 1 - style.css | 2 +- 15 files changed, 659 insertions(+), 497 deletions(-) create mode 100644 Logo.svg create mode 100644 fonts.css create mode 100644 fonts/FiraCode-VF.woff2 create mode 100644 fonts/FiraMath-Regular.woff2 create mode 100644 fonts/gelasio-latin-italic.woff2 create mode 100644 fonts/gelasio-latin.woff2 diff --git a/Logo.svg b/Logo.svg new file mode 100644 index 0000000..77eb306 --- /dev/null +++ b/Logo.svg @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/article.js b/article.js index 723d97f..292d61c 100644 --- a/article.js +++ b/article.js @@ -1,24 +1,63 @@ +function addMetadata() { + // Favicon + const favicon = document.createElement("link"); + favicon.rel = "icon"; + favicon.href = "/Logo.svg"; + favicon.type = "image/svg+xml"; + document.head.appendChild(favicon); + + // UTF-8 (for special characters) + const charset = document.createElement("meta"); + charset.setAttribute("charset", "UTF-8"); + document.head.appendChild(charset); + + // viewport (for mobile) + const viewport = document.createElement("meta"); + viewport.setAttribute("name", "viewport"); + viewport.setAttribute("content", "width=device-width, initial-scale=1.0"); + document.head.appendChild(viewport); + + // css + const proseCss = document.createElement("link"); + proseCss.rel = "stylesheet"; + proseCss.href = "prose.css"; + document.head.appendChild(proseCss); +} + function addHeader() { const header = document.querySelector("header"); - - const h1 = document.createElement('h1'); + + // Logo + const logoLink = document.createElement("a"); + logoLink.href = "/writing.html"; + logoLink.classList.add("header-logo-link"); + header.appendChild(logoLink); + + // Right-side content + const info = document.createElement("div"); + info.classList.add("header-info"); + + const h1 = document.createElement("h1"); h1.textContent = document.title; - header.appendChild(h1); - - const time = document.createElement('time'); + info.appendChild(h1); + + const time = document.createElement("time"); const metaDate = document.querySelector('meta[property="article:published_time"]'); - const dateString = metaDate.getAttribute('content'); - const displayDate = (new Date(dateString)).toLocaleDateString('en-US', { - month: 'short', - day: 'numeric', - year: 'numeric', - timeZone: 'UTC' + const dateString = metaDate.getAttribute("content"); + const displayDate = (new Date(dateString)).toLocaleDateString("en-US", { + month: "short", + day: "numeric", + year: "numeric", + timeZone: "UTC" }); - time.setAttribute('datetime', dateString); - time.textContent = displayDate; - header.appendChild(time); - const hr = document.createElement('hr'); + time.setAttribute("datetime", dateString); + time.textContent = `Published ${displayDate}`; + info.appendChild(time); + + header.appendChild(info); + + const hr = document.createElement("hr"); header.appendChild(hr); } @@ -47,6 +86,7 @@ function addTOC() { } document.addEventListener("DOMContentLoaded", () => { + addMetadata() addHeader() addTOC() }) \ No newline at end of file diff --git a/fib.html b/fib.html index 998308e..29d5e71 100644 --- a/fib.html +++ b/fib.html @@ -1,55 +1,55 @@ - - I accidentally derived a formula for the Fibonacci Sequence - - - - - -
-
+ + I accidentally derived a formula for the Fibonacci Sequence + + + + +
+
-

Last night my brother pitched me this math problem over dinner (which he later revealed came from this video). It goes something like this:

-
-

There is a flight of n stairs in front of you.

-

You can only ascend in steps of 1 or 2 stairs.

-

How many different ways are there for you to go up the stairs?

-
-

For the rest of the article, I will go over my thought process (and stupidity) when solving the problem. Enjoy!

-
-

First, I drew out some stairs and some tables to get base-cases and a feel for the problem.

- - - - - - - - - - - - - - -
# of stairs# of ways to ascend
11
22
33
45
58
+

Last night my brother pitched me this math problem over dinner (which he later revealed came from this video). It goes something like this:

+
+

There is a flight of n + stairs in front of you.

+

You can only ascend in steps of 1 or 2 stairs.

+

How many different ways are there for you to go up the stairs?

+
+

For the rest of the article, I will go over my thought process (and stupidity) when solving the problem. Enjoy!

+
+

First, I drew out some stairs and some tables to get base-cases and a feel for the problem.

+ + + + + + + + + + + + + + +
# of stairs# of ways to ascend
11
22
33
45
58
-

Now, if you already see a familiar pattern in these numbers, shh! I somehow failed to see it, although it's obvious in hindsight, but I guess that's a good thing since it led me to the results of this article.

-

Next, I decided to take a look at the lengths of jumps. I made a list of numbers, where each number represented a jump of that height. So, for example, one ascent of the 10-stair staircase example might look like:

-
[1 2 2 1 2 1 1]
-

Since this list encodes a sequence of jumps that would climb 10 stairs, it's trivial to say the list must sum to 10.

-

This allowed me to rewrite the problem as the following:

-
-

For any n, how many unique sequences of 2s and 1s add to n?

-
-

While this was definitely more abstract, it reframed the problem using numbers, which I could play with using math.

-
+

Now, if you already see a familiar pattern in these numbers, shh! I somehow failed to see it, although it's obvious in hindsight, but I guess that's a good thing since it led me to the results of this article.

+

Next, I decided to take a look at the lengths of jumps. I made a list of numbers, where each number represented a jump of that height. So, for example, one ascent of the 10-stair staircase example might look like:

+
[1 2 2 1 2 1 1]
+

Since this list encodes a sequence of jumps that would climb 10 stairs, it's trivial to say the list must sum to 10.

+

This allowed me to rewrite the problem as the following:

+
+

For any n, how many unique sequences of 2s and 1s add to n?

+
+

While this was definitely more abstract, it reframed the problem using numbers, which I could play with using math.

+
-

Next, since I had no idea how I would go about counting the sequences, I looked at how I could group them, in hoping that would make them easier to count.

-

Arbitrarily, I decided to group the sequences by how many 2s were in them.

-

For the 5-stair staircase example, all of the possible sequences of 1s and 2s that sum to 5 look like:

-
[1 1 2 1]
+			

Next, since I had no idea how I would go about counting the sequences, I looked at how I could group them, in hoping that would make them easier to count.

+

Arbitrarily, I decided to group the sequences by how many 2s were in them.

+

For the 5-stair staircase example, all of the possible sequences of 1s and 2s that sum to 5 look like:

+
[1 1 2 1]
 [2 1 2]
 [1 2 1 1]
 [1 1 1 1 1]
@@ -57,247 +57,262 @@
 [1 2 2]
 [1 1 1 2]
 [2 2 1]
-

Grouping each sequence by the number of 2s in it yields the table:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# of 2s (t)0123
[1 1 1 1 1][2 1 1 1]
[1 2 1 1]
[1 1 2 1]
[1 1 1 2]
[1 2 2]
[2 1 2]
[2 2 1]
length of sequences (kt)543
# of sequences (mt)1430
-

This adds to a grand total of 8 sequences for a 5-stair staircase.

+

Grouping each sequence by the number of 2s in it yields the table:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
# of 2s (t)0123
sequences[1 1 1 1 1][2 1 1 1]
[1 2 1 1]
[1 1 2 1]
[1 1 1 2]
[1 2 2]
[2 1 2]
[2 2 1]
length of sequences (kt)543
# of sequences (mt)1430
+

This adds to a grand total of 8 sequences for a 5-stair staircase.

-

From the table, I made a few insights:

-
    -
  • - Any two sequences with the same number of 2s have the same length. - This made sense because sequences with the same number of 2s always have the same number of 1s, so their total length must be the same. -

  • -
  • - k seemed to follow the pattern k=n-t. - This made sense because with each introduction of one more 2, then length of the list must decrease by 1 to still sum to 5. -

  • -
  • - The pattern k=n-t only worked for 2t≤n. - This made sense because if the sequence must sum to 5, then it can not contain 3 2s. This allowed me to define a general maximum for t. - - - - t - max - - = - ⌊ - - n - 2 - - ⌋ - - -

  • -
-
+

From the table, I made a few insights:

+
    +
  • + Any two sequences with the same number of 2s have the same length. + This made sense because sequences with the same number of 2s always have the same number of 1s, so their total length must be the same. +

  • +
  • + k + seemed to follow the pattern k=n-t. + This made sense because with each introduction of one more 2, then length of the list must decrease by 1 to still sum to 5. +

  • +
  • + The pattern k=n-t + only worked for 2t≤n. + This made sense because if the sequence must sum to 5, then it can not contain 3 2s. This allowed me to define a general maximum for t. + + + + t + max + + = + ⌊ + + n + 2 + + ⌋ + + +

  • +
+
-

Okay, so now that I had a way to split the sequences into pieces, I just needed a way to count the number of sequences for each value of t, and sum those together.

-

The sum is the easy part. I knew the final number would be the the sum of all of the mts, or:

- - - - ∑ - - t - = - 0 - - - t - max - - - mt - - -

Plugging in our definition for tmax,

- - - - ∑ - - t - = - 0 - - - ⌊ - - n - 2 - - ⌋ - - - mt - - +

Okay, so now that I had a way to split the sequences into pieces, I just needed a way to count the number of sequences for each value of t, and sum those together.

+

The sum was the easy part. I knew the final number would be the the sum of all of the mts, or:

+ + + + ∑ + + t + = + 0 + + + t + max + + + mt + + +

Plugging in our definition for tmax,

+ + + + ∑ + + t + = + 0 + + + ⌊ + + n + 2 + + ⌋ + + + mt + + -

After thinking about the sequences for a while, I realized that the number of sequences boils down to the question "how many ways can you uniquely arrange a list of t special items out of k total items?"

-

Then I realized: this was a combinatorics problem! Specifically, I remembered the Binomial Coefficient, or "n choose k", which counts "the number of ways to choose a subset of k elements from a larger set of n elements."

-

Each sequence of length k contained exactly t 2s. So counting the number of sequences mt for some t was equivelant to counting the number of ways to choose t elements from a larger set of k elements. By this definition,

- - - mt - = - ( - - - k - - t - - ) - - -

Plugging in the prior definition for k, and using the summation from above, I arrived at a final equation:

- - f(n) - = - - - ∑ - - t - = - 0 - - - ⌊ - - n - 2 - - ⌋ - - +

After thinking about the sequences for a while, I realized that the number of sequences boils down to the question "how many ways can you uniquely arrange a list of t + special items out of k + total items?"

+

Then I realized: this was a combinatorics problem! Specifically, I remembered the Binomial Coefficient, or "n + choose k", which counts "the number of ways to choose a subset of k elements from a larger set of n elements."

+

Each sequence of length k + contained exactly t + 2s. So counting the number of sequences mt + for some t + was equivelant to counting the number of ways to choose t + elements from a larger set of k + elements. By this definition,

+ + + mt + = + ( + + + k + + t + + ) + + +

Plugging in the prior definition for k, and using the summation from above, I arrived at a final equation:

+ + f(n) + = + + + ∑ + + t + = + 0 + + + ⌊ + + n + 2 + + ⌋ + + - - ( - - - n - - - t - - t - - ) - - - -

Yay!

-
+ + ( + + + n + - + t + + t + + ) + + + +

Yay!

+
-

Okay, if you didn't see the pattern from the beginning, [1 2 3 5 8] is the Fibonacci Sequence, starting at the 2nd element. You might be more familiar with it starting from the 1st element [1 1 2 3 5 8 ...].

-

So we really just derived a formula for the n+1th Fibonacci number!

-

When I first learned this, I thought I was some kind of genius or something, but a quick check on ProofWiki told that a very similar function was already discovered in 1971, so I guess I'm 55 years late to the party.

-

The formula on ProofWiki is for the nth fibonacci number, so here's how you could arrive at the real Fibonacci Number as Sum of Binomial Coefficients function:

-

Begin with the derived formula, replacing n for a to avoid variable conflicts later.

- - f(a) - = - - - ∑ - t=0 - - ⌊ - a2 - ⌋ - - - - ( - - a-t - t - - ) - - - -

Since this is really for the n+1th Fibonacci number, substitute a=n-1.

- - f(n) - = - - - ∑ - t=0 - - ⌊ - n-12 - ⌋ - - - - ( - - n-t-1 - t - - ) - - - -

The original function uses k instead of t.

- - f(n) - = - - - ∑ - k=0 - - ⌊ - n-12 - ⌋ - - - - ( - - n-k-1 - k - - ) - - - -

This is the exact same function that appears on ProofWiki!

-
- - \ No newline at end of file +

Okay, if you didn't see the pattern from the beginning, [1 2 3 5 8] + is the Fibonacci Sequence, starting at the 2nd element. You might be more familiar with it starting from the 1st element [1 1 2 3 5 8 ...].

+

So we really just derived a formula for the n+1th Fibonacci number!

+

When I first learned this, I thought I was some kind of genius or something, but a quick check on ProofWiki told that a very similar function was already discovered in 1971, so I guess I'm 55 years late to the party.

+

The formula on ProofWiki is for the nth fibonacci number, so here's how you could arrive at the real Fibonacci Number as Sum of Binomial Coefficients function:

+

Begin with the derived formula, replacing n + for a + to avoid variable conflicts later.

+ + f(a) + = + + + ∑ + t=0 + + ⌊ + a2 + ⌋ + + + + ( + + a-t + t + + ) + + + +

Since this is really for the n+1th Fibonacci number, substitute a=n-1.

+ + f(n) + = + + + ∑ + t=0 + + ⌊ + n-12 + ⌋ + + + + ( + + n-t-1 + t + + ) + + + +

The original function uses k + instead of t.

+ + f(n) + = + + + ∑ + k=0 + + ⌊ + n-12 + ⌋ + + + + ( + + n-k-1 + k + + ) + + + +

This is the exact same function that appears on ProofWiki!

+
+ + diff --git a/fonts.css b/fonts.css new file mode 100644 index 0000000..7ce76d4 --- /dev/null +++ b/fonts.css @@ -0,0 +1,37 @@ +@font-face { + font-family: "Gelasio"; + font-style: normal; + font-weight: 400 700; + font-display: swap; + src: url("/fonts/gelasio-latin.woff2") format("woff2"); +} + +@font-face { + font-family: "Gelasio"; + font-style: italic; + font-weight: 400 700; + font-display: swap; + src: url("/fonts/gelasio-latin-italic.woff2") format("woff2"); +} + +@font-face { + font-family: "Fira Math"; + src: url("/fonts/FiraMath-Regular.woff2") format("woff2"); + font-weight: 400; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: "Fira Code"; + src: url("/fonts/FiraCode-VF.woff2") format("woff2"); + font-style: normal; + font-weight: 300 700; + font-display: swap; +} + +:root { + --fontSerif: 'Gelasio', serif; + --fontMono: 'Fira Code', monospace; + --fontMath: 'Fira Math', serif; +} \ No newline at end of file diff --git a/fonts/FiraCode-VF.woff2 b/fonts/FiraCode-VF.woff2 new file mode 100644 index 0000000..e755a9d Binary files /dev/null and b/fonts/FiraCode-VF.woff2 differ diff --git a/fonts/FiraMath-Regular.woff2 b/fonts/FiraMath-Regular.woff2 new file mode 100644 index 0000000..fd08e65 Binary files /dev/null and b/fonts/FiraMath-Regular.woff2 differ diff --git a/fonts/gelasio-latin-italic.woff2 b/fonts/gelasio-latin-italic.woff2 new file mode 100644 index 0000000..7f95e1d Binary files /dev/null and b/fonts/gelasio-latin-italic.woff2 differ diff --git a/fonts/gelasio-latin.woff2 b/fonts/gelasio-latin.woff2 new file mode 100644 index 0000000..fe18998 Binary files /dev/null and b/fonts/gelasio-latin.woff2 differ diff --git a/forgejno.html b/forgejno.html index e36b358..100c606 100644 --- a/forgejno.html +++ b/forgejno.html @@ -3,7 +3,6 @@ You don't need Forgejo - diff --git a/minimalnetworkinglaptop.html b/minimalnetworkinglaptop.html index f9ca405..bc07c9b 100644 --- a/minimalnetworkinglaptop.html +++ b/minimalnetworkinglaptop.html @@ -1,52 +1,49 @@ - - - - Minimal Laptop Networking with NixOS - - - - - -
-
- -

- The default networking stack on NixOS uses NetworkManager. - While it's a great choice for many users, I prefer a lighter setup built around systemd-networkd, systemd-resolved, and iwd. It integrates well with the rest of the systemd stack, has fewer moving pieces, and exposes powerful networking features without an additional network management daemon. -

- -

- This article focuses on laptops that connect to wifi. - If you're configuring a server, you probably don't need iwd at all; systemd-networkd and systemd-resolved are usually sufficient. -

- -
- -

The default stack

-

If not configured otherwise, NixOS uses the following stack:

- -

We'll be replacing it with:

- -

- This has a few benefits. - Firstly, switching to resolved allows you to enable features like encrypted DNS over TLS (DoT) and DNSSEC validation, which reduces the potential for DNS spoofing and man-in-the-middle attacks[2]. - Additionally, the default stack uses 3 extra packages (NM, dhcpcd, resolvconf) and some bash scripts, while this setup only uses one extra package (iwd). - Also, I'm kind of a systemd nerd, and this is a way to dig into systemd a bit more. -

- -

So the first thing we can do is disable all of the default stuff:

-
{
+	
+		Minimal Laptop Networking with NixOS
+		
+		
+	
+	
+		
+
+ +

+ The default networking stack on NixOS uses NetworkManager. + While it's a great choice for many users, I prefer a lighter setup built around systemd-networkd, systemd-resolved, and iwd. It integrates well with the rest of the systemd stack, has fewer moving pieces, and exposes powerful networking features without an additional network management daemon. +

+ +

+ This article focuses on laptops that connect to wifi. + If you're configuring a server, you probably don't need iwd at all; systemd-networkd and systemd-resolved are usually sufficient. +

+ +
+ +

The default stack

+

If not configured otherwise, NixOS uses the following stack:

+
    +
  • NetworkManager for wifi
  • +
  • dhcpcd for DHCP
  • +
  • resolvconf for DNS
  • +
  • a "legacy script based system" for network configuration[1]
  • +
+

We'll be replacing it with:

+
    +
  • iwd for wifi
  • +
  • systemd-networkd for DHCP and network configuration
  • +
  • systemd-resolved for DNS
  • +
+

+ This has a few benefits. + Firstly, switching to resolved allows you to enable features like encrypted DNS over TLS (DoT) and DNSSEC validation, which reduces the potential for DNS spoofing and man-in-the-middle attacks[2]. + Additionally, the default stack uses 3 extra packages (NM, dhcpcd, resolvconf) and some bash scripts, while this setup only uses one extra package (iwd). + Also, I'm kind of a systemd nerd, and this is a way to dig into systemd a bit more. +

+ +

So the first thing we can do is disable all of the default stuff:

+
{
   networking = {
     networkmanager.enable = false;
     dhcpcd.enable = false;
@@ -55,14 +52,14 @@
   };
 }
-

And let's get to configuring!

+

And let's get to configuring!

-

iwd

-

- First up is iwd. - The important parts of the configuration are delegating network configuration to networkd, delegating name resolution (DNS) to resolved, and configuring MAC randomization for some extra privacy. -

-
{
+			

iwd

+

+ First up is iwd. + The important parts of the configuration are delegating network configuration to networkd, delegating name resolution (DNS) to resolved, and configuring MAC randomization for some extra privacy. +

+
{
   networking.wireless.iwd = {
     enable = true;
     settings = {
@@ -76,28 +73,28 @@
   };
 }
-

- At this point, we don't have any network configuration yet, so internet access won't work. However, you can verify that iwd is functioning correctly: -

-
    -
  • iwctl station wlan0 scan: Scans for new wifi networks
  • -
  • iwctl station wlan0 get-networks: lists the networks that it found
  • -
  • iwctl station wlan0 connect "<SSID>": connects to the network, prompting for a PSK if necessary
  • -
- -

systemd-networkd

-

- Next up is systemd-networkd. - Networkd has lots of advanced options for things like static IP config, Wireguard tunnels, VLANs, domain-based DNS routing, and more. - However, here we'll just do a basic configuration to enable DHCP and deny DHCP-advertised DNS. -

-
- why disable DHCP-advertised DNS? - By default, most networks advertise their own DNS resolver via DHCP. - Since we'll configure our own encrypted upstream DNS servers in the next section, we tell networkd to ignore the ones provided by the network. -
- -
{
+			

+ At this point, we don't have any network configuration yet, so internet access won't work. However, you can verify that iwd is functioning correctly: +

+
    +
  • iwctl station wlan0 scan: Scans for new wifi networks
  • +
  • iwctl station wlan0 get-networks: lists the networks that it found
  • +
  • iwctl station wlan0 connect "<SSID>": connects to the network, prompting for a PSK if necessary
  • +
+ +

systemd-networkd

+

+ Next up is systemd-networkd. + Networkd has lots of advanced options for things like static IP config, Wireguard tunnels, VLANs, domain-based DNS routing, and more. + However, here we'll just do a basic configuration to enable DHCP and deny DHCP-advertised DNS. +

+
+ why disable DHCP-advertised DNS? + By default, most networks advertise their own DNS resolver via DHCP. + Since we'll configure our own encrypted upstream DNS servers in the next section, we tell networkd to ignore the ones provided by the network. +
+ +
{
   systemd.network = {
     enable = true;
 
@@ -113,27 +110,28 @@
   networking.useNetworkd = true;
 }
-

- The name = "wl*" refers to the network interface name that this configuration applies to. - According to the systemd docs, wireless LAN devices should start with the two-character prefix "wl"[3]. - Here we use a glob (*) to match all wireless interfaces. -

- -

You can verify that your configuration worked with a few commands:

-
    -
  • ip addr: make sure that there's an IP address associated with your wireless interface. That means DHCP is working.
  • -
  • networkctl status: make sure there's no significant errors in the logs.
  • -
- -

systemd-resolved

-

- Now all we have left is DNS configuration, then we're done. - This is probably the part where you can nerd out the hardest, but I try to keep it pretty minimal. - The important parts are selecting upstream DNS servers that support secure DNS protocols (like DNS over TLS and DNSSEC) and that respect your privacy. - For these reasons, I use quad9, but do your own research and find the best upstream DNS server for you! - Some other options include Cloudflare DNS, Google's DNS, or AdGuard Public DNS. -

-
{
+			

+ The name = "wl*" + refers to the network interface name that this configuration applies to. + According to the systemd docs, wireless LAN devices should start with the two-character prefix "wl"[3]. + Here we use a glob (*) to match all wireless interfaces. +

+ +

You can verify that your configuration worked with a few commands:

+
    +
  • ip addr: make sure that there's an IP address associated with your wireless interface. That means DHCP is working.
  • +
  • networkctl status: make sure there's no significant errors in the logs.
  • +
+ +

systemd-resolved

+

+ Now all we have left is DNS configuration, then we're done. + This is probably the part where you can nerd out the hardest, but I try to keep it pretty minimal. + The important parts are selecting upstream DNS servers that support secure DNS protocols (like DNS over TLS and DNSSEC) and that respect your privacy. + For these reasons, I use quad9, but do your own research and find the best upstream DNS server for you! + Some other options include Cloudflare DNS, Google's DNS, or AdGuard Public DNS. +

+
{
   networking.nameservers = [
     "9.9.9.9#dns.quad9.net"
     "149.112.112.112#dns.quad9.net"
@@ -151,23 +149,25 @@
   };
 }
-

You can verify your DNS configuration by using the resolvectl status command or by just opening a website.

- -

P.S. Captive Portals

-

- Captive portals are those wifi login pages that pop up when you connect to some public wifi networks. - Some captive portals don't behave correctly when you're using an encrypted third-party DNS server instead of the network's advertised resolver. - To get around this, I use Captive Browser (nixpkgs), which launches an instance of Chromium through a SOCKS5 proxy, avoiding the system DNS configuration altogether. - This allows you to access a captive portal for long enough to log in and gain internet access. - Pretty neat! -

- -

P.P.S. I miss nm-applet

-

- Probably the biggest downside to this setup is the lack of desktop integration. - GNOME and Plasma only support NetworkManager in their network configuration menu, so you're kinda out of luck. - For tiling window manager people, I can recommend iwmenu, which is a launcher (dmenu, rofi, fuzzel)-based menu for connecting to wifi networks via iwd. -

-
- - \ No newline at end of file +

You can verify your DNS configuration by using the resolvectl status + command or by just opening a website.

+ +

P.S. Captive portals

+

+ Captive portals are those wifi login pages that pop up when you connect to some public wifi networks. + Some captive portals don't behave correctly when you're using an encrypted third-party DNS server instead of the network's advertised resolver. + To get around this, I use Captive Browser + (nixpkgs), which launches an instance of Chromium through a SOCKS5 proxy, avoiding the system DNS configuration altogether. + This allows you to access a captive portal for long enough to log in and gain internet access. + Pretty neat! +

+ +

P.P.S. I miss nm-applet

+

+ Probably the biggest downside to this setup is the lack of desktop integration. + GNOME and Plasma only support NetworkManager in their network configuration menu, so you're kinda out of luck. + For tiling window manager people, I can recommend iwmenu, which is a launcher (dmenu, rofi, fuzzel)-based menu for connecting to wifi networks via iwd. +

+
+ + diff --git a/no_ai.html b/no_ai.html index 3a142a0..d0127b4 100644 --- a/no_ai.html +++ b/no_ai.html @@ -2,7 +2,6 @@ Taking a break - diff --git a/prose.css b/prose.css index db54f26..3a053c5 100644 --- a/prose.css +++ b/prose.css @@ -1,6 +1,11 @@ -@import url('https://fonts.googleapis.com/css2?family=Gelasio:ital,wght@0,400..700;1,400..700&display=swap'); @import url('style.css'); +:root { + --sx: 1rem; + --lx: 3rem; + --lh: 1.5; +} + article { width: 100%; max-width: 75ch; @@ -11,13 +16,22 @@ article { p { color: #e6e6e6; - font-family: 'Gelasio'; - line-height: 1.3; + font-family: var(--fontSerif); + line-height: var(--lh); font-size: 1.1rem; + margin: var(--sx) 0; +} + +sup { + font-size: 0.8em; + line-height: 0; + vertical-align: baseline; + position: relative; + top: -0.5em; } a { - color: #4DA3FF; + color: #49f; text-decoration: none; &:hover { @@ -27,8 +41,8 @@ a { li { color: #e6e6e6; - font-family: 'Gelasio'; - line-height: 1.3; + font-family: var(--fontSerif); + line-height: var(--lh); font-size: 1.1rem; &::marker { @@ -36,29 +50,12 @@ li { } } -h1 { - color: #e6e6e6; - line-height: 1.15; - margin-bottom: 0; - font-family: 'Gelasio'; - font-weight: 600; -} - -h2 { - color: #e6e6e6; - line-height: 1; - margin-top: 3rem; - margin-bottom: 0; - font-family: 'Gelasio'; - font-weight: 600; -} - -h3 { +h1, h2, h3 { color: #e6e6e6; - line-height: 1; - margin-top: 2rem; - margin-bottom: 0; - font-family: 'Gelasio'; + margin-top: var(--lx); + margin-bottom: var(--sx); + font-family: var(--fontSerif); + line-height: var(--lh); font-weight: 600; } @@ -71,15 +68,14 @@ hr { height: 2px; border: 0; border-top: 2px solid #888; - margin: 1em 0; + margin: var(--sx) 0; padding: 0; } time { display: block; - font-family: 'Gelasio'; + font-family: var(--fontSerif); color: #888; - margin-top: 0.5rem; } @media (max-width: 1000px) { @@ -94,7 +90,7 @@ time { } details { - font-family: 'Gelasio'; + font-family: var(--fontSerif); color: #888; summary::marker { @@ -103,13 +99,18 @@ details { } table { + --tsx_x: calc(var(--sx) / 3); + --tsx_y: calc(var(--sx) / 1.5); + + font-family: var(--fontSerif); + margin: var(--sx) 0; + border-collapse: collapse; - margin: 0 auto; th { color: #e6e6e6; text-align: center; border: solid; - padding: 0 1.5ch; + padding: var(--tsx_x) var(--tsx_y); border-width: 0 0 1px 0; &[scope="row"] { @@ -117,40 +118,94 @@ table { } } td { - color: #00ff78; + color: #6e7; text-align: center; - padding: 0 1.5ch; + padding: var(--tsx_x) var(--tsx_y); } } -code .path { - color: #888; +math { + font-family: var(--fontMath); + font-size: 1.2rem; + transform: translateZ(0); + + msub > :nth-child(2) { + transform: translateY(-0.2em); + font-size: 0.8rem; + } } -/* inline code */ +/* CODEBLOCKS */ code { - color: #00ff78; - font-family: 'Roboto Mono'; + font-size: 0.95rem; + color: #e6e6e6; + white-space: pre; + font-family: 'Fira Code', monospace; + + kw { color: #49f; } + ty { color: #4d9; } + fn { color: #7bf; } + mac { color: #d69; } + str { color: #6e7; } + num { color: #9c9; } + com { color: #888; } + prop { color: #8cf; } + mod { color: #bcd; } + id { color: inherit; } } -/* CODEBLOCKS */ pre { - color: #00ff78; - font-family: 'Roboto Mono'; + max-width: 100%; + overflow-x: auto; + overflow-y: hidden; + box-sizing: border-box; - code { - color: #e6e6e6; + margin: var(--sx) 0; + line-height: var(--lh); +} + +/* HEADER */ +header { + display: grid; + grid-template-columns: auto minmax(0, 1fr); + grid-template-rows: auto auto; + gap: var(--sx); + + .header-logo-link { + display: block; + height: 100%; + aspect-ratio: 1; + + background-color: #e6e6e6; + + mask-image: url("/Logo.svg"); + mask-size: contain; + mask-repeat: no-repeat; + mask-position: center; } - kw { color: #6cb8ff; } /* keywords */ - ty { color: #4ec9b0; } /* types */ - fn { color: #dcdcaa; } /* functions */ - mac { color: #c586c0; } /* macros */ - str { color: #ce9178; } /* strings */ - num { color: #b5cea8; } /* numbers */ - com { color: #7f848e; font-style: italic; } - prop { color: #9cdcfe; } /* fields */ - mod { color: #e6e6e6; } /* modules */ - id { color: inherit; } /* local variables */ -} + .header-logo-link:hover { + background-color: #49f; + } + + .header-info { + min-width: 0; + align-self: center; + h1 { + line-height: 1; + margin: 0; + } + } + + time { + line-height: var(--lh); + margin: 0; + } + + hr { + margin: 0; + grid-column: 1 / -1; + width: 100%; + } +} \ No newline at end of file diff --git a/reversible.html b/reversible.html index 378045f..24b5b87 100644 --- a/reversible.html +++ b/reversible.html @@ -2,11 +2,8 @@ - - Reversible Programming Blew my Mind (Reversible Part 1) - @@ -24,18 +21,21 @@

Math basis

-

So remember in math class when you learned to take the inverse of a function?

-

For example, say you have y = 3*x + 6.

-

You can take the inverse by solving for x. In this case, the inverse of our function is x = y/3 - 2.

-

The idea behind reversible programming is that there's a specific way to write your code such that it can automatically compute the inverse.

+

+ So remember in math class when you learned to take the inverse of a function? + For example, say you have y = 3*x + 6. + You can take the inverse by solving for x. + In this case, the inverse of our function is x = y/3 - 2. + The idea behind reversible programming is that there's a specific way to write your code such that it can automatically compute the inverse. +

This has some wild implications:

  • Writing a parser automatically gives you a pretty-printer implementation
  • -
  • Database migrations are only half as scary (writing your up script automatically gives you your down script)
  • +
  • Database migrations are only half as scary (writing your up script automatically gives you your down script)
  • Writing operations on an image (ex. Photoshop clone) gives you free undo and redo.

- These are just a few of the crazy things you could theoretically do with Reversible Programming. + These are just a few of the crazy things you could theoretically do with reversible programming. But how does it actually work?

@@ -58,7 +58,7 @@

As a nice starter, let's write a block that would compute addition. - We can model this with a struct and an impl of the Rev trait. + We can model this with a struct and an impl of the Rev trait.

struct Addition<A> {
     amount: A
@@ -84,7 +84,7 @@
 
         

While the generics might look scary, this is just saying "the input and output can be any type that you can add and subtract with." - Honestly these are light work compared to what's coming up. + Honestly these are light work compared to what's coming up.

Oh, and it will look nicer if we have an easy way to construct an Addition block:

fn plus<A>(amount: A) -> Addition<A> {
@@ -95,7 +95,7 @@
         
fn main() {
     let operation = plus(5);
 
-    println!("{}", operation.forward(6)); // prints 11 (6 + 5 = 11)
+    println!("{}", operation.forward(6));  // prints 11 (6 + 5 = 11)
     println!("{}", operation.reverse(11)); // prints 6 (11 - 5 = 6)
 }
@@ -103,14 +103,14 @@ trait impl said.

I've implemented a few more in the source code:

    -
  • neg() negates a number
  • -
  • times(x) multiplies a number by x
  • -
  • discrete(x: Vec<(A, B)>) creates a reversible block out of a set of discrete inputs and outputs.
  • +
  • neg() negates a number
  • +
  • times(x) multiplies a number by x
  • +
  • discrete(x: Vec<(A, B)>) creates a reversible block out of a set of discrete inputs and outputs.

First Combinators

- The first combinator we'll implement is Pipe. + The first combinator we'll implement is Pipe. This takes in two Revs and and makes one that applies them in sequential order.

struct Pipe<X, Y>(X, Y);
@@ -132,7 +132,7 @@
 }

- Additionally, we'll implement Inverse (not to be confused with .reverse()). + Additionally, we'll implement Inverse (not to be confused with .reverse()). This flips the forward and reverse methods.

struct Inverse<X>(X);
@@ -194,7 +194,7 @@
 
         

Under

- under is a higher order combinator, which means it's implemented in terms of other combinators. + under is a higher order combinator, which means it's implemented in terms of other combinators. Under basically says "do a thing, do another thing, then undo the first thing. With this foundation built up, we can implement it quite easily:

diff --git a/soplt.html b/soplt.html index a80c81e..60ba75b 100644 --- a/soplt.html +++ b/soplt.html @@ -3,7 +3,6 @@ Summer of PLT - diff --git a/style.css b/style.css index 19c33e7..23162b3 100644 --- a/style.css +++ b/style.css @@ -1,4 +1,4 @@ -@import url('https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap'); +@import url('fonts.css'); *, *::before, *::after { box-sizing: border-box; -- cgit v1.3.1