The temperature has just barely gotten above -10°C (14°F) today, with a possibility of more tolerable temperatures by Saturday. Still, the official NWS forecast has us below freezing as far out as it goes; some commercial forecasts hint at, but do not commit to, an above-freezing reading sometime next Friday. We've already had 13 days below freezing; that would make it 21.

Our local television station says it's the coldest back half of January in 63 years. Plus, "the entire eastern two thirds of the U.S. remains firmly in the deep freeze as highs were some 15° to 20° [Fahrenheit, 8° to 12°C] below normal." However, our local PBS station posted a graphic from the National Weather Service showing the possibility of above-freezing temperatures on February 8th, 23 days into the freeze. That's still not as bad as the freeze from 28 December 1976 to 8 February 1977 (43 days), or the runner-up from 15 January to 16 February 1985 (33 days) that also saw the coldest temperature ever recorded here, -33°C (-27°F).

It is sunny, though. I'll give it that. It might not be warm enough to walk Cassie home from day care, however.

Only 29 days of winter left.

I just pushed a minor update to the Daily Parker's blog engine, the thing that you're looking at right now. I fixed a couple of performance bottlenecks, so I hope the experience is a bit faster. (You can always check out the release notes for a summary of what I've done.)

I also checked the app metrics in Azure. Since this runs on Azure hardware, I can see a lot of data about how well it's running, which is how I kept track of the painful senescence of its previous incarnation. Unlike every day with the BlogEngine.NET implementation that I retired two weeks ago, this software has no glaring failures or crashes so far. So while I got it to speed up a little bit in a few places this week, it's not like before when it could take 30-40 seconds for a post to load if more than 100 people tried to read the blog at the same time.

Next up: improvements to the Search by Tag feature, followed by the new privacy levels I've planned for years. That will segue into the first "life event" data type: my reading list. Logged-in users will be able to see most of it; I'll be able to see all of it, plus private notes. I'm starting with that in order to limit the blast radius of any data leaks if I don't get the security right.

Stay tuned.

On 28 January 1986, 40 years ago today, the Space Shuttle Challenger exploded 73 seconds after launch from Kennedy Space Center in Cape Canaveral, Fla. Six astronauts and a teacher from New Hampshire died when the crew cabin of the orbiter impacted the Atlantic Ocean more than three minutes later; most of them were likely conscious and aware at the time.

The Rogers Commission Report on the disaster concluded that Morton Thiokol managers Jerry Mason, Joe Kilminster, and Robert Lund had overruled their engineers, particularly Bob Eberling, under pressure from Lawrence Mulloy and George Hardy at NASA.

Physicist Richard Feynman revealed the systemic failures at both organizations, in particular NASA's habit of determining what the probability of disaster ought to be, and then working backward to the data they actually had, rather than determining the probability from the data. NASA claimed that the probability of a shuttle disaster was 1 in 100,000; the actual probability turned out to be 1 in 67.5 over the life of the program. I am not aware of any other vehicle ever produced that killed its occupants 1.4% of the time and stayed in service for 20 years.

In unrelated news, NPR revealed this morning that the Department of Energy has secretly loosened nuclear safety regulations to encourage development of the next-generation of reactors. According to NPR,

The orders slash hundreds of pages of requirements for security at the reactors. They also loosen protections for groundwater and the environment and eliminate at least one key safety role. The new orders cut back on requirements for keeping records, and they raise the amount of radiation a worker can be exposed to before an official accident investigation is triggered.

The new orders strip out some guiding principles of nuclear safety, notably a concept known as "As Low As Reasonably Achievable" (ALARA), which requires nuclear reactor operators to keep levels of radiation exposure below the legal limit whenever they can. The ALARA standard has been in use for decades at both the Department of Energy and the Nuclear Regulatory Commission.

Removing the standard means that new reactors could be constructed with less concrete shielding, and workers could work longer shifts, potentially receiving higher doses of radiation, according to Tison Campbell, a partner at K&L Gates who previously worked as a lawyer at the Nuclear Regulatory Commission.

Any connection with the Challenger disaster is purely coincidental, except for the part about how both occurred in the second terms of Republican presidents obsessed with corporate profitability at the expense of safety.

On January 27th, we still have 5 weeks until spring officially begins. The forecast doesn't predict any above-freezing temperatures as far as it can see, and we've already had 10 days below freezing in this seemingly endless cold snap.

But also today, the sun sets at 5pm for the first time in 88 days. In only 24 days it sets after 5:30pm, and just 16 days after that, we change the clocks and get a 6:50pm sunset. That's when it will feel like spring.

Another bit of news that warmed my heart today: Customs and Border Patrol "commander at large" Greg Bovino has been sent out to pasture and will retire "soon" according to Dept of Homeland Security officials, which suggests that even if the OAFPOTUS doesn't think Bovino and his goons did anything wrong when they murdered two US citizens in cold blood, someone in the administration can read a poll. There's also a rumor going around that DHS Secretary Kristi "Puppy Killer" Noem has been shoved aside and may soon resign.

One more tidbit that indirectly implicates the OAFPOTUS and Reichsführer-ICE Stephen Miller: the US Census Bureau announced this morning that population growth in the US has slowed dramatically because—wait for it—international migration has fallen by 54% in just one year.

So, things are looking just a bit brighter. Things will get worse, of course, but only temporarily.

No grilling today

    David Braverman
ChicagoWinter

Oh, look, the temperature is going up! It's almost all the way to -15°C (5°F).

Temperatures at IDTWHQ 26 January 2026

And yet, I've decided not to take my lunch on the patio this afternoon:

My back patio in snow

Now that the Calendar feature works, I spent an hour today writing a utility to count all the public blog posts by month, and to give me a cumulative count. It turns out, most of my posts exhorting big milestones, like the 5,000th or, more recently, the 9,000th, were off by a few weeks.

Rather than sometime next week as I had thought, I actually published the 10,000th post of the modern era (i.e., since 13 November 2005), on December 26th. The 10,000th post overall was this one from July 10th, not the one on August 8th as previously believed1.

This, therefore, is the 10,248th Daily Parker post since braverman.org added proto-blogging features in July 1997, and the 10,046th since this became a proper blog in 2005.

The corrected data doesn't meaningfully change the overall statistics. I post 1.36 times per day on average, with a mean of 41.34 and a median of 42 posts per month (standard deviation, 7.868). The maximum for a month remains 60 (November 2008) and the minimum is still 15 (October 2007).

At my current rate of posting (38.42 times per month in 2025), I should reach 15,000 posts in May 2036 and 20,000 posts in March 2047. Stay tuned!


  1. I did promise to revise my conclusions once I identified the real 10,000th post.

Yesterday morning, Immigration and Customs Enforcement—who have no jurisdiction over US citizens—murdered another US citizen in what witness videos clearly show as a depraved act involving at least two shooters. Alex Pretti, the murdered ICU nurse who tried to shield other observers from being assaulted with chemical irritants, was unarmed and subdued when ICE agents shot him at least 8 times.

This morning, a Federal judge in Minneapolis ordered ICE not to destroy or alter the evidence they've collected about the murder, because even the dimmest bulb in the ICE marquee knows they had no justification for this.

I'm not going to link to the videos; they're not hard to find. You should watch them, though, from at least two angles. If you don't believe there is probable cause to charge at least two of the ICE agents with at least 2nd-degree murder, please find the nearest inpatient facility and tell them you're a psychopath.

ICE claimed that Pretti had a gun and planned to shoot the agents. The videos clearly show he made no aggressive moves toward the agents and was in fact trying to remove himself and another victim of ICE violence from the scene. And, of course, until recently the same people yelling "he had a gun!" are exactly the same people who pushed so hard for an extremist interpretation of the 2nd Amendment that allowed Pretti to carry his pistol completely legally. As much as I think we should not have average citizens carrying pistols in cities like Minneapolis, Pretti didn't deserve to die.

And as much as the "2A" fanatics raved about carrying guns to the grocery store was necessary to prevent the government from trampling our rights, I ask them, what the fuck do you think happened yesterday? It's funny how they seem to have forgotten that squishy little diarrhea blossom Kyle Rittenhouse.

Speaking of the 2nd Amendment, Tim Walz needs to remember why we have that amendment, and use the state's well-regulated militia to protect Minnesotans from further violence.

Josh Marshall warns that OAFPOTUS administration officials want to escalate the violence to dominate the area:

Escalation dominance” is a concept in military theory and strategy. Imagine you have two countries in a tit-for-tat confrontation. The country with escalation dominance has superior capabilities on every rung up the so-called escalation ladder. So at every stage that country has the upper hand. It has more and better guns. So every escalation puts the weaker country in greater danger and with less hope of ever getting the upper hand. The weaker power faces the bad choice of either backing down or incurring ever greater injury and ultimately destruction.

Why would the White House continue to escalate in the face of rising public opposition? One answer is that they’re fanatics and true believers. But a complementary explanation is this belief in escalation dominance. It may not be popular but they believe public resisters will eventually have to knuckle under. So they’re happy to keep escalating. Because they have more and bigger guns and eventually those who oppose them will have to give in. I don’t think that’s the case. But I’m pretty sure they do.

My party's top officials, who haven't yet figured out that the Republican Party left the land of the sane 32 years ago, made the usual noises and press releases. (Senator Schumer, just fucking retire already.)

This has to stop. It will stop. But clearly, the OAFPOTUS and his droogs will continue to escalate, as their unconstitutional and dangerous1 secret May memo made clear. Like all authoritarians, neither the OAFPOTUS, nor Reichsführer-ICE Stephen Miller, nor CBP chief Greg Bovino2 don't care who dies, as long as they "win." But like all authoritarians, their own psychopathy prevents them from understanding a basic truth: empathy makes collective action more effective. And there are way more of us than there are of them.


  1. By encouraging ICE agents to illegally enter people's homes without an Article III warrant, it seems like Miller et al. want one of them to get shot as an excuse to rachet up the militarization of the operation. It's a tried-and-true technique of authoritarians everywhere.

  2. Someone said "Bovino looks like an aging lesbian" and I can't unsee it.

The temperature at Inner Drive Technology World HQ dropped below freezing at 8:52 pm last Friday and will probably not go above freezing until at least February 6th. We have had three-week stretches below freezing many times, and every one of them has sucked. I lived through the longest below-freezing stretch in Chicago history, the 43 days between 28 December 1976 and 8 February 1977. I also lived through the record low of -33°C (-27°F) on 20 January 1985, the earliest first freeze on 22 September 1995, and the latest freeze on 25 May 1992.

At least the forecast predicts it'll get above -17°C (0°F) by noon. The temperature bottomed out at -20.8°C (-5.4°F) at dawn but it's already 2.4°C (4.3°F) warmer two hours later. If we get to the forecast high of -13°C (9°F), Cassie will be able to stay outside for 10 whole minutes, if she wants to.

I have to remind myself that we stay in this part of the country in part because this weather sucks to biting insects way more than it sucks to large mammals with central heating. Also, it Builds Character™.

Like so much in the world, we had ample warning that things would not go well. Seven weeks ago I noted that the La Niña phase had started to collapse, and that while La Niña correlates with cold winters here, the transition to ESNO-neutral wouldn't happen in time to save us from...this.

After bottoming out at -21.3°C (-6.3°F) around 8:30 this morning, the temperature has skyrocketed to -18.7°C (-1.7°F) a few minutes ago. I decided to walk to my optometrist appointment, 12 minutes there and 13 minutes back thanks to a red light, which wasn't too bad in my swaddling. When I got back, Cassie lasted just over 4 minutes before bolting for my front door. Smart dog.

Outside Chicago, things look a lot worse: a major winter storm has formed west of Texas with a trajectory that will hit just about every population center from Albuquerque to Boston over the next 72 hours—except us. Even Louisiana Governor Jeff Landry had to warn his constituents to "get off the roads, get comfortable, and cook a gumbo." (My dinner tonight will be homemade chicken soup, but same principle.)

In other news:

  • Tom Nichols dreads finding out how the US military will react to truly unhinged orders that could come from the OAFPOTUS. Julia Ioffe concurs.
  • Matthew Yglesias looks at the collapse of childhood vaccinations and wonders if we'll be able to fix this horrible legacy.
  • Jeff Maurer tries to make sense of a new poll showing a plurality of voters calling themselves "independent" but don't seem to want a new, centrist party. That said, "to some extent, Gallup’s question doesn’t measure how much people identify with either party, but rather how cool it is to call yourself 'independent.'"

Finally, fitness technology company Strava is going public, a move that The Economist thinks is cause for a below-average dad joke.

The temperature at Inner Drive World HQ has slid down to -20.9°C (-5.6°F), the coldest temperature we've had in two years. O'Hare shows -23.9°C (-11°F), which is colder than the low temperature in January 2024; the last day it got this cold was 31 January 2019, when it hit -29.4°C (-21°F).

Most of the schools in the area have closed for the day, Metra has a reduced schedule (not that anyone is riding the trains today), and Cassie did not feel any need to sniff every blade of snow-covered grass before doing her business this morning.

No danger of a record low, however. On 23 January 1963, it was -27.8°C (-18°F). That said, if the temperature doesn't go above -19°C by midnight Sunday, we'll set the record for the coldest high temperature.

I can't wait for my eye doctor appointment at lunchtime. Hey, it's only a 15-minute walk, right?

In my last post on how the Daily Parker blog engine works, I talked about the fundamental abstractions that I built it around. Today I'm going to talk about the code some more, but more concretely, by explaining how the application decides who can see or do what. I'm a little proud of this design, to be honest.

Just a quick reminder of the difference between authentication and authorization: authentication confirms that you are who you say you are; authorization decides what you can do. The Daily Parker lets Microsoft handle authentication and just trusts that they're doing it correctly. (I'm planning to add other authentication services, including Google and Facebook.)

So assuming that a user is who she claims to be, what does the blog engine do with that information?

When someone attempts to do something that requires a permission, the app first asks the security middleware for the person's user ID, then uses that ID to read the person's profile, which is stored in the app's database. The profile contains a list of the user's roles and the privileges they have within each role. Role names are arbitrary; I can define them as I need them without changing the software. So far I've defined 9 roles, including "Blog post" and "Comment," which are the two visitors interact with the most even if they don't know they do. Each role has five possible privileges: List, Read, Change, Delete, and Self. For example, to write a blog entry like I'm doing now, a user has to have the Blog Post role with Change privilege. (Of course, most of the app's basic functions work fine if you don't bother authenticating. Anonymous users account for over 99% of the blog's page views, after all. But even anonymous users need to be authorized to do stuff. The application still checks authorizations at every step,)

In some cases, a user just has to be in a particular role to see certain information. For example, to see the "add blog post" icon on the navigation bar, you have to have the Blog Post role. The Blazor middleware enforces that with AuthorizeView containers.

Once you're on a page, though, authorization may get more finely-tuned. The view blog post page (on which you're probably reading this right now) makes five specific checks before revealing things like the edit button and the post metadata footer. Here's where we get to the code I'm pretty jazzed about.

At the top of the authorization chain is a call to IAuthorizationService.IsAuthorizedAsync, which simply returns true or false. It looks like this:

Task<bool> IsAuthorizedAsync(
	Project? project,
	UserProfile? user,
	IAuthorizable? item,
	string feature,
	Privileges demand,
	CancellationToken cancellationToken = default);

(The Async keyword and suffix just means that the code runs on its own thread so it doesn't block the rest of the application from running. Lack of async code caused most of the performance problems with the BlogEngine.NET version of this application, so it was important for me to build the entire app around asynchronous code blocks.)

The project, user, item that you want to use, role that you need to have, and privileges you require to use it comprise an AuthorizationState, which is used by this method:

public async Task<bool> IsAuthorizedAsync(
	AuthorizationState state,
	bool logResult = false,
	CancellationToken cancellationToken = default)
{
	var allowed = false; // If no strategy applies, deny by default
	var strategyName = "no strategy";
	var userName = state.User?.Id ?? "(anonymous)";

	var strategies = state.Item is null
		? DefaultAuthorizationStrategies
		: DefaultAuthorizationStrategies.Union(state.Item.AuthorizationStrategies); // General, then specific

	foreach (var strategy in strategies)
	{
		var result = strategy(state);
		switch (result)
		{
			case AuthorizationResult.Allow:
				allowed = true;
				break;

			case AuthorizationResult.Deny:
				allowed = false;
				break;

			case AuthorizationResult.None:
			default:
				continue;
		}

		strategyName = strategy.Method.Name.Humanize();
		if (!allowed) break; // Any explicit Deny takes precedence
	}

	StrategyUsed = strategyName;
	if (!logResult) return allowed;

	var description = string.Concat(state.Description, " (", strategyName, ")").Trim();
	if (allowed)
	{
		await actionLog.WriteAsync(state.Feature, state.Demand.ToString(), userName, ActionLogResult.Authorized,
			state.Item?.Id, description, cancellationToken).ConfigureAwait(false);
		logger.LogDebug("{User} authorized to {Demand} {Feature} on {Type} {Item} using {Strategy}",
			userName, state.Demand, state.Feature, state.Item?.GetType().Name, state.Item?.Id, strategyName);
	}
	else
	{
		await actionLog.WriteAsync(state.Feature, state.Demand.ToString(), userName, ActionLogResult.Unauthorized,
			state.Item?.Id, description, cancellationToken).ConfigureAwait(false);
		logger.LogInformation("{User} not authorized to {Demand} {Feature} on {Type} {Item} using {Strategy}",
			userName, state.Demand, state.Feature, state.Item?.GetType().Name, state.Item?.Id, strategyName);
	}

	return allowed;
}

Have you seen the clever bit? It's on the 4th line (beginning with var strategies =). You see, every type of item that requires authorization implements an interface called IAuthorizable that has this member:

Func<AuthorizationState, AuthorizationResult>[] AuthorizationStrategies { get; }

That's a bit of functional programming hiding out inside an object-oriented interface. It allows the objects themselves to decide how they authorize actions based on their own internal state. Each item in a class's AuthorizationStrategies collection is a function that takes an AuthorizationState and returns an AuthorizationResult which is either Allow, Deny, or None. Allow means "the action is authorized," deny means "the action is prohibited," and none means "it's not my place to decide." As you can see in the IsAuthorizedAsync code, though, actions must have an explicit Allow result to be authorized. Once an action is denied, the discussion ends; "allow" and "none" are always provisional until all of the applicable authorization strategies is checked.

For example, here's the BlogPost.FuturePost method, which is one of the checks that occurs nearly every time someone tries to read a blog post:

private static AuthorizationResult FuturePost(AuthorizationState state)
{
	if (state.Item is not BlogPost post
		 || state.Project is null
		 || post.Start <= DateTimeOffset.UtcNow) return AuthorizationResult.None;

	if (state.User is null) return AuthorizationResult.Deny;

	var user = state.User.Id;
	if (post.Owner == user) return AuthorizationResult.Allow;
	if (state.Project.Users.Contains(user)) return AuthorizationResult.Allow;

	return AuthorizationResult.Deny;
}

First, the method makes sure that the item is a blog post, that it has a project associated with it, and if it's a blog post, that its start (post) time is in the future. If the answer to any of those questions is "no," the method returns None, because it's not up to the BlogPost class to determine what to do.

Next, if there is no user—i.e., it's an anonymous request—the request is denied. This ensures that you have to be logged in to see a future post.

But we're not done, because the next three lines require either that the person requesting to see the post is the one who created it (the owner), or if not, that the person is a member of the project associated with the post. If either of those things is true, the request is tentatively allowed. If neither is true, it's denied.

Why tentatively? Remember that an "allow" result is provisional. Before the class-specific authorization strategies even start, the authorization service runs its own checks in this order:

  • Is the authorization state itself valid?
  • Was the user deleted?
  • Does the user have the requested privilege? (Sure, you're a member of the project, but you don't have BlogPost/Read privileges, so...nope.)
  • If the request is to change or delete something, is the user a member of the project?
  • Is the request just to list something that only requires authentication to list? (This solves a specific problem with anonymous users that wasn't immediately obvious to me.)
  • Is the user requesting authorization the owner of the item?
  • Is the item open for public reading? (This is the one that lets you, dear anonymous visitor, read this post.)
  • Is the item itself deleted?

Only if every one of those checks and the item's own checks ends with "Allow" does IsAuthenticatedAsync return Allow.

And because the individual classes have their own authorization strategies, I don't have to change any of the authorization code when I create new things for the project. The authorization service doesn't care what the item it's authorizing is, as long as it implements the IAuthorizable interface. So if I create a new FuelRecord class for keeping track of when I fill up my car, the FuelRecord can decide for itself who can use it, and I don't have to change any other lines of code.

By the way, there are about 150 unit tests around this, including dozens of checks against all five privilege types for each authorization state I could think of. It's tedious, but like the Inner Drive Money class, it's something I want very much not to screw up.

I mentioned in a post weeks ago that I've been thinking about this software for 10 years. This was the second-hardest problem to solve. I think I came up with a pretty cool solution. Let me know what you think in the comments.

The longest cold snap in years is right now descending upon us from the northwest. It's still a tolerable -5°C at Inner Drive Technology WHQ, but this forecast, man... It looks like temperatures will dip below -17°C (0°F) around 2am tonight and stay there until 7am Saturday, bottoming out around -22°C (-7°F) right before dawn tomorrow.

Cassie has a double coat and paw beans of steel, but she's not a husky, nor does she have great judgment about how cold she feels. She also completely fails to predict the future farther than about 30 seconds in advance. So as a rule, I limit her outside time based on the temperature. Above -5°C she can stay out as long as she likes; at -10°C it's 15 minutes, declining to 3 minutes at -18°C or below. So it's possible she will only get 12 minutes of outside time tomorrow. Have you ever seen a Weimaraner mix on only 12 minutes of walkies? Yeek.

Somehow I'll get stuff done tomorrow and Saturday, including an eye exam at lunch time. Ordinarily I walk about 15 minutes to the optometrist, but tomorrow I think I'll drive. Can't wait.

I've just had a lot to do today and I'm not feeling particularly creative. So, nu, maybe Friday?

Meanwhile:

Finally, despite the temperature having risen to the January 21st normal of -1°C this afternoon, just look at this graphical forecast for the 48 hours starting at midnight tonight:

Brrrr

Wonderful. Looks like a solid 28 hours below -17°C (0°F) before "warming up" to -11°C (12°F) late Saturday. And poor Cassie has only gotten 4½ hours of walkies in the last 7 days. Even the 10-day forecast has us below freezing as far as it can predict.

We last had a temperature of -21°C (-6°F) two years ago, and wow, I didn't like it at all when I got off the plane from Seattle. I can hardly wait to bundle up and hunker down Friday. Yay.

New release, new bugs

    David Braverman
BlogsSoftware

I just released a new production version of the Inner Drive Journal (the software the Daily Parker runs on) with 7 bug fixes, 9 new stories, and a technical task. Most of these Jira cases took me less than 15 minutes. Yesterday, though, I wound up spending 5 hours on a new system configuration management tool because (a) it's complex and (b) I changed my mind about the interface after I ran it a couple of times.

The coolest new feature is the Calendar, which allows you to view whatever was posted on a particular date. That's...well, that's the only feature that anonymous users can see. (So create an account already!)

The same with the bug fixes; for now, I'm the only one who will notice them, because I'm 100% dogfooding. For example, the Edit Blog Post page has an auto-save feature: every n seconds (which is now configurable by project), it saves what you're working on as a draft. Once the post is published, though, the feature turns itself off. You can control whether it's on or not at any time using a checkbox on the Edit page.

That's a super-useful feature, solving one of my biggest irritations with BlogEngine.NET. We can all agree it's no fun losing a draft you've worked half an hour writing. However, as I first implemented the auto-save feature, it simply called the general Save method on the page, which happily tells you about its every success with a banner at the top of the page. This causes everything to shift briefly and can cause the editing box to lose focus, which interrupts the writing flow. I fixed it by only showing the "success" banner when you actively click the Save button, but not when it auto-saves. I'm now 10 minutes into writing this post and, yes, it's a lovely improvement.

Unfortunately, a couple of the new features work in the dev/test environment but not in production (timing issues, I'm pretty sure), and I got the logic wrong in a couple of places. I'll fix those quickly and probably have a new release on Sunday or Monday. I'm also going to start working on some of the more journal-like features, starting with new layers of privacy, and possibly some external interactions I've wanted to do for years. We'll see. Plus, I'm starting to see some opportunities for better app performance, though I am really very happy by how it's running—especially compared with its predecessor.

And, yes, I'll have another How This Works explainer up as soon as I can.

Exactly one year ago this hour, the worst administration in American history took office. One hopes they will always be the worst administration in history (though I can see some ways that becomes true for some pretty horrible reasons).

In the past year, as the OAFPOTUS has descended deeper into dementia and his existing malignant narcissism, his droogs have torn down the domestic and international structures that provided the longest period of prosperity in history. Not everyone is horrified, of course; the OAFPOTUS has done Vladimir Putin's work so effectively the Russian dictator openly gloats about it.

Will we have three more years of this, or will the Republicans in Congress and in the Cabinet who keep him there end the nightmare sooner?

Even the people who believe in their tiny, cold hearts that destroying the welfare state is the only way we can have a prosperous billionaire class (looking at you, Russell Vought), or you believe that getting rid of every immigrant who arrived after 1830 will make up for you not getting to sit with the cool kids in 2nd grade (looking at you, Stephen Miller), aren't you tired of the chaos?

I should note, today is also the anniversary of the Wannsee Conference, when Stephen Miller's boyhood crush Reinhard Heydrich and his pals planned the murder of 11 million Jews in Europe. That was only 9 years after the National Socialists took power in a (mostly) democratic election. We're living through history repeating as farce, to be sure; but Miller has built concentration camps while the OAFPOTUS celebrates brownshirts killing moms in Minneapolis.

Elections for the 120th Congress take place in just 287 days. Everything points to an overwhelming swing towards the Democrats. Taking back Congress will slow but not stop the mayhem, unless the Republican Party decides they decide to take action with us. We'll see; so far, they seem to want everything to burn down so they can rule the ashes.

Woe to thee, O land, when thy king is a child, and thy princes eat in the morning.—Ecclesiastes 10:16

Before I throw my chicken soup in my slow cooker, and before I take advantage of this holiday from work to release a package of minor improvements and fixes for bugs I discovered using the new Daily Parker blog engine for a week, I need to mention the latest clear and convincing evidence that the OAFPOTUS has lost his mind and needs to be removed from power.

This morning, the government of Norway and some of our own embassies abroad released a letter the head of our government sent to the head of theirs. Schoolchildren will read about this letter centuries from now:

Dear Jonas [Gahr Støre, prime minister of Norway]:

Considering your Country decided not to give me the Nobel Peace Prize for having stopped 8 Wars PLUS, I no longer feel an obligation to think purely of Peace, although it will always be predominant, but can now think about what is good and proper for the United States of America. Denmark cannot protect that land from Russia or China, and why do they have a “right of ownership” anyway? There are no written documents, it’s only a boat that landed there hundreds of years ago, but we had boats landing there, also. I have done more for NATO than any person since its founding, and now, NATO should do something for the United States. The World is not secure unless we have Complete and Total Control of Greenland. Thank you! President DJT

If an assistant manager at a Wendy's had written this letter, he'd be fired on the spot. You wouldn't tolerate this from an 8th grader. As Adam Kinzinger said, it's time to put him in a home:

This is not parody. This is not a meme. This is not a joke taken out of context. This is the sitting president of the United States explaining how he thinks.

That is not strength. That is not realism. That is not America First.

It is grievance-driven governance, powered by ego and resentment, with nuclear consequences.

This isn’t diplomacy. It’s a warning.

Anne Applebaum:

Donald Trump now genuinely lives in a different reality, one in which neither grammar nor history nor the normal rules of human interaction now affect him.

Years of careful diplomacy, billions of dollars in trade, are now at risk because senators and representatives who know better have refused to use the powers they have to block him. Now is the time.

James Fallows tries to make sense of "what the hell is this about?" and shrugs:

Does the Trump-era obsession with Greenland seem completely irrational? That’s because it is—as no less an authority than Trump himself has told us.

Because the feeling of ownership is “psychologically important” for this one damaged man, the US is throwing alliances and interests built over centuries into a bonfire. Great. But not what Hamilton, Madison, and Jefferson had in mind.

This showdown has gone from idiotic to actually dangerous.

As a child I was afraid during the Cuban Missile Crisis of 1962. In retrospect, it was in fact the closest the world has come to nuclear devastation, in the 80+ years since the first use of atomic weapons, by the US on Hiroshima and Nagasaki.

I am afraid now when I think that one un-informed, gut-driven man is breaking up alliances, imposing tariffs by decree, and putting our collective fate in his bandaged, shaky, undersized hands.

I think we all need to remember the words of Jane Goodall: "What you do makes a difference, and you have to decide what kind of difference you want to make."

Cassie will not get a lot of walks today. Just now at O'Hare the temperature hit -18°C (-1°F) with a wind chill of -29°C (-20°F); here at Inner Drive Technology World HQ it's -15°C (5°F). Of course, this is nowhere near a record: on 19 January 1985 it was -31°C (-23°F), and the next day, 20 January 1985, Chicago hit its all-time coldest temperature of -33°C (-27°F).

I wondered how cold it would have to get for Cassie to notice. I have my answer. I let her off leash when we got back to our complex after a 4-minute speed-walk around the block, and she beelined for the front door. But now I have a Weimaraner mix who usually gets a full hour of walks every day who will get, if the wind dies down, 30 minutes today.

The forecast predicts a normal-ish -5°C (21°F) tomorrow.

The first problem of developing a new software application is to determine what it does. The second problem is to decide the fundamental abstractions that will govern the system. If you don't figure this out early, you'll either write a hideous pile of rotting spaghetti that no one will want to maintain, or you'll do that and change careers entirely.

Sorting the "what it does" problem often makes the "what represents it" question easier to answer. If you want to build a building, for example, having a clear idea of what it does ("it provides living space for lots of people") should give you a good idea of its fundamental abstraction ("people live in apartments" or "people live in houses"). If you get the fundamental abstraction wrong, it just won't work ("people live in cubicles"). This is why airports with huge shopping centers don't feel right, and condos carved out of de-sanctified churches look weird.

Fortunately, the first fundamental abstraction of this project was obvious, even before I decided to make a blog engine its first realization. Everything in the Inner Drive Journal is an Event.

Now, I'm an old Object Oriented guy. So when describing software concepts, I think of classes that have is-a and has-a characteristics. So an Event is a thing that has or will happen, and has a start time, type, and name, and maybe other characteristics like an end time, a location, comments, and text. (Because the Event lives inside a software system, it also is a DataItem that has an ID, created time, modified time, and control bits to determine whether it's published, deleted, or test data.)

This means that everything that everything you see on The Daily Parker is, fundamentally, an Event. A BlogPost is an event that has additional characteristics specific to blogging. In time, I'll add other event types with other characteristics, for example to represent when I read a book or took a hike with Cassie.

The blog post's class hierarchy looks like this:

public class BlogPost : Event { }

public class Event : DataItem, IEvent, IGeoLocatable { }

public abstract class DataItem : IDataItem, IAuthorizable { }

The I prefix indicates an interface, which simply defines what a thing has to have without specifying how any of those characteristics work. That lets developers care only about the minimum characteristics of a thing without caring about what the thing actually is. For example, the authorization system only cares that things implement the IAuthorizable interface, and doesn't care if the thing is a blog post, a book review, or a squirrel.

The other principal abstraction is a Project, which is a collection of Events. There are two reserved projects, Public and Administration, but otherwise what goes in a Project is completely arbitrary. The Daily Parker is a Project containing Events, and most (but not all) of those Events are Blog Posts.

The application has two other things that people interact with, Users and Comments. But altogether, the application has (as of this morning) about 50 other classes that are and have specific characteristics that make the application work. For example, the View page is a class that includes the Blazor page definition, the code behind the page, and a list of text items like field names and tooltips.

As always, use the comments to ask questions or ask for specific topics of these explainers.

Next time: the authorization architecture, which is how the application decides who can see and do what.

In Friday's explainer, I gave a 10,000-meter view of the application and its basic components. Today I'm going to show you the software's basic features; I'll go deeper on some of them in later posts.

(Since I'm actively developing this software, some of the details that follow could change, so they're accurate only as of the date of this post.)

The most obvious feature is that you can read blog posts. You're doing it now, in fact. If you just landed on https://www.thedailyparker.com, you're seeing this post in the reverse-chronological feed, which shows you posts from the past 7 days. If you went to the permalink https://www.thedailyparker.com/2026/01/17/how-all-this-works-what-the-blog-engine-does, you're seeing the single post page. You might also see any comments that people have left.

Before you can see the post, I have to write it on the edit post page, which looks like this:

The editing page

The edit post page has a bunch of features that give me precise control over what you see:

  • An indication that the post is a draft next to controls that allow me to save and pin the post
  • The title, used to build the permalink
  • Tags, which provide a quick way to find posts related to a common topic
  • The body text, which is what you're reading
  • A preview button, which generates the HTML that you see, so that I can make sure I'm formatting everything correctly
  • An author box, pre-populated with the name of whoever is editing if it's a new post
  • The project selector, which I'll get into later
  • The encoding selector, which defaults to Markdown for new posts but also has settings for HTML (any post before January 2026) and plain text
  • A control to set the start date of the post, which allows me to post something in the future (like this post)
  • Location controls, to populate the little globe icon you see in the header above
  • A selector to open or close comments, which defaults to closing them after 60 days
  • Checkboxes that determine whether the post is published and whether the editor auto-saves what I'm working on
  • Buttons to save, publish or re-publish, view, or delete the post
  • A readout of the metadata about the post, including its permalink, unique ID, owner (the person who created it), and last modified time and editor
  • A separate history tab, showing all the changes to the post's metadata (but not to the post text, for reasons I'll get into later)

As you can see above, all these controls are just stacked on one big page. I've put the most frequently used controls at the top and the less-frequently used at the bottom, and a lot of them start off with default values that don't change very often.

Other major features of the UI include:

  • Full-text search, which will find any word or set of words in any post
  • User profiles, which you can set up if you log in using a Microsoft account (including Outlook, XBox, etc.)
  • Administrative tools that let me read the event log, audit log, diagnostic information, the user list, and the project list

Plus a couple of features that you won't necessarily see:

  • A flexible permissions architecture, which I will discuss in depth later on
  • reCAPTCHA verification for comments

It's a lot, I know! And I'm constantly developing more features, one of which I plan to deploy on Monday.

Let me know in the comments which features you want to know more about.

I have a list of 6 or 7 short plumbing tasks that I hope will take less than an hour, which is 1/8th the time window the plumbing service provided for the plumber's arrival. We all know how that goes. And at my real job, I'm coordinating a bunch of processes for a biweekly release that, so far, is pretty boring—just how we like it.

Meanwhile, the rest of the world persists in not boring anyone:

  • In a moment that should make all patriotic Americans vomit from embarrassment and which Paul Krugman called "the inanity of evil," exiled Venezuelan opposition leader María Corina Machado presented the OAFPOTUS with her Nobel medal, which he promptly stuck in his mouth while making happy little squealy noises. No report yet on whether he actually peed his pants or just drooled onto them.
  • The US has admitted it obtained a directed-energy weapon that could cause brain injuries similar to the so-called "Havana Syndrome," despite years of Pentagon denials that such a thing could exist.
  • Local public transport officials have drawn up plans for a long-overdue regional transit police force. One hopes they will have the authority to stop people smoking, pissing, and shitting on CTA trains. It's a little thing, I know, but it's important to some of us.
  • Bruce Schneier looks back on Aaron Swartz's JSTOR dump and subsequent suicide, arguing that private hoarding of taxpayer-funded knowledge abetted by pro-corporate public policies has gotten worse since then.
  • Jeff Maurer nails it: "In Fairness, “Reconstitute ICE So That Internal Border Enforcement Can Be Done in a Professional Manner by an Agency That Has the Public’s Trust” Is a Bad Slogan."

Finally, a story on NPR this morning had me yelling at my radio. The Heritage Foundation, who in saner times brought us Romney-slash-Obamacare, now fret about "what happens to a nation when its citizens largely stop having children and eschew marriage," as a section of their latest report has it. The report argues that marriage is the foundation of society, and therefore the government should make marriage more attractive. Nowhere do they argue for things that could make having children more attractive, like free day care, free pre-school and pre-K, free lunches in primary schools, and free health care for kids under 10. Or, you know, immigration, which has been proven to increase the population of every country that has tried it.

It's almost as if Heritage is raising the alarm over declining birth rates but not being particularly honest about whose birthrate they mean. Not to mention, the policies they do propose also create incentives for women to leave the workforce and return to the idyllic lifestyle they led in the 1950s and 1960s.

Is it possible that the organization that brought us Project 2025 and all the wonderous things we've experienced over past year has some other agenda? Hmm.

In my last post about the Daily Parker's new blog engine, I explained why I built this and what it's for. This post will give you an overview of the app's basic structure; that is, the physical building blocks that make the blog happen.

When you point your browser at https://www.thedailyparker.com, the request goes to the front door of a Microsoft Azure App Service, which runs on a server in Microsoft's US East data center, located outside the tiny town of Boydton, Va, on the Virginia-North Carolina border about halfway between Richmond, Va., and Raleigh, N.C. I put this app there because lots of Inner Drive apps live there, including Weather Now.

Once the request hits the server, it goes to a Microsoft Blazor WebAssembly application called InnerDrive.Journal.UI, which sends and receives messages to a stack of other components:

  • A Microsoft Cosmos DB NoSQL database that stores all of the blog posts as fully-indexed JSON documents.
  • Multiple Microsoft Azure Tables, which are high-speed flat structures that store simple rows of data with only two indices. The tables store information that needs to be written and read very quickly but doesn't have a lot of overhead. The blog engine uses tables for:
    • Audit logs
    • Event logs
    • Indexes
    • Comments
    • Tags
  • An Azure Key Vault that stores keys and secrets, so that the source code never does. For example, to read from the database, the application needs the database's secret connection information, so it knows where to look and what password to use. That "connection string" goes in Key Vault.
  • Microsoft Azure Blob storage to keep the photos and other files that you see.

Unlike Weather Now, the Daily Parker runs entirely in a single Blazor WebAssembly app. Weather Now uses two: a user interface app, which shows all the data, and a separate API, which stores and processes all the data. That makes it easy for Weather Now to serve its data to other apps. But the way I expect people will use the blog engine is entirely different, so I chose the simpler, one-app approach.

That doesn't mean everything is stuffed into one big executable file, though. The application architecture of the blog splits responsibilities into a collection of small-ish assemblies:

  • Core contains the most basic components that every other part of the system uses, like the definitions for Privacy and Accuracy.
  • Data defines how the application uses the database and other data structures like indexes. The basic abstraction for the app, the Event, lives here, as do the definitions for Factory and Repository, which represent different ways of dealing with certain kinds of data.
  • Blog holds the bits that are specific to blogs and not generally used by other kinds of events. The BlogPost class lives here, as does the BlogPostFactory; both of those things extend their Data counterparts (Event and EventFactory).
  • Services orchestrates how those other parts interact with each other. For example, the BlogService has a method to find a blog post by its ID. That code in turn calls the EventFactory.Find method to get the post, but then it calls a several other pieces of code to determine if the person trying to find the post has permission to see it, as well as code to log information to the event log (things that the software does) and the audit log (things that the user does).
  • UI uses Services to generate the pages that you see in your browser.

All of this currently runs on .NET 10 and was written in the C# language. Plus, there are a bunch of 3rd-party components, including the Inner Drive Extensible Architecture™ (which I also wrote) that do specific tasks, like time zone calculations and translating the Markdown I'm typing right now into the HTML you see in your browser.

Over the next few weeks, I'll go into much more detail about all of this. But my next post will be about the features I developed for this new blog engine, and why I think they're cool.

Earlier posts

Copyright ©2026 Inner Drive Technology. Donate!