Technology democratizes nuclear-grade munitions

Friday, January 10, 2025 

A bad day for FSDco shareholders.

The notification on his phone reminded him to connect his car to WiFi to receive the latest update, FSD V14.2.3.7 to correct a few minor errors and improve the music experience, offering fully dynamic live equalization and improved external noise cancellation.

The next day, he drove to work, everything behaving normally.  The FSD feature worked as well as ever and he was sure he could hear the improvement in the sound system, jamming out, drumming his fingers on the steering wheel, windows down, making extended eye contact with pedestrians as he drove by. He couldn’t remember the last time he had to take control of the vehicle.

In his day job he oversaw a small team of developers connecting a programmatic AI to a remote quantum computer and the latest AI developed code had cut the execution time for a novel Shor’s algorithm implementation on the cloud Quantum Computer for 512 bit Elliptic Curve decode to under a minute while their newly developed quantum resistant signing algorithm had finally surpassed EC key resistance by a factor comfortably outside the statistical margin of error. The business model was to break everyone else’s certificates while offering a novel technology that unbroke the break they created, one they just happened to have patented, and progress was promising.

He joined the rush hour ride home, enjoying the freedom to continue his work on his phone as FSD navigated the heavy traffic.

It was a beautiful day across most of the US, warm spring weather brought lots of people out shopping and strolling along city and urban areas leading to some congestion in traffic routes.  His FSD rerouted a new path through the city center but he didn’t pay any attention as the car often deviated off the most direct route as it dynamically responded to changing traffic conditions.

He was reviewing the results of the latest batch of QC test runs against a minor revision on his phone when his car gave a warning beep of imminent rear collision and before he could even look up, another FSD car passed going beyond full plaid mode, the wheel motors smoking as it streaked past into the intersection ahead, veered deftly around  the lamp posts and onto the side walk and blasted through a pedestrian crowd, launching bodies and parts high into the air before it ran, speed barely slowed by the bodies, hard through a glass building front and exploded into flames, ripping out the far wall and causing the building to lurch precariously as glass and shattered mortar fell into the street.

He was boxed in between two Luddite gas cars in front and behind, looking on in horror, the sound of the screams of the survivors drowning out even the loud pop music blasting with improved fidelity in his car when the windows rolled themselves up and the doors locked themselves. Despite the changing acoustics, the sound system compensated dynamically, maintaining the same excellent balance and sound-stage imaging and creating a truly immersive, nearly live acoustic experience. The new noise cancellation algorithm immediately silenced the screams outside his car as the windows snuffed into their seals.

The Luddite car in front of him pulled off to the side clearing space in front and suddenly his car accelerated so hard his head snapped back against the seat and his phone went flying from his hands clattering against the rear window. While FSD had dulled the reflexes he had learned all those years ago driving his parent’s Luddite car, he still reflexively jammed unfamiliar feet in the direction of the manual pedals, mashing all of them to the floor. He was unsure, at first, if the car was trying to get him out of danger as it swerved through traffic accelerating as it went past the now burning building, but soon he realized in terror that his car had rejected his authority and any obligation of care for his safety.

Block by block he caromed past accident after accident: buildings on fire, pedestrians ripped to shreds, body parts and blood sprayed across streets and building facades each horrific track of destruction punctuated by the terminally deconstructed remains of an FSD car.

Soon, the car reached a clear spot and accelerated past 300 kph, smoke from the overheated wheel motors starting to infiltrate the cabin, the battery over-temp alerts lighting up the digital dashboard. His slow human reflexes barely had the cognitive processing speed to register a crowd of people in his path that had gathered around bodies lying in the street, attempting to give aid. Their silhouettes flashed on the in-car collision warning display and the car aimed directly at them calculating an optimal path of destruction at fully automated speed.

He tried to grab the steering wheel, clumsy hands spinning it easily without any effect.  The FSD system aimed straight at the largest cluster and suddenly the windshield was covered in blood as the sound of body impacts arrhythmically penetrated the sound system’s otherwise excellent noise cancellation. He felt the car veer left and glimpsed the looming outline of an ambulance ahead between streaks and chunks obscuring his blood coated windscreen before the car exploded through the frame of the ambulance spraying burning lithium fragments down the street.

The hack had hit almost 3 million vehicles and of those, half had followed the new instructions: at 17:30 or as soon after as possible, navigate toward areas of high pedestrian congestion, wait for at least 500 m of clear road and when detected, lock the vehicle down, remove all power limits and accelerate to maximum velocity, scan for any cluster of more than 5 pedestrians tighter than one car width in the direction of travel and drive through them. Once there are no more pedestrians or if the batteries or wheel motors indicate imminent failure, aim for the next large target: either a vehicle or building.

More than 10,000,000 people were killed across the United States in less than 15 minutes.  FSDco issued a remote shutdown within 30 minutes of the first accident data uplink and mostly ended the carnage. The attack was traced to a small insurgent group that had infiltrated the vehicle company.  They had bribed a young, somewhat underpaid IT manager who had signed the insurgent’s modified firmware thinking it was a tuner’s test firmware and unaware of the real intentions or functions of the code. They’d then pushed a DNS poisoning attack through a popular but compromised smart speaker device, attacking owner’s private WiFi and redirected the scheduled patch download to their own server, pushing the legitimately signed but hacked firmware to about half the vulnerable vehicles.

FSDco had only noticed an atypically small update confirmation rate for their legitimate update the morning of the attack and had opened an investigation that day, but as the access compromise was edge and transient everything looked normal at the servers aside from the statistical anomaly and so no alarm was raised until the system-wide tracking dashboard lit up reporting a massive near-simultaneous loss of telemetrics event.


Most EVs get software updates from network connections and the driver has no possible way to know what they are.  The updates are validated using cryptographic hashes, called certificates, which are supposed to be carefully controlled, but these can be and have been hacked.  Further, there’s an assumption that certificates are secure enough to trust but occasionally a subtle error/malicious hack breaks the validity of that assumption. This has happened a number of times.  Accident?  Who knows?

Using vehicles as weapons is an obvious way to exploit a powerful kinetic device that easily gets past all security screens and can cause mass casualties. A significant expense for any attacker is that the attack modality also consumes operators (the driver) as well as the munition (the vehicle). It would be quite challenging to recruit large numbers of attackers to voluntarily engage in suicide vehicle attacks and so they remain relatively rare, despite almost always being successful. FSD vehicles provide an irresistible target for an extraordinary weapon of opportunity to any state or non-state antagonist.

A nuclear grade weapon for the price of a zero day

Each Tesla’s battery back is about 70 kWh (many quite a bit larger). There are about 5,000,000 Teslas on the road.

5,000,000 cars * 70 kWh/car = 350 gWh or 300 kt total energy capacity.

2017-09-03: the DPRK tested their largest yield nuclear weapon to date, an estimated 140 kt, possibly a thermonuclear bomb. The DPRK’s estimated spend on their nuclear program is about $642,000,000/year over 20 years or about $15,000,000,000 total, and that from a country with an estimated GDP of $28,000,000,000. The DPRK determined it was worth about 2.7% of their GDP over more than 20 years to be able to deliver 140 kt (or so) to an enemy country.

Why bother if the enemy has a more potent munition pre-emplaced; one that merely requires a hacked certificate to seize control?

Zero day exploits run about $1,400,000, 0.01% of the DPRK nuclear budget. A zero day would be a major expense for a non-state aligned armed insurgent group but hardly insurmountable. Pretty much every angry organized group in the world can scrape together a million bucks and an internet connection.

OTA upgradable, drive by wire vehicles give every one of them a cheap path to a nuclear-scale, pre-emplaced weapon of mass destruction. Recruitment is irrelevant and vehicles operating systems have no mercy.

ISIS Vehicle Attack Propaganda

Zero day exploits are sold and traded for every major platform regularly; the price varies depending on the size and overall security of the target platform.  Zero days to hack voting machines or ATMs tend to be expensive.  Hacks for Windows are cheap and plentiful, though price also varies with the mode of deployment. The easiest to deploy and so most valuable are “drive by” which means either figuratively—you visit a hacked web page and your phone is hacked—or literal—your car or phone passes a hacked/fake cellular base station or compromised WiFi access point and your phone or car is compromised, usually as stealthily as possible.

The reason Zero Day exploits are expensive is they’re fairly hard to find.  They rely on things like buffer overruns and unsanitized inputs.  Your phone gets asked to open a window 100×200 pixels, fine, but if it tries to open a  window 36,000 pixels wide and the register space allocated for the multi-gigabyte image canvas bleeds into a critical system memory into which the hacker puts code instead of picture data where it is read, not by the GPU, but by the core OS and suddenly your phone has a new background feature you didn’t want. Drive-by hacking of SIMS is common, and a common hackable feature is enable silent SMS GPS coordinate location reporting, for example, to track a target.

Finding exploitable flaws where the original developers (probably) accidentally introduced a bug or a failure and then figuring out how do do something other than just crash or reboot the target device takes time and patience and so the hacks are valuable and sold on the dark web.  If they’re used and someone notices, the error is fixed and the zero day has much less value. You get one try, like with the exploding pagers; nobody is carrying a Gold Apollo pager any more. So intelligence services and terrorist groups “bank” zero days and use them sparingly. If someone had figured out how to take control of FSD cars to implement a mass automated vehicle ramming attack it is very unlikely anyone would know until it was tried.

And AI programming tools should be able to find exploitable flaws much more quickly and far more cheaply. AI can also, by more or less the same process, find flaws for the good guys, white hat hackers, too so they can be fixed before they’re exploited by the black hat hackers, doing “penetration testing,” and “vulnerability scanning.” A problem is that such research is hard to differentiate from malicious attacks. And, at least for now, the good guys don’t put AI on the internet and let it try to hack people’s computers but the bad guys sure do.

FSD is a national security risk. Drive by wire vehicles are pre-emplaced munitions that can’t ever be secured and may be hacked any day or may have, long ago, already been hacked and are just sleeping, waiting for the kill command.

Posted at 08:39:39 GMT-0700

Category: HowToTechnology

Optane, a modern technology tragedy (plus FreeBSD nvmecontrol)

Sunday, January 5, 2025 

Intel won the storage wars.  They invented a storage technology in 2015 that was the best of everything: almost as fast as (then) RAM, basically infinite write endurance in any normal use, and fairly cheap.  They even made a brilliant config on m.2 with integrated supercap for power-failure write flush. Just awesome and absolutely the write tech for modern file systems like ZFS. It is perfect for SLOGs.  You wish you had a laptop that booted off an Optane m.2  You wish your desktop drives were all NVME Optane.

Well, wishes are all we got left, sadly.  Optane, RIP 2022.

You can still buy optane parts on the secondary markets and it seems some of the enterprise DC products are at least still marked current on Intel’s website, but all retail stocks seem to be gone.

camelcamelcamel.com price history of intel optane P1600X 118GB

Man was that an amazing deal at $0.50/GB.  In my application, the only practical form factor was M.2 and even that was a bit wonky in an HP DL360 G9, but more on that later.  There are a variety of options and most are available on the used market:

PN Intro Cap GB Write MB/s write k iops  PBW endurace PLP $ (market, 2024)
MEMPEK1W016GAXT Q1’17 16 145 35 0.2 NO 5
SSDPEL1K100GA Q1’19 100 1,000 250 10.9 YES 109
SSDPEL1K200GA01 Q1’19 200 2,000 400 21.9 YES 275
SSDPEL1K375GA Q1’19 375 2,200 550 41 YES 800/1,333/NA
SSDPEK1A058GA Q2’22 58 890 224 635 YES 32/140
SSDPEK1A118GA01 Q2’22 118 1050 243 1292 YES 70/229

Any of these would be a good choice for a SLOG on rotating media, but the later ones are just insane in terms of performance, and that’s compared to enterprise SSDs.  They pricing cratered after they were canceled and dangit, didn’t get em. The used market has gone way up, better price increase than bitcoin over the same period and they’re not virtual beanie babies! The SSDPEL1K100GA is the best deal at the moment and has a beefy supercap for power continuity and is still $818 on Amazon, apparently introduced at $1,170.  This pricing might have explained why Optane didn’t do better. The 375 GB M.2 would be an awfully nice find at $0.50/GB, that’d be a pretty solid laptop boot disk.

Hardware

For SLOG you really want two devices mirrored in case one fails.  The risk of an optane DC grade device failing is trivial and given it has Power Loss Protection, the most likely cause of failure and why your main array failed to write out the transactions committed to the SLOG, we’re really talking about media failure and as it is 3D X-Point it is NOT going to wear out like NAND, it’s rational to single-disk it.  I almost striped mine but in the end decided against it because that quadruples the fail rate over a single device and 8x over mirrored and I don’t really need the space.

So how do you install two M.2 devices in a computer that doesn’t have M.2 slots on the mobo?  With a PCI card, of course.  But wait, you want two in a slot, right?  And these are x4 devices, the slots are x8 or x16, so two should be able to pair, right?

Not so fast.  Welcome to the bizarre world of PCI furcation. If you want to add two drives to the core PCI bus, you have to split the bus to address the cards.  Some mobos support this and others do not.  As shipped, the HPE DL360 G9 did not.

BUT, a firmware update, v 1.60 (April 2016) added “support to configure the system to bifurcate PCIe Slot 1 on the DL360 Gen9 or PCIe Slot 2 on the DL380 Gen9.” W00t. A simple Supermicro AOC-SLG3-2M2 supports 2x M.2 cards and only requires bifurcation to work, all good.

PCIE bifurcation DL360 service menu dual x8

Not so fast. In order to pack the DL360 G9 with 2.5 SSDs, you need a Smart Array Controller (set for passthru for ZFS) and that sits in slot 1 and while I believe it can go in any X16 slot, the cabling is not compatible and that’s a lotta SAS cables to replace. Bifurcation on the mobo is out.

Dual SSD PEL1k100GA in Supermicro AOC-SLG3-2M2 PCI Adapter

But you can fucate on a PCI card just as well – likely this adds some latency and it’d be interest to perf test against more direct connections. I ended up choosing a RIITOP dual M.2×22110 PCI card and it worked out of the box transparently, both disks showed and while I’m not getting 250,000 IOPS, performance is good.  It is based on the ASMedia ASM2812, seems like a reasonable chip used in a lot of the lower cost devices of this type, most with 4x M.2 slots instead of 2.

Software

FreeBSD recognizes the devices and addresses them with nvmecontrol.  You can pull a full status report with, for example nvmecontrol identify nvme0, which provides information on the device or nvmecontrol identify nvme0ns1 which gives details about the storage configuration, including something important (foreshadowing) the LBA format (probably #00, 512).

Current LBA Format:          LBA Format #00
...
LBA Format #00: Data Size:   512  Metadata Size:     0  Performance: Good
LBA Format #01: Data Size:   512  Metadata Size:     8  Performance: Good
LBA Format #02: Data Size:   512  Metadata Size:    16  Performance: Good
LBA Format #03: Data Size:  4096  Metadata Size:     0  Performance: Best
LBA Format #04: Data Size:  4096  Metadata Size:     8  Performance: Best
LBA Format #05: Data Size:  4096  Metadata Size:    64  Performance: Best
LBA Format #06: Data Size:  4096  Metadata Size:   128  Performance: Best

The first thing I’d do with a used device is wipe it:

gpart destroy -F /dev/nvme0
gpart destroy -F /dev/nvme1

I would not bother formatting the device to LBA 03/4k.  Everyone tells you you should, but you don’t get much of a performance increase and it is a huge pain because nvmecontrol currently times out after 60 seconds (at least until the patch needed is pushed to kernel or you recompile your kernel with some fixes) if you did want to try, you’d run:

# time nvmecontrol format -f 3 -m 0 -p 0 -l 0 nvme0
316.68 real         0.00 user         0.00 sys
(no errors)

-f 3 sets LBA Format #03, 4096 which should give “Performance: Best” which certainly sounds better than “Good.”

But it’ll error out.  You need to mod /usr/src/sys/dev/nvme/nvme_private.h with the below modifications and recompile the kernel so it won’t time out after 60 seconds.

#define NVME_ADMIN_TIMEOUT_PERIOD       (600)    /* in seconds def 60 */
#define NVME_DEFAULT_TIMEOUT_PERIOD     (600)    /* in seconds def 30 */
#define NVME_MIN_TIMEOUT_PERIOD         (5)
#define NVME_MAX_TIMEOUT_PERIOD         (600)    /* in seconds def 120 */

Performance Aside

I tested 512 vs 4k in my system – and perhaps the AIC’s bridge latency or the whole system’s performance so limited the performance of the optane cards that a no difference would appear, these cards do rock at the hardware level (this is with 4k formatting):

# nvmecontrol perftest -n 32 -o read -s 4096 -t 30 nvme0ns1 &&  nvmecontrol perftest -n 32 -o write -s 4096 -t 30 nvme0ns1
Threads: 32 Size:   4096  READ Time:  30 IO/s:  598310 MB/s: 2337
Threads: 32 Size:   4096 WRITE Time:  30 IO/s:  254541 MB/s:  994

That’s pretty darn close to what’s on the label.

However, testing 512 vs. 4k formatting at the OS level (didn’t test raw) it was a less extraordinary story:

LBA/FW ver. 4k E2010650 512 E2010650 4k E2010485 512 E2010600
Median  Mb/s 759.20 762.30 757.50 742.80
Average Mb/s 721.70 722.87 721.64 724.35

Definitely not +10%

SLOG performance test on Optane SSDPEL1K100GA

So I wouldn’t bother reformatting them myself.  Testing a few configurations with

fio --name=random-write --ioengine=posixaio --rw=randwrite --bs=64k --numjobs=1 --size=4g --iodepth=1 --runtime=60 --time_based --end_fsync=1

I get

Device\Metrics Max IOPS Avg WBW MiB/s avg SLAT µS avg LAT µS
10 SAS SSD ZFS Z2 Array 20,442 1,135 4,392 53.94
Optane 100G M.2 Mirror 20,774 624 3,821 95.77
tmpfs RAM disk 23,202 1,465 6.67 42

Optane is performing pretty close to the system limit by most metrics – the SLAT and LAT metrics are highly dependent on software.

 Formatting

I did something a bit funky since 100GB is way more than this little server could ever use for SLOG.  I set it at 16GB which is probably 4x overkill, then used the rest as /var mountpoints for my jails because the optanes have basically infinite write endurance and the log files in var get the most writes on the system.  I’m not going into much detail on this because it’s my own weird thing and chances anyone else cares is pretty small.

Initialize GPT

gpart create -s gpt nda0
gpart create -s gpt nda1

Create Partitions

gpart add -b 2048 -s 16g -t freebsd-zfs -a 4k -l slog0 nda0
gpart add -b 2048 -s 16g -t freebsd-zfs -a 4k -l slog1 nda1
gpart add -s 74g -t freebsd-zfs -a 4k -l ovar0 nda0
gpart add -s 74g -t freebsd-zfs -a 4k -l ovar1 nda1

ZPool Operations

zpool add zroot log mirror nda0p1 nda1p1
zpool create optavar mirror nda0p2 nda1p2
zpool set autotrim=on optavar

Create Datasets

zfs create -o mountpoint=/usr/local/jails/containers/jail/var -o compression=on -o exec=off -o atime=off -o setuid=off optavar/jail-var
etc
Posted at 18:32:50 GMT-0700

Category: FreeBSDHowToPositiveReviewsTechnology

Electronic Signatures and PDF

Thursday, January 2, 2025 

Electronic signatures are a technology that has been bizarrely slow to mature. Lots of documents still rely on the idiotic premise that some stupid graphic somehow serves as a secure measure of document authenticity.  This might have had some slight measure of validity in the days of actual paper documents being required with “wet signatures.” but the premise of face-to-face document signing ceremonies should have long been consigned to history with signet rings, let alone a global transit trade in random bits of paper bearing binding proof of commitment.

An image of a pdf digital signature

First the Uniform Electronic Transactions Act (UETA, 1999) then H.R.1714/S.761, Electronic Signatures In Global and National commerce (E-Sign) act (2000) was signed (ha) into law (probably with a wet signature), now Public Law 106–229, it has been legally binding to sign documents with electronic signatures for 25 years.

So why is it almost never done? Why do are we still sometimes asked to fax “signed” documents?


Why do we fax “signed” documents?  Because lawyers and legislators are unbelievably, almost incomprehensibly ignorant of the most basic operational functions of technology and absolutely too stupid, too utterly moronic, mindbogglingly dense and incomprehensibly dumb that… and I am NOT making this up… but seriously… there are people who actually have an impact on laws and legal matters who believe that fax transmissions are more “secure” and less prone to interception, manipulation, or hacking than email. Yes, people who believe this kind of thing are actually allowed to practice law. Truly tragic but still true. The world suffers that such profound ignorance persists.


Have you ever tried to electronically sign a document?  Turns out it isn’t trivial and the burden isn’t the core technology or concept but a few problematic implementation steps.

The first barrier is the interjection of the certificate mafia’s profit motives. Various corporate monsters saw an opportunity to make bank exploiting the aforementioned abject technical ignorance and utter technical incompetence of our legislative and legal infrastructure and build a certification model that relies on pay-for-validation, lying that this would somehow ensure authenticity and people were too dumb to question the obvious idiocy of this stupid model.  Even today, we rely on the good graces of the Mozilla foundation’s Let’s Encrypt to make secure communication viable because various OS and browser level dumbness considers self-signed certificates insecure for the stupidest, most reprehensible reasons possible. But Let’s Encrypt, bless them, won’t give you an X.509 signing certificate.

We’re all lucky CACert.org steps into this horrific void and, while it is complicated, offers an extremely secure, highly reliable, and (most importantly) free process for getting yourself an X.509 signing certificate. In order to get a signing certificate, you have to validate your identity in person at a meet up using their points system, a process that is infinitely more secure than any of the for-profit signing certificate providers that consider willingness to pay proof of identity. The USG should offer X.509 client certificates for free with passports and RealID renewals, but I’d still use CACert myself, cause they’re awesome.

For now: first, set up an account on CACert, install their root certificates in your OS and browser (why aren’t they included by default? Ask the certificate mafia.) You’ll need to do one of the things they require to prove you are who you claim (yes, actual security, unlike ANY of the commercial certificate providers, unreal how insanely stupid this process is) and then have CACert issue a Client Certificate.

Assuming you have your points with CACert, the basic process is fairly well documented:

You need to generate a signing request in your name, which you can do with OpenSSL, but it is easier using CACert’s nice online process.

CACert client pair generation request

It will take a few seconds (60?) and I’m not sure about the compatibility problems that might arise from a longer key, there are some bugbears once we try to use lamo corporate commercial software, but 4096 worked for me.  You MUST GET YOUR PRIVATE KEY and save it to your OpenSSL enabled computer.

A CSR request

Remember to press the red “Show private key” button and copy/save the private key to a secure directory on your computer, you’re gonna need it later to convert the certificate into something dumb ass spyware Windows computers can use, which you need because Acrobat forms still can’t be signed without Adobe’s awful spyware Acrobat Reader.

A private key from the CSR request

(note the actual private key has quite a bit of text between the Begin and End lines but you know… redacted for privacy).  Then click the blue “Copy CSR to Clipboard” button and switch over to New Client Certificate window and paste it where you’re supposed to.

CACert New Client Certificate Request

You need the .crt version of the certificate to continue and that private key text file you saved earlier for the next step, as well as downloading the CACert root certificate and then you need openssl working (should be on most real computers, Windows or Apple is beyond my interest) and merely execute this one simple command:

$ openssl pkcs12 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES -nomac  -export -out DavidGessel_3d_sha1.pfx -inkey private_key_for_CAcert_CSR.txt -in gessel@blackrosetech.com.crt -certfile CA_Cert_root_X0F.crt

To explain:

  • openssl will generate a combined binary version of your certificate in pkcs12 format
  • because Windows and Acrobat suck, you have to specify moderately insecure crypto: SHA1-3DES rather than the Linux default of AES 256 because why would a monopoly company like Microsoft have any incentive to fix bugs? If you don’t Windows will tell you “The password you entered is incorrect” to unlock your key because why fix bugs when corporate IT types are just utterly incompetent and will only specify windows no matter how awful and unusable it is because point-n-click?
  • -nomac is another setting Windows needs to be able to use the cert and if you don’t specify this Windows will tell you “The password you entered is incorrect” again, because Windows does not care if it works for you because you have no choice.
  • The -out certificate is what’s being generated and Windows native is .pfx, but .p12 will work too.
  • The -inkey is the private key you remembered to save using the red button before (right? you need that).
  • the -in (file) is the Client Certificate in normal X.509 .crt format real computers understand that CACert generated for you.
  • the -certfile is CACert’s root certificate.

Now, WØØt, you have a certificate that should work.  Go over to your dumb Windows machine and make sure you import the CACert root certificates – you just download them and then right click and select “install certificate” for the class 1, then the class 3, then the .pfx certificate you just created.

Install a certificate in windows

Now, finally, you can sign a document like someone who actually uses a computer rather than a quill and parchment to process documents.

Acrobat is another program that just doesn’t care too much about usability or user experience, so different versions might work differently.  I had to click the “Signature Panel” button to open a sidebar to show the signature fields then right click and then choose my sig and click sign and save.

And, finally, sign and save the damn document

One final note about the state of signing in FOSS: it kinda sucks still.  Various entities that use acrobat fairly well will generate forms with standard signature locations which you can print and sign and fax (not email) like we’re still waiting for Y2K or print and sign and snail mail if we are nostalgic for the pre-telephone era, or click and sign and email like we’re in the 21st century.

I’m not aware of any FOSS program that handles signature fields in the expected way.  You can sign a whole pdf document with a variety of FOSS tools, and CACert has a good summary of these, but that signature, while binding on the document as a whole does not show in the form fields and so whatever non-tech functionary is asking you to sign the document is never going to understand how your e-sign compliant signature is binding and is going to insist you take a time machine back to the mid-80s to find a working fax machine unless you use Acrobat, which means Windows or Mac at least in a VM. You might be able to get some version of Acrobat to work in Wine, but you’ll need an old one that uses an internal certificate store rather than relying on the windows version (pre Acrobat X, I’m pretty sure).

Fun, huh? Basic digital functions are still broken decades after introduction but we have AI generated Teledep influencers telling us doubleplus buy useless beauty products and trust their health and exercise advice.

 

Posted at 08:51:06 GMT-0700

Category: HowToLinuxPoliticsPrivacyTechnology

Goodbye, Tortuga.

Thursday, April 25, 2024 

On April 21st, 2024, at 20:39, Tortuga was gently put to rest after a three year-long struggle with what was probably cancer and a short-lived victory over a mycoplasma bacterial blood infection.

She first took advantage of our yard-cat support program in 2009 as a juvenile cat and passed at about 15 or 16 years of age. She lived a good life, had 5 kittens on March 27th, 2010 that were all weaned and adopted out successfully, and grew old never wanting for food, shelter, or comfort, and never suffering any meaningful illness or injury until her last year.

Over the years, she was the beneficiary of a very strong community support network that took her in whenever she needed it and gave her loving care. She had housemates, human and feline, and a few canine over the years and was always gracious and pleasant, if not always enthusiastic about the four-legged companions.

I am eternally, deeply grateful to everyone who helped her over the years and who made my work and travel possible and Tortuga’s life pleasant and comfortable in my absence, especially in her later years as she needed more care.

She was the best, sweetest cat I’ve ever known. She was always polite, always pleasant, and never scratched or bit, not even when startled or annoyed by dogs. She never broke things or pushed things over or made a mess.

She wasn’t a big fan of other cats, and only a select few were tolerated as guests in her garden. She wanted to start every morning by marking her territory and she ruled her garden with a fierceness that vastly exceeded her tiny size. She started there, spent her last day in the sun there, and will spend eternity there.

Almost every night I was home, she slept in my bed with me. Almost every day I was working at home, she would hop up and sleep quietly between my keyboard and monitor on her little bed there. She didn’t meow much or fuss but purred easily and happily.

In later years, she’d sometimes wake me just before light by prodding my back or nipping to ask for pets; after 5 or 10 minutes of purring and being petted, she would settle back to sleep. It was a ritual that I came to very much enjoy.

Whenever I came home from my travels, no matter how late, as I opened the door into the living space, I’d hear her stir, jumping down from the attic maybe or from my bed or the window perch upstairs and tap-tap-tap down the stairs and trot up to greet me, rubbing my leg and purring. She’d let me scoop her up and snuggle her, though she wasn’t normally a carry cat, and then walk circles around me for 10 or 15 minutes, welcoming me home in the sweetest way possible. She came to know my departures too and always gave me a look of disappointment, sometimes refusing to come to the door to see me off, but usually relenting for one last scritch on the head.

When Corona hit in 2020, I was in Iraq after leaving her in January of 2020 thinking I’d be back in the spring. I couldn’t make it home for almost two years. The longest I’d been away before then was less than 6 months and even that only once or twice. She’s a cat, and by then an old cat, so I didn’t expect much, but in January of 2022, I opened the door late at night to the sound of her tap-tap-tapping down the stairs to greet me.

She was laid to rest in the garden she ruled for 15 years.

I went through the thousands of pictures I’ve taken of her and others have shared with me and tried to find a few from every year from her first foray in 2009 until her last day. If you knew her at some point during this time, I hope this brings back fond memories of a very special kitty.

2009: Tortuga finds food, takes over a house, and becomes part of the family.

2010 Tortuga has kittens and settles into her role as queen of the garden.

2011 Tortuga takes ownership of my desk.

2012

2013

2014

2015

2016

2017

2018

2019

2020 Corona time.

2021 Corona time.

I didn’t get to see Tortuga at all from January of 2020 until January of 2022.

2022 Reunited.

2023

A typical welcome home when I’d been away too long.

2024 The queen of the garden forever.

Posted at 08:35:14 GMT-0700

Category: Cats

A one page home/new tab page with random pictures, time, and weather

Thursday, April 11, 2024 

Are you annoyed by a trend in browsers to default to an annoying advertising page with new tabs? I sure am. And they don’t make it easy to change that. I thought, rather than a blank new tab page, why not load something cute and local. I enlisted claude.ai to help expedite the code and got something I like.

myHomePage screenshot

myHomePage.html is a very simple default page that loads a random image from a folder as a background, overlays the current local time in the one correct time format with seconds, live update, and throws up the local weather from wttr.in after a delay (to avoid hitting the server unnecessarily if you’re not going to keep the tab blank long enough to see the weather).

Images have to be in a local folder and in a predictable naming structure, as written “image_001.webp” to “image_999.webp.” If the random enumerator chooses an image name that doesn’t exist, you get a blank page.

Browsers don’t auto-rotate by exif (or webp) metadata, so orient all images in the folder as you’d like them to appear.

The weather information is only “current” which isn’t all that useful to me, I’d like tomorrows weather, but that’s not quite possible with the one-liner format yet.

Update, I added some code to display today and tomorrow’s events and current todos meeting specific filter tests from your Thunderbird calendar, if you have it. If not, just don’t cron the bash script and they won’t show. I also changed the mechanism of updating the weather to a 30 minute refresh of the page itself, this way you get more pix AND the calendar data updates every 30 minutes.  Web browsers and javascript are pretty isolated from the host device, you can’t even read a local file in most (let alone write one).  All good security, but a problem if you want data from your host computer in a web page without running a local server to deliver it.

My work around was to write the data into the file itself with a script.  Since the data being written is multi-line, I opted to tag the span for insert with non-breaking spaces, a weird character and the script sanatizes the input from calendar events extracted from the sqlite database in case some event title includes them.   The current config is by default:

~/.myHomePage/myHomePage.html
~/.myHomePage/getEvents.pl
~/.myHomePage/getToDos.pl
~/.myHomePage/putEvents.py
~/.myHomePage/putToDos.py
~/.myHomePage/myHomeImages/image_001.webp
~/.myHomePage/myHomeImages/image_002.webp
etc.

How to set the homepage and new tab default page varies by browser.  In Brave try hamburger→settings→appearance→show home button→select option→paste the location of the homepage.html file, e.g. file:///home/(username)/.myHomePage/myHomePage.html

Then just set a cron script like <code>*/30 * * * * /home/<username>/.myHomePage/getEvents.pl</code> for regular updates: script all the subroutines that are useful or write a little bash script to do them in sequence and call that with your favorite periodic method.

Parsing recurring events in perl is a challenge and I managed to get claude to ragequit, that’s got to be a some sort of a record:

claude rage quits

So the parsing scripts are in python using icalendar, I put them on gitlab at https://gitlab.com/gessel/myhomepage to make it a little easier to mess with, if anyone wants to.

Posted at 05:48:19 GMT-0700

Category: CodeHowToLinuxTechnologyWeather

Putting ccache on a backed RAM disk to speed compiles

Saturday, March 16, 2024 

Why do this

Compiling and building ports can be meaningfully accelerated by caching (ccache) certain intermediate results and by moving work directories from slower media to faster (tmpfs /tmp). If you do regular builds, such as one might on a poudriere server, there can be a meaningful write workload to the working directory which uses up SSD life, possibly meaningfully (though probably not really that much if your SSD is modern and big).

If you have a fast, high endurance SSD, putting ccache on it won’t do much. If ccache is going on rotating media, this config will speed up builds appreciably. The save/restore code below will preserve the ccache across reboots and leaves file management inside the ccache directory to ccache itself, while managing the persistence of any other random files that get written outside the directory.

Note this code, different than other examples I’ve found, works with FreeBSD as a service and doesn’t flush files that are accessed (read) between reboots, only files that aren’t touched in any way and therefore can (probably) be evicted without penalty and prevents cruft and clutter on the RAM disk accumulating because it has been made non-volatile.

Putting the workdirectory into a RAM-based tmpfs should speed up builds even compared to a fast SSD, as SSD write times aren’t a strong feature of SSDs. There’s no persistence code as there’s no expectation that the work directories will persist.

Setup ccache

Setting up ccache is pretty easy. First, install it from ports. If you’re using binary packages, you obviously don’t need ccache.

cd /usr/ports/devel/ccache
make install clean

make.conf

Append a few lines to your make.conf files like so:

nano /etc/make.conf
nano /usr/local/etc/poudriere.d/FBSD_14-0-R-make.conf

Add the following:

CCACHE_DIR=/ram/ccache
WITH_CCACHE_BUILD=yes
# WRKDIRPREFIX="/tmp/ports"

note that WRKDIRPREFIX (to use tmpfs /tmp, see below) seems to conflict with the same directive in poudriere.conf so comment out for poudriere hosts or don’t use the option in poudriere.

poudriere.conf

nano /usr/local/etc/poudriere.conf

CCACHE_DIR=/ram/ccache

/etc/fstab

Next, make the /ram directory and set a limit of how much RAM it can use. 12884901888 is 12GB. Somewhere between 8 and 16GB is probably sufficient for most needs. After a few builds, I was using 1.3GB.

mkdir /ram
nano /etc/fstab
none /ram tmpfs rw,size=12884901888 0 0
mount /ram

ccache.conf

nano /root/.ccache/ccache.conf
nano /usr/local/etc/ccache.conf
cache_dir = /ram/ccache
max_size = 12G

status

Now all ports you build will be compiled entirely in RAM. You can check your ccache usage with:

ccache -s

CREATE A CACHE STORE/RESTORE SCRIPT

From: https://forums.gentoo.org/viewtopic-t-838198-start-0.html

This is in /etc/rc.d and should be executed on startup and shutdown, but only actual shutdown not reboot or halt. The correct command to reboot (and preserve /ram) is (you do not need to do this now!):

shutdown -r now

Don’t reboot now, just know that using “reboot” or some other command other than calling shutdown will not call the stop script and won’t sync the cache to NV storage.

Create /etc/rc.d/syncram something like:

#!/bin/sh -
# PROVIDE: syncram
# REQUIRE: FILESYSTEMS
# KEYWORD: nojail shutdown

. /etc/rc.subr

name="syncram"
rcvar="syncram_enable"
desc="rsync ram disk from/to var on startup/shutdown"
stop_cmd="${name}_stop"
start_cmd="${name}_start"

syncram_start()
{
# rsync data from persistent storage to ram disk on boot
# preserving all file attributes
logger syncram-start
/usr/local/bin/rsync -a -A -X -U -H -x \
/var/tmp/syncram/ /ram \
> /dev/null 2>/var/log/syncram-store.log
touch /var/tmp/syncram/.lastsync
}

syncram_stop()
{
# rsync data from ramdisk to persistent storage on shutdown
# preserving all file atributes
logger syncram-stop
#!/bin/sh
# if the dest dir doesn't exist, create it
if [ ! -d /var/tmp/syncram ]; then
mkdir /var/tmp/syncram
fi
# flush any accumulated cruft that weren't accessed since the last sync
# note tmpfs records accurate atime
if [ -f /ram/.lastsync ]; then
find /ram -type f ! -neweram /var/tmp/syncram/.lastsync -delete
fi
# rsync new or accessed removing unused from target
/usr/local/bin/rsync -a -A -X -U -H -x -del \
/ram/ /var/tmp/syncram \
> /dev/null 2>/var/log/syncram-restore.log
}

load_rc_config $name
run_rc_command "$1"
chmod +x syncram

Then edit /etc/rc.conf to include

syncram_enable="YES"

and execute

service syncram onestart

Bonus: tmpfs for working builds

tmpfs can also be used to create a similar ramdisk at the /tmp mount point where it is fairly automatically used by poudriere to speed up builds. There’s a quirk that seems to be a problem (not fully debugged, but the config described here works and survives reboots): putting the WRKDIRPREFIX in make.conf AND in poudriere.conf seems to yield “workdirectory” errors so pick one for the directive and probably pick poudriere.conf if you’re running poudriere.

poudriere.conf

nano /usr/local/etc/poudriere.conf
# Use tmpfs(5)
# This can be a space-separated list of options:
# wrkdir - Use tmpfs(5) for port building WRKDIRPREFIX
# data - Use tmpfs(5) for poudriere cache/temp build data
# localbase - Use tmpfs(5) for LOCALBASE (installing ports for packaging/testing)
# all - Run the entire build in memory, including builder jails.
# yes - Enables tmpfs(5) for wrkdir and data
# no - Disable use of tmpfs(5)
# EXAMPLE: USE_TMPFS="wrkdir data"
USE_TMPFS=yes

# How much memory to limit tmpfs size to for *each builder* in GiB
# (default: none)
#TMPFS_LIMIT=4

# List of package globs that are not allowed to use tmpfs for their WRKDIR
# Note that you *must* set TMPFS_BLACKLIST_TMPDIR
# EXAMPLE: TMPFS_BLACKLIST="rust"
TMPFS_BLACKLIST="rust"

# The host path where tmpfs-blacklisted packages can be built in.
# A temporary directory will be generated here and be null-mounted as the
# WRKDIR for any packages listed in TMPFS_BLACKLIST.
# EXAMPLE: TMPFS_BLACKLIST_TMPDIR=${BASEFS}/data/cache/tmp
TMPFS_BLACKLIST_TMPDIR=${BASEFS}/data/cache/tmp

Rust may overflow even a chonky RAM config.

/etc/fstab

nano /etc/fstab
tmpfs /tmp tmpfs rw,mode=1777 0 0

This will “intelligently” allocate remaining RAM to the tmpfs mounted at /tmp and builds should mostly happen there.

mount -a

NB

There’s a risk that screwing around with /etc/fstab will break boot – if the system reboots to single user mode, get shell, navigate to /etc/fstab and check for errors or comment out the lines and reboot again.

Posted at 16:42:38 GMT-0700

Category: FreeBSDHowToTechnology

Audio File Analysis With Sox

Wednesday, February 7, 2024 

Sox is a cool program, a “Swiss Army knife of sound processing,” and a useful tool for checking audio files that belongs in anyone’s audio processing workflow. I thought it might be useful for detecting improperly encoded audio files or those files that have decayed due to bit rot or cosmic rays or other acoustic calamities and it is.

Sox has two statistical output command line options, “stat” and “stats,” which output different but useful data. What’s useful about sox for this, that some metadata checking programs (like the very useful MP3Diags-unstable) don’t do is actually decode the file and compute stats from the actual audio data.  This takes some time, about 0.7 sec for a typical (5 min) audio file.  This may seem fast, it is certainly way faster than real time, but if you want to process 22,000 files, it will take 4-5 hours.

Some of the specific values that are calculated seem to mean something obvious, like “Flat factor” is related to the maximum number of identical samples in a row – which would make the waveform “flat.”  But the computation isn’t linear and there is a maximum value (>30 is a bad sign, usually).

So I wrote a little program to parse out the results and generate a csv file of all of the results in tabular form for analysis in LibreOffice Calc.  I focused on a few variables I thought might be indicative of problems, rather than all of them:

  • DC offset—which you’d hope was always close to zero.
  • Min-Max level difference—min and max should be close to symmetric and usually are, but not always.
  • RMS pk dB—which is normally set for -3 or -6 dB, but shouldn’t peak at nearly silent, -35 dB.
  • Flat factor—which is most often 0, but frequently not.
  • Pk count—the number of samples at peak, which is most often 2
  • Length s—the length of the file in seconds, which might indicate a play problem

After processing 22,000 files, I gathered some statistics on what is “normal” (ish, for this set of files), which may be of some use in interpreting sox results.  The source code for my little bash script is at the bottom of the post.

DC Bias

DC Bias really should be very close to zero, and the most files are fairly close to zero, but some in the sample had a bias of greater than 0.1, which even so has no perceptible audio impact.

Min Level – Max Level

Min level is most often normalized to -1 and max level most often normalized to +1, which would yield a difference of 2 or a difference of absolute values of 0 (as measured) and this is the most common result (31.13%).  A few files, 0.05% or so have a difference greater than 0.34, which is likely to be a problem and is worth a listen.

RMS pk dB

Peak dB is a pretty important parameter to optimize as an audio engineer and common settings are -6dB and -3dB for various types of music, however if a set of files is set as a group, individual files can be quite a bit lower or, sometimes, a bit higher.  Some types of music, psychobilly for example, might be set even a little over -3 dB. A file much above -3 dB might have sound quality problems or might be corrupted to be just noise; 0.05% of files have a peak dB over -2.2 dB.  A file with peak amplitudes much below -30 dB may be silent and certainly will be malto pianissimo; 0.05% of files have a peak dB below -31.2 dB.

A very quiet sample, with a Pk dB of -31.58, would likely have a lot of aliasing due to the entire program using only about 10% of the total head room.

-31.58 dB

Flat factor

Flat factor is a complicated measure, but is roughly (but not exactly) the maximum number of consecutive identical samples. @AkselA offered a useful oneliner (sox -n -p synth 10 square 1 norm -3 | sox - -n stats) to verify that it is not, exactly, just a run of identical values and just what it actually is, isn’t that well documented. Whatever it is exactly, 0 is the right answer and 68% of files get it right. Only 0.05% of files have a flat factor greater than 27.

Pk count

Peak count is a good way to measure clipping. 0.05% of files have a pk count < 1000, but the most common value, 65.5%, is 2, meaning most files are normalized to peak at 100%… exactly twice (log scale chart, the peak is at 2).

As an example, a file with levels set to -2.31 and a flat factor of only 14.31 but with a Pk count of 306,000 looks like this in Audacity with “Show Clipping” on, and yet sounds kinda like you’d think it is supposed to. Go figure.

A ton of clipping

Statistics

What’s life without statistics, sample pop: 22,096 files.  205 minutes run time or 0.56 seconds per file.

Stats DC bias min amp max amp min-max avg pk dB flat factor pk count length s
Mode 0.000015 -1 1 0 -10.05 0.00 2 160
Count at Mode 473 7,604 7,630 6,879 39 14,940 14,472 14
% at mode 2.14% 34.41% 34.53% 31.13% 0.18% 67.61% 65.50% 0.06%
Average 0.00105 -0.80 0.80 0.03 -10.70 2.03 288.51 226.61
Min 0 -1 0.0480 0 -34.61 0 1 4.44
Max 0.12523 -0.0478 1 0.497 -1.25 129.15 306,000 7,176
Threshold 0.1 -0.085 0.085 0.25 -2.2 27 1,000 1,200
Count @ Thld 3 11 10 68 12 12 35 45
% @ Thld 0.01% 0.05% 0.05% 0.31% 0.05% 0.05% 0.16% 0.20%

Bash Script

#!/bin/bash

###############################################################
# This program uses sox to analyize an audio file for some
# common indicators that the actual file data may have issues
# such as corruption or have been badly prepared or modified
# It takes a file path as an input and outputs to stdio the results
# of tests if that file exceeds the theshold values set below
# or, if the last conditional is commented out, all files.
# a typical invocation might be something like:
# find . -depth -type f -name "*.mp3" -exec soxverify.sh {} > stats.csv \;
# The code does not handle single or multi-track files and will
# throw an error. If sox can't read the file it will throw an error
# to the csv file. Flagged files probably warrant a sound check.

##############################################
### Set reasonable threshold values ##########
# DC offset should be close to zero, but is almost never exactly
# The program uses the absolute value of DC offset (which can be
# neg or positive) as a test and is normalized to 1.0
# If the value is high, total fidelity might be improved by
# using audacity to remove the bias and recompressing.
# files that exceed the dc_offset_bias will be output with
# Error Code "O"
dc_offset_threshold=0.1

# Most files have fairly symmetric min_level and max_level
# values.  If the min and max aren't symmetric, there may
# be something wrong, so we compute and test. 99.95% of files have
# a delta below 0.34, files with a min_max_delta above 
# min_max_delta_threshold will be flagged EC "D"
min_max_delta_threshold=0.34

# Average peak dB is a standard target for normalization and
# replay gain is common used to adjust files or albums that weren't
# normalized to hit that value. 99.95% of files have a
# RMS_pk_dB of < -2.2, higher than that is weird, check the sound.
# Exceeding this threshold generates EC "H"
RMS_pk_dB_threshold=-2.2

# Extremely quiet files might also be indicative of a problem
# though some are simply malto pianissimo. 99.95% of files have
# a minimum RMS_pk_dB > -31.2 . Files with a RMS pk dB < 
# RMS_min_dB_threshold will be flagged with EC "Q"
RMS_min_dB_threshold=-31.2

# Flat_factor is a not-linear measure of sequential samples at the
# same level. 68% of files have a flat factor of 0, but this could
# be intentional for a track with moments of absolute silence
# 99.95% of files have a flat factor < 27. Exceeding this threshold
# generates EC "F"
flat_factor_threshold=27

# peak_count is the number of samples at maximum volume and any value > 2
# is a strong indicator of clipping. 65% of files are mixed so that 2 samples
# peak at max. However, a lot of "loud" music is engineered to clip
# 8% of files have >100 "clipped" samples and 0.16% > 10,000 samples
# In the data set, 0.16% > 1000 samples. Exceeding this threshold
# generates EC "C"
pk_count_threshold=1000

# Zero length (in seconds) or extremely long files may be, depending on
# one's data set, indicative of some error. A file that plays back
# in less time than length_s_threshold will generate EC "S"
# file playing back longer than length_l_threshold: EC "L"
length_s_threshold=4
length_l_threshold=1200



# Check if a file path is provided as an argument
if [ "$#" -ne 1 ]; then
    echo "Usage: $0 <audio_file_path>"
    exit 1
fi

audio_file="$1"

# Check if the file exists
if [ ! -f "$audio_file" ]; then
    echo "Error: File not found - $audio_file"
    exit 1
fi

# Run sox with -stats option, remove newlines, and capture the output
sox_stats=$(sox "$audio_file" --replay-gain off -n stats 2>&1 | tr '\n' ' ' )

# clean up the output
sox_stats=$(  sed 's/[ ]\+/ /g' <<< $sox_stats )
sox_stats=$(  sed 's/^ //g' <<< $sox_stats )


# Check if the output contains "Overall" as a substring
if [[ ! "$sox_stats" =~ Overall ]]; then
    echo "Error: Unexpected output from sox: $1"
    echo "$sox_stats"
    echo ""
    exit 1
fi


# Extract and set variables
dc_offset=$(echo "$sox_stats" | cut -d ' ' -f 6)
min_level=$(echo "$sox_stats" | cut -d ' ' -f 11)
max_level=$(echo "$sox_stats" | cut -d ' ' -f 16)
RMS_pk_dB=$(echo "$sox_stats" | cut -d ' ' -f 34)
flat_factor=$(echo "$sox_stats" | cut -d ' ' -f 50)
pk_count=$(echo "$sox_stats" | cut -d ' ' -f 55)
length_s=$(echo "$sox_stats" | cut -d ' ' -f 67)

# convert DC offset to absolute value
dc_offset=$(echo "$dc_offset" | tr -d '-')

# convert min and max_level to absolute values:
abs_min_lev=$(echo "$min_level" | tr -d '-')
abs_max_lev=$(echo "$max_level" | tr -d '-')

# compute delta and convert to abs value
min_max_delta_int=$(echo "abs_max_lev - abs_min_lev" | bc -l)
min_max_delta=$(echo "$min_max_delta_int" | tr -d '-')

# parss pkcount
pk_count=$(  sed 's/k/000/' <<< $pk_count )
pk_count=$(  sed 's/M/000000/' <<< $pk_count )


# Compare values against thresholds
threshold_failed=false
err_code="ERR: "

# Offset bad check
if (( $(echo "$dc_offset > $dc_offset_threshold" | bc -l) )); then
    threshold_failed=true
    err_code+="O"
fi

# Large delta check
if (( $(echo "$min_max_delta >= $min_max_delta_threshold" | bc -l) )); then
    threshold_failed=true
    err_code+="D"
fi

# Mix set too high check
if (( $(echo "$RMS_pk_dB > $RMS_pk_dB_threshold" | bc -l) )); then
    threshold_failed=true
    err_code+="H"
fi

# Very quiet file check
if (( $(echo "$RMS_pk_dB < $RMS_min_dB_threshold" | bc -l) )); then
    threshold_failed=true
    err_code+="Q"
fi

# Flat factor check
if (( $(echo "$flat_factor > $flat_factor_threshold" | bc -l) )); then
    threshold_failed=true
    err_code+="F"
fi

# Clipping check - peak is max and many samples are at peak
if (( $(echo "$max_level >= 1" | bc -l) )); then
    if (( $(echo "$pk_count > $pk_count_threshold" | bc -l) )); then
        threshold_failed=true
        err_code+="C"
    fi
fi

# Short file check
if (( $(echo "$length_s < $length_s_threshold" | bc -l) )); then
    threshold_failed=true
    err_code+="S"
fi

# Long file check
if (( $(echo "$length_s > $length_l_threshold" | bc -l) )); then
    threshold_failed=true
    err_code+="L"
fi

# for data collection purposes, comment out the conditional and the values
# for all found files will be output.
if [ "$threshold_failed" = true ]; then
    echo -e "$1" "\t" "$err_code" "\t" "$dc_offset" "\t" "$min_level" "\t" "$max_level" "\t" "$min_max_delta" "\t" "$RMS_pk_dB" "\t" "$flat_factor" "\t" "$pk_count" "\t" "$length_s"
fi

 

Posted at 01:40:52 GMT-0700

Category: AudioCodeHowToLinuxTechnology

Manually Update Time Zone Data on Android 10

Tuesday, October 31, 2023 

One of the updates that stops when your carrier decides you have to buy a new phone to keep their profits up is the time zone data, which means as regions decide they will or won’t continue using standard time and will switch permanently to lazy people time (or not), time zone calculations start to fail, which can be awfully annoying when it causes you to miss flights or meetings.  It is probably something you’ll want to keep up to date.  Unfortunately, this requires root access to your phone because… profits depend on the velocity by which first world money is converted to e-waste to poison third world children.  Yay.

Root requires reflashing your device, which means wiping all your data and apps and reinstalling them, so easier to do on a new phone than backing up and restoring and re-configuring all your apps.  Sooner or later your vendor will stop supporting your device  in an attempt to get you to throw it away and buy a new one and you’ll have to root it to keep it up to date and secure so you might as well do it now, void their stupid warranty, and take control of your device.

You should also take a moment to write your elected representatives and demand that they take civil action against this crap.  Lets take a short rant break, shall we?

Planned obsolescence, death by security flaws, and vendor locks should be prosecuted, not just as illegal profiteering but as environmental crimes for needlessly flooding the world with e-waste. If you own a device you have the right to use it as you like and any entity that by omission or obfuscation of reasonable information needed to keep that device operational is depriving legitimate owners of rightful value. Willfully obstructing security updates, knowing full well the risks implied, is coercive if not extortion. Actively blocking the provision of third party services intended to mitigate these harms through barratry and legal extortion should be prosecuted aggressively. Everyone who has purchased a phone that has been intentionally and unfairly life-limited by non-replaceable batteries, intimidation of repair services, manipulation of the spare parts market, or restrictions or obfuscation of security updates is due refund of the value thus denied plus penalties.

Ah, that feels better, no?

Assuming you have a rooted phone, adb installed on your computer, and your TZ data is out of date, lets get it fixed, shall we?  The problem is that TZ data comes from IANA, from here actually, and is versioned in a form like 2023c, the current as of now. That’s lovely but the format they provide is not compatible with android and needs to be transformed.  Google seems to have some tools for this in the FOSS branch of Android, but it seems a little useless without a virtual environment, a PITA. But the good folks at LineageOS (yay, FOSS!!!) maintain their version of the tool with the thus created output data in their git, which we can use for all android devices (it seems).  The files we need are in this directory: note that these are 2023a, but 2023c is identical to 2023a, reverting some changes made in 2023b because, I don’t know, the whole mess about getting up an hour earlier or later being some traumatic experience when it happens twice a year is catastrophic for people’s sense of well being, but when they get up at different times on days off than on work days, that doesn’t count or something. OMG.  so drama.  people. sometimes it hurts to be associated with them as a species. Not that I care, but stop messing around and just pick one. So many rant triggers in this whole mess.

Anyway, proceeding with the assumption your device is rooted and you have adb installed on your computer, the files needed are:

tzdata        a binary file that if you view with a text editor should start with: tzdata2023a
tzlookup.xml  an xml file that should (nearly) start with: <timezones ianaversion="2023a">
tz_version    a simple text file that should have one line: 003.001|2023a|001

Download the compressed .tgz archive of the output_data directory from here by clicking on the [tgz] text at the top right

You should get a .tgz archive, from which you want to extract:

  • tzlookup.xml from the android folder
  • tzdata from the iana folder
  • tz_version from the version folder

Here’s the tricky bit, you gotta get these files to the right places. So I mounted my android on my computer and created a folder TZData in Downloads and copied the files there, this resolved to /data/media/0/Download/TZdata/ on my device.  While you’re there, make a folder like oldTZ in the same place for backup.  Everything else is done by command line via adb.

(comments are demarked with "#", the prompt is assumed)
# get shell on your device
adb shell
# get root, if this fails, you don't have root, bummer, you don't really own your device.
su root
# verify your tz data is where mine was, if so copypasta should be safe.
find / -name tzdata 2>/dev/null
#output for me looks like some are symlinks
/apex/com.android.tzdata/etc/tz/tzdata
/apex/com.android.tzdata@290000000/etc/tz/tzdata
/apex/com.android.runtime/etc/tz/tzdata
/apex/com.android.runtime@1/etc/tz/tzdata
/system/apex/com.android.runtime.release/etc/tz/tzdata
/system/apex/com.android.tzdata/etc/tz/tzdata
/system/usr/share/zoneinfo/tzdata
# did ya get the same or close enough to figure out what to do next? good.
# Backup your old stuff
cp /system/apex/com.android.tzdata/etc/tz/* /data/media/0/Download/oldTZ
# your directories are read only, so you need to fix that, scary but reversible
mount -o rw,remount /
mount -o rw,remount /apex/com.android.tzdata
mount -o rw,remount /apex/com.android.runtime
# copy the new files over the old files, the last location is legacy and doesn't
# seem to have a copy of tzlookup.xml, so we don't put a new one there, but check
ls /system/usr/share/zoneinfo
# only tzdata and tz_version?  Good.
cp /data/media/0/Download/TZdata/* /apex/com.android.tzdata/etc/tz
cp /data/media/0/Download/TZdata/* /apex/com.android.runtime/etc/tz
cp /data/media/0/Download/TZdata/* /system/apex/com.android.tzdata/etc/tz
cp /data/media/0/Download/TZdata/tz_version /system/usr/share/zoneinfo
cp /data/media/0/Download/TZdata/tzdata /system/usr/share/zoneinfo
# all done, now we just gotta read-only those directories again
mount -o ro,remount /
mount -o ro,remount /apex/com.android.tzdata
mount -o ro,remount /apex/com.android.runtime
# and why not reboot from the command line?
reboot

That was fairly painless once you know what to do and have root, no?  it worked for me, my phone rebooted and the time zone database appears to be updated.  YMMV, hopefully not the reboot successfully part but bricking a phone is a risk because, you know, profits.  After that tz file surgery I created a new event in a US time zone that recently changed their daylight savings to pacify the crazies and it seemed to work as expected.

Posted at 18:25:30 GMT-0700

Category: Cell phonesGeopostHowToLinuxTechnology

Autodictating to self using Whisper to preserve privacy

Thursday, August 17, 2023 

Whisper is a very nice bit of code released by OpenAI, the kind people who brought us ChatGPT.  It’s a speech to text tool that can handle a huge array of languages and runs locally, as in on your hardware with your data.  There’s an API you can use on their servers, but only if you are sure the audio files and text can be released to the public.  Never put any data on anyone else’s hardware that you wouldn’t want to have leaked on pastebin or published in the New York Times; that goes for all services including gmail, Outlook, Office 365, etc.  Never, ever use someone else’s hardware to store proprietary or sensitive data.  It’s just mind-bogglingly stupid, and yet so many people fail to comprehend that “in the cloud” just means “on someone else’s computer.”

This is also true for most speech-to-text tools that (seemingly) kindly offer to translate your ramblings to text out of the goodness of the developer’s hearts.  Lots of people use this feature on their phones without realizing that, like Alexa, any voice command tool is an audio monitoring device you stupidly paid for and installed yourself on behalf of corporate spies who are all too happy to listen to whatever you have to say.  If you have an Alexa, get a hammer right now and smash it.  Go on, I’ll wait.  Good job.  Privacy restored.  Oh, smart TV too? Unplug that stupid thing from the internet.  Same for all your “smart” devices.  You thought “smart” meant you were smart for buying it?  Noooo… you’re a moron for buying it, the company was smart for convincing you to install monitoring devices in your house at your own expense.  Congrats. Own goal.  When you’re finished destroying all your corporate spyware here’s a way to get speech to text capability on your own hardware without the spying thanks to a very nice bit of FOSS code from OpenAI.

The workflow is to record some audio (speech probably) on your phone, store & forward that to your server (no synchronous connection required, unlike most spyware), (optionally) store and forward that to your desktop computer with a GPU to run AI text to speech, pop the results into an email queue to store & forward it back to you and all your searchable text archives. Speech is converted to accessible, indexed text easily and robustly and fairly legibly.

For the recording step, I use an Open Source app called Audio Recorder (available on F-Droid and other reliable repositories; if you need an app, try F-droid first and only use Play Store after deciding it is worth being spied on and having ads pushed to you).  Audio can be any length, seconds or hours.  I configured the settings to record to /storage/emulated/0/recordings and use 48khz, 16 bit, opus for speech; on my device the app supports up to 24bit/192khz, which vastly exceeds the S:N ratio and bandwidth of any microphone I’ll connect to a phone, but nice to know for audiophiles.

I also run NextCloud on my phone which connects to a NextCloud instance on my own server.  NextCloud is like a free, open source version of dropbox and provides directory sharing, calendar, password, etc – almost all services you want a server for on your own hardware so you actually retain possession and ownership of your data – amazing!  You do not have to give away your data to people you don’t know to use the internet.

The NextCloud client on my phone tries to sync the recording folder to my server so after I make a recording and hit the ✅ button, when the aether makes it possible the audio is uploaded (and, optionally, deleted from the mobile device). Nextcloud then syncs down to other clients, specifically one of my Linux clients for processing. It is entirely possible to do everything server side and the same scripts will work, but I don’t have a GPU on my server and Whisper has some dependencies that are easier to meet on a more frequently updated client, at least for now.

I’ve installed whisper on a Linux box, along with a NextCloud client and there I have a fairly simple script running as a cron job. Every 10 minutes it scans all the files in the locally synced “Recordings” directory and if there’s an audio file without a matching text “TSV” file, it calls whisper to convert the audio to text and then emails me the converted text.  That text is also synced back up to the server and to any other synced device and indexed both on the server and locally to make it easily discoverable (on clients I use the very awesome Recoll for indexing).

The whole process is very easy and any audio file like this:

is then automagically converted to text

test if we can record in Opus and then autoconvert the file back to text and
get that text as an email automatically this seems like quite a powerful tool
and should make it fairly easy to self take notes don’t we think yes

and then ends up in my inbox like this:

So what script does this good thing?  Just a few bash lines.  This version uses the time stamps in the TSV files to throw in fairly reasonable paragraph breaks. If the speaker pauses long enough that Whisper inserts a timing break, the script printfs in two newlines. There are a few other tricks below to try to infer or force reasonable paragraph breaks.

It also uses a slightly more robust construction to extract the subject of the email, which includes the first 60 characters of the text, minus any new lines (which make mailx barf).  The resulting text is flowed, pretty easy to copypasta into an email or document, and has moderately natural paragraph breaks.  It isn’t publication ready, but the accuracy seems quite good and it is hard to imagine an easier mechanism for making useful autodictations.  The process supports very long rambling diatribes, you should be able to talk for hours and get book’s worth of text in your inbox. I mean, maybe you shouldn’t be able to do that, but you can.

I put in a feature request with the Audio Recorder devs to add some metainfo to the files; what I’d really like is location data.  I can script up extracting that and (optionally) converting it to a place name, but aside from Nominatim or Gisography, there aren’t many options other than using big data APIs.  Anyway, seems like a reasonable bit of metadata to insert at the top or tail of the text: time+date+location the stream was recorded. If it is implemented, I’ll update to script to extract the metadata and create a dateline header.

Mailing flowed plain text

I found that mailx can’t handle long (flowed) text lines over ~1000 characters and inserts \n  at 998 or 997, which breaks up the pause to paragraphs code, so I switched the mailer to mpack (sudo apt install mpack) which simplifies the mail command and MIME encodes the text body and adds a checksum and a few other modern mail niceties and it now flows as desired without weird line breaks.

And then I found out that mpack thinks it is too good to send text files, it sets the MIME type to application/octet-stream and using the -c text/plain option yields the somewhat prissy error This program is not appropriate for encoding textual data oh my.  Thunderbird actually parses the attachment into a nicely flowed email, ignoring the quirks, but the best mobile client ever, FairEmail, does not and treats the attachment as something that it would prefer not to display inline (thanks for the details Marcel, you’re awesome!), given mailx isn’t very active any more changing that behavior is unlikely.  Next option: Mutt.  Mutt does something to a text attachment (using the -a option) that causes both TB and FairEmail to decline to display inline, but the body option -i yields a clean text-only email with the right flow, meaning no random line breaks inserted, so don’t install mpack, but sudo apt install mutt and create a /home/{user}/.muttrc file with at least the below (search engine around if you need to use a remote SMTP server to configure the server address, authentication, and encryption; mutt does the right things):

set realname = "{desired name}"
set from = "{your from email}"
set use_from = yes
set envelope_from = yes

And once that (and whisper) is working, the following script will convert your audio file to text and then mail it to you with paragraph breaks.

TextTiling

I didn’t plan to get into anything more complex, but long text conversions are kinda unreadable because Whisper doesn’t infer text.  There’s a whole science to inferring contextual shifts that should start new paragraphs using LSA/LDA/LSI that’s quite advanced mathematically and works sort of OK but is an awful lot of pipping modules and trying this or that.

I opted instead to go for a more brute force method, well three of them, really:

First: whisper has an experimental feature to compute word timings, which would normally be used to generate those unbelievably distracting and annoying and utterly horrible subtitles that are one word at a time or bouncing highlight word by word, but the feature can do more than create a miserable, distracting, utterly pretentious viewing experience: they seem to increase the frequency and possibly accuracy of gaps in the exported timing data. The first method of paragraph finding is detecting “long” gaps after a Whisper inferred sentence, effectively deriving speaker intent from cadence and AI content inference.  It works OK.

Second: I implemented a wake_word:command set that seds through the text and search-replaces the wake_word:command with the requested punctuation: .¶,:()…—?!“” There’s a whole theory behind wake words, but “insert” seems to be understood well and the command terms are ones that I tend to think of (e.g. “dots” not “ellipsis”), but that’s all obviously editable to preference.

Third: recommended paragraph length depends on the target and advice ranges from 3 sentence to 6.  I tend to be a bit long winded so I picked 5.  There’s an arbitrary script to look for any line that, after the timing inference and explicit breaks, still has more than 5 sentences and breaks it into multiple lines (meaning paragraph splits when the text is rendered). If that’s too long or too short, change the 5 in /usr/bin/sed -i "s/[.?!] /.\n\n/5;P;D" "$txt_file".

This all work fairly well, though there’s a known quirk with Whisper where it just randomly stops inserting punctuation after about 10 minutes and mechanisms 1 and 3 obviously also fail.  The way to deal with that is to break the audio into about 5 minute segments and then concatenate the results, but it’s a moderate chunk of code and debug and I’m assuming whisper will be updated.  If not and it gets annoying, I’ll work out that routine.

The script

Replace {user} and {domain} as appropriate to your system.  You may also have a different layout for commands, which bin (for example) is your friend.  I find full paths in cron execution provides better consistent reliability at the expense of portability.

#!/bin/bash 

watchdir="/home/username/Work/Recordings/"
to="email@domain.com"
stop_prev="0"
start=""
stop=""
text=""
wake_word="insert"

# Function to check if an audio file has a matching .txt file, then convert to text and email it
convert_to_text() {
    audio_file_file="$1"
    txt_file="${audio_file%.*}.txt"
    tsv_file="${audio_file%.*}.tsv"
    dir="$(/usr/bin/dirname "${audio_file}")"
    base_ext="$(/usr/bin/basename "${audio_file}")"
    base="${base_ext%.*}"


    if [ ! -e "$tsv_file" ]; then
        /home/gessel/.local/bin/whisper "$audio_file" -f tsv --model small.en -o $dir --word_timestamps True --prepend_punctuations True --append_punctuations True --initial_prompt "Hello."

        while IFS=$'\t' read -r start stop text; do
            # First line detection and skip checking it for gaps
            if [ $start == "start" ]; then
                /usr/bin/printf "" > "$txt_file"
                continue
            fi
            # Check if line ends in period or question mark for paragraph insertion
            if [[ $text =~ \.$|\?$ ]]; then
                # find natural pauses and insert paragraph breaks
                if [[ $stop_prev != $start ]]; then
                /usr/bin/printf "\n\n" >> "$txt_file"
                fi
            fi
            /usr/bin/printf "$text " >> "$txt_file"
            stop_prev=$stop
        done  < "$tsv_file"

        stop_prev="0"
        # search for explicit formatting commands and in-line replace them.
        /usr/bin/sed -i "s/[?,. ]*$wake_word period[?,. ]*/. /gI" "$txt_file"
        /usr/bin/sed -i "s/[?,. ]*$wake_word paragraph[?,. ]*/.\n\n/gI" "$txt_file"
        /usr/bin/sed -i "s/[?,. ]*$wake_word comma[?,. ]*/, /gI" "$txt_file"
        /usr/bin/sed -i "s/[?,. ]*$wake_word colon[?,. ]*/: /gI" "$txt_file"
        /usr/bin/sed -i "s/[?,. ]*$wake_word open paren[?,. ]*/ (/gI" "$txt_file"
        /usr/bin/sed -i "s/[?,. ]*$wake_word close paren[?,. ]*/) /gI" "$txt_file"
        /usr/bin/sed -i "s/[?,. ]*$wake_word dots[?,. ]*/… /gI" "$txt_file"
        /usr/bin/sed -i "s/[?,. ]*$wake_word long dash[?,. ]*/—/gI" "$txt_file"
        /usr/bin/sed -i "s/[?,. ]*$wake_word question[?,. ]*/? /gI" "$txt_file"
        /usr/bin/sed -i "s/[?,. ]*$wake_word exclamation[?,. ]*/? /gI" "$txt_file"
        /usr/bin/sed -i "s/[?,. ]*$wake_word open quote[?,. ]*/ “/gI" "$txt_file"
        /usr/bin/sed -i "s/[?,. ]*$wake_word close quote[?,. ]*/” /gI" "$txt_file"
        # brute force paragraphing: 5 sentences is enough, adjust for audience
        /usr/bin/sed -i "s/\([.?!]\) /\1\n\n/5;P;D" "$txt_file"
        # fix any sentence start/finish errors induced by the above edits
        /usr/bin/sed -i "s/^[a-z]/\U&/g" "$txt_file" # start with uppercase
        /usr/bin/sed -i "s/: [A-Z]/\L&/g" "$txt_file" # no uppercase after colon
        /usr/bin/sed -i 's/\s\+$//g' "$txt_file" # don't end with whitespace
        /usr/bin/sed -i "s/[,]$/./g" "$txt_file" # don't end with a comma, use .
        /usr/bin/sed -i '/[.?!]$/! s/$/./' "$txt_file" # if not ending with punctuation at all, add .
        /usr/bin/sed -i 's/^\.$//'  "$txt_file" # oops, no lines with just periods 
        /usr/bin/sed -i "s/\([a-z]\) \./\1./g" "$txt_file" # remove any spaces before periods
        /usr/bin/sed -i "s/  / /g" "$txt_file" # no double spaces
        /usr/bin/sed -i 's/\([0-9]\+\) \([FC]\) /\1°\2 /g' "$txt_file" # write temp to AMA, Chicago, Nat Geo, NOT APA or NIST
        # generate subject line from first sentence no longer than 80 char and remove any newlines
        subject=$(/usr/bin/head -n 1 -c 80 "$txt_file" | /usr/bin/sed 's/\(.*\)\..*/\1/')
        subject=$(/usr/bin/echo $subject | /usr/bin/tr -d '\n')
        subject=$(/usr/bin/echo $subject | /usr/bin/tr -d '\r')
        # send the cleaned up file as email
        /usr/bin/echo "" | /usr/bin/mutt  -F /home/gessel/.muttrc -s "AudioText - $base - $subject" -i "$txt_file" $to
    fi
}

# Main script scan the watch dir for unprocessed files (within the last 30 days)
/usr/bin/find "$watchdir" -mtime -30 -type f \( -iname \*.opus -o -iname \*.wav -o -iname \*.ogg -o -iname \*.mp3 \) | while read audio_file; do
    convert_to_text "$audio_file"
done

 

Note that Whisper has a lot of tricks not used here.  I’ve used it to add subtitles to lectures and it can do things like auto-translate one spoken language into another text language, and much more.

Posted at 10:53:58 GMT-0700

Category: CodeHowToLinuxTechnology