My credit union called this morning: “Did you just make a purchase from OnlyFans?” Nope. Thus ends my longest recent streak of not having my debit card compromised. The security department said it looks like I’ve been the victim of a “BIN stuffing” attack where a criminal tries random combinations of card numbers, expiration dates, and CVV numbers until they get lucky. One day I may have a debit card that reaches the expiration date printed on it. Not this time, though.

I got the first “your credit card was declined” email from one of my monthly bills a few minutes later. This will be an irksome week.

Keeva wants pets.

A Boston terrier with the sweetest little face is smiling up at the camera. She’s standing on a wood floor half in, half out of the sun streaming in through a door.

The BASIC programming language turns 60 | Ars Technica

The BASIC programming language turns 60 | Ars Technica

Like so many others, I got my start typing in program listings for games, utilities, art projects, and all kinds of other things I found in magazines. Inevitably there’d be some small thing I wished a program would do differently, so I’d tweak and alter it — usually breaking things horrendously along the way — until I made it do what I wanted. That was an addictive rush of magical power.

While BASIC wasn’t a great language, I’ve never seen a programming environment more approachable an alluring than turning on a Commodore 64 and instantly seeing the word “READY.” and a blinking cursor waiting for me to give it instructions.

What sadist invented this captcha?

A picture of a number, then series of pictures of a bunch of dice. You have to pick the one where the dice add up to the number, and you have to do it 3 times.

What's my Apple Card balance?

I spent 1 hour and 25 minutes on a call with Goldman Sachs about their mistakes on my Apple Card statement. It’s not resolved but I think we’re finally making progress.

I’m a stickler about reconciling my monthly account statements. My dad taught me how to balance a checkbook when I was a kid and I’m diligent about that. This was the first time I’ve ever been unable to make sense of a statement. The process normally looks like this:

  1. Start with last month’s balance.
  2. Subtract any money you paid toward that balance.
  3. Add any new transactions.
  4. Add any fees and interest.
  5. Compare the result to what the bank says your new closing balance is, and if it’s not an exact match, go back to the beginning until you find the missing piece.

Last month’s Apple Card statement worked like that. So did the month before that. And the month before that, all the way back 5 years. This month they threw a twist:

  1. Start with last month’s balance, $1000.001.
  2. Subtract the $500.00 payment I made.
  3. Add $100.00 in new transactions.
  4. Add $50 in fees and interest.
  5. My arithmetic came out to a new balance of $650. Goldman Sachs computed my new balance as $425.

However I juggled the numbers, I couldn’t reproduce their result. I gave up and contacted the support chat. That was useless. The conversation went like this:

Me: There’s a problem with my statement.
Them: Your balance is $425! Is there anything else I can help you with? disconnect
Me: reconnecting There’s a problem with my statement.
Them: Oh no! It looks like that’s $425. Have a nice day! disconnect

I asked them to escalate, which resulted in someone sending me an email like:

Here’s how we resolved your case: Start with $1000.00. Now, the moon weighs more than a duck, so carry the 5 and you get $893. Add the length of the Titanic and subtract purple. That’s $425. Share and enjoy!

Today I called them and repeated “talk to a human” into the phone tree until it connected me to a person. This time I got to explain my situation to a sentient being, who went off to repeat my calculations before uttering those magic tech support words: “huh, that’s strange.” It sure is! The agent was able to reproduce my math and couldn’t figure out how to compute Goldman Sachs’s balance. I can’t exaggerate the relief I felt. I’m not alone. It’s not my imagination or inability to add a few numbers together.

Although we haven’t fixed the problem, a thinking person wrote up my problem and opened an official inquiry for me. I’m optimistic.

And don’t waste your time on Apple Card’s online chat. Nothing good comes from it.


  1. All numbers are fictional for storytelling purposes. ↩︎

Today’s first software update for the Rabbit r1 adds missing keys to its on-screen keyboard, and now I can type in our Wi-Fi password. That’s a nice fix!

Next up: Make it trust its own GPS instead of IP geolocation so that it doesn’t think we’re 50 miles away from here. That wreaks havoc on its weather reports.

Drug Scheduling

On the subject of Drug Scheduling:

Schedule IV

Schedule IV drugs, substances, or chemicals are defined as drugs with a low potential for abuse and low risk of dependence. Some examples of Schedule IV drugs are: Xanax, Soma, Darvon, Darvocet, Valium, Ativan, Talwin, Ambien, Tramadol

So the devil’s lettuce is currently Schedule I with "a high potential for abuse”, but Xanax and Valium are not. Got it. That tells you what you need to know about the DEA’s evaluation processes.

US will reclassify marijuana in historic shift: AP sources | AP News

US will reclassify marijuana in historic shift: AP sources | AP News:

Once OMB signs off, the DEA will take public comment on the plan to move marijuana from its current classification as a Schedule I drug, alongside heroin and LSD. It moves pot to Schedule III, alongside ketamine and some anabolic steroids, following a recommendation from the federal Health and Human Services Department. After the public-comment period the agency would publish the final rule.

That’s fantastic news! It’s ludicrous that weed was ever Schedule I, i.e. “with no currently accepted medical use and a high potential for abuse”, when alcohol isn’t. I can’t think of a single criterion by which marijuana is worse for users or for society than America’s current favorite drug of choice.

My Rabbit R1 just arrived. I haven’t played with it enough yet to have an opinion on the software’s usability. The hardware itself is nice, though. Photos can’t accurately convey how very orange! the thing is. It just about glows in the dark.

A cardboard box with diamonds on the top and º + º on the front so that it looks kind of like a bunny from the right angle.An open box with plain grey foam.The R1 in its clear plastic case that also doubles as a stand.A Rabbit R1 laying on its foam packing. It's reflecting light so brightly that it almost looks like the camera's broken, but no, it really is that colorful.

I wish OmniFocus used perspectives in Forecast

I wish OmniFocus would replace the way its Forecast view selects items to display with a user-selectable perspective. Then I could make my own choices about what to include, and OmniFocus would display those items in its handy integrated view alongside calendar events.

I can’t make those choices today. For example, the Forecast view doesn’t allow me to include actions that have a defer date in the past. That is, once an action is past its “start date” and available to be worked on, it no longer shows up on Forecast’s Today tab, or even in the Past tab. This is all the configuration available to decide what the Forecast view should show:

Forecast configuration tab

That’s one place I think Things is better than OmniFocus: If I have an action like “pay the rent (after the 20th of the month)”, the Things Today view will still show that action as something I could and should be doing on the 22nd of the month.

Purists might argue that I’m using OmniFocus wrong. I shouldn’t be leaning on the Forecast view at all, but should be regularly checking my tags and projects to see what I should be doing. That workflow isn’t the right fit for me. I know. I’ve tried it many times. What does work is a nice Today view that shows all my available scheduled actions in one place, along with actions I’ve tagged with “Today” during a review. I have a personal items perspective like that which ends up looking much like Things if I squint at it the right way:

Perspective configuration tab

Notice that the Forecast configuration looks an awful lot like a pared-down version of a regular perspective. If I had a magic wand to wave, I’d remove the “Items” checkboxes from the “In Forecast, include” and “Today includes” sections and replace them with the name of the perspective that would select all the items I wanted to show on the Forecast. Ta-da, done. Then I could customize the Forecast to make it perfect for my own needs. Others could make their own perspective, or use a default that OmniGroup could include to emulate the current behavior. Alternatively, a perspective could gain a “Display as Forecast” checkbox where I could have multiple Forecasts, each with its own filtered view of items. Tell me a separate “Personal Forecast” and “Work Forecast” view doesn’t sound nice. Imagine that you could associate each one with the appropriate focus filter so that they show up automatically when you’re doing personal or work things on your computer. The heart flutters!

Please consider this, Omni Group. OmniFocus is powerfully customizable in so many ways! I’d be delighted if this one last set-in-stone limitation were removed.

Palo Alto's exploited Python code

watchTowr Labs has a nice blog post dissecting CVE-2024-3400. It’s very readable. Go check it out.

The awfulness of Palo Alto’s Python code in this snippet stood out to me:

def some_function():
    ...
    if source_ip_str is not None and source_ip_str != "": 
        curl_cmd = "/usr/bin/curl -v -H \"Content-Type: application/octet-stream\" -X PUT \"%s\" --data-binary @%s --capath %s --interface %s" \
                     %(signedUrl, fname, capath, source_ip_str)
    else:
        curl_cmd = "/usr/bin/curl -v -H \"Content-Type: application/octet-stream\" -X PUT \"%s\" --data-binary @%s --capath %s" \
                     %(signedUrl, fname, capath)
    if dbg:
        logger.info("S2: XFILE: send_file: curl cmd: '%s'" %curl_cmd)
    stat, rsp, err, pid = pansys(curl_cmd, shell=True, timeout=250)
    ...

def dosys(self, command, close_fds=True, shell=False, timeout=30, first_wait=None):
    """call shell-command and either return its output or kill it
       if it doesn't normally exit within timeout seconds"""

    # Define dosys specific constants here
    PANSYS_POST_SIGKILL_RETRY_COUNT = 5

    # how long to pause between poll-readline-readline cycles
    PANSYS_DOSYS_PAUSE = 0.1

    # Use first_wait if time to complete is lengthy and can be estimated 
    if first_wait == None:
        first_wait = PANSYS_DOSYS_PAUSE

    # restrict the maximum possible dosys timeout
    PANSYS_DOSYS_MAX_TIMEOUT = 23 * 60 * 60
    # Can support upto 2GB per stream
    out = StringIO()
    err = StringIO()

    try:
        if shell:
            cmd = command
        else:
            cmd = command.split()
    except AttributeError: cmd = command

    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, bufsize=1, shell=shell,
             stderr=subprocess.PIPE, close_fds=close_fds, universal_newlines=True)
    timer = pansys_timer(timeout, PANSYS_DOSYS_MAX_TIMEOUT)

It uses string building to create a curl command line. Then it passes that command line down into a function that calls subprocess.Popen(cmd_line, shell=True). What? No! Don’t ever do that!

I fed that code into the open source bandit static analyzer. It flagged this code with a high severity, high confidence finding:

ᐅ bandit pan.py
[main]  INFO    profile include tests: None
[main]  INFO    profile exclude tests: None
[main]  INFO    cli include tests: None
[main]  INFO    cli exclude tests: None
[main]  INFO    running on Python 3.12.1
Run started:2024-04-16 17:14:52.240258

Test results:
>> Issue: [B604:any_other_function_with_shell_equals_true] Function call with shell=True parameter identified, possible security issue.
   Severity: Medium   Confidence: Low
   CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html)
   More Info: https://bandit.readthedocs.io/en/1.7.8/plugins/b604_any_other_function_with_shell_equals_true.html
   Location: ./pan.py:14:26
13              logger.info("S2: XFILE: send_file: curl cmd: '%s'" % curl_cmd)
14          stat, rsp, err, pid = pansys(curl_cmd, shell=True, timeout=250)
15

--------------------------------------------------
>> Issue: [B602:subprocess_popen_with_shell_equals_true] subprocess call with shell=True identified, security issue.
   Severity: High   Confidence: High
   CWE: CWE-78 (https://cwe.mitre.org/data/definitions/78.html)
   More Info: https://bandit.readthedocs.io/en/1.7.8/plugins/b602_subprocess_popen_with_shell_equals_true.html
   Location: ./pan.py:49:8
48              bufsize=1,
49              shell=shell,
50              stderr=subprocess.PIPE,
51              close_fds=close_fds,
52              universal_newlines=True,
53          )
54          timer = pansys_timer(timeout, PANSYS_DOSYS_MAX_TIMEOUT)

--------------------------------------------------

Code scanned:
        Total lines of code: 41
        Total lines skipped (#nosec): 0

Run metrics:
        Total issues (by severity):
                Undefined: 0
                Low: 0
                Medium: 1
                High: 1
        Total issues (by confidence):
                Undefined: 0
                Low: 1
                Medium: 0
                High: 1
Files skipped (0):

From that we can infer that Palo Alto does not use effective static analysis on their Python code. If they did, this code would not have made it to production.

I fought State Farm (and won)

State Farm claimed we owed them money. I said we didn’t. They pursued it. I countered. They ended up owing us money instead.

My wife’s small business purchased our unemployment insurance through State Farm until we sold the company a couple years ago. Unemployment insurance premiums are proportional to your payroll: you pay the insurer a certain percentage of each dollar you pay your employees. When you cancel a policy, you reconcile your payroll numbers with them to settle up one last time.

State Farm said they estimated we’d been paying our employees $100,000 a year1. Therefore, by their reckoning, we owed them another $1,000 in additional premiums as if we’d paid out $100,000 in payroll that final year, even though we sold the business in May. They sent me an audit form to complete if we wanted to use our true numbers instead of their estimate. I submitted their form and promptly forgot all about it.

6 months later I got an email from our insurance agent saying that we still owed State Farm $1,000. I replied that we did not and that they needed to recompute our supposed debt using the real numbers that I’d submitted to the audit.

We had the same interaction about 6 months later, then again another 6 months after that. State Farm claimed they’d sent us all the information in writing. We found that they’d been sending letters to the old office that we’d lost access to on the day we sold the business, and the new owner never bothered forwarding them to us. Regardless, I wasn’t about to pay them the $1,000.

I got a more urgent email from our agent toward the end of last year. State Farm wanted their money and were turning our account over to a bill collector if we didn’t pay it. I replied and made our position clear: if State Farm would put it in writing that they had computed our amount due based on our real payroll numbers, and if they mailed that to us at our current home address and not the old business address we weren’t at anymore, only then would I pay them.

Again, silence.

A couple months ago I got a call from a bill collector. He was OK to talk to. I told him his customer was smoking crack and he laughed. Then I repeated our demands: I wanted State Farm to give us an itemized invoice showing their accurate calculations, and I wanted it sent to our house. I promised him that if both happened, I’d cheerfully make arrangements to pay the invoice in full immediately. He said that was reasonable. We parted ways.

However, I’d run out of patience. I filed a formal complaint with California’s Department of Insurance explaining our side of the conversation, asking them to rule on our behalf, and loading them with evidence proving our argument.

2 weeks later, the Department of Insurance replied saying that we needed to appeal the dispute through State Farm’s internal process before involving the state. Their letter contained details about the precise person we needed to contact and the legal jargon to use.

I did that. I got a response from that person yesterday. Their letter contained the itemized calculations I’d asked for all along, a final ruling that State Farm owes us $200, and a promise to mail a refund check to our correct address by the end of the week.

It took 2 years for State Farm to straighten out their math. They could have offered to write off our “debt” a year ago and stop pestering us. I would have accepted that. Instead, they kept it up and lost.

Yay me!

If that check isn’t here in the next few days, I have the number of a bill collector I might hire.


  1. All numbers are fictional for storytelling purposes. ↩︎

Tennessee bans kids playing in sprinklers

Tennessee’s new “chemtrail bill” is inherently ludicrous. It’s also as poorly written as cold be expected. From the bill itself:

The intentional injection, release, or dispersion, by any means, of chemicals, chemical compounds, substances, or apparatus within the borders of this state into the atmosphere with the express purpose of affecting temperature, weather, or the intensity of the sunlight is prohibited.

Strictly speaking, the big government types in Tennessee are banning residents from setting up lawn sprinklers for their kids to play in on a hot day.

On the plus side, it will be explicitly illegal to “roll coal” with the intent of covering another person in a cloud of smoke.

Fixing Things with Keyboard Maestro

I can’t help playing with Things sometimes. Even though there are plenty of reasons not to use Things, it’s pretty. It’s my attractive nuisance. However, I can’t stand its inability to complete repeating items before they’re scheduled, so I fixed it.

You know I like Keyboard Maestro and Shortcuts. I combined them to work around Things’s glaring shortcoming. So can you!

First, install my Shortcut, Things: Get ID of current selection. Look inside it. It only copies the internal ID of the currently selected item to the clipboard.

Then, install my Things: Repeat action early Keyboard Maestro macro and set it to trigger with a hotkey you like. Since cmd-K is the using Things shortcut for completing an item, I set mine to trigger when I press shift-cmd-K. Then it takes these steps:

  1. Calls the Shortcut to get the ID of the current Things item.
  2. Goes to the latest completed copy of that item.
  3. Duplicates the completed copy and navigates to the new copy.
  4. Calls the Shortcut to get the ID of the new copy.
  5. Marks that copy as “open”, that is, not completed.
  6. That causes Things to move the copy from the “logged items” section back up to the list of open items, so the macro calls a Things URL to jump back to the re-opened, copied item via its ID that we saved a couple steps ago.
  7. Marks the new copy as deleted. That causes Things to update the repeating task so that its When and/or Deadline dates are relative to today.
  8. Calls the Things URL to jump all the way back to the repeating item, via its ID that we saved in the first step.

Whew. That’s a handful, huh? But it mostly works!

Caveats:

  1. There’s no error handling. Keyboard Maestro just blindly sends keyboard presses and menu selections to Things and assumes that everything’s going well.
  2. I’m not really sure what would happen if you run the shortcut with no items selected, or more than 1 item.
  3. If it’s been ages since the last time the item was completed and there’s no longer a “latest” item to go to, I don’t know what happens next.

In short, use this at your own risk. There are a dozen things it could be doing better or more safely and I haven’t (yet) done any of them. Still, it works! If I squint hard enough and get lucky, the new macro makes Things repeating actions work like every other to-do app in existence. I’m calling that a win.

Testing my fountain pen inks' water resistance

I wondered how water-resistant the inks from the various pens on my desk would be. For my unscientific test, I wrote a small sample of text with each of these inks on a sheet of plain white copier paper:

Don’t judge my penmanship. I know. I know.

Dry inks

I let them dry overnight. Then I used a wet toothpick to put one drop of water on each sample, being careful not to move the paper or water at all. The results were mixed:

Wetted inks
  • Jacques Herbin melted away.
  • LAMY was as ruined.
  • Herbin feathered badly but was readable.
  • Noodler didn’t notice.
  • Fisher blurred slightly.
  • Zebra: what water?
  • Pentel was also lost.

While I don’t make a habit of getting my notes wet, if were carrying a notebook out of the house, I’d pick one of the survivors. Baystate Blue and the Zebra F-701 weren’t affected. The space pen was fine, and Perle Noire was readable. I wouldn’t risk Émeraude de Chivor, LAMY, or EnerGel to rain, drops of water off an ice tea glass, or even damp hands.

My notebooks often spend their entire lives on my desk and I don’t exactly take them scuba diving. Yet, this is a good thing to know.

For my next experiment, I’m going to let the same inks dry for a week before testing.


Followup 2024-03-17: I tried again after letting the inks sit for 2 weeks. The results were similar to the original test:

Two weeks later

The extra time didn’t let them “cure” or “harden” or “set in” or such.

Reliable Shortcuts with Stream Deck and Keyboard Maestro

I talked myself into buying a Stream Deck to control my Mac. I didn’t want one for the media features. I wanted a cool, programmable external keyboard-like thing to trigger actions. For example, I have buttons to turn my office lights on and off, toggle between playing sounds through my external speakers and headphones, and open my notes app to the Today’s Journal page. I like it.

Most docs I found suggest using the Shortcuts plugin to execute Apple Shortcuts. I recommend that you use Keyboard Maestro instead. The “Shortcuts” plugin is neat in principle. It’s free. It looks like exactly the right tool for the job. For me, it’s not. Using the most current macOS (version 14.3.1), Stream Deck app (v6.5.0), and plugin (v1.0.7.1), keypresses work about half the time. After using the setup for a few days straight, it always hangs and stops responding altogether until I quit and restart the Stream Deck app. It’s frustrating to have this nice device to boost productivity, then have to pause for a beat every time I’ve used it to see if it worked.

The Keyboard Maestro setup’s experience has been the opposite. Once configured, if I press a button, that button does what it’s supposed to do 100% of the time. It has some drawbacks: it’s slightly more complex to configure, and you have to pay for Keyboard Maestro (which if you’re a Mac power user, you’ll want to do anyway). Still, the result has been worth it.

Here’s how I used it to build the toggle I mentioned that switches between speakers and headphones.

First, I created Shortcuts called “SoundSource: Output to Headphones” and “SoundSource: Output to Speakers”, with each Shortcut doing the expected thing. The names don’t matter: I could have called them “Spam” and “Eggs” for all my Mac would care. I just like being verbose so I can quickly find things again next time I want to tweak them.

The Shortcuts

Next, I made Keyboard Maestro macros that execute those Shortcuts:

"SoundSource: Output to Headphones" (without trigger) "SoundSource: Output to Speakers" (without trigger)

Then I opened the Stream Deck app to create the “Multi Action Switch” button. I put mine on row 1, column 3. That’ll be important in a moment.

Toggle 1 Toggle 2

When you create a Keyboard Maestro action inside a Multi Action Switch, the Stream Deck app doesn’t fill in the “Virtual Row” and “Virtual Column” values like it would if you put the Keyboard Maestro action directly into an empty key. That’s OK. We’re going to change the column value anyway! See how I used Virtual Columns “301” and “302”? That lets the Keyboard Maestro app treat these as separate buttons. The Stream Deck app will do the work of remembering which action we’re currently on.

With that done, I went back into the Keyboard Maestro editor and added “USB Device Key Triggers” to each macro. When it was waiting for me to press a button, I tapped the physical Stream Deck button I was setting up.

"SoundSource: Output to Headphones" (with trigger) "SoundSource: Output to Speakers" (with trigger)

That’s a little bit more complicated than the “Shortcuts plugin” setup, but only a little bit:

  • I’d have to create the Shortcuts either way.
  • I’d have to create the Multi Action Switch either way.
  • Instead of using the “Shortcuts” plugin to run Shortcuts directly, I send a trigger to Keyboard Maestro and have it run the Shortcuts.

In exchange for this smidgen of extra one-time work, now my Stream Deck buttons work perfectly and instantly every time I press them. I don’t hesitate to see if the effect I wanted to happen had indeed happened because I can trust that it did. That made an enormous difference in how productively I can use the little Stream Deck.

Opt out of Hulu's new binding arbitration clause

Hulu’s new subscriber agreement claims to require users to resolve significant disputes through arbitration. It specifically prevents us from participating in class action lawsuits:

ANY DISPUTE BETWEEN YOU AND US, EXCEPT FOR SMALL CLAIMS, IS SUBJECT TO A CLASS ACTION WAIVER AND MUST BE RESOLVED BY INDIVIDUAL BINDING ARBITRATION.

This is a terrible deal for users.1 Hulu gets the right to hire someone to settle disputes. We lose the right to protect ourselves as a group if Hulu does something horrible that hurts us.

They provide a method for rejecting these clauses in section 7, subsection 7 “Opt-out.” If you wish to retain your legal rights, you have to send them a physical letter stating that you wish to opt out of both the arbitration agreement and the class action waiver. This is the letter I’m sending them:

Me
123 Main St.
Tampa, FL
me@example.com

February 1, 2024

Disney Opt-Out
P.O. Box 11565
Burbank, CA, 91510

Dear Opt-Out Team:

I am opting out of the Hulu Subscriber Agreement’s arbitration agreement and class action waiver.

Sincerely,
 
 
 
Me

I highly recommend you send your version of this typo: email physical mail to Hulu. Otherwise, you’ll lose important legal rights to protect yourself legally if Hulu acts in a way that harms you.


  1. I’m not a lawyer. Ask your own lawyer if they agree. I believe they will. ↩︎

Making Notes look like a Markdown editor, if you squint

I use Apple’s Notes app to, well, take notes. It’s the only non-Markdown I regularly use for such things. While I can, should, and mostly do try to use its built-in keyboard shortcuts to format text, sometimes I find myself looking at the screen wondering why ``` didn’t put it into a pre-formatted text mode. Today I decided to use Keyboard Maestro to indulge my Markdown muscle memory. The results are on my Gitea server.

It’s a collection of short little macros that let me type something like this:

# My title

## A heading

```
def hello():
    print("Hey, world!")
```

---

And that's about it.

and have it render like this:

Resulting note in Notes

Hey! That looks and feels a lot like typing in a Markdown editor!

I don’t want to rely on this. It’s usually better to lean into an app and use it the way it’s built to be used than try to make it act like another. Still, if this reduces a tiny bit of friction on those days when I’m crossing my signals, I’ll be glad to have it.

Adding CarPlay to our Toyota's Entune system

Our 2016 Toyota Sienna is perfect, except for its janky entertainment system. Every time I plugged in my phone, the Entune radio started playing “A a a a a Very Good Song”. It doesn’t have maps, at least that you’d want to bother with using. “Hey Siri” replied with an old, robotic-sounding voice. If you were lucky, playing a song would show an old photo of the band. Music from bands newer than the van would display something generic like “Alternative”. While it worked alright, the whole interface felt like it would’ve been nifty and current on my old Palm PDA.

I envied the CarPlay setups I got to fiddle with in my friends’ cars and in rentals. However, nice replacement entertainment systems that supported CarPlay plus all the same features as the original head unit were way more expensive than I could justify. Then I found a much cheaper CarPlay retrofit unit (affiliate link) with decent ratings, and despite my misgivings, I had to try it.

This little thing is brilliant. The important bits:

  • It works. When I get in the van, after a few seconds my phone connects to the unit and I have a full-featured CarPlay display.
  • It was easy to install myself. While I’m comfortable working on cars, I’d never pulled the family transport apart before without having to fix something broken. Thank you, Toyota, for designing our van like a LEGO kit.
  • Everything else still works. Tapping the head unit’s power button gets back to the original display. Shifting into reverse still shows the backup camera. It adds features without blocking anything that the original system could do. That was my biggest worry, and it was groundless. I can’t overemphasize this: everything still works.
  • The product description and several reviews mention that the Sienna’s display is low-resolution. I had also worried that CarPlay would assume a high-res display and that it would be unreadable on the lousy screen. Nope. It’s fine. Although it’s noticeably blockier than my iPhone’s screen, small text is perfectly readable, street labels and markings are sharp and clear, and it’s not an issue at all. My wife didn’t even realize that it isn’t “Retina” quality.

If you’re on the fence, do it. This relatively cheap little unit fixed all the things I loathed about the original Entune system while keeping all the cool features we enjoyed. I wouldn’t hesitate to recommend the upgrade to a friend or family member.

Biden pardons cannabis users

US President Joe Biden pardoned all Federal convictions for the use and simple possession of cannabis. I don’t use cannabis. If it were to go away tomorrow, my life wouldn’t change one bit.

I am thrilled with this blanket pardon.

Modify the statement, like:

I am pardoning additional individuals who may continue to experience the unnecessary collateral consequences of a conviction for simple possession of beer, attempted simple possession of beer, or use of beer.

and it sounds utterly obvious, and ludicrous that it ever would have been an issue in the first place. I enjoy a good stout or porter, and I can walk into almost any grocery store, flash my ID, hand over my money, and walk out with a bottle of drugs that’s caused far more societal harm than cannabis ever did. That I can drink a beer in public and no one bats an eye, while my neighbors could smoke a joint in their own house and go to jail for it, is insanity.

Good on you, Mr. President, for making life better for a whole lot of Americans.