## Only thing that'll stop a bad guy with a gun...

Dr. Keynes Was Right:

There were at least 433 active shooter attacks — in which one or more shooters killed or attempted to kill multiple unrelated people in a populated place — in the United States from 2000 to 2021. Of those 433, guess how many were stopped by that Good Guy With a Gun? 12. That's 2.7%. And as the report makes clear, response to a motivated shooter, is almost never in real-time.

## Imagine that your job is to preserve every word and make it tell a story. Meet the lexicographers behind the OED

The English language evolves at such a pace that, for the OED lexicographers, the goalposts aren’t so much shifting as sprinting away from them. Once a word has gained its place, it may be moved – for example, to be listed as a variant spelling – but it is never taken out, meaning that the dictionary only ever expands. (This is true even of mistakes. The word “astirbroad” was added in 1885, but when an editor came to revise it in 2019, they discovered that it was an early-modern typo: the typesetter for the 17th-century book in which the word was originally found had dropped the word “stir” into “abroad”. Still, astirbroad remains.) Nor is the OED limited to British English: the dictionary includes varieties spoken outside the UK – what its editors refer to as “World Englishes” – from Singapore to Jamaica.

## The perfect crime – undone by the perfect email backups

“You mean,” came the horrified question, “when we press delete, the emails don't actually delete, they get saved to backup tape?”

## Back-to-office mandates won't work, says Salesforce's Benioff

Salesforce is no stranger to the debate, having cancelled the lease on an unbuilt 325,000 square foot (30,193sqm) tower. Last year, Brent Hyder, Salesforce president and chief people officer, said that “the employee experience is about more than ping-pong tables and snacks” as he announced an end to the assumption that most staff would work from the office, and introduced a flexible working plan.

This week CEO Marc Benioff has gone further, saying an enforced return to the old normal won't be successful.

## The Rabbit Died

The scientists have said to prepare for another Covid Winter. Listen to them.

#covid19

## The Controversial Economics of Abortion Law

Competing views on the economics of abortion were a part of the Court’s considerations. A group of 240 female researchers who oppose abortion filed an amicus brief in the case, arguing that abortion access had set women back after Roe. Legalization, they argued, coincided with more women falling into poverty, women reporting lower levels of happiness in surveys and fewer women saying they were in satisfying long-term relationships.

An opposing group of 154 economists, led by Prof. Myers, filed their own amicus brief in response, pointing to “a substantial body of well-developed and credible research” that contradicted the anti-abortion brief. They argued that in giving women more control over their childbearing preferences, abortion legalization led to a range of social and economic benefits for women, particularly related to education and work.

Research on these questions hinges on the fact that a number of states legalized abortion before the Supreme Court did so nationally with its 1973 decision in Roe. Economists saw an opportunity to examine the economic and social effects of abortion access by looking at the states that had legalized abortion by 1970—Alaska, California, Hawaii, New York and Washington—and several others that had liberalized restrictions. By comparing them to states that legalized later, they had a natural experiment.

## Introduction: The Questions of Minimal Computing

Broadly speaking, minimal computing connotes digital humanities work undertaken in the context of some set of constraints. This could include lack of access to hardware or software, network capacity, technical education, or even a reliable power grid.

#digitalhumanities

## Government Watchdogs Attack Medicare Advantage for Denying Care and Overcharging

Congress should crack down on Medicare Advantage health plans for seniors that sometimes deny patients vital medical care while overcharging the government billions of dollars every year, government watchdogs told a House panel Tuesday.

## WSJ on the pointlessness of cover letters

Some job seekers say writing cover letters is a job itself, and one that yields little reward for the effort. Before Devin Miller’s most recent job, he wrote about 10 cover letters to companies he wanted to work for. Each was different, and he wanted to signal that he knew what the work would entail, he said. He heard back from none. To get his current role, he responded to a recruiter who had reached out to him and asked just for a résumé, the 33-year-old Mr. Miller said.

My experience looking for a job last year was the same as Devin's. For all the applications with carefully-crafted cover letters, I got one, five-minute conversation with an HR specialist where I explained that, no, that salary offer isn't adequate. Every other interview I had came from a recruiter who found my LinkedIn profile and messaged me here.

## Samsung accused of cheating on hardware benchmarks ... again

“Not that we cheated or anything, but we want to make it clear that we're totally allowed to cheat.”

An algorithm to detect and hoodwink benchmarking software is just what Samsung was accused of employing in those earlier examples. The chaebol never denied or admitted any wrongdoing, instead arguing it wasn't obligated to tell consumers if its devices included code that allowed it to best benchmarks.

## Google sidelines engineer who claims its AI is sentient

Lemoine, a military veteran who has described himself as a priest, an ex-convict and an AI researcher, told Google executives as senior as Kent Walker, president of global affairs, that he believed LaMDA was a child age 7 or 8. He wanted the company to seek the computer program’s consent before running experiments on it. His claims were founded on his religious beliefs, which he said the company’s human resources department discriminated against.

“They have repeatedly questioned my sanity,” Lemoine said. “They said, ‘Have you been checked out by a psychiatrist recently?’” In the months before he was placed on administrative leave, the company had suggested he take a mental health leave.

#insurance

## Court Says Bees Are Fish

In 1969, the Legislature decided to expand the Commission’s authority to include amphibians. Did it do so by narrowing the “fish” definition to fish and then adding one for amphibians? Nope. It just stuck them in with the fish. And then in 1984, it wanted to add “invertebrates.” Did it take this opportunity to straighten things out? Nope. In they went. And this is how we got the statute that the Court of Appeal was interpreting in the Almond Alliance case. It now says this:

“Fish” means a wild fish, mollusk, crustacean, invertebrate, amphibian, or part, spawn, or ovum of any of those animals.

### We've never even built datacenters using robots here on Earth

Making a call on the quality of a new idea in tech can be hard. But if you ask me, not in the case of Lonestar Data Holdings, whose plan to build datacenters on the Moon is literal lunacy.

Take a look at Azure's or AWS's infrastructure maps. Think about what would have to happen to make your data, backed up across even half those locations, permanently unavailable. Would you be able to download anything from the moon? Would you be around to care?

The only data that might be worth putting on the moon is a greeting to any aliens who wander by after we're extinct.

The study, published yesterday in JAMA Network Open, found that children who received inappropriate or non-recommended antibiotics for common viral and bacterial infections had an increased risk of adverse side effects such as Clostridioides difficile infection, severe allergic reactions, and rashes. The additional medical care needed to address these adverse events resulted in roughly $74 million in excess healthcare costs in 2017. ### A Profile of PimEyes, Which Performs Facial Recognition on Public Photos PimEyes disclaims responsibility the results of its search tool through some ostensibly pro-privacy language. In a blog post published, according to metadata visible in the page source, one day before the Times’ investigation, it says its database “contains no personal information”, like someone’s name or contact details. The company says it does not even have any photos, storing only “faceprint” data and URLs where matching photos may be found. Setting aside the question of whether a “faceprint” ought to be considered personal information — it is literally information about a person, so I think it should — perhaps you have spotted the sneaky argument PimEyes is attempting to make here. It can promote the security of its database and its resilience against theft all it wants, but its real privacy problems are created entirely through its front-end marketed features. If its technology works anywhere near as well as marketed, a search will lead to webpages that do contain the person’s name and contact details. ### Big Tech loves talking up privacy – while trying to kill privacy legislation The report examined 31 states when state legislatures were considering privacy legislation and identified 445 lobbyists and lobbying firms working on behalf of Amazon, Apple, Google, Meta, and Microsoft, along with industry groups like TechNet and the State Privacy and Security Coalition. ### How We All Got in Debt “For the first time, money from the core of capitalism, the consumer banks, was invested, albeit indirectly, in consumer debt,” Hyman writes. “What began with automobiles spread to vacuum cleaners, furniture, radios, and nearly every kind of durable good desired in the great boom of the 1920s.” ### Computers Beat Oncologists In Predicting Death From Cancer: Now What? Put bluntly, an oncologist saying they would not be surprised that a patient would die within 3 months is a poor prognostic sign. But them saying they would be surprised is not terribly reassuring. Oncologists are optimistic. They only correctly identify about 30% of the patients who died within that 3-month period. ### Despite a First-Ever ‘Right-to-Repair’ Law, There’s No Easy Fix for Wheelchair Users The multibillion-dollar power-wheelchair market is dominated by two national suppliers, Numotion and National Seating and Mobility. Both are owned by private equity firms that seek to increase profits and cut spending. One way they do that is by limiting what they spend on technicians and repairs, which, when combined with insurance and regulatory obstacles, frustrates wheelchair users seeking timely fixes. ### Pulse Oximeters Are Less Accurate Among Black, Hispanic and Asian Covid-19 Patients Even a small inaccuracy in estimated oxygen saturation can have significant implications for a patient’s treatment options, said Tianshi David Wu, a study co-lead author and assistant professor of medicine at Baylor College of Medicine. In the Johns Hopkins Health System, for instance, patients who had pulse oximeter measurements below 94% were considered to have severe Covid-19. ### Why masks work, but mandates haven’t From the beginning of the pandemic, there has been a paradox involving masks. As Dr. Shira Doron, an epidemiologist at Tufts Medical Center, said, “It is simultaneously true that masks work and mask mandates do not work.” ## Building Gopher services with Python For April Fools, 2021, I migrated Dinerville to Gopher (I know: lol). It was a refreshingly simple change from web development. Three evenings of work gave me a gopher server that presents all the content from a much more complex website. Pituophis is a Python module for writing both Gopher servers and clients. Pituophis's default “handler” function acts as a basic Gopher server, publishing items in a specified directory to Gopherspace; an optional user-defined alternate handler function responds when a missing file is requested. You can also replace the default handler and build your own Gopher application from the ground up. One limitation of Pituophis compared to a web framework is the lack of a routing engine. That's easy enough to work around with a list of regular expressions and “controller” functions: if request.path in ('', '/'): return homePage(request) if request.path == '/about': return aboutPage(request) paths = [ (re.compile('/image/([\w-]+)\.(gif|jpg|png)$', re.IGNORECASE), sendImage),
(re.compile('/([a-z]{2})$'), statePage), (re.compile('/([a-z]{2})/([\w-]+)$'), cityPage),
]

for pat, func in paths:
m = pat.match(request.path)
if m:
return func(request, m)


## Gopher Responses

While it’s possible to just serve text files from Gopher, at some point you’ll need to construct a menu (Wikipedia was surprisingly helpful with the syntax here). The term “menu” covers any gopher interface that includes links. Menus are tab-separated value files—the first column is a one-character content-type code followed by text that’s displayed to the user; that’s followed by an address on the server you’re linking to, the server address itself, and a port number. These columns are all required even for informational lines.

The lines below that start with “1” are links to other menus; lines with “i” (lowercase i) are “informational”, meaning just lines of text. Other important codes are “h” for HTML pages and “I” (uppercase I) for images.

iSOME OTHER USEFUL GOPHER SITES	/		0
i	/		0
1Gopherpedia	/	gopherpedia.com	70
1Floodgap systems, including the Veronica-2 search engine	/	gopher.floodgap.com	70
1The Gopher Movie Database	/1/cgi-bin/gmdb.py	jan.bio	70
1gopher.club (A collection of Gopher logs, or "phlogs")	/1/phlogs/	gopher.club	70


Pituophis provides an Item class that represents an individual line of a gopher menu and will convert a list of them, returned from a handler function, into a Gopher menu page. This code comes after a few database queries and returns basic information about a diner, including links to photos and outside info:

outp =  [Item(text=f'{diner.name} ({diner.make}{serial})'),
Item(text=f"{diner.city}, {diner.state}  {diner.zip}"),
Item(),
Item(text=f"Status: {diner.status_str}"),]
outp += [Item(itype='h', text=row.title, path=f"URL:{row.url}") for row in links]
outp += [Item(itype='I', text=caption[0], path=f"/image/{photo.filename}", host=settings.HOST, port=settings.PORT)]


(Item(), in the code above, produces a blank line).

## Finally

That's a very basic overview, but hopefully enough for some exploration if you're interested.

## PowerShell prompts

In PowerShell, you modify your shell prompt by defining a function called prompt, generally in your profile.ps1 file (or wherever $PROFILE.CurrentUserAllHosts points to). Its return value is used as your prompt. I've spent a fair amount of time tinkering with mine, but currently there's nothing particularly special there, just the current time, path, and information about the Git repository the current path is part of, if applicable (courtesy of posh-git). One thing I'm not entirely happy about here is that the path is sometimes far to long, and won't even fit within the width of my shell window. I'd like to find a way to truncate it if it's above a certain length, but haven't spent much time on this problem yet. Import-Module posh-git New-Alias which Get-Command ... function prompt {$(if (Test-Path variable:/PSDebugContext) { '[DBG]: ' }
else { '' }) +
"($(Get-Date -Format 'H:m:ss')) " +$(if ($NestedPromptLevel -ge 1) { '>>' }) +$(Get-Location).Path +
\$(Write-VcsStatus) +
'> '
}


#powershell

## Improved MiniZinc Cryptarithms

Previously, I posted an experiment in solving cryptarithms with Python and MiniZinc. I've just put an improved version on GitHub, since I figured out how to generalize the problem somewhat—Python now just converts your problem into a dictionary and feeds that to an existing script that doesn't have to change. This new model still has some rough edges—artifacts of the learning process—but it works well enough.

## Cryptarithms with MiniZinc, Python, and pymzn

A couple of entries in the AMS Page a Day Calendar so far have been cryptarithms. I most recently encountered these in the Coursera course on “Basic Modeling for Discrete Optimization”, which uses them as an early example to teach MiniZinc. It's fairly easy to adapt existing code to solve this problem:

ZEROES + ONES = BINARY:

%From the AMS page-a-day calendar
var 0..9: Z;
var 0..9: E;
var 0..9: R;
var 0..9: O;
var 0..9: S;
var 0..9: N;
var 0..9: B;
var 0..9: I;
var 0..9: A;
var 0..9: Y;

constraint Z != 0;
constraint O != 0;
constraint B != 0;

constraint
100000 * Z + 10000 * E + 1000 * R + 100 * O + 10 * E + S
+                          1000 * O + 100 * N + 10 * E + S
= 100000 * B + 10000 * I + 1000 * N + 100 * A + 10 * R + Y;

include "alldifferent.mzn";
constraint alldifferent([Z,E,R,O,S,N,B,I,A,Y]);

%solve maximize (10000 * V + 1000 * E + 100 * R + 10 * S + E);


It's probably fairly easy to make a MiniZinc script that reads the problem from a data file instead of having it hardcoded, but I'm not that good with MiniZinc (I haven't finished the course). But this does seem like a good excuse to tinker with pymzn, a Python interface to MiniZinc (NB: Besides pymzn, there's also an official Python minizinc module). Here's my Python script to build a MiniZinc cryptarithm-solver script, run it, and return the results:

import io
import json
import re

import pymzn

def cryptarithm(problem):
mznscript = io.StringIO('')
prob = problem.replace(' ', '')
(facs, solution) = prob.split('=')
facs = facs.split('+')

#Set of all unique letters in the problem
letters = set(re.sub('[+=\s]', '', prob))
#All letters at the beginning of a "number"
initials = set([fac[0] for fac in facs]+[solution[0]])

#declare all variables.
#First letters != 0.
print(*[f'var 1..9: {l};' for l in initials], sep="\n", file=mznscript)
print(*[f'var 0..9: {l};' for l in letters.difference(initials)], sep="\n", end="\n\n", file=mznscript)

#Each letter stands for a different number.
print('include "alldifferent.mzn";', file=mznscript)
print(f'constraint alldifferent([{",".join(letters)}]);', file=mznscript)

print('\nconstraint', file=mznscript)

#This is ugly. Don't do this in actually-useful code.
print('    '+'\n  + '.join([' + '.join(f'{10**n} * {l}' for n,l in enumerate(reversed(tuple(fac)))) for fac in facs]), file=mznscript)
print('  = '+' + '.join([f'{10**n} * {l}' for n,l in enumerate(reversed(tuple(solution)))])+';', end="\n\n", file=mznscript)

print('solve satisfy;', file=mznscript)

mznscript.seek(0)

return (script, [dict(sorted(json.loads(sol).items(),  key=lambda x: problem.index(x[0])))
for sol
in pymzn.minizinc(script, output_mode='json')])


And some use examples:

>>> script, solutions = cryptarithm('ZEROES + ONES = BINARY')
>>> print(solutions)
[{'Z': 6, 'E': 9, 'R': 8, 'O': 3, 'S': 2, 'N': 1, 'B': 7, 'I': 0, 'A': 5, 'Y': 4}]

>>> script, solutions = cryptarithm('SEND+MORE=MONEY')
>>> print(solutions)
[{'S': 9, 'E': 5, 'N': 6, 'D': 7, 'M': 1, 'O': 0, 'R': 8, 'Y': 2}]

>>> script, solutions = cryptarithm('SO+MANY+MORE+MEN+SEEM+TO+SAY+THAT+THEY+MAY+SOON+TRY+TO+STAY+AT+HOME+SO+AS+TO+SEE+OR+HEAR+THE+SAME+ONE+MAN+TRY+TO+MEET+THE+TEAM+ON+THE+MOON+AS+HE+HAS+AT+THE+OTHER+TEN=TESTS')
>>> print(solutions)
[{'T': 9, 'A': 7, 'O': 1, 'M': 2, 'H': 5, 'S': 3, 'E': 0, 'N': 6, 'Y': 4, 'R': 8}]

>>> script, solution = cryptarithm('TWO + TWO = FOUR')
>>> print(solution)
[{'F': 1, 'T': 7, 'W': 3, 'R': 8, 'U': 6, 'O': 4}]