2021 Income Sources

In 2019 and 2020, I published posts on where folks buy my books. People seem interested, so I’m doing it again for 2021. I suspect that covid is skewing the data, but perhaps this is simply the new normal.

My income still comes from writing books. I don’t consult. I don’t generally accept speaking fees. (I did make a couple hundred bucks speaking to a lunchtime crowd at a big tech firm this year, but that was a rare event and I have no particular desire to do it again.) I desire to make my living as an author, creating and licensing intellectual property. For the writers out there, I’m a hybrid wide author. I want my books available in every channel that offers reasonable terms.

How did 2021 look?

  • Amazon – 33.94%
  • Royalties – 17.74%
  • Direct sales – 15.63%
  • Ingramspark – 8.15%
  • Kickstarter – 6.38%
  • Patreon – 4.68%
  • Sponsorships – 4.42%
  • Direct patronizers – 4.24%
  • Gumroad – 1.91%
  • Apple – 1.05%
  • Kobo – 0.61%
  • Aerio – 0.57%
  • Google – 0.32%
  • Draft2Digital – 0.27%
  • tips – 0.13%
  • Barnes & Noble – 0.07%
  • Redbubble – 0.05%

Everything that’s listed here is part of my deliberate publishing strategy. My minuscule affiliate income and other minor streams are excluded. I use them, and every so often someone drops fifty bucks in my bank account, but they are not part of my strategy.

Amazon is still my biggest single distributor. I do not prioritize them, or use their exclusive programs like Kindle Unlimited. Indeed, I want to reduce the amount I sell through Amazon and increase other channels. This percentage is basically unchanged since last year. It appears to be the natural floor. Next year might be different, though. OpenBSD Storage Mastery will be on Amazon in print, but not on Kindle. Kindle users will be able to buy Kindle versions in lots of places, just not on Amazon.

Royalties are traditional publishing income. This is slightly up from last year, thanks to me selling short stories to Fiction River as well as the Absolute books going into Humble Bundles. Can’t knock that.

Direct sales are up a few points over 2020, which was up a few points over 2019. Good. Disintermediation remains my primary goal. Increasing this share makes me happy. I will continue to improve my bookstore to make this easier.

On the other paw, my IngramSpark share is down. IS handles non-Amazon print sales. People are not visiting bookstores, so this is not a surprise.

Kickstarter is a new category for me. It worked. This category is a little weird, though. While the other channels are raw income, this bucket includes the money I must spend to print and ship books. I plan to experiment more with Kickstarter, and perhaps even offer Kickstarter-like functionality on my own store.

At first glance, it looks like income from my Patronizers has plunged since 2020. Look a little further down, though, and you’ll see the share of income from my direct patronage makes up for it. My experiment in offering direct patronage sales hasn’t quite broken even, but it’s been successful enough that I’m willing to give it another year and see if I can grow it. Even if I can’t boost that any further, diversifying patronage sources and disintermediating roughly half of my backers is inherently worthwhile.

My Patronizers get a horrid deal, by the way. I don’t recommend it. But I appreciate every single Patronizer.

Sponsorship income is down, but I only had one book on sponsorship in 2020. If I want more sponsors, I must write more. That’s a goal for 2022. I’ll be using pre-scheduled Internet blocking software to reduce distraction.

I’m not going to go through the other channels one at a time. I will quote Blaze Ward in saying, “them nickles spend.” My comments on all of these are basically unchanged from previous years. I do wish Barnes and Noble would rise from the dead, though. I fondly remember wandering through their shelves, and deciding I would rather read a favorite author’s new book than eat.

So, to sum up:

  • If I lost any one channel, I would endure (yay)!
  • Disintermediate. Sell as directly to your customers as possible.
  • Try new things. Like Kickstarter. Or dropping Amazon Kindle as a distributor for a new book.

What else is coming up in 2022? More books. Print price increases. Gelato. Staying home, making words, and avoiding unclean idiots who choose to not get vaccinated.

The New York Times, featuring: me?

Several years ago (yes, December 2020, but covid distorts time), I tweeted about my Capital One credit card. The world validated my thoughts. I moved on.

A few weeks ago, a New York Times reporter discovered that tweet as she was researching a story.

Which leads to me being on the front page of the New York Times’ Business section. It has my picture and everything. (In case the Times removes the page, here’s an archive.)

The reporter skillfully caught the most important thing I said during the whole hour-long conversation, and quoted me on it.

Also, the photographer worked miracles. Somehow, he made me look like I belong on the front page of the Crime Business section. I suspect sorcery, or perhaps a body double.

Screwing Up, and Recovering

I scheduled an all-Patronizer video hangout for last Saturday, and didn’t show up. This is obviously unacceptable. I’ve already apologized to my Patronizers on the various sites they back me on, but I wanted to blog about dealing with this kind of screwup.

The root cause was pretty simple: my house has been full of workmen for several days, busting concrete and ripping out walls to fix a tiny leak in 70-year-old plumbing. It was either that, or let the bathroom fall into the basement. I am not accustomed to jackhammers under my feet. My nerves were, to put it mildly, frayed. I completely forgot about the video hangout, and decided to go to the dojo to work off some stress. I remembered about the hangout right before parking.

How do I keep this from happening again, and minimize the impact in case I do?

First, I have installed Zoom on my phone. If I forget about a hangout, I can now join from anywhere.

Second, my most consistent attendee now has my phone number. If I’m 15 minutes late to a hangout, he will call me.

Third, I must ensure that when I create the meeting in Zoom, the waiting room is disabled. If I don’t show up for hangout, people can talk to each other while my Designated External Memory calls to poke me. I’m looking for a way to make this the default for all meetings I create, because any process that relies on my brain is doomed to fail.

I have already scheduled a make-up hangout for next Saturday, so that my Patronizers can chide me in person.

When I became a full-time writer, I thought I would leave root cause failure analysis and remediation behind. Silly me.

My Bookstore Now Using a CDN

When you buy ebooks direct from me via tiltedwindmillpress.com, your books will now be delivered via BookFunnel. After a purchase, they’ll send you an email containing your download links.

Why make this change after eight years? In short, customer service.

BookFunnel can help you sideload books onto your weird ereader. I cannot. Bookfunnel can cope with weird network issues more easily than I can. They have an actual support staff and multiple delivery channels, where TWP has me and I’d rather be writing. I should have made this change a few years ago, but the barely adequate is the enemy of the better.

The only personal information BookFunnel collects is your email address, so they can maintain a library of all the books you’ve bought and let you re-download them.

It also means I won’t be firing up tcpdump as you try to download your book, because your telco has a weird proxy server that chokes on zip files. Which is a clear win for everyone.

Kickstarter Campaign Results

My small, low-risk trial of Kickstarter, where I hoped to raise $500? It 1768% funded.

I guess there’s a demand for this book?

My back-of-an-envelope math says that my total expenses will be about half of that. I’ll keep detailed notes, of course, but for a work with no obvious audience in a field where I’m not known, Kickstarter made writing DYB not a financial loss. Plus I’ve learned how Kickstarter works and how to assemble videos.

DYB is due back from copyedit in mid-December. With anything resembling luck, I’ll have the ebook for backers and Patronizers before the end of the month. Print will take longer.

My copyeditor has requested that I not send her two of my books simultaneously. (Other people’s sure. But not mine.) Once DYB returns, I’ll punt the DNSSEC over.

Will I do another Kickstarter? I’ll probably Kickstart a short fiction collection next year. If that works, I might both Kickstart and sponsor the OpenBSD storage book.

Now, if you’ll pardon me, I’m off to get BookFunnel integrated into my bookstore so I can send people some books…

New Test System

Now that “DNSSEC Mastery 2/e” is ready for copyedit, I can turn my attention to “OpenBSD Storage Mastery.”

Back in 2014, I bought a machine for writing the ZFS books. Ten hard drives. 32 GB memory. Enough power supply to heat my office during a Michigan winter, which was great during Michigan winters and not so great in the summer. Fan noise that belonged in a datacenter. That machine’s now in the basement, ready for me to test things that require large amounts of storage.

As of today I have a more modern system on my desk, running a current OpenBSD snapshot. Clean and simple, the way God and Dennis Ritchie intended.

By unpopular request, here’s the details. It’s clean out of the box, I don’t even have tcsh installed yet, let alone my .cwmrc copied over.


OpenBSD 7.0-current (GENERIC.MP) #132: Mon Nov 29 08:51:58 MST 2021
deraadt@amd64.openbsd.org:/usr/src/sys/arch/amd64/compile/GENERIC.MP
real mem = 33592328192 (32036MB)
avail mem = 32558276608 (31049MB)
random: good seed from bootblocks
mpath0 at root
scsibus0 at mpath0: 256 targets
mainbus0 at root
bios0 at mainbus0: SMBIOS rev. 3.3 @ 0xc6a02000 (72 entries)
bios0: vendor American Megatrends Inc. version "2423" date 08/10/2021
bios0: ASUS ROG STRIX B550-F GAMING
acpi0 at bios0: ACPI 6.0
acpi0: sleep states S0 S3 S4 S5
acpi0: tables DSDT FACP IVRS SSDT SSDT SSDT FIDT FPDT MCFG HPET VFCT BGRT WPBT TPM2 SSDT CRAT CDIT SSDT SSDT SSDT WSMT APIC SSDT SSDT
acpi0: wakeup devices X162(S4) GP17(S4) XHC0(S4) XHC1(S4) X161(S4) PTXH(S4) X1_1(S4) X1_2(S4) X1_3(S4) I225(S4) X162(S4) M2_2(S4)
acpitimer0 at acpi0: 3579545 Hz, 32 bits
acpimcfg0 at acpi0
acpimcfg0: addr 0xf0000000, bus 0-127
acpihpet0 at acpi0: 14318180 Hz
acpimadt0 at acpi0 addr 0xfee00000: PC-AT compat
cpu0 at mainbus0: apid 0 (boot processor)
cpu0: AMD Ryzen 5 5600G with Radeon Graphics, 3893.28 MHz, 19-50-00
cpu0: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,PCLMUL,MWAIT,SSSE3,FMA3,CX16,SSE4.1,SSE4.2,MOVBE,POPCNT,AES,XSAVE,AVX,F16C,RDRAND,NXE,MMXX,FFXSR,PAGE1GB,RDTSCP,LONG,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,ABM,SSE4A,MASSE,3DNOWP,OSVW,IBS,SKINIT,TCE,TOPEXT,CPCTR,DBKP,PCTRL3,MWAITX,ITSC,FSGSBASE,BMI1,AVX2,SMEP,BMI2,ERMS,INVPCID,PQM,RDSEED,ADX,SMAP,CLFLUSHOPT,CLWB,SHA,UMIP,PKU,IBPB,IBRS,STIBP,SSBD,XSAVEOPT,XSAVEC,XGETBV1,XSAVES
cpu0: 32KB 64b/line 8-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 8-way L2 cache
cpu0: ITLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu0: DTLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu0: smt 0, core 0, package 0
mtrr: Pentium Pro MTRR support, 8 var ranges, 88 fixed ranges
cpu0: apic clock running at 99MHz
cpu0: mwait min=64, max=64, C-substates=1.1, IBE
cpu1 at mainbus0: apid 2 (application processor)
cpu1: AMD Ryzen 5 5600G with Radeon Graphics, 3892.69 MHz, 19-50-00
cpu1: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,PCLMUL,MWAIT,SSSE3,FMA3,CX16,SSE4.1,SSE4.2,MOVBE,POPCNT,AES,XSAVE,AVX,F16C,RDRAND,NXE,MMXX,FFXSR,PAGE1GB,RDTSCP,LONG,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,ABM,SSE4A,MASSE,3DNOWP,OSVW,IBS,SKINIT,TCE,TOPEXT,CPCTR,DBKP,PCTRL3,MWAITX,ITSC,FSGSBASE,BMI1,AVX2,SMEP,BMI2,ERMS,INVPCID,PQM,RDSEED,ADX,SMAP,CLFLUSHOPT,CLWB,SHA,UMIP,PKU,IBPB,IBRS,STIBP,SSBD,XSAVEOPT,XSAVEC,XGETBV1,XSAVES
cpu1: 32KB 64b/line 8-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 8-way L2 cache
cpu1: ITLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu1: DTLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu1: smt 0, core 1, package 0
cpu2 at mainbus0: apid 4 (application processor)
cpu2: AMD Ryzen 5 5600G with Radeon Graphics, 3892.70 MHz, 19-50-00
cpu2: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,PCLMUL,MWAIT,SSSE3,FMA3,CX16,SSE4.1,SSE4.2,MOVBE,POPCNT,AES,XSAVE,AVX,F16C,RDRAND,NXE,MMXX,FFXSR,PAGE1GB,RDTSCP,LONG,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,ABM,SSE4A,MASSE,3DNOWP,OSVW,IBS,SKINIT,TCE,TOPEXT,CPCTR,DBKP,PCTRL3,MWAITX,ITSC,FSGSBASE,BMI1,AVX2,SMEP,BMI2,ERMS,INVPCID,PQM,RDSEED,ADX,SMAP,CLFLUSHOPT,CLWB,SHA,UMIP,PKU,IBPB,IBRS,STIBP,SSBD,XSAVEOPT,XSAVEC,XGETBV1,XSAVES
cpu2: 32KB 64b/line 8-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 8-way L2 cache
cpu2: ITLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu2: DTLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu2: smt 0, core 2, package 0
cpu3 at mainbus0: apid 6 (application processor)
cpu3: AMD Ryzen 5 5600G with Radeon Graphics, 3892.69 MHz, 19-50-00
cpu3: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,PCLMUL,MWAIT,SSSE3,FMA3,CX16,SSE4.1,SSE4.2,MOVBE,POPCNT,AES,XSAVE,AVX,F16C,RDRAND,NXE,MMXX,FFXSR,PAGE1GB,RDTSCP,LONG,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,ABM,SSE4A,MASSE,3DNOWP,OSVW,IBS,SKINIT,TCE,TOPEXT,CPCTR,DBKP,PCTRL3,MWAITX,ITSC,FSGSBASE,BMI1,AVX2,SMEP,BMI2,ERMS,INVPCID,PQM,RDSEED,ADX,SMAP,CLFLUSHOPT,CLWB,SHA,UMIP,PKU,IBPB,IBRS,STIBP,SSBD,XSAVEOPT,XSAVEC,XGETBV1,XSAVES
cpu3: 32KB 64b/line 8-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 8-way L2 cache
cpu3: ITLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu3: DTLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu3: smt 0, core 3, package 0
cpu4 at mainbus0: apid 8 (application processor)
cpu4: AMD Ryzen 5 5600G with Radeon Graphics, 3892.69 MHz, 19-50-00
cpu4: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,PCLMUL,MWAIT,SSSE3,FMA3,CX16,SSE4.1,SSE4.2,MOVBE,POPCNT,AES,XSAVE,AVX,F16C,RDRAND,NXE,MMXX,FFXSR,PAGE1GB,RDTSCP,LONG,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,ABM,SSE4A,MASSE,3DNOWP,OSVW,IBS,SKINIT,TCE,TOPEXT,CPCTR,DBKP,PCTRL3,MWAITX,ITSC,FSGSBASE,BMI1,AVX2,SMEP,BMI2,ERMS,INVPCID,PQM,RDSEED,ADX,SMAP,CLFLUSHOPT,CLWB,SHA,UMIP,PKU,IBPB,IBRS,STIBP,SSBD,XSAVEOPT,XSAVEC,XGETBV1,XSAVES
cpu4: 32KB 64b/line 8-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 8-way L2 cache
cpu4: ITLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu4: DTLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu4: smt 0, core 4, package 0
cpu5 at mainbus0: apid 10 (application processor)
cpu5: AMD Ryzen 5 5600G with Radeon Graphics, 3892.69 MHz, 19-50-00
cpu5: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,PCLMUL,MWAIT,SSSE3,FMA3,CX16,SSE4.1,SSE4.2,MOVBE,POPCNT,AES,XSAVE,AVX,F16C,RDRAND,NXE,MMXX,FFXSR,PAGE1GB,RDTSCP,LONG,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,ABM,SSE4A,MASSE,3DNOWP,OSVW,IBS,SKINIT,TCE,TOPEXT,CPCTR,DBKP,PCTRL3,MWAITX,ITSC,FSGSBASE,BMI1,AVX2,SMEP,BMI2,ERMS,INVPCID,PQM,RDSEED,ADX,SMAP,CLFLUSHOPT,CLWB,SHA,UMIP,PKU,IBPB,IBRS,STIBP,SSBD,XSAVEOPT,XSAVEC,XGETBV1,XSAVES
cpu5: 32KB 64b/line 8-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 8-way L2 cache
cpu5: ITLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu5: DTLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu5: smt 0, core 5, package 0
cpu6 at mainbus0: apid 1 (application processor)
cpu6: AMD Ryzen 5 5600G with Radeon Graphics, 3892.69 MHz, 19-50-00
cpu6: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,PCLMUL,MWAIT,SSSE3,FMA3,CX16,SSE4.1,SSE4.2,MOVBE,POPCNT,AES,XSAVE,AVX,F16C,RDRAND,NXE,MMXX,FFXSR,PAGE1GB,RDTSCP,LONG,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,ABM,SSE4A,MASSE,3DNOWP,OSVW,IBS,SKINIT,TCE,TOPEXT,CPCTR,DBKP,PCTRL3,MWAITX,ITSC,FSGSBASE,BMI1,AVX2,SMEP,BMI2,ERMS,INVPCID,PQM,RDSEED,ADX,SMAP,CLFLUSHOPT,CLWB,SHA,UMIP,PKU,IBPB,IBRS,STIBP,SSBD,XSAVEOPT,XSAVEC,XGETBV1,XSAVES
cpu6: 32KB 64b/line 8-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 8-way L2 cache
cpu6: ITLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu6: DTLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu6: smt 1, core 0, package 0
cpu7 at mainbus0: apid 3 (application processor)
cpu7: AMD Ryzen 5 5600G with Radeon Graphics, 3892.69 MHz, 19-50-00
cpu7: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,PCLMUL,MWAIT,SSSE3,FMA3,CX16,SSE4.1,SSE4.2,MOVBE,POPCNT,AES,XSAVE,AVX,F16C,RDRAND,NXE,MMXX,FFXSR,PAGE1GB,RDTSCP,LONG,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,ABM,SSE4A,MASSE,3DNOWP,OSVW,IBS,SKINIT,TCE,TOPEXT,CPCTR,DBKP,PCTRL3,MWAITX,ITSC,FSGSBASE,BMI1,AVX2,SMEP,BMI2,ERMS,INVPCID,PQM,RDSEED,ADX,SMAP,CLFLUSHOPT,CLWB,SHA,UMIP,PKU,IBPB,IBRS,STIBP,SSBD,XSAVEOPT,XSAVEC,XGETBV1,XSAVES
cpu7: 32KB 64b/line 8-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 8-way L2 cache
cpu7: ITLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu7: DTLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu7: smt 1, core 1, package 0
cpu8 at mainbus0: apid 5 (application processor)
cpu8: AMD Ryzen 5 5600G with Radeon Graphics, 3892.69 MHz, 19-50-00
cpu8: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,PCLMUL,MWAIT,SSSE3,FMA3,CX16,SSE4.1,SSE4.2,MOVBE,POPCNT,AES,XSAVE,AVX,F16C,RDRAND,NXE,MMXX,FFXSR,PAGE1GB,RDTSCP,LONG,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,ABM,SSE4A,MASSE,3DNOWP,OSVW,IBS,SKINIT,TCE,TOPEXT,CPCTR,DBKP,PCTRL3,MWAITX,ITSC,FSGSBASE,BMI1,AVX2,SMEP,BMI2,ERMS,INVPCID,PQM,RDSEED,ADX,SMAP,CLFLUSHOPT,CLWB,SHA,UMIP,PKU,IBPB,IBRS,STIBP,SSBD,XSAVEOPT,XSAVEC,XGETBV1,XSAVES
cpu8: 32KB 64b/line 8-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 8-way L2 cache
cpu8: ITLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu8: DTLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu8: smt 1, core 2, package 0
cpu9 at mainbus0: apid 7 (application processor)
cpu9: AMD Ryzen 5 5600G with Radeon Graphics, 3892.69 MHz, 19-50-00
cpu9: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,PCLMUL,MWAIT,SSSE3,FMA3,CX16,SSE4.1,SSE4.2,MOVBE,POPCNT,AES,XSAVE,AVX,F16C,RDRAND,NXE,MMXX,FFXSR,PAGE1GB,RDTSCP,LONG,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,ABM,SSE4A,MASSE,3DNOWP,OSVW,IBS,SKINIT,TCE,TOPEXT,CPCTR,DBKP,PCTRL3,MWAITX,ITSC,FSGSBASE,BMI1,AVX2,SMEP,BMI2,ERMS,INVPCID,PQM,RDSEED,ADX,SMAP,CLFLUSHOPT,CLWB,SHA,UMIP,PKU,IBPB,IBRS,STIBP,SSBD,XSAVEOPT,XSAVEC,XGETBV1,XSAVES
cpu9: 32KB 64b/line 8-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 8-way L2 cache
cpu9: ITLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu9: DTLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu9: smt 1, core 3, package 0
cpu10 at mainbus0: apid 9 (application processor)
cpu10: AMD Ryzen 5 5600G with Radeon Graphics, 3892.69 MHz, 19-50-00
cpu10: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,PCLMUL,MWAIT,SSSE3,FMA3,CX16,SSE4.1,SSE4.2,MOVBE,POPCNT,AES,XSAVE,AVX,F16C,RDRAND,NXE,MMXX,FFXSR,PAGE1GB,RDTSCP,LONG,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,ABM,SSE4A,MASSE,3DNOWP,OSVW,IBS,SKINIT,TCE,TOPEXT,CPCTR,DBKP,PCTRL3,MWAITX,ITSC,FSGSBASE,BMI1,AVX2,SMEP,BMI2,ERMS,INVPCID,PQM,RDSEED,ADX,SMAP,CLFLUSHOPT,CLWB,SHA,UMIP,PKU,IBPB,IBRS,STIBP,SSBD,XSAVEOPT,XSAVEC,XGETBV1,XSAVES
cpu10: 32KB 64b/line 8-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 8-way L2 cache
cpu10: ITLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu10: DTLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu10: smt 1, core 4, package 0
cpu11 at mainbus0: apid 11 (application processor)
cpu11: AMD Ryzen 5 5600G with Radeon Graphics, 3892.69 MHz, 19-50-00
cpu11: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,PCLMUL,MWAIT,SSSE3,FMA3,CX16,SSE4.1,SSE4.2,MOVBE,POPCNT,AES,XSAVE,AVX,F16C,RDRAND,NXE,MMXX,FFXSR,PAGE1GB,RDTSCP,LONG,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,ABM,SSE4A,MASSE,3DNOWP,OSVW,IBS,SKINIT,TCE,TOPEXT,CPCTR,DBKP,PCTRL3,MWAITX,ITSC,FSGSBASE,BMI1,AVX2,SMEP,BMI2,ERMS,INVPCID,PQM,RDSEED,ADX,SMAP,CLFLUSHOPT,CLWB,SHA,UMIP,PKU,IBPB,IBRS,STIBP,SSBD,XSAVEOPT,XSAVEC,XGETBV1,XSAVES
cpu11: 32KB 64b/line 8-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 8-way L2 cache
cpu11: ITLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu11: DTLB 64 4KB entries fully associative, 64 4MB entries fully associative
cpu11: smt 1, core 5, package 0
ioapic0 at mainbus0: apid 13 pa 0xfec00000, version 21, 24 pins
ioapic1 at mainbus0: apid 14 pa 0xfec01000, version 21, 32 pins
acpiprt0 at acpi0: bus 0 (PCI0)
acpiprt1 at acpi0: bus -1 (GPP6)
acpiprt2 at acpi0: bus -1 (GPP7)
acpiprt3 at acpi0: bus -1 (GPP8)
acpiprt4 at acpi0: bus -1 (GPP9)
acpiprt5 at acpi0: bus 8 (GP17)
acpiprt6 at acpi0: bus -1 (GPP0)
acpiprt7 at acpi0: bus -1 (GP18)
acpiprt8 at acpi0: bus 7 (GPP4)
acpiprt9 at acpi0: bus -1 (GPP5)
acpiprt10 at acpi0: bus 1 (GPP3)
acpipci0 at acpi0 PCI0: 0x00000010 0x00000011 0x00000000
acpicmos0 at acpi0
acpibtn0 at acpi0: PWRB
amdgpio0 at acpi0 GPIO uid 0 addr 0xfed81500/0x400 irq 7, 184 pins
tpm0 at acpi0 TPM_: unsupported TPM2 start method
"ACPI0010" at acpi0 not configured
acpicpu0 at acpi0: C3(0@350 io@0x415), C2(0@18 io@0x414), C1(0@1 mwait), PSS
acpicpu1 at acpi0: C3(0@350 io@0x415), C2(0@18 io@0x414), C1(0@1 mwait), PSS
acpicpu2 at acpi0: C3(0@350 io@0x415), C2(0@18 io@0x414), C1(0@1 mwait), PSS
acpicpu3 at acpi0: C3(0@350 io@0x415), C2(0@18 io@0x414), C1(0@1 mwait), PSS
acpicpu4 at acpi0: C3(0@350 io@0x415), C2(0@18 io@0x414), C1(0@1 mwait), PSS
acpicpu5 at acpi0: C3(0@350 io@0x415), C2(0@18 io@0x414), C1(0@1 mwait), PSS
acpicpu6 at acpi0: C3(0@350 io@0x415), C2(0@18 io@0x414), C1(0@1 mwait), PSS
acpicpu7 at acpi0: C3(0@350 io@0x415), C2(0@18 io@0x414), C1(0@1 mwait), PSS
acpicpu8 at acpi0: C3(0@350 io@0x415), C2(0@18 io@0x414), C1(0@1 mwait), PSS
acpicpu9 at acpi0: C3(0@350 io@0x415), C2(0@18 io@0x414), C1(0@1 mwait), PSS
acpicpu10 at acpi0: C3(0@350 io@0x415), C2(0@18 io@0x414), C1(0@1 mwait), PSS
acpicpu11 at acpi0: C3(0@350 io@0x415), C2(0@18 io@0x414), C1(0@1 mwait), PSS
"AMDIF030" at acpi0 not configured
"PNP0C14" at acpi0 not configured
"PNP0C14" at acpi0 not configured
"PNP0C14" at acpi0 not configured
"PNP0C14" at acpi0 not configured
"PNP0C14" at acpi0 not configured
cpu0: 3893 MHz: speeds: 3900 1700 1400 MHz
pci0 at mainbus0 bus 0
ksmn0 at pci0 dev 0 function 0 "AMD 17h/6xh Root Complex" rev 0x00
"AMD 17h/6xh IOMMU" rev 0x00 at pci0 dev 0 function 2 not configured
pchb0 at pci0 dev 1 function 0 "AMD 17h/6xh Host" rev 0x00
pchb1 at pci0 dev 2 function 0 "AMD 17h/6xh Host" rev 0x00
ppb0 at pci0 dev 2 function 1 "AMD 17h/6xh PCIE" rev 0x00: msi
pci1 at ppb0 bus 1
xhci0 at pci1 dev 0 function 0 "AMD 500 Series xHCI" rev 0x00: msi, xHCI 1.10
usb0 at xhci0: USB revision 3.0
uhub0 at usb0 configuration 1 interface 0 "AMD xHCI root hub" rev 3.00/1.00 addr 1
ahci0 at pci1 dev 0 function 1 "AMD 500 Series AHCI" rev 0x00: msi, AHCI 1.3.1
ahci0: port busy after first PMP probe FIS
ahci0: port busy after first PMP probe FIS
ahci0: port 1: 6.0Gb/s
scsibus1 at ahci0: 32 targets
sd0 at scsibus1 targ 1 lun 0: naa.5002538fc16090b3
sd0: 953869MB, 512 bytes/sector, 1953525168 sectors, thin
ppb1 at pci1 dev 0 function 2 "AMD 500 Series PCIE" rev 0x00
pci2 at ppb1 bus 2
ppb2 at pci2 dev 0 function 0 "AMD 500 Series PCIE" rev 0x00: msi
pci3 at ppb2 bus 3
ppb3 at pci2 dev 4 function 0 "AMD 500 Series PCIE" rev 0x00: msi
pci4 at ppb3 bus 4
nvme0 at pci4 dev 0 function 0 "SanDisk WD Black NVMe" rev 0x00: msix, NVMe 1.3
nvme0: WDBRPG0010BNC-WRSN, firmware 111130WD, serial 213733803989
scsibus2 at nvme0: 2 targets, initiator 0
sd1 at scsibus2 targ 1 lun 0:
sd1: 953869MB, 512 bytes/sector, 1953525168 sectors
ppb4 at pci2 dev 8 function 0 "AMD 500 Series PCIE" rev 0x00: msi
pci5 at ppb4 bus 5
ppb5 at pci2 dev 9 function 0 "AMD 500 Series PCIE" rev 0x00: msi
pci6 at ppb5 bus 6
igc0 at pci6 dev 0 function 0 "Intel I225-V" rev 0x03, msix, 4 queues, address 7c:10:c9:45:b2:d1
ppb6 at pci0 dev 2 function 2 "AMD 17h/6xh PCIE" rev 0x00: msi
pci7 at ppb6 bus 7
nvme1 at pci7 dev 0 function 0 "SanDisk WD Black NVMe" rev 0x00: msix, NVMe 1.3
nvme1: WDBRPG0010BNC-WRSN, firmware 111130WD, serial 213733806541
scsibus3 at nvme1: 2 targets, initiator 0
sd2 at scsibus3 targ 1 lun 0:
sd2: 953869MB, 512 bytes/sector, 1953525168 sectors
pchb2 at pci0 dev 8 function 0 "AMD 17h/6xh Host" rev 0x00
ppb7 at pci0 dev 8 function 1 "AMD 17h/6xh PCIE" rev 0x00
pci8 at ppb7 bus 8
amdgpu0 at pci8 dev 0 function 0 "ATI Cezanne" rev 0xc9
drm0 at amdgpu0
amdgpu0: msi
azalia0 at pci8 dev 0 function 1 "ATI Renoir HD Audio" rev 0x00: msi
azalia0: no supported codecs
ccp0 at pci8 dev 0 function 2 "AMD 17h/1xh Crypto" rev 0x00
xhci1 at pci8 dev 0 function 3 "AMD 17h/6xh xHCI" rev 0x00: msi, xHCI 1.10
usb1 at xhci1: USB revision 3.0
uhub1 at usb1 configuration 1 interface 0 "AMD xHCI root hub" rev 3.00/1.00 addr 1
xhci2 at pci8 dev 0 function 4 "AMD 17h/6xh xHCI" rev 0x00: msi, xHCI 1.10
usb2 at xhci2: USB revision 3.0
uhub2 at usb2 configuration 1 interface 0 "AMD xHCI root hub" rev 3.00/1.00 addr 1
azalia1 at pci8 dev 0 function 6 "AMD 17h/1xh HD Audio" rev 0x00: apic 14 int 12
azalia1: codecs: Realtek ALC1220
audio0 at azalia1
piixpm0 at pci0 dev 20 function 0 "AMD FCH SMBus" rev 0x51: polling
iic0 at piixpm0
iic1 at piixpm0
pcib0 at pci0 dev 20 function 3 "AMD FCH LPC" rev 0x51
pchb3 at pci0 dev 24 function 0 "AMD 19h/5xh Data Fabric" rev 0x00
pchb4 at pci0 dev 24 function 1 "AMD 19h/5xh Data Fabric" rev 0x00
pchb5 at pci0 dev 24 function 2 "AMD 19h/5xh Data Fabric" rev 0x00
pchb6 at pci0 dev 24 function 3 "AMD 19h/5xh Data Fabric" rev 0x00
pchb7 at pci0 dev 24 function 4 "AMD 19h/5xh Data Fabric" rev 0x00
pchb8 at pci0 dev 24 function 5 "AMD 19h/5xh Data Fabric" rev 0x00
pchb9 at pci0 dev 24 function 6 "AMD 19h/5xh Data Fabric" rev 0x00
pchb10 at pci0 dev 24 function 7 "AMD 19h/5xh Data Fabric" rev 0x00
isa0 at pcib0
isadma0 at isa0
com0 at isa0 port 0x3f8/8 irq 4: ns16550a, 16 byte fifo
pckbc0 at isa0 port 0x60/5 irq 1 irq 12
pckbd0 at pckbc0 (kbd slot)
wskbd0 at pckbd0: console keyboard
pcppi0 at isa0 port 0x61
spkr0 at pcppi0
efifb at mainbus0 not configured
dt: 451 probes
uhidev0 at uhub0 port 10 configuration 1 interface 2 "AsusTek Computer Inc. AURA LED Controller" rev 2.00/1.00 addr 2
uhidev0: iclass 3/0, 236 report ids
uhid0 at uhidev0 reportid 236: input=64, output=64, feature=0
ugen0 at uhub0 port 10 configuration 1 "AsusTek Computer Inc. AURA LED Controller" rev 2.00/1.00 addr 2
uhub3 at uhub0 port 11 configuration 1 interface 0 "Genesys Logic USB2.0 Hub" rev 2.00/60.90 addr 3
uhidev1 at uhub0 port 13 configuration 1 interface 0 "Unicomp Endura Pro Keyboard" rev 1.10/43.34 addr 4
uhidev1: iclass 3/1
ukbd0 at uhidev1: 8 variable keys, 6 key codes
wskbd1 at ukbd0 mux 1
uhidev2 at uhub0 port 13 configuration 1 interface 1 "Unicomp Endura Pro Keyboard" rev 1.10/43.34 addr 4
uhidev2: iclass 3/1, 3 report ids
ums0 at uhidev2 reportid 1: 3 buttons, Z dir
wsmouse0 at ums0 mux 0
ucc0 at uhidev2 reportid 2: 573 usages, 18 keys, array
wskbd2 at ucc0 mux 1
uhid1 at uhidev2 reportid 3: input=1, output=0, feature=0
ugen1 at uhub1 port 2 "Realtek USB3.0 802.11ac 1200M Adapter" rev 2.10/2.10 addr 2
urtwn0 at uhub2 port 2 configuration 1 interface 0 "Realtek 802.11n NIC" rev 2.10/2.00 addr 2
urtwn0: MAC/BB RTL8192EU, RF 6052 2T2R, address 98:de:d0:0f:c9:62
vscsi0 at root
scsibus4 at vscsi0: 256 targets
softraid0 at root
scsibus5 at softraid0: 256 targets
root on sd0a (d25c4224901b9485.a) swap on sd0b dump on sd0b
[drm] *ERROR* sdma_v4_0: Failed to load firmware "amdgpu/green_sardine_sdma.bin"
[drm] *ERROR* Failed to load sdma firmware!
drm:pid0:psp_init_asd_microcode *ERROR* fail to initialize asd microcode
[drm] *ERROR* Failed to load psp firmware!
[drm] *ERROR* sw_init of IP block failed -2
drm:pid0:amdgpu_device_init *ERROR* amdgpu_device_ip_init failed
drm:pid0:amdgpu_attachhook *ERROR* Fatal error during GPU init
efifb0 at mainbus0: 1920x1080, 32bpp
wsdisplay0 at efifb0 mux 1: console (std, vt100 emulation), using wskbd0
wskbd1: connecting to wsdisplay0
wskbd2: connecting to wsdisplay0
wsdisplay0: screen 1-5 added (std, vt100 emulation)

Dang, that’s a whole mess of CPUs. Maybe I should have replaced my desktop earlier?

Pretty sure this will spark questions, so:

  • Yes, I’m writing an OpenBSD storage book next.
  • No, I have no date on its release, or on a release of a third edition of Absolute OpenBSD.
  • Sponsorships will open once I ship the DNSSEC sponsor gifts.
  • No, I don’t have a hashtag yet.
  • I have no answer to any questions about any related topics.

Thank you for understanding.

640% Kickstarter, Sponsorships, and Shipping

In forty-eight hours, my experimental Kickstarter funded six hundred and forty percent.

Those of you who told me so, may now commence declaring that you told me so.

I am considering using Kickstarter for future books, in combination with my sponsorship program. (Sponsors pay me while I’m still writing the book.) The sponsor program will never go away, mind you. My end goal is reader disintermediation; I want folks coming directly to me for their books, instead of buying through Amazon or whoever. Sponsorship is the culmination of disintermediation. But sponsorship is for dedicated readers, while Kickstarter attracts casual ones. I’m thinking that I’ll use sponsorship to pay bills as I write, while Kickstarter will pay the bills of publishing. I’ll have to figure out how to make any sponsor books more precious than the Kickstarter ones, though. Maybe a special SPONSOR EDITION note on the cover.

One wrinkle with Kickstarter that’s raised a bunch of questions, though, is shipping. Overseas shipping costs are EXPENSIVE. They are set by my experience with sponsor gifts.

When it comes to shipping books internationally, the US post office provides three options.

  1. Media Mail. I can get it just about anywhere in the world for less than $10. No international tracking. No guarantee of delivery. Might take months or years. Those container ships moored outside every port in the world, waiting months for an opportunity to unload? There are Media Mail packages adrift in every one.
  2. First class mail. Costs $25 +/- $5-ish. Delivery guaranteed, eventually. Might take months. I can complain to the post office, and they’ll fill out a form. What they’ll do with that form is another issue.
  3. International Priority Mail. Costs about $40 ($30 to Canada). Ouch. Delivers within a week or two, sort of guaranteed. Insured. Complaints are taken mostly seriously.

I normally use First Class mail.

Ever since the pandemic started, sponsor gifts anywhere outside the USA keep going astray. Thanks to the tracking number I am able to watch packages bounce between, say, Chicago and London, England. I don’t know if the actual package keeps circling or if the computer is confused, but either way the sponsor does not get their gift. This is unacceptable. If some maniac generous soul puts food on my table as I write the book, my ethics declare that I must get their thank-you gift to them. Asking the post office staff for a better solution gets me the same answer every time: Use International Priority Mail.

Delivery failures are not my fault, but they are my responsibility. Here in the USA, a backer with a tracking number can contact the Post Office themselves. That’s not an option for a backer in Farawayistan. I must be able to investigate and resolve problems. That means tracking. I elected to go with Priority Mail all around this time, so that any complaints merit more than a tally in a database.

I would prefer to offer backers shipping options like “Would you like cheap ‘I promise to ship it, good luck getting it and I can’t help you’ or expensive ‘will arrive ASAP’?” Kickstarter does not offer that flexibility.

When I offer OpenBSD Storage Mastery for sponsorship, I will offer that choice. Sponsors already accept some risk–if I drop dead while writing the book, they’re out of luck. 1 Some of them will choose the cheap mail, probably the same people who tell me not to ship them a gift.

“Domesticate Your Badgers” Kickstarter Opens

My first ever Kickstarter crashed past its first stretch goal in three hours.

I think nonfiction books should be written by people who have done the thing. If you write a book about systems administration, you ought to have been a working sysadmin for years. If you write a book about rats, you better spend quantity time with the squeaky little bastards. If you write a book about martial arts, you better have been a serious student for decades. That’s why I don’t write a book about, say, devops. The book would make me a heap of money, at the expense of my reputation and integrity. Friends know better than to get me started about how-to books written by dilettantes, because the rant can go on for hours.

Well, minutes. But they feel like hours.

Similarly, someone who writes a book about the long game of writing, how to establish your writing skills, and how to build a long-term writing career, had better have written a heap of books that got published. Sadly, that person is now me.

Last year, I figured out something unique to say about the craft of writing. This year, I wrote Domesticate Your Badgers: Become a Better Writer through Deliberate Practice.

Every time I publish a book, I run an experiment or test. Most of these experiments are invisible, and of no interest to anyone except publishing nerds. This time, I’m experimenting with Kickstarter. Other writers have success launching books there, so I’ll try it. If it’s successful, I might add Kickstarter options to my other books. My goal is still reader disintermediation, but sponsorships target existing hard-core fans and Kickstarter is about more casual fans and attracting new readers.

The stretch goal format also lets me play with my expenses. I’d like to illustrate the interior, because badgers, but are people willing to pay for it? Is including a Foreword written by an enemy (a “Foeword”) as funny as I think it is? Dunno. People will tell me, though, and as they’re speaking with their wallets they will tell the truth.

And I learned how to glue snippets together to create more complicated videos. I have no idea what I’ll do with this skill. Probably something ill-advised.

If you have any interest in how I not only write books, but keep writing books, I wrote it all down. Take a look.

New time travel short story escaped, new Kickstarter approaching

In the aftermath of getting DNSSEC Mastery to tech review and getting my first ever Kickstarter ready to launch, I went in search of easy dopamine. I have maybe forty-odd short stories ready to publish, so I seized the one on top of the heap and flung it out into the cold hard world.

My tale Drag Air Through Fire is now available at all fine bookstores. Supply chain problems have made the paper chapbook stupid expensive, so I solidly recommend the ebook.

She isn’t dead.
He just hasn’t saved her yet.

He invented new kinds of math, new engineering, new science. His colleagues and friends failed to stop him. He surrendered everything for last one chance to rescue his love.

The chances of a new Big Bang? Acceptable.

Originally appeared in “Boundary Shock Quarterly: What Might Have Been”

And oh yeah, I’m trying Kickstarter. After 45 books and uncounted other stuff, I’ve finally written something on how to write. You can’t back it yet, but you can tell Kickstarter to poke you when you can. I’ll post Monday when it opens.

October 2021’s Bipolar Updates

This business is enough to make you bipolar.

Yesterday, someone went out of their way to inform me that while the technical content in TLS Mastery was impeccable, the book was not as funny as my other tech books. If any other author had written this book they would give it five stars, but on the Lucas Scale it rated only four.

First: it is very true that writers rely on reviews for their business. I appreciate reviews posted anywhere, for any reason, of any rating. I explicitly don’t want to know about them, however. It’s number five in the beginning of my FAQ.

Second: When you encounter a book that weirdly lacks some of the author’s usual glee, check the publication date. Any book written in 2020 is not going to have the usual bonfire of delight. We were lucky to strike even a spark.

I started writing TLS on 5 May 2020, as we were realizing exactly how awful the pandemic would be. I finished the first draft on 1 March 2021, when vaccines were an exotic treasure limited to health care workers. My wife is a nurse. We lost colleagues and family members to covid. It was not a good year. The mortgage waits for no writer, though.

Thinking I’ll use Camus’ “The Plague” as a motif for the OpenBSD storage book.

Also yesterday, I got copies of two new anthologies I’m in: Fantastic Christmas and Mysterious Christmas, both edited by Kristine Kathryn Rusch. She has won so many dang awards for writing and editing that she uses the heavier ones as doorstops. (Truth.) While it’s horrid form to quote from one’s own reviews, quoting what an anthology editor says about your story is merely gauche and I’m all about gauche. The editor’s intro to my story in Fantastic Christmas says:

The reason I decided to lead with “The Last Hour of Hogswatch,” though, is that it is one of the best stories I’ve read all year, if not one of the best I’ve read in the past several years.

Both of these, on the same day.

I probably should see a physical therapist about that whiplash.

In other news: DNSSEC Mastery 2/e is now at the technical review. It uses BIND as the reference implementation, but it’s less BIND-centric than the first edition. If you’re a DNSSEC expert and want to tech review, drop me a note. Tech reviews are due 8 November. It’s only 35,000 words, so a smaller book. I’ll be on OpenBSD Storage Mastery next. Sponsorships for that will open when I ship the DNSSEC sponsors their gifts.

Here’s the current 2020 books. I suspect this will be it for the year, but one of the things currently cooking might sneak out before the end of the year.

The question you’re all dying to ask, I’m sure, is: does this make the total stack taller than me? I don’t think so. Maybe next year. But publishing eight and a half inches in a year isn’t bad.