URLs du Jour


  • It only hurts if you think about it. J.D. Tuccille provides a reminder: Tax Day Is Here, Because Government Bungling Won’t Pay for Itself.

    Well, actually, that's two reminders.

    In recent weeks, the Centers for Disease Control and Prevention (CDC) conceded that, perhaps, the agency really sucks at performing its assigned tasks and should reevaluate how it does things; a federal jury told off the Federal Bureau of Investigation (FBI) for entrapping a handful of dummies into a high-profile political kidnapping plot; and several of the federal government's own economists placed the blame for soaring prices on runaway government spending. That's some impressive governance, for a certain value of "impressive," and it certainly doesn't come cheap. In fact, on this Tax Day, some of us might be forgiven for wishing we could skip not just the tab, but also the services for which it's supposed to pay.

    It's no joke that government doesn't come cheap. In revisiting its federal spending and revenue forecasts for 2021, the Congressional Budget Office conceded in January that its "projection of $3.43 trillion for federal revenues in 2021 was too low—by $614 billion" and its "projection of $7.07 trillion for federal outlays in 2021 was too high—by $250 billion." Not that taking in more money than anticipated and spending a bit less means the feds balanced their books. No, not even close. In the end, the feds spent "only" $2.78 trillion more than they collected. And they do that every year, so it adds up.

    Also the Red Sox lost badly today. Sigh.

  • To repeat: abolish the FDA. OK, their bungling bureaucracy might have helped kill thousands of Americans during the pandemic, but they at least keep our food safe, right?

    Well, Baylen Linnekin offers some disillusionment: New Investigation Finds FDA's Food Safety Division Is 'Broken'.

    Last week, Politico published the results of an in-depth, months-long investigation into the Food and Drug Administration's (FDA) regulation of our nation's food supply. The findings? The agency "is failing to meet American consumers' expectations on food safety and nutrition."

    The Politico investigation, which focuses chiefly on food safety, nutrition, and structural issues within FDA, includes interviews with dozens of current and former senior FDA officials, industry representatives, members of Congress, and trade groups—all of them familiar with the inner workings of the FDA. Those who spoke with Politico for the investigation characterized the agency's regulation of the food supply invariably as "ridiculous," "impossible," "broken," "byzantine" and "a joke." The piece notes even many agency supporters are now "questioning whether the agency is making the best use of its roughly $1 billion food budget," pointing out that even though around two-thirds of that budget goes to pay for food safety inspections, "the number of food safety inspections performed each year has been going down despite increased resources." Such complaints about the FDA—that the agency consistently does less with more—have been at the heart of my own criticisms of the agency over the years.

    Unfortunately, statists will have a ready comeback: "This goes to show they need more money and power to do their job."

  • Uff da! Lee Edwards describes a Scandinavian myth that doesn't involve Thor, Yggdrasil, etc.: The Myth of Scandinavian Socialism.

    When the U.N. released its latest index of “happiest countries,” it probably came as no surprise to Bernie Sanders and Alexandria Ocasio-Cortez that all of the Scandinavian countries finished in the top ten. They often cite them as models for their far-left policy prescriptions.

    Sanders doesn’t point to China, Cuba, or Venezuela when pushing his vision for America, but to Denmark. Surveying its spacious safety net and liberal benefits such as free education and universal health care, the socialist senator says enthusiastically, “We can learn a lot from Denmark.”

    Ocasio-Cortez agrees. As the unofficial head of the House’s Progressive Caucus, explains: “My policies most closely resemble what we see . . . in Norway, in Finland, in Sweden.”

    Sanders, AOC, and their socialist cohorts laud the Nordic model (comprising Denmark, Sweden, Norway, and Finland) for its supposed management of the market, draconian taxes on the rich, and cradle-to-grave welfare system. Polls show that a large number of Americans, especially those under 30, would welcome the Nordic way.

    But there is a problem: Scandinavian “socialism” does not exist, except in the Marxian imagination of radical progressives. It is a chimera wrapped in an illusion inside a dream.

    Edwards' thesis might be familiar to many: the Scandinavian countries are pretty free-market. They have massive welfare programs, but those are financed with massive taxes.

  • But that would risk those pushing-granny-off-a-cliff ads again. The wonderful Jane Galt (aka Megan McArdle—I knew her when) has advice: Republicans are on track to regain power. They should decide what to do with it..

    All signs portend a historic Democratic wipeout in the midterms, and if things don’t change, a Republican presidency in 2024. Many analysts fret that Democrats are sleepwalking into disaster. They’re not wrong to worry, but at this point I’m more worried that Republicans are sleepwalking into success.

    Let’s say the GOP manages to hit the trifecta: control of the presidency and both houses of Congress. What, exactly, is it planning to do with all that power?

    Currently, the entire Republican agenda seems to consist of complaining about moderation policies at Twitter and Facebook and trying to curb perceived radicalism on race and gender in the nation’s schools. In fairness, the best case for this narrow focus is that it gets results at the ballot box.

    I'm pretty sure that success at the ballot box is all they want at this point.

  • Kafka traps: much more literate than Catch-22's. Julian Adorney writes on White Fragility: Unpacking the Kafka Traps of Robin DiAngelo's NYT Bestseller. Specifically, under DiAngelo's rules, white people have no way to refute or otherwise defend themselves an incoming charge of "racisim".

    If you're accused of racism, under DiAngelo's approach, even asking a third party to weigh in is considered unacceptable. DiAngelo says that sometimes, if someone calls her a racist, she's tempted to ask another person of color for their perspective. But she dismisses this urge as "inappropriate" and something that "upholds racism."

    Even weirder, for DiAngelo, denial of the accusation of racism is proof of your racism. In a telling passage, DiAngelo talks about, "white people who think they are not racist, or are less racist, or are in the 'choir' or already 'get it'." Those people, she asserts, "cause the most daily damage to people of color."

    That is: if you deny that you are racist, you are part of the group that (according to DiAngelo) does more actual damage to people of color than the KKK.

    This is a logical fallacy known as a Kafka trap. A Kafka trap is when someone is accused of something, and if they defend themselves then it's considered proof of their guilt.

    I'm glad Adorney read her book so I don't have to.

My Book Picker (and Lister)

2022 Version



This blogpost describes the most recent version of my "book picking" system. It assumes a Linux operating system, and uses Perl. Some "extra" Perl modules are used, not in the core Perl distribution: Const::Fast, version, and HTML::Template. (My current distribution, Fedora, makes installing these modules pretty easy. Your mileage… etc.) Files are available at GitHub.

I've used this system for a number of years, and have tweaked it significantly over that period.

But one thing hasn't changed at all: it's another example of the mental aberration that causes me to write Perl scripts to solve life's little everyday irritants. In this case two little irritants:

  1. I noticed that I had a lot of books on my shelves, acquired long past, that I never got around to reading. Either because (a) they were dauntingly long and dense (I'm thinking about Infinite Jest by David Foster Wallace); or because (b) they just fell through the cracks. Both poor excuses, but there you are.

  2. I sometimes want to methodically read (or reread) a series of books in a particular order.

In other words, I needed a way to bring diligence and organization to my previous chaotic and sloppy reading habits.

I think of what I came up with as the "To-Be-Read" (hereafter TBR) database. That's a slightly lofty title, but anyway:

High-Level View

All the TBR books are in zero or more stacks, each stack containing zero or more titles. Each stack contains a list of books in maintained in the order I want to read them. (This goes back to the issue mentioned above: sometimes a series really "should" be read in publishing order, for example C.J. Box's novels featuring protagonist Joe Pickett.)

So picking a book to read involves (a) choosing an "eligible" stack; and (b) "popping" the top book from the chosen stack. Very computer science-y.

The interesting part is the "choosing an eligible stack" step. There are a number of possible ways to do it. But first, more details on "eligibility".

  • "Obviously" you can't pick a book off an empty stack. So a stack with no books in it is ineligible. (Why are there empty stacks? Because I might want to add one or more books to them someday. Like if Steve Hamilton ever writes another book.)
  • The stacks also contain books I don't have yet. I want to read them someday. But I'm waiting. Maybe a book has been announced but not released yet. (Example below.) Or I'm waiting for the price to come down, either via the Barnes & Noble remainder table or the Amazon used market. I'm RetiredOnAFixedIncome, after all. So: If the top book on a stack is unowned, there's no point in picking it. Hence, that stack is ineligible.
  • One final tweak: I found that I didn't want to read a book "too soon" after just reading a previous book in the stack. So each stack has an "age": the time that's elapsed since I previously picked a book from that stack. And a "minimum age", the amount of time that must elapse after a pick before that stack becomes eligible again.

Executive summary: an eligible stack is one that:

  • is non-empty;
  • the top book is owned;
  • the stack is older than its specified minimum age.
OK, so how do we choose among eligible stacks? Possibilities:
  1. Pick the "oldest" stack; the one for which it's been the longest time since a book from it was previously picked.
  2. Pick the highest stack, the one with the most titles therein. (Because it needs the most work, I guess.)
  3. Just pick a stack at random.
  4. Pick a random stack weighted by stack height. That is, any stack can be picked, but one with eight titles in it is twice as likely to be picked as one with four titles. (This was the algorithm used in the previous version.)
  5. Pick a random stack, weighted by age. That is, a stack that's 90 days old is twice as likely to be picked as a 45-day old one.
  6. But what I'm doing is a combination of the last two: the stack-weighting function is the stack height times the stack age. So (for example) a 120-day-old stack with 5 titles is twice as likely to be picked as a 50-day-old stack with 6 titles. Because 120 * 5 = 600 and 50 * 6 = 300. This is totally arbitrary, but it seems to work for me so far.

Now, on to the gory details.

The data file ~/var/bookstacks.pl

Previous versions of the system used CSV files to store all this data. I've switched over to a single file (~/var/bookstacks.pl), containing executable Perl code that is used to initialize an array of hashes named @STACKS. At a high level, it looks like:

         hash elements for stack 0
         hash elements for stack 1
         hash elements for stack N-1

(It Is No Coincidence that this resembles output from the standard Perl Data::Dumper module. See below.)

Each @STACKS array element is a hash. Here's the (actual, as I type) entry for my Michael Connelly stack:

      'name' => 'Michael Connelly',
      'minage' => 30,
      'lastpicked' => '2021-08-21',
      'books' => [
		     'title' => 'The Dark Hours',
		     'author' => 'Michael Connelly',
		     'ASIN' => 'B08WLRG1L2',
		     'owned' => 1
		     'title' => 'Desert Star',
		     'author' => 'Michael Connelly',
		     'ASIN' => 'B09QKSLPN9',
		     'owned' => 0

In words: this @STACKS element contains the stack's name ("Michael Connelly"); the stack's minimum age before becoming eligible (30 days); the date the stack was previously picked (August 21, 2021); and the books currently in the stack. (There are two, The Dark Hours, which I own on Kindle, and Dark Star, not out until November 2022, hence unowned.)

(Yes, that's a subarray of hashes inside the outer array of hashes. Why are you looking at me like that?)

(And no, I haven't memorized the rules about when/whether to use […], {…}, or (…). After decades of Perl coding, I still crack open the Perl Data Structures Cookbook or peruse my existing code where I see if I've done something similar that worked in the past.)

A complete file (my actual version as of April 2022) is here. No comments from the peanut gallery about my lack of literary taste, please.

I named it with a .pl extension because some editors will use that as a hint to do Perl syntax highlighting. It can be read into a script with Perl's do command. For example…


The booklister script (here) is the simplest script in the system. It reads the data file described above and displays its contents in a (slightly) more verbose and readable form. It also prints, for each eligible stack, its weight and pick-probability.

Sample booklister output is here.


The booklister_html script (here) is slightly more complicated. It uses an HTML::Template template to generate an HTML page of the book stacks. It uses text formatting to display stack eligibility/ineligibility, and whether a book is owned or not. Finally, it generates a nice pie chart to display each eligible stack's pick-probabilities, using Google Charts code. It saves the generated page in /tmp/booklist.html; example here.


The bookpicker script (here) simply ("simply") sucks in the bookstacks data, filters out the eligible stacks, then picks one of the eligible stacks at (weighted) random. It "pops" the book at the top of the stack (actually uses a Perl shift, because…). And finally, it writes the modified stack data back out to ~/var/bookstacks.pl, saving the previous version with a .old appended to its name.

(Perl's Data::Dumper module is used for that last part. Some tweaks are used to get it usable for initialization and to get the hash keys to print in a non-random order.)

If you'd like a little more detail on the picking process, you can add the -v (verbose) flag. Speaking of that, a small digression on…

Picking a random stack according to a weighting function

It's not hard. Just imagine throwing a dart at that pie chart mentioned above. Your probability of hitting any one segment is proportional to its area. So…

I'd pseudocode the algorithm like this:

Given: N eligible stacks (indexed 0..N-1), with Wi being the calculated weight of the ith list (assumed integer) …

Let T be the total weight, W0 + W1 + ⋯ + WN-1

Pick a random number r between 0 and T-1.

p = 0
while (r >= Wp)
     r -= Wp

… and on loop exit p will index the list picked.

To anticipate CS pedants: I know this is O(N) and using a binary search instead could make it O(log N). In practice, it's plenty fast enough. And other steps in the process are O(N) anyway.

Editing the stacks, an apology

But what if you want to add a new stack? Or add books to a stack? Or delete something? Or (just generally) change something?

I don't have any handy scripts for that. It's a hard problem. I, personally, just edit ~/var/bookstacks using My Favorite Editor (that would be vim).

I have some ideas for a user-friendlier script. Maybe someday. Now that I've said it, maybe someday soon.


I feel better getting this off my chest..

Last Modified 2022-04-18 10:05 AM EDT