Shiitake Mushroom Jerky

We saw jerky-style shiitake mushrooms on Shark Tank a few days ago, and their SEO isn’t awesome because searching for “shiitake mushroom jerky” doesn’t show their company’s site in the first page. And, since I didn’t remember the company’s name … that makes ordering it difficult. The first page of results does, however, provide a lot of recipes. So I picked up a pound of shiitake mushrooms at the grocery store (a.k.a. every not-dodgy-looking shiitake they had in the bulk mushroom section). I marinated them for 24 hours in a combination of 1/4 c soy sauce, 1/4 c low-sodium soy sauce, 1/4 c apple vinegar, a clove of garlic (diced into small pieces), and a sprinkle of crushed red pepper (ground). I roasted them at 200 F for a LONG time. The recipes said 90 minutes to two hours, but it was after midnight when I turned off the oven, and I had started cooking the things at 7PM. So that’s at least five hours. A food dehydrator would be a good investment if we’re going to keep making mushroom jerky!

End result — it’s way too salty. Possibly using 1/2 c of low sodium soy would have been OK … but thinking of using veggie stock for some of the soy. And possibly making one with a few tablespoons of maple syrup instead of garlic.

VSCode Search/Replace Using Regex Capture Groups

Regex adds a lot of flexibility to search/replace operations. Capture groups allow you to manipulate the found data in the replacement text. As an example, I have simple mathematical equations that are not spaced out reasonably. I could replace “+” with ” + “, “-” with ” – “, “*” with ” * “, “/” with ” / “, and “=” with ” = “, but using a capture group to identify non-whitespace characters and the range of operators allows a single search/replace operation to add spaces to my equations.

Selecting the regex option (in blue below), I can use the regular expression (\S+)([\+,\-,\*,\/])(\S+)=(\S+) as my search string. This means the first capture group is one or more non-whitespace characters, the second capture group is one of the characters +,-,*,/, the third capture group is one or more non-whitespace characters, there’s an equal sign (which I could make into a fourth capture group), and the fourth capture group is one or more non-whitespace characters.

An alternate regex finds zero or more whitespace characters — (\S*)([\+,\-,\*,\/])(\S*)=(\S*)

The replacement text then uses each capture group — $1 $2 $3 = $4 — to add spaces around the operators and around the equal sign.

 

Impossible Meatball Sub

Our power went out last week, and we were discussing where to pick up dinner for the night. I kind of wanted to get sandwich-makings, but it was cold. While I could easily have sold warm sandwiches … cold sandwich makings from the store had limited appeal. And, unfortunately, there’s nowhere around here to get a veggie meatball sub. We ended up getting pizzas from Pizza Hut because they now offer Beyond’s Italian sausage as a topping. It was really good (good enough we ordered another pizza the next night of our power outage), but I was still hungry for a meatball sub.

Now that we’ve got power again, I picked up a package of Impossible’s ground-beef-style stuff. It looked pretty dodgy — a grainy lump of red stuff. I added panko, salt, shredded Parmesan cheese, ground pepper, an egg, and Italian herbs. Mixed it all up and rolled them into balls. Fried them until crispy. For a comparison, I used the same basic recipe with mushed cannellini beans. I should have made the cannellini balls smaller so they’d have been crispier.

The Impossible meatballs were awesome. Not exactly a meatball — they were a little dry, but that would have been solved by simmering them in the sauce (something I intentionally didn’t do because I wanted them to be crispy). I think rolling the meatball around a little bit of mozzarella cheese might work too.

Either way, we had really good meatball subs. And between the can of cannellini beans and the pack of Impossible ground-beef-style stuff, it was enough for dinner yesterday and lunch again today.

Chicken Tractor

Scott started putting together a mobile chicken tractor. The metal tube is repurposed from one of those canvas covered pavilion things that came with the house. Massive wind storm, years ago, took it out. It’s been a hop arbor and now a chicken tractor. Since it articulates a little bit, it fits the contours of the ground. We still need to mount some fencing … well, sand it down a bit and repaint it too! But it’s a large, portable space for the chickens to roam when we’re not hanging out in the yard keeping an eye on them.

Musing on Pardons

 
Trump’s potentially got exposure in issuing pardons if he’s covering up crimes in which he was involved. Bit of a legal stretch (and proving corrupt intent would be difficult). No point *now* with the OLC policy against indicting a sitting president, and we’ll probably get another “for the sake of unity, put the past in the past” administration. But it seems feasible.
 
And I’m curious how pardons impact 5th amendment protection. If you’ve got a pardon for *your* part in the crime, you’re not being ‘compelled in any criminal case to be a witness against himself’ and I expect could be compelled to testify against others (including Trump) who were involved. Or be charged for failing to provide honest testimony.

Understanding Exponential Growth

Using the data from https://covidtracking.com/data/national/cases: in the most recent seven day span (10-16 November), 1,056,346 people in the US have been infected with this coronavirus. The total number of cases yesterday was 11,047,064. That means 9.562% of the *total cases* in the US were new cases in the past week.

 

This is how exponential growth works — and why you heard a lot about ‘flattening the curve’ earlier in the year. If you put a penny on the first square of a chess board, double it and put two pennies on the second square, double it and put four pennies on the third square, and continue in that fashion … mathematically, you have 2^n pennies on each square, where n is the numeric sequence of the square, 0-63. On the last square in the first row, square #7, there are 2^7 pennies — 128 pennies, or a buck and twenty eight cents. Not a lot. And the end of the second row, you have 2^15 pennies — 32,768 pennies. That’s $327.68 — over three hundred bucks. A lot more than a buck, but not a huge amount of money. But you’re up to 2^23 at the end of the third row — 8,388,608 pennies or $83,886.08. Eighty three grand is a lot of money. By the time you get to the mid-point on the board, the end of the fourth row, you have 2^31 pennies on a square. 2,147,483,648 pennies for $21,474,836.48 — over twenty million dollars. A lot of money, but it’s possible. The second half of the chessboard is where exponential growth becomes unsustainable. The end of the fifth row is 2^39 — 549,755,813,888 pennies. The end of the sixth row is 2^47 — 140,737,488,355,328 pennies. The end of the seventh row is 2^55 —  On the final square, you have 2^63 … 9,223,372,036,854,775,808 pennies for $92,233,720,368,547,758.08 … 92 quadrillion dollars. If the going price of Earth is only five quadrillion dollars, you’re putting a marker for the entire solar system (and then some) on that last square.

And that ignores the accumulating total — while you have 92 quadrillion dollars on the final square, you have another 92 quadrillion dollars on the entire rest of the board. Now, obviously, we are not doubling our rate of infections every day. But we’re entering “second half of the board” territory just the same.

Discourse acme.sh Script Failure

I had a hellacious time updating the certificate on my Dockerized Discourse server — the acme.sh script doesn’t have a slash delimiter between the hostname and the ./well-known folder within the URI. Which means the request fails. Repeatedly.

 

[Sat Oct 10 00:01:09 UTC 2020] _post_url='https://acme-v02.api.letsencrypt.org/acme/chall-v3/7784162898/nr42-g'
[Sat Oct 10 00:01:09 UTC 2020] _CURL='curl -L --silent --dump-header /shared/letsencrypt/http.header -g '
[Sat Oct 10 00:01:10 UTC 2020] _ret='0'
[Sat Oct 10 00:01:10 UTC 2020] code='200'
[Sat Oct 10 00:01:10 UTC 2020] trigger validation code: 200
[Sat Oct 10 00:01:10 UTC 2020] sleep 2 secs to verify
[Sat Oct 10 00:01:12 UTC 2020] checking
[Sat Oct 10 00:01:12 UTC 2020] url='https://acme-v02.api.letsencrypt.org/acme/chall-v3/7784162898/nr42-g'
[Sat Oct 10 00:01:12 UTC 2020] payload
[Sat Oct 10 00:01:12 UTC 2020] POST
[Sat Oct 10 00:01:12 UTC 2020] _post_url='https://acme-v02.api.letsencrypt.org/acme/chall-v3/7784162898/nr42-g'
[Sat Oct 10 00:01:12 UTC 2020] _CURL='curl -L --silent --dump-header /shared/letsencrypt/http.header -g '
[Sat Oct 10 00:01:13 UTC 2020] _ret='0'
[Sat Oct 10 00:01:13 UTC 2020] code='200'
[Sat Oct 10 00:01:13 UTC 2020] discourse.example.com:Verify error:Fetching https://discourse.example.com.well-known/acme-challenge/XY02T_40TL92IADByQ45JMj4JzC2qJCatVd2odJMAlU: Invalid host in redirect target
[Sat Oct 10 00:01:13 UTC 2020] pid
[Sat Oct 10 00:01:13 UTC 2020] No need to restore nginx, skip.

 

Turns out that’s my bad config — I’ve got a reverse proxy in front of Discourse, and we don’t use the clear text http site. The reverse proxy just bounces you over to the https site. Two problems — one, I failed to put the trailing slash after my redirect, s http://discourse.example.com/.well-known/blah is being redirected to https://discourse.example.com.well-known/blah

<VirtualHost 10.1.2.3:80>
ServerName discourse.example.com
ServerAlias discourse

Redirect 301 / https://discourse.example.com

</VirtualHost>

 

That’s easy enough to fix — add the trailing slash I should have had anyway. But the subsequent problem is that the bootstrap nginx config that is used to serve up the validation page only listens on port 80. So I cannot redirect the clear-text traffic over to the SSL site. I have to reverse proxy the clear text site as well (at least whenever the certificate needs to be renewed).

ProxyPass / https://discourse.example.com/
ProxyPassReverse / https://discourse.example.com/

Voila, a web server with an updated certificate.

New Teams Features for Developers

Two new features announced that might be of interest to developers — the first one might provide a mechanism to move (well, copy) content between Teams spaces. You can read channel messages from a Teams space, analyze it, then use this new API to mirror the content into a new Teams space.

Importing third-party platform messages to Microsoft Teams is now available in beta

These new capabilities give you the ability to import channel messages into a new team, specify the message sender and timestamp and link to files. These capabilities are built with scale in mind. At a high level, the import process consists of the following:
• Create a team with a back-in-time timestamp
• Create a channel with a back-in-time timestamp
• Import external back-in-time dated messages
• Complete the team and channel migration process
• Add team members
https://developer.microsoft.com/en-us/microsoft-365/blogs/importing-3rd-party-platform-messages-to-microsoft-teams-is-now-available-in-beta/

Teams Meeting Scheduling Link Template

With the new Teams Meeting Scheduling Link Template, developers can embed a meeting link generator directly into their scheduling platform–providing an easy way for users to create Teams meeting links and share them directly with participants.
https://developer.microsoft.com/en-us/microsoft-teams/meeting-scheduling