The q-axis is 0deg→︎; the r-axis is 120deg↙︎. ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌─┘ └─┬─┘ └─┬─┘ └─┬─┘ └─┬─┘ └─┬─ │ (0,0) │ (1,0) │ (2,0) │ (3,0) │ (4,0) │ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─ ┌─┘ └─┬─┘ └─┬─┘ └─┬─┘ └─┬─┘ └─┬─┘ │ (0,1) │ (1,1) │ (2,1) │ (3,1) │ (4,1) │ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─ ┌─┘ └─┬─┘ └─┬─┘ └─┬─┘ └─┬─┘ └─┬─┘ │ (0,2) │ (1,2) │ (2,2) │ (3,2) │ (4,2) │ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─ ┌─┘ └─┬─┘ └─┬─┘ └─┬─┘ └─┬─┘ └─┬─┘ │ (0,3) │ (1,3) │ (2,3) │ (3,3) │ (4,3) │ ─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─ └─┬─┘ └─┬─┘ └─┬─┘ └─┬─┘ └─┬─┘

Here's a simple way to implement edges and intersections, for example if you're making a bootleg of *Catan*:

Say that your logical array for the *tiles* has a geometry of H×W; this array will of course be sparse if you have a board that's any shape other than a parallelogram.

- For edges — Catan “roads” — allocate a logical array of (H+1)×(W+1)×3
- For intersections — Catan “settlements” — allocate a logical array of (H+1)×(W+1)×2
- Define the intersections “adjacent” to tile (q,r) to be {(q+1,r,2), (q+1,r+1,1), (q,r+1,0), (q,r,2), (q,r,1), (q,r,0)}
- In other words, intersection 0 is due-north of its quasi-corresponding tile, and intersection 1 is north-west of it

- Define the edges “adjacent” to intersection (q,r,0) to be {(q,r,0), (q,r,1), (q,r-1,2)}; and define the edges “adjacent” to intersection (q,r,1) to be {(q,r,2), (q-1,r-1,0), (q-1)}
- In other words, edge 0 is north-east of its quasi-corresponding tile, edge 1 is north-west of it, and edge 2 is due-west of it.

You could have chosen any arbitrary 2 intersections and 3 edges for each tile, but choosing them this way is optimal for tile-first applications. If a tile exists, all adjacent edges and intersections are *guaranteed* to exist; and for a non-sparse board, there are no wasted intersection or edge allocations.

`tkinter.messagebox`

module shows Windows native dialogs (win/tkWinDialog.c#L2950), and it shows Mac OS native dialogs (macosx/tkMacOSXDialog.c#L1399), but since Linux doesn't However, Python does *not* currently have any non-ugly "ttk" bindings for this (Lib/tkinter/messagebox.py#L61).

```
set /p="Install this extension, then press Enter: https://microsoftedge.microsoft.com/addons/detail/gamjhjfeblghkihfjdpmbpajhlpmobbp"
set /p="Download this file, then press Enter: https://res-dod.cdn.office.net/owasmime/20.21.804.1/SmimeOutlookWebChrome.msi?v=4.0800"
msiexec /a %USERPROFILE%\Downloads\SmimeOutlookWebChrome.msi /qb TARGETDIR="%LOCALAPPDATA%\Microsoft\Edge"
REG ADD HKCU\SOFTWARE\Microsoft\Edge\NativeMessagingHosts\com.microsoft.outlook.smime.chromenativeapp /ve /d "%LOCALAPPDATA%\Microsoft\Edge\SmimeOutlookWebChrome\native-app-host-manifest.json"
set /p="Restart Edge, then press Enter."
```

]]>The tldr is:

- Pip 23.3 or newer "just works" after you add a simple snippet to your config file.
`; %AppData%\pip\pip.ini ; "${XDG_HOME-$HOME/.config}/pip/pip.ini" [global] use-feature = truststore`

**However**, said snippet will break older versions of pip.- In particular,
`pip < 23.3, >= 22.2`

will break, complaining that you need to install the "truststore" package before you can install*any*packages—a perfect "catch 22".

- In particular,
- As of the last time I checked (CPython 3.12.1), ensurepip, which is what's used to bootstrap virtual environments) installs one of these broken versions of pip.
- If you create your venvs with PyPA's "virtualenv" (specifically
`virtualenv >= 20.24.6`

) rather than venv, you will get a version of pip that works.- If you're using PyPA's "build" tool, it will automatically switch to using virtualenv if available, which means your "isolated" builds will work behind a corporate firewall.

- If you create your venvs with PyPA's "virtualenv" (specifically

```
REM on Windows
pip install -v "readme-renderer < 42.0" & REM https://github.com/pypa/twine/issues/1015
pip install twine
```

```
# on Mac and Linux
pip install -v "readme-renderer < 42.0" # https://github.com/pypa/twine/issues/1015
pip install twine
```

This won't pollute your registry or any other folders than the current one with an installation of rust or rustc or cargo or the rust updater or the rust updater installer or whatever other weird litter the kids are advocating for your system these days

*Alternatively*, if you really need some feature of `readme-renderer >= 42.0`

, here's a less simple workaround that provides all the same guarantees as the previous one:

```
REM on Windows
REM https://github.com/pypa/twine/issues/1015
REM https://github.com/pypa/readme_renderer/blob/42.0/pyproject.toml#L10
REM https://github.com/messense/nh3/blob/v0.2.15/.github/workflows/CI.yml#L58
REM https://github.com/rust-lang/rust-forge/issues/225
REM https://github.com/rust-lang/rust/issues/116028
REM https://github.com/rust-lang/cargo/issues/1734
set /p="Download TGZ from https://forge.rust-lang.org/infra/other-installation-methods.html#standalone-installers then press Enter"
msiexec /a "%USERPROFILE%\Downloads\rust-1.75.0-x86_64-pc-windows-msvc.msi" /qb TARGETDIR="%cd%"
cmd /C set ^"PATH=%cd%\Rust\bin;%PATH%^" ^& set ^"CARGO_TARGET_DIR=%cd%\Rust\.cargo^" ^& python -m pip install -v twine
```

```
# on Linux
# https://github.com/pypa/twine/issues/1015
# https://github.com/pypa/readme_renderer/blob/42.0/pyproject.toml#L10
# https://github.com/messense/nh3/blob/v0.2.15/.github/workflows/CI.yml#L58
# https://github.com/rust-lang/rust-forge/issues/225
# https://github.com/rust-lang/rust/issues/116028
# https://github.com/rust-lang/cargo/issues/1734
read -p "Download MSI from https://forge.rust-lang.org/infra/other-installation-methods.html#standalone-installers then press Enter"
tar x -zf "$HOME/Downloads/rust-1.75.0-x86_64-unknown-linux-gnu.tar.gz"
PATH="$PWD/rust-1.75.0-x86_64-unknown-linux-gnu/rustc/bin:$PWD/rust-1.75.0-x86_64-unknown-linux-gnu/cargo/bin:$PATH" python -m pip install -v twine
```

]]>After merely scooping a libdvdcss RPM from this cool guy's repository (the CentOS 8 RPM installed without issue on Rocky Linux 9), VLC instantly gained the ability to play DVDs. I could not find any other obvious source of the library for this operating system.

]]>On investigation, it was using the "llvmpipe" Mesa backend, because it lacked ati_drv.so (from “xf86-video-ati”,) for the AMD Radeon HD 7570M GPU; backporting[?] that package from Rocky Linux 8 then rebooting left Steam not finding r600_dri.so (though it seems to have fixed hardware acceleration for Firefox/etc.); scooping up that library from the Rocky Linux Stream 8 RPM (had to transplant it since the RPM had dependency issues; had to transplant it to /usr because Steam wouldn't find it at /usr/local; Steam complained *both* about the absence of the 32-bit and 64-bit versions; so I got them both) for some reason still left Steam kinda non-functional.

Previously on: struggles with RHEL 9 on this laptop…

]]>Addition works, and multiplication works. **But** subtraction is broken, because there isn't any natural number equal to $2-3$.

We might think about fixing subtraction, and *one* way of doing this is by moving to the integers, which allows negative numbers: $\mathbb{Z}=\left\{\dots, -2, -1, 0, 1, 2, \dots\right\}$.

But that still leaves division broken—there isn't any integer equal to $3 \div 4$!

One path forward is to move over to the rational numbers: $\mathbb{Q}=\text{“Proper Fractions”}$. This fixes division and subtraction at the same time. But… this path forward locks us into an infinitely large set. Sometimes (especially in cryptography) it's useful to have a smaller set of numbers that you can actually do ALL the math on.

The official word for “a set of numbers you can do all the math on” is a field. For example, $\mathbb{Q}$ is a field. But (obviously) there are infinitely many fractions, so it's an infinite field. Today you're going to learn about **finite** fields—which are exactly what they say on the tin. They're sometimes called “Galois fields” (gal'waah fields). They're used in almost all cryptographic algorithms. (They probably have other uses, too. [TODO look this up])

However, building these is a bit complicated. I'll need to explain 3 ideas first.

One popular starting block for thinking about smaller universes of numbers is **modular arithmetic**. It starts out just like the natural numbers, but when you're about to reach the limit—the “modulus”—the numbers loop back around to 0. Also, if you try to go back below 0, you get sent up to the highest number. This gives you a miniature “toy version” of the integers that you can do math on without having to worry about looking infinity in the eye! (The way that galaxy-brained mathematicians think of this is “the quotient set of the integers, using the remainder of division by the modulus as the equivalence operator”—but you *absolutely don't* need to learn about that to get a basic understanding of how modular arithmetic works.)

Now, no matter what modulus you pick (as long as it's an integer $\ge 2$), addition works great, and multiplication at least kinda works. (Subtraction works perfectly, too; but I'll leave that as an exercise for the reader, since it doesn't matter for what we're doing today.)

For example, here's **the integers modulo 8**, which I'll write as $\textcolor{indigo}{\mathbb{Z}_8}$ (colored indigo so you can tell the modular integers from this “miniature universe” apart from regular integers):

**Addition in $\textcolor{indigo}{\mathbb{Z}_8}$**

$$\begin{array} {r|r|} + & \textcolor{indigo}{0} & \textcolor{indigo}{1} & \textcolor{indigo}{2} & \textcolor{indigo}{3} & \textcolor{indigo}{4} & \textcolor{indigo}{5} & \textcolor{indigo}{6} & \textcolor{indigo}{7} \\ \hline \textcolor{indigo}{0} & \textcolor{indigo}{0} & \textcolor{indigo}{1} & \textcolor{indigo}{2} & \textcolor{indigo}{3} & \textcolor{indigo}{4} & \textcolor{indigo}{5} & \textcolor{indigo}{6} & \textcolor{indigo}{7} \\ \hline \textcolor{indigo}{1} & \textcolor{indigo}{1} & \textcolor{indigo}{2} & \textcolor{indigo}{3} & \textcolor{indigo}{4} & \textcolor{indigo}{5} & \textcolor{indigo}{6} & \textcolor{indigo}{7} & \textcolor{indigo}{0} \\ \hline \textcolor{indigo}{2} & \textcolor{indigo}{2} & \textcolor{indigo}{3} & \textcolor{indigo}{4} & \textcolor{indigo}{5} & \textcolor{indigo}{6} & \textcolor{indigo}{7} & \textcolor{indigo}{0} & \textcolor{indigo}{1} \\ \hline \textcolor{indigo}{3} & \textcolor{indigo}{3} & \textcolor{indigo}{4} & \textcolor{indigo}{5} & \textcolor{indigo}{6} & \textcolor{indigo}{7} & \textcolor{indigo}{0} & \textcolor{indigo}{1} & \textcolor{indigo}{2} \\ \hline \textcolor{indigo}{4} & \textcolor{indigo}{4} & \textcolor{indigo}{5} & \textcolor{indigo}{6} & \textcolor{indigo}{7} & \textcolor{indigo}{0} & \textcolor{indigo}{1} & \textcolor{indigo}{2} & \textcolor{indigo}{3} \\ \hline \textcolor{indigo}{5} & \textcolor{indigo}{5} & \textcolor{indigo}{6} & \textcolor{indigo}{7} & \textcolor{indigo}{0} & \textcolor{indigo}{1} & \textcolor{indigo}{2} & \textcolor{indigo}{3} & \textcolor{indigo}{4} \\ \hline \textcolor{indigo}{6} & \textcolor{indigo}{6} & \textcolor{indigo}{7} & \textcolor{indigo}{0} & \textcolor{indigo}{1} & \textcolor{indigo}{2} & \textcolor{indigo}{3} & \textcolor{indigo}{4} & \textcolor{indigo}{5} \\ \hline \textcolor{indigo}{7} & \textcolor{indigo}{7} & \textcolor{indigo}{0} & \textcolor{indigo}{1} & \textcolor{indigo}{2} & \textcolor{indigo}{3} & \textcolor{indigo}{4} & \textcolor{indigo}{5} & \textcolor{indigo}{6} \\ \hline \end{array}$$

Notice that (for example) $\textcolor{indigo}{6} + \textcolor{indigo}{2} = \textcolor{indigo}{0}$, because $6 + 2 = 8$, which wraps back around to $8-8 = \textcolor{indigo}{0}$!

**Multiplication in $\textcolor{indigo}{\mathbb{Z}_8}$**

$$\begin{array} {r|r|} \times & \textcolor{indigo}{1} & \textcolor{indigo}{2} & \textcolor{indigo}{3} & \textcolor{indigo}{4} & \textcolor{indigo}{5} & \textcolor{indigo}{6} & \textcolor{indigo}{7} \\ \hline \textcolor{indigo}{1} & \textcolor{indigo}{1} & \textcolor{indigo}{2} & \textcolor{indigo}{3} & \textcolor{indigo}{4} & \textcolor{indigo}{5} & \textcolor{indigo}{6} & \textcolor{indigo}{7} \\ \hline \textcolor{indigo}{2} & \textcolor{indigo}{2} & \textcolor{indigo}{4} & \textcolor{indigo}{6} & \textcolor{indigo}{0} & \textcolor{indigo}{2} & \textcolor{indigo}{4} & \textcolor{indigo}{6} \\ \hline \textcolor{indigo}{3} & \textcolor{indigo}{3} & \textcolor{indigo}{6} & \textcolor{indigo}{1} & \textcolor{indigo}{4} & \textcolor{indigo}{7} & \textcolor{indigo}{2} & \textcolor{indigo}{5} \\ \hline \textcolor{indigo}{4} & \textcolor{indigo}{4} & \textcolor{indigo}{0} & \textcolor{indigo}{4} & \textcolor{indigo}{0} & \textcolor{indigo}{4} & \textcolor{indigo}{0} & \textcolor{indigo}{4} \\ \hline \textcolor{indigo}{5} & \textcolor{indigo}{5} & \textcolor{indigo}{2} & \textcolor{indigo}{7} & \textcolor{indigo}{4} & \textcolor{indigo}{1} & \textcolor{indigo}{6} & \textcolor{indigo}{3} \\ \hline \textcolor{indigo}{6} & \textcolor{indigo}{6} & \textcolor{indigo}{4} & \textcolor{indigo}{2} & \textcolor{indigo}{0} & \textcolor{indigo}{6} & \textcolor{indigo}{4} & \textcolor{indigo}{2} \\ \hline \textcolor{indigo}{7} & \textcolor{indigo}{7} & \textcolor{indigo}{6} & \textcolor{indigo}{5} & \textcolor{indigo}{4} & \textcolor{indigo}{3} & \textcolor{indigo}{2} & \textcolor{indigo}{1} \\ \hline \end{array}$$

Again using the “wrap-around arithmetic”, notice that $\textcolor{indigo}{3} \times \textcolor{indigo}{5} = \textcolor{indigo}{7}$, because $3 \times 5 = 15$, which wraps back around to $15-8 = \textcolor{indigo}{7}$.

However, if you look carefully, you'll also see that $\textcolor{indigo}{4} \times \textcolor{indigo}{6} = \textcolor{indigo}{0}$—that is, two things, neither of which is $\textcolor{indigo}{0}$, multiply to produce $\textcolor{indigo}{0}$! This is technically "allowed", but is very cringe because it flies in the face of common sense, which dictates “If a×b is zero, then either a or b must have been zero!”

In fact, this violation of common sense is *so* cringe that Nature's God will punish you for it by punching a bunch of holes in your division tables (which ruins them):

**"Division" in $\textcolor{indigo}{\mathbb{Z}_8}$**

$$\begin{array} {r|r|} \div & \textcolor{indigo}{1} & \textcolor{indigo}{2} & \textcolor{indigo}{3} & \textcolor{indigo}{4} & \textcolor{indigo}{5} & \textcolor{indigo}{6} & \textcolor{indigo}{7} \\ \hline \textcolor{indigo}{1} & \textcolor{indigo}{1} & \textcolor{indigo}{2} & \textcolor{indigo}{3} & \textcolor{indigo}{4} & \textcolor{indigo}{5} & \textcolor{indigo}{6} & \textcolor{indigo}{7} \\ \hline \textcolor{indigo}{2} & & \textcolor{indigo}{1} & & \textcolor{indigo}{2} & & \textcolor{indigo}{3} & \\ \hline \textcolor{indigo}{3} & \textcolor{indigo}{3} & \textcolor{indigo}{6} & \textcolor{indigo}{1} & \textcolor{indigo}{4} & \textcolor{indigo}{7} & \textcolor{indigo}{2} & \textcolor{indigo}{5} \\ \hline \textcolor{indigo}{4} & & & & \textcolor{indigo}{1} & & & \\ \hline \textcolor{indigo}{5} & \textcolor{indigo}{5} & \textcolor{indigo}{2} & \textcolor{indigo}{7} & \textcolor{indigo}{4} & \textcolor{indigo}{1} & \textcolor{indigo}{6} & \textcolor{indigo}{3} \\ \hline \textcolor{indigo}{6} & & \textcolor{indigo}{3} & & \textcolor{indigo}{6} & & \textcolor{indigo}{1} & \\ \hline \textcolor{indigo}{7} & \textcolor{indigo}{7} & \textcolor{indigo}{6} & \textcolor{indigo}{5} & \textcolor{indigo}{4} & \textcolor{indigo}{3} & \textcolor{indigo}{2} & \textcolor{indigo}{1} \\ \hline \end{array}$$

Joking aside, the technical reason the division table is ruined is that $\textcolor{indigo}{2}$, $\textcolor{indigo}{4}$, and $\textcolor{indigo}{6}$ don't have any multiplicative inverse in $\textcolor{indigo}{\mathbb{Z}_8}$—that is, there *isn't any* solution to “$\textcolor{indigo}{2} \times \textcolor{indigo}{\text{?}} = \textcolor{indigo}{1}$”*. Because of that, we say that division *just isn't defined* on $\textcolor{indigo}{\mathbb{Z}_8}$.

(*Yes, you guessed right: “$\textcolor{indigo}{4} \times \textcolor{indigo}{\text{?}} = \textcolor{indigo}{1}$” and “$\textcolor{indigo}{6} \times \textcolor{indigo}{\text{?}} = \textcolor{indigo}{1}$” *also* have no solution. You can double-check this yourself by looking back at the multiplication table and noticing there isn't any $\textcolor{indigo}{1}$ to be found in the $\textcolor{indigo}{2}$, $\textcolor{indigo}{4}$, or $\textcolor{indigo}{6}$ columns!)

Now, you might ask: can this be fixed? The answer: yes, but it's hard. (But that's what we're here today to do!)

The easy solution is just to give up and instead use a prime number (like 2; 7; or 6,277,101,735,386,680,763,835,789,423,207,666,416,083,908,700,390,324,961,279) as your modulus. Then, multiplication and division will just work right away, without any problem.

The hard solution requires two more ideas before we can start to explain it… actually, the first of these ideas *is* the easy solution, so let's look into that!

What if we tried to make a modular arithmetic table with $7$ (which is prime) as the modulus, rather than 8?

Well, I already spoiled it earlier: all the math—including division—will just work. (But let's look at the example anyway!)

**Addition in $\textcolor{teal}{\mathbb{F}_7}$**

$$\begin{array} {r|r|} + & \textcolor{teal}{0} & \textcolor{teal}{1} & \textcolor{teal}{2} & \textcolor{teal}{3} & \textcolor{teal}{4} & \textcolor{teal}{5} & \textcolor{teal}{6} \\ \hline \textcolor{teal}{0} & \textcolor{teal}{0} & \textcolor{teal}{1} & \textcolor{teal}{2} & \textcolor{teal}{3} & \textcolor{teal}{4} & \textcolor{teal}{5} & \textcolor{teal}{6} \\ \hline \textcolor{teal}{1} & \textcolor{teal}{1} & \textcolor{teal}{2} & \textcolor{teal}{3} & \textcolor{teal}{4} & \textcolor{teal}{5} & \textcolor{teal}{6} & \textcolor{teal}{0} \\ \hline \textcolor{teal}{2} & \textcolor{teal}{2} & \textcolor{teal}{3} & \textcolor{teal}{4} & \textcolor{teal}{5} & \textcolor{teal}{6} & \textcolor{teal}{0} & \textcolor{teal}{1} \\ \hline \textcolor{teal}{3} & \textcolor{teal}{3} & \textcolor{teal}{4} & \textcolor{teal}{5} & \textcolor{teal}{6} & \textcolor{teal}{0} & \textcolor{teal}{1} & \textcolor{teal}{2} \\ \hline \textcolor{teal}{4} & \textcolor{teal}{4} & \textcolor{teal}{5} & \textcolor{teal}{6} & \textcolor{teal}{0} & \textcolor{teal}{1} & \textcolor{teal}{2} & \textcolor{teal}{3} \\ \hline \textcolor{teal}{5} & \textcolor{teal}{5} & \textcolor{teal}{6} & \textcolor{teal}{0} & \textcolor{teal}{1} & \textcolor{teal}{2} & \textcolor{teal}{3} & \textcolor{teal}{4} \\ \hline \textcolor{teal}{6} & \textcolor{teal}{6} & \textcolor{teal}{0} & \textcolor{teal}{1} & \textcolor{teal}{2} & \textcolor{teal}{3} & \textcolor{teal}{4} & \textcolor{teal}{5} \\ \hline \end{array}$$

(As you probably expected, nothing to see here; addition never had any problems. Moving along…)

**Multiplication in $\textcolor{teal}{\mathbb{F}_7}$**

$$\begin{array} {r|r|} \times & \textcolor{teal}{1} & \textcolor{teal}{2} & \textcolor{teal}{3} & \textcolor{teal}{4} & \textcolor{teal}{5} & \textcolor{teal}{6} \\ \hline \textcolor{teal}{1} & \textcolor{teal}{1} & \textcolor{teal}{2} & \textcolor{teal}{3} & \textcolor{teal}{4} & \textcolor{teal}{5} & \textcolor{teal}{6} \\ \hline \textcolor{teal}{2} & \textcolor{teal}{2} & \textcolor{teal}{4} & \textcolor{teal}{6} & \textcolor{teal}{1} & \textcolor{teal}{3} & \textcolor{teal}{5} \\ \hline \textcolor{teal}{3} & \textcolor{teal}{3} & \textcolor{teal}{6} & \textcolor{teal}{2} & \textcolor{teal}{5} & \textcolor{teal}{1} & \textcolor{teal}{4} \\ \hline \textcolor{teal}{4} & \textcolor{teal}{4} & \textcolor{teal}{1} & \textcolor{teal}{5} & \textcolor{teal}{2} & \textcolor{teal}{6} & \textcolor{teal}{3} \\ \hline \textcolor{teal}{5} & \textcolor{teal}{5} & \textcolor{teal}{3} & \textcolor{teal}{1} & \textcolor{teal}{6} & \textcolor{teal}{4} & \textcolor{teal}{2} \\ \hline \textcolor{teal}{6} & \textcolor{teal}{6} & \textcolor{teal}{5} & \textcolor{teal}{4} & \textcolor{teal}{3} & \textcolor{teal}{2} & \textcolor{teal}{1} \\ \hline \end{array}$$

Without putting your finger on it, doesn't that table look… prettier? Tidier? Neater?

OK, now put your finger on it: notice that each column and each row includes each (non-$\textcolor{teal}{0}$) element exactly once! That means that you can turn any (non-$\textcolor{teal}{0}$) element into any other element, just by a single multiplication! And you'll never *accidentally* get $\textcolor{teal}{0}$; the only way to reach it by multiplication is by multiplying by $\textcolor{teal}{0}$ *on purpose*. Of course, this means…

**Division in $\textcolor{teal}{\mathbb{F}_7}$**

$$\begin{array} {r|r|} \div & \textcolor{teal}{1} & \textcolor{teal}{2} & \textcolor{teal}{3} & \textcolor{teal}{4} & \textcolor{teal}{5} & \textcolor{teal}{6} \\ \hline \textcolor{teal}{1} & \textcolor{teal}{1} & \textcolor{teal}{2} & \textcolor{teal}{3} & \textcolor{teal}{4} & \textcolor{teal}{5} & \textcolor{teal}{6} \\ \hline \textcolor{teal}{2} & \textcolor{teal}{4} & \textcolor{teal}{1} & \textcolor{teal}{5} & \textcolor{teal}{2} & \textcolor{teal}{6} & \textcolor{teal}{3} \\ \hline \textcolor{teal}{3} & \textcolor{teal}{5} & \textcolor{teal}{3} & \textcolor{teal}{1} & \textcolor{teal}{6} & \textcolor{teal}{4} & \textcolor{teal}{2} \\ \hline \textcolor{teal}{4} & \textcolor{teal}{2} & \textcolor{teal}{4} & \textcolor{teal}{6} & \textcolor{teal}{1} & \textcolor{teal}{3} & \textcolor{teal}{5} \\ \hline \textcolor{teal}{5} & \textcolor{teal}{3} & \textcolor{teal}{6} & \textcolor{teal}{2} & \textcolor{teal}{5} & \textcolor{teal}{1} & \textcolor{teal}{4} \\ \hline \textcolor{teal}{6} & \textcolor{teal}{6} & \textcolor{teal}{5} & \textcolor{teal}{4} & \textcolor{teal}{3} & \textcolor{teal}{2} & \textcolor{teal}{1} \\ \hline \end{array}$$

…our division table doesn't have any holes in it—division actually works now!

All this to say that, if (and only if) $p$ is prime, then $\mathbb{Z}_p$ (the integers modulo $p$) is just exactly the same thing as $\mathbb{F}_p$ (the finite field with $p$ elements). Now you know about finite fields with a prime number of elements!

But there are some finite fields with a non-prime number of elements, and we occasionally need those, so let's keep learning until we find out how they work…

Now, the mathematicians call a group of numbers that has addition, subtraction, and multiplication that at least kinda works a ring. (Rings don't care whether division works. As you might have guessed, $\textcolor{indigo}{\mathbb{Z}_8}$ from earlier is a ring.)

Actually, the elements of the ring don't even have to be numbers. They can be any object. Let's create a ring right now with a ridiculous object in it!

We'll start out with $\textcolor{olive}{\mathbb{F}_3}$ (which is a field, admittedly)—

**Addition in $\textcolor{olive}{\mathbb{F}_3}$**

$$\begin{array} {r|r|} + & \textcolor{olive}{0} & \textcolor{olive}{1} & \textcolor{olive}{2} \\ \hline \textcolor{olive}{0} & \textcolor{olive}{0} & \textcolor{olive}{1} & \textcolor{olive}{2} \\ \hline \textcolor{olive}{1} & \textcolor{olive}{1} & \textcolor{olive}{2} & \textcolor{olive}{0} \\ \hline \textcolor{olive}{2} & \textcolor{olive}{2} & \textcolor{olive}{0} & \textcolor{olive}{1} \\ \hline \end{array}$$

**Multiplication in $\textcolor{olive}{\mathbb{F}_3}$**

$$\begin{array} {r|r|} \times & \textcolor{olive}{1} & \textcolor{olive}{2} \\ \hline \textcolor{olive}{1} & \textcolor{olive}{1} & \textcolor{olive}{2} \\ \hline \textcolor{olive}{2} & \textcolor{olive}{2} & \textcolor{olive}{1} \\ \hline \end{array}$$

and we just throw some garbage in there and say “this is an element now”—for example, if we added an arbitrary symbol in just to see how the math would cope: ${\textcolor{olive}{\mathbb{F}_3}}{[{\text{}}]}$.

The good news is: this “adjoinment” does not break addition, subtraction, or multiplication!

The bad news is: it breaks division (which is why the result is called a “ring”), *and* it has an infinite amount of elements—

**Addition in $\textcolor{olive}{\mathbb{F}_3}{[{\text{}}]}$**

$$\begin{array} {r|r|} + & \textcolor{olive}{0} & \textcolor{olive}{1} & \textcolor{olive}{2} & \textcolor{olive}{1}\text{} & {({\textcolor{olive}{1}\text{} + \textcolor{olive}{1}})} & {({\textcolor{olive}{1}\text{} + \textcolor{olive}{2}})} & \textcolor{olive}{2}\text{} & {({\textcolor{olive}{2}\text{} + \textcolor{olive}{1}})} & {({\textcolor{olive}{2}\text{} + \textcolor{olive}{2}})} & \textcolor{olive}{1}\text{}^2 & \dots & \textcolor{olive}{1}\text{}^{100} & \dots \\

\hline \textcolor{olive}{0} & \textcolor{olive}{0} & \textcolor{olive}{1}& \textcolor{olive}{2} & \textcolor{olive}{1}\text{} & {({\textcolor{olive}{1}\text{} + \textcolor{olive}{1}})} & {({\textcolor{olive}{1}\text{} + \textcolor{olive}{2}})} & \textcolor{olive}{2}\text{} & {({\textcolor{olive}{2}\text{} + \textcolor{olive}{1}})} & {({\textcolor{olive}{2}\text{} + \textcolor{olive}{2}})} & \textcolor{olive}{1}\text{}^2 & \dots & \textcolor{olive}{1}\text{}^{100} & \dots \\

\hline \textcolor{olive}{1} & \textcolor{olive}{1} & \textcolor{olive}{2} & \textcolor{olive}{0} & {({\textcolor{olive}{1}\text{} + \textcolor{olive}{1}})} & {({\textcolor{olive}{1}\text{} + \textcolor{olive}{2}})} & \textcolor{olive}{1}\text{} & {({\textcolor{olive}{2}\text{} + \textcolor{olive}{1}})} & {({\textcolor{olive}{2}\text{} + \textcolor{olive}{2}})} & \textcolor{olive}{2}\text{} & {({\textcolor{olive}{1}\text{}^2 + \textcolor{olive}{1}})} & \dots & {({\textcolor{olive}{1}\text{}^{100} + \textcolor{olive}{1}})} & \dots \\

\hline \textcolor{olive}{1}\text{} & \textcolor{olive}{1}\text{} & {({\textcolor{olive}{1}\text{} + \textcolor{olive}{1}})} & {({\textcolor{olive}{1}\text{} + \textcolor{olive}{2}})} & \textcolor{olive}{2}\text{} & {({\textcolor{olive}{2}\text{} + \textcolor{olive}{1}})} & {({\textcolor{olive}{2}\text{} + \textcolor{olive}{2}})} & \textcolor{olive}{0} & \textcolor{olive}{1} & \textcolor{olive}{2} & {({\textcolor{olive}{1}\text{}^2 + \textcolor{olive}{1}\text{}})} & \dots & \_ & \dots \\

\hline {({\textcolor{olive}{1}\text{} + \textcolor{olive}{1}})} & {({\textcolor{olive}{1}\text{} + \textcolor{olive}{1}})} & {({\textcolor{olive}{1}\text{} + \textcolor{olive}{2}})} & \textcolor{olive}{1}\text{} & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \dots & \_ & \dots \\

\hline {({\textcolor{olive}{1}\text{} + \textcolor{olive}{2}})} & {({\textcolor{olive}{1}\text{} + \textcolor{olive}{2}})} & \textcolor{olive}{1}\text{} & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \dots & \_ & \dots \\

\hline \textcolor{olive}{2}\text{} & \textcolor{olive}{2}\text{} & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \dots & \_ & \dots \\

\hline {({\textcolor{olive}{2}\text{} + \textcolor{olive}{1}})} & {({\textcolor{olive}{2}\text{} + \textcolor{olive}{1}})} & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \dots & \_ & \dots \\

\hline {({\textcolor{olive}{2}\text{} + \textcolor{olive}{2}})} & {({\textcolor{olive}{2}\text{} + \textcolor{olive}{2}})} & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \dots & \_ & \dots \\

\hline \textcolor{olive}{1}\text{}^2 & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \dots &\_ & \dots \\

\hline \dots & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \dots &\_ & \dots \\

\hline \textcolor{olive}{1}\text{}^{100} & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \dots & \textcolor{olive}{2}\text{}^{100} & \dots \\

\hline \dots & \dots & \dots & \dots & \dots & \dots & \dots & \dots & \dots & \dots & \dots & \dots \\

\hline \end{array}$$

]]>\hline \textcolor{olive}{0} & \textcolor{olive}{0} & \textcolor{olive}{1}& \textcolor{olive}{2} & \textcolor{olive}{1}\text{} & {({\textcolor{olive}{1}\text{} + \textcolor{olive}{1}})} & {({\textcolor{olive}{1}\text{} + \textcolor{olive}{2}})} & \textcolor{olive}{2}\text{} & {({\textcolor{olive}{2}\text{} + \textcolor{olive}{1}})} & {({\textcolor{olive}{2}\text{} + \textcolor{olive}{2}})} & \textcolor{olive}{1}\text{}^2 & \dots & \textcolor{olive}{1}\text{}^{100} & \dots \\

\hline \textcolor{olive}{1} & \textcolor{olive}{1} & \textcolor{olive}{2} & \textcolor{olive}{0} & {({\textcolor{olive}{1}\text{} + \textcolor{olive}{1}})} & {({\textcolor{olive}{1}\text{} + \textcolor{olive}{2}})} & \textcolor{olive}{1}\text{} & {({\textcolor{olive}{2}\text{} + \textcolor{olive}{1}})} & {({\textcolor{olive}{2}\text{} + \textcolor{olive}{2}})} & \textcolor{olive}{2}\text{} & {({\textcolor{olive}{1}\text{}^2 + \textcolor{olive}{1}})} & \dots & {({\textcolor{olive}{1}\text{}^{100} + \textcolor{olive}{1}})} & \dots \\

\hline \textcolor{olive}{1}\text{} & \textcolor{olive}{1}\text{} & {({\textcolor{olive}{1}\text{} + \textcolor{olive}{1}})} & {({\textcolor{olive}{1}\text{} + \textcolor{olive}{2}})} & \textcolor{olive}{2}\text{} & {({\textcolor{olive}{2}\text{} + \textcolor{olive}{1}})} & {({\textcolor{olive}{2}\text{} + \textcolor{olive}{2}})} & \textcolor{olive}{0} & \textcolor{olive}{1} & \textcolor{olive}{2} & {({\textcolor{olive}{1}\text{}^2 + \textcolor{olive}{1}\text{}})} & \dots & \_ & \dots \\

\hline {({\textcolor{olive}{1}\text{} + \textcolor{olive}{1}})} & {({\textcolor{olive}{1}\text{} + \textcolor{olive}{1}})} & {({\textcolor{olive}{1}\text{} + \textcolor{olive}{2}})} & \textcolor{olive}{1}\text{} & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \dots & \_ & \dots \\

\hline {({\textcolor{olive}{1}\text{} + \textcolor{olive}{2}})} & {({\textcolor{olive}{1}\text{} + \textcolor{olive}{2}})} & \textcolor{olive}{1}\text{} & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \dots & \_ & \dots \\

\hline \textcolor{olive}{2}\text{} & \textcolor{olive}{2}\text{} & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \dots & \_ & \dots \\

\hline {({\textcolor{olive}{2}\text{} + \textcolor{olive}{1}})} & {({\textcolor{olive}{2}\text{} + \textcolor{olive}{1}})} & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \dots & \_ & \dots \\

\hline {({\textcolor{olive}{2}\text{} + \textcolor{olive}{2}})} & {({\textcolor{olive}{2}\text{} + \textcolor{olive}{2}})} & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \dots & \_ & \dots \\

\hline \textcolor{olive}{1}\text{}^2 & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \dots &\_ & \dots \\

\hline \dots & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \dots &\_ & \dots \\

\hline \textcolor{olive}{1}\text{}^{100} & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \_ & \dots & \textcolor{olive}{2}\text{}^{100} & \dots \\

\hline \dots & \dots & \dots & \dots & \dots & \dots & \dots & \dots & \dots & \dots & \dots & \dots \\

\hline \end{array}$$

sudo dnf install \ "https://mirrors.rpmfusion.org/free/el/rpmfusion-free-release-$(rpm -E '%rhel').noarch.rpm" \ "https://mirrors.rpmfusion.org/nonfree/el/rpmfusion-nonfree-release-$(rpm -E '%rhel').noarch.rpm" \ && \ sudo dnf install ffmpeg

I didn't even need to restart Firefox afterwards; it just all seemed to start working immediately

]]>I diagnosed this via dmesg:

```
[ 108.888963] Intel(R) Wireless WiFi driver for Linux
[ 108.889046] iwlwifi 0000:25:00.0: enabling device (0000 -> 0002)
[ 108.889135] iwlwifi 0000:25:00.0: can't disable ASPM; OS doesn't have ASPM control
[ 108.937577] iwlwifi 0000:25:00.0: Direct firmware load for iwlwifi-6000-6.ucode failed with error -2
[ 108.969279] iwlwifi 0000:25:00.0: Direct firmware load for iwlwifi-6000-5.ucode failed with error -2
[ 108.969412] iwlwifi 0000:25:00.0: Direct firmware load for iwlwifi-6000-4.ucode failed with error -2
[ 108.969462] iwlwifi 0000:25:00.0: no suitable firmware found!
[ 108.969495] iwlwifi 0000:25:00.0: minimum version required: iwlwifi-6000-4
[ 108.969530] iwlwifi 0000:25:00.0: maximum version supported: iwlwifi-6000-6
[ 108.969577] iwlwifi 0000:25:00.0: check git://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git
```

The “solution” was to do this (on a **live system** which can't persist any changes between reboots and doesn't have easy access to install packages):

- Mount an existing, functioning Linux installation at
`/mnt`

(or download the RPM package at the below link) - Copy
`iwlwifi-6000-4.ucode`

from`$source/lib/firmware`

to`/lib/firmware`

`modprobe -r iwlwifi; modprobe iwlwifi`

Disturbingly, this seems to be a ** regression** policy decision. They have the firmware available for RL8—

`iwl6000-firmware`

—only it's vanished from the RL9 repos.If you want to ignore this omen (don't do it!) and continue installing RL9 anyway, you can just save that RPM file somewhere and then install it again on the system after it reboots into the installed RL9. Unlike a live system, you don't need to do the above mumbo-jumbo; you only need to install that package and then reboot.

If you don't have an (additional) flash drive on hand, and just using Ethernet isn't an option, I recommend alt-tabbing out of the installer while it's running to smuggle the file into the in-progress system, specifically `/mnt/sysroot/root`

, so you can access it easily in any event.