MacBook, defective by design banner

Put the knife down and take a green herb, dude.


One feller's views on the state of everyday computer science & its application (and now, OTHER STUFF) who isn't rich enough to shell out for

Using 89% of the same design the blog had in 2001.

Back-up your data and, when you bike, always wear white.

As an Amazon Associate, I earn from qualifying purchases. Affiliate links in green.


MarkUpDown is the best Markdown editor for professionals on Windows 10.

It includes two-pane live preview, in-app uploads to imgur for image hosting, and MultiMarkdown table support.

Features you won't find anywhere else include...

You've wasted more than $15 of your time looking for a great Markdown editor.

Stop looking. MarkUpDown is the app you're looking for.

Learn more or head over to the 'Store now!

Tuesday, October 26, 2021


Take for example Canon's history of disabling the scanning and faxing functionality on some printer models if the printer itself runs out of ink. It's a policy designed to speed up the rate at which users buy expensive cartridges (god forbid you go a few months just scanning things without adequate levels of magenta), but it's exemplary of the outright hostility that plagues the sector.

And now Canon is facing a $5 million lawsuit (pdf) for its behavior. 


Again, being a misleading jackass to goose printer cartridge sales is not a cogent business strategy. 

Truer words, man.

posted by Jalindrine at 10/26/2021 04:32:00 PM
Monday, October 18, 2021

Before you consider buying new AirPods, some quick advice...

If you have an older version of AirPods that you enjoyed, just replace their batteries. I replaced my first generation AirPods by sending them to PodSwap back in February for $60, and I've been meaning to say they work every bit as well as new for a while now.

Look, there's one place Apple gives you more battery than you need, just one: The AirPods case. Even when my AirPods were down to just one functional pod keeping maybe a 30 min charge, my case was still ready to go. PodSwap trades out your existing pods with refreshed ones, and they even send them ahead of time so you're never out of headphones. You keep your case -- mine is very nearly as good as new, charge wise, it appears -- and you're only out $60 for your "new" 'phones.

I don't see much about the new ones that'd have me buying. I mean, I wish my 1st gen AirPods did "Hey, Siri" like 2nd gen, and Spatial Audio has me interested (though see the Verge's "Apple Music’s Spatial Audio is sometimes amazing but mostly inconsistent", including the hint that all headphones can play Spatial Audio?), but I never miss either when listening. (Again, my AirPod "taps" are mapped to 1. fast forward and 2. rewind, which is much more useful than "tap to Siri". Take one out to pause & put it in the play.)

I tried Beats Solo and found myself going back to the AirPods even when they still had dying batteries. There's something about that handy lighter-sized case and top snapping (foreshadowing intended) that's wonderfully portable and enjoyable to use.

The longer you can push back your Apple hardware upgrades the better for your pocketbook. Refreshing your AirPods is one of the easiest ways to save some dough.

Labels: , ,

posted by ruffin at 10/18/2021 02:06:00 PM
Wednesday, September 29, 2021

Remember in April when I complained about how hard Apple is selling me services, and how it made it sound like I would lose email?

Guess who else is selling me services? You got it. Google. Well, specifically Gmail.

That look familiar? 
But Google allows me to "learn more" with the weird hamburger straw menu.

Let's give that a shot.

Wait, okay, that's actually kind of helpful! has:attachment larger:10M is a neat search suggestion to get rid of some oversized emails.

Unfortunately I only have 125 that match. That's not nothing -- 125 at even just 10 megs each is well over a gigabyte, giving me nearly 8% of my 15 gigs of free space back and hopefully silencing this message for a while.

But what really hits me is the coincidence that Apple and Google are both yelling at me to pay something [or pay more in Apple's case] at the same time. 

Interestingly, Outlook seems to hard cap at 50 gigs even when you're paying $70 a year (includes 1 tb OneDrive). Google offers 100 gigs in gmail for $20 a year. Apple lets you lump email in with your iCloud, so potentially 2 terabytes (!??!), but that's shared with your iCloud backups, messages, and pictures, and runs $10 a month, so... Fastmail charges $5 a month for 30 gigs and $9 for 100, which seems to be obviously too much until you recall they aren't profiting on what's in your emails.

Regardless, what getting caught on both ends with "upgrade now!!1!" adverts tells me is that companies aren't scaling storage over time, as it becomes cheaper for them. And storage isn't being updated year over year because having people run out of storage is a profit center.

Not crazy, but not coincidental either. This is a decided, "let's all charge for services" play by all the companies. There's money in them thar hills.

Labels: , , , , , ,

posted by ruffin at 9/29/2021 12:11:00 PM
Tuesday, September 28, 2021


I haven’t seen this issue, but I sympathize with those of you who’ve been hit by it. “Unlock With Apple Watch” almost completely mitigates the annoyance of using an iPhone with Face ID while wearing a mask.

I realize Grubes isn't quite committing the sin of assuming Apple lock-in, but it's close. "Hey, your iPhone works great with your watch!" is verrrrry close to, "Your iPhone doesn't work as intended without one, so of course you have one."

And, let's be clear, the iPhone assemblage expects a watch at this point.

I recall reading a review for the original AirPods by someone who didn't have a watch. She complained that it was too difficult to control volume with the AirPods she was reviewing, and she was 100% right.

The volume button on the AirPods is on your watch. It's the "digital crown". If you don't have a watch, you can't adequately control volume; a crucial part of your Apple AirPods is missing. It can even be a Series 2 watch like mine. Works perfectly. Not only sound, which is slick, but the pause, fast-forward, and rewind are also all there on the watch interface waiting on you.

You could argue that she should have been aware of how the watch would complete the AirPods, Jerry McGuire style, but the review was absolutely spot on saying the AirPods' design stinks out of the box.

Ostensibly, Siri would solve all your extra control problems, and the always-on "Hey Siri" of AirPods Pro and AirPods v2+ likely helps mitigate this a bit. Currently, though it's an adequate solution in theory, it's a huge fail in practice. I map my AirPods' double-tap away from Siri and to forward (left ear) and back (right) to get back some measure of control. Removing one pauses, of course.

(That said, when we finally figure out how to integrate Siri culturally and socially, it's going to be amazing. I think I've mentioned how once, in a crowed and extremely loud Apple Store, I was able to nearly whisper a text reply into my watch and have the perfectly transcribed text sent without so much as removing my phone from my pocket. That's how Siri should work, and, at some point, I bet it does -- a nearly subvocal interface that allows rich interactions.)

If you're wearing a watch, AirPods work great -- better than reaching for some dumb volume wart on a wire hanging down from your ears.

But if you're not, AirPods are a bad idea. You're almost precisely up the proverbial Sonic Creek without a paddle.

And, apparently, you're stuck up Face ID Creek too.

To be clear, this Face ID pain is not something I've felt since I quickly gave away my XR. I still prefer a phone with Touch ID so I don't have to have a clear line of sight to my full visage to use my phone. I've been on the SE train for a while now -- and am currently, unexpectedly, using an SE v1 again. What a beautifully sized phone. And I'm now the iPad mini train again too, a perfect balance of easy to carry away from the house (iPhone SE1) and maximized interactions when I'm at home and pockets no longer matter (iPad mini 6). Both are sooooo much nicer with Touch ID. No watch required.

I do, however, love using my AirPods. I've even PodSwapped them and feel good about that so far.

Labels: , , , , ,

posted by ruffin at 9/28/2021 09:09:00 PM
Monday, September 27, 2021

One problem I keep running into and don't quite file away in my memory is how to handle settings files with sensitive information in git.

My solution is pretty simple:

  • Create a dummy file in an early commit that says, "Contains sensitive information! Contact other developers for the contents of this file."
  • Explain how to use git skip-worktree (which I've apparently blogged about before)
  • Have the new developer skip that config from their worktree.

Now this can bite you, I'm afraid. If you try to swap branches to one where the dummy file has been edited, you'll get an error that you have changes in your branch that would be overridden, even though git status or your GUI client or whatever will [almost properly] show that no chnages have been made.

How do you fix that? Here's the best I can figure (edited somewhat):

If you end up in NeverGiveUp161's situation where changing branches gives you, "Your local changes to the following files would be overwritten by checkout", the only fix I can figure is to run a git update-index --no-skip-worktree path/to/myFile.file, stash that, and then change branches.

Note that that's --no-skip-worktree with a no- in that command to remove a file from skipping.

Not super ideal, but it works.

Labels: ,

posted by ruffin at 9/27/2021 11:04:00 AM
Monday, September 20, 2021

When Bill Wyman left the Rolling Stones shortly after Steel Wheels, I recall Jagger saying something heartless like, "It's just the bassist. We can hire another bassist."

I can't find that exact quote, but I did find this at, um,

Wyman, who retired from the band following its mammoth 115-date “Steel Wheels/Urban Jungle” world tour, admitted, “When I first left the Stones it took a few months to rebuild that relationship with them. It was quite stressful and they didn’t want me to leave. So they became bitchy. Instead of being nice and saying: 'Great 30 years. Cheers mate,' Mick (Jagger) would say the most absurd, stupid things, with that spoilt attitude he had. He’d say things like: 'Oh well, if anybody has to play bass I’ll do it. It can’t be that hard.'

That's pretty close. I'm not saying Wyman is a musical genius (isn't "In Another Land" his? Interesting, but not a rock song), but he's well past good, and he and Watts were apparently good friends, not just because they made up the rhythm section. Pro tip: Laying a bass line in the groove isn't child's play. It's not Hendrix (though Hendrix did play bass -- and I'm not sure he thought it took much to play bass either), but it's not nothing.

Wyman and the Stones apparently made up, but I was worried initially that I'd see something similar for Watts when he died. "Oh well, we'll just hire another drummer."

Luckily that didn't happen, not exactly, and the group not only brought down their website to put up a tribute, but also released a video.

That said, if you look at the lyrics for "If You Can't Rock Me", the only mention of Charlie is arguably this line:

The band's on stage and it's one of those nights, oh yeah.
The drummer thinks that he is dynamite, oh yeah.

The rest is about (assumedly) the singer looking for, um, some satisfaction.

Seems to me there was a much better, nearly haunting, track from the same album that would've shown a little more introspection, "Time Waits For No One":

Yes, star-crossed in pleasure, the stream flows on by
Yes, as we're sated in leisure, we watch it fly, yes 
And time waits for no one, and it won't wait for me
And time waits for no one, and it won't wait for me 
Time can tear down a building or destroy a woman's face
Hours are like diamonds, don't let them waste 
Time waits for no one, no favors has he
Time waits for no one, and he won't wait for me

That would've been a heck of a hat tip that even the Stones won't last forever, and would've marked that they aren't precisely the same Stones going forward.

Do I think the Stones should've cancelled their tour? I don't know. Watts was already off the bill for health. Seems they likely knew what was coming.

But I do I think the take home is that Mick is living his best life and isn't one to get, um, caught up in being overly sentimental or retrospective. The bread is buttered on one side, and that's his... and Keith's.

And though I really don't want to wade out in a pandemic to see them "one last time"1, I'm tempted.

1 I think this would mark the second or third time I've used that "this could be the last time" argument to excuse going to a concert, starting with that Steel Wheels tour. And yes, I'm finally old enough that I can't recall if I've seen them two or three times; Voodoo Lounge and Bridges to Babylon have kinda converged for me. I think I saw both, probably both in the same place, and they don't really distinguish themselves one from another in my memory now.

Labels: ,

posted by ruffin at 9/20/2021 08:04:00 PM
Sunday, September 05, 2021

I liked the idea of Charmin Forever Rolls. Less overhead, easily shipped, definitely a bulk item, allows subscriptions. It's easy to fill up a buggy with toilet paper, and it's nice to have it delivered to your door instead.

But are they a good deal?

Well, I can get 18 Mega rolls at Walmart for $17.88. That's 47.4 square meters of paper.

And I can get 3 forever rolls for $26.97 or $24.28 with the subscription discount.

That's 37.7¢ per meter squared for Mega.

It's 52.4¢ or 47.1¢ with discount, per meter squared for Forever.

That is, Forever rolls are 39% more expensive for a single order and 25% more if you get a subscription.

That's not a good deal.

MyFreakinName, doing the hard work so you don't have to. You're welcome. ;^)

Labels: ,

posted by ruffin at 9/05/2021 04:42:00 PM
Thursday, August 26, 2021


Notice that the controller class depends on ProductRepository, and we are letting the controller create the ProductRepository instance. However, it's a bad idea to hard code the dependency in this way, for several reasons.

  • If you want to replace ProductRepository with a different implementation, you also need to modify the controller class.
  • If the ProductRepository has dependencies, you must configure these inside the controller. For a large project with multiple controllers, your configuration code becomes scattered across your project.
  • It is hard to unit test, because the controller is hard-coded to query the database. For a unit test, you should use a mock or stub repository, which is not possible with the current design.
[emphasis mine - mfn]

You know, I've often wondered why dependency injection is so popular. It truly is just an inversion of control. The control concerns themselves don't change. It's another variation of "it's all zeroes and ones" where you rearrange some deck chairs to make things look new again.

That's not all bad. Cargo culting is much too popular a development mentality. At least rearranging deck chairs makes people look at their architecture closely with fresh eyes, though I fear the result is often trading one cult for another that has better marketing or community buy-in when the decision to join is made.

And I often get the answer highlighted in green when the discussion comes up: "But we have to have interfaces so that we can test it!" Um... not always true. There are other equivalent options. And because there are good ways to test that existed before DI, that's really not a good explaination for its adoption.

DI isn't free; it has a significant cost. It requires a good head rethread and a ton of boilerplate. Easier testing doesn't (again imo) explain its explosive popularity. (Though I'm very happy it's become the industry's party line to proclaim we value testing so much.)

But this line (highlighted in yellow earlier) from Microsoft actually explains the DI advantage:

If the ProductRepository has dependencies, you must configure these inside the controller. For a large project with multiple controllers, your configuration code becomes scattered across your project.

I really think that's it -- put another way, DI helps enable clean encapsulation that, in turn, fosters anonymous collaboration between coding teams.

If I have to learn how to spin up Foo and pass in all of its dependencies, I'm having to schlep around a lot of objects I may have never used before, much less contributed to. If I'm a single-person indie shop, the advantages of Dependency Injection are slim. But if I want to access Foo.NeatMethod without bothering to open the Foo box, well, I'd rather you put all of its dependencies in a row for me.

That's what DI does. It's a decent amount of extra work up front to save everyone down the line from being nickel and dimed -- or, when they're protected from having to learn a whole new domain, dollar and pounded.

This shows that DI's advantages clearly appeal to enterprises; DI is literally an enterprise architecture strategy, not to improve system load or because it's an inherently superior -- again, for a small team, the DI boilerplate might ultimately slow them down -- but because it can help enable a specific type of work, which is work by multiple teams and workers with very little knowledge transfer overlap.

Enterprise development is really a pretty fascinating study in cultural evolution.

Labels: ,

posted by ruffin at 8/26/2021 06:43:00 PM
Thursday, August 12, 2021

If you've been working with JavaScript for a while, you'll know that things have changed from the day when the code end users saw in production was the same code you hacked with your hands. Though I might prefer the days of Vanilla.js, it's gotten nearly impossible to hold a job without knowing how to transpile code.

If you're still on the Vanilla side of the chart, transpiling JavaScript code is when you take a recent version of JavaScript, or, more properly, ECMAscript, and essentially compile it into an older, more compatible version. Transpiling is a "source-to-source" compilation, from one programming language (or version) to another, so to speak.

Maybe you want to use "farts" or "fat arrow functions" where you can exchange this code...

function (x) {
    return x + 1;

... with the shorthand...

(x) => x + 1;

Or maybe you want to use shorthand property definitions, which turns this:

var o = {
  a: a,
  b: b,
  c: c

... into...

let o = {a, b, c};

Or maybe you just want to use let and const instead of being limited to var.

Or, even better, maybe you want to use TypeScript, which is a great idea, bringing along the bug-squashing safety of strong-typing without sacrificing the abilty to go full dynamic when you need it.

You get the point. JavaScript keeps adding features (as does TypeScript), but older browsers won't magically support all of them. You need to turn your cutting-edge code into something [insert lowest common denominator based on your browser requirements] can run.

That's transpilation. Even if you're not going to transpile something, you need to be aware of how it works so that you can pick the right tools for your projects.

I'll probably make a video at some point, but I would like to quickly get down the steps I think I'd take when moving from a vanilla, es5-compatible JavaScript codebase.

Notes, warnings, and caveats

Why target your transpilation for es5? es5 is the latest version IE supports, as a benchmark. es6 requires more modern browsers. Luckily requirements to support IE seem to be going the way of the dinosaur.

That said, I haven't (yet) run into a situation where a transpiler balks at targeting es5. That is, why not include IE if transpiling to something newer buys me nothing? Everything I can do in es6 I can, thanks to some insane transpiler shimming, do in es5.

Warning: This is not going to be a howto, I'm afraid, but a command recipe for those who already kind of know what they're doing.

It's also not a really nuanced recipe. For instance, when you run npm init, you probably don't want to use the -y flag and should instead pick a specific license. For some reason, using the -y flag means you'll pick "ISC", "a permissive free software license published by the Internet Software Consortium" instead of "UNLICENSED" for your project, and "UNLICENSED" is what the docs say to use for copyrighted code.

So use at your own risk.

And to be overly clear, this is for browser development, not server-side node dev, natch.

Recipe to move es5 codebase to modern JS (with snowpack, webpack, & babel)

Here's the 10,000' view:

  • Use Snowpack to transpile your TypeScript into modern JavaScript.
  • Use webpack to fold your modern JavaScript into a single file.
  • Use babel to transpile your modern JavaScript into es5 compliant code.
  • (Use some node code, called by your build process, to link to that single es5 page from your starting html.)

Here are the specific steps:

  1. Ensure you've got node installed globally
    • The node install will include installing npm.
    • If you know you will need to swap to different versions of node for different projects (as in you know you have some older ones that won't work in the latest version of node), google nvm ("node version manager").
      • You should, however, know if this applies to you.
      • (If this is your first transpilation project, different versions of node don't apply. Yet.)
  2. Navigate to an es5 code base.
  3. In the home directory of the codebase, run npm i -y
    • See caveat about licensing, above.
  4. Now run npm install -D snowpack
    • Snowpack is a development tool only imo.
    • It is not a conventional transpiler so much as a package manager.
    • snowpack's goal is to allow you to develop in a browser that supports whatever version of JavaScript you want to program in (vs. deploy) quickly.
    • It does, however, support compiling TypeScript on the fly. That and the more deliberate management of libraries are the biggest gains snowpack buys for me.
  5. "Port" your existing es5 to TypeScript by changing all JavaScript files' extensions from .js to .ts
    • TypeScript is a superscript of JavaScript, so that's all you have to do.
    • On macOS, you can use this command:
      • find . -iname "*.js" -exec bash -c 'mv "$0" "${0%\.js}.ts"' {} \;
    • I've got a PowerShell script to do this somewhere, but until I find it, try these answers.
  6. Add a snowpack.config.js file to the root directory.
  7. Add "start": "snowpack dev" to your package.json's scripts collection
  8. Install webpack as a "dev dependency" for your project with npm install -D webpack-cli
  9. Add this build command to your package.json's scripts collection:
    • "build": "snowpack build && webpack"
    • Here, snowpack is going to compile your TypeScript into JavaScript.
    • Then webpack is going to take the compiled JavaScript and pack it into a single index.js file.
    • Hang in there. We're getting to the transpilation.
  10. npm install --save-dev babel-loader @babel/core
    • We're using Babel to transpile the code.
    • Up until this point, we needed a modern browser that understood our untranspiled code.
    • Not a big deal as you develop, but potentially a very big deal before releasing.
  11. Add this command to package.json:
    • "launderIndexHtml": "node ./buildscripts/build.js"
  12. Add build.js to your project's home directory using the template, below.
  13. Edit package.json's build command to include this new build command:
    • "build": "snowpack build && webpack && npm run launderIndexHtml",
    • Why didn't we just start with that for our build command? Idk. This recipe is too tutorial-ly, I suppose.

Suggested initial snowpack.config.js

/*global module */
module.exports = {
    mount: {
        public: { url: "/", static: true },
        app: "/",
    buildOptions: {
        out: "./dist",
    devOptions: {
        open: "brave",

Why does this open Brave when in Well, I like to have a browser dedicated to testing and Canary wasn't an option snowpack supported at the time of this writing, strangely enough.

Suggested initial webpack.config.js

/*eslint-disable */
const path = require("path");
module.exports = {
    entry: "./dist/index.js",
    output: {
        filename: "./index.js",
        path: path.resolve(__dirname, "dist"),
    module: {
        rules: [
                test: /\.(js)$/,
                exclude: /node_modules/,
                use: ["babel-loader"],
    resolve: {
        extensions: ["*", ".js"],

Custom build.js script

/* eslint-env node */
// We need to do two things after we've compiled our TypeScript with snowpack,
// transpiled into es5 with babel, and bundled & minified with webpack:
// 1. Update index.html to load our minified es5 file as-is, not as a module.
// 2. Get rid of the source we bundled into our webpack output.
var fs = require("fs");
var indexLoc = "./dist/index.html";
fs.readFile(indexLoc, "utf8", function (err, data) {
    if (err) {
        return console.log(err);
    var result = data.replace('script type="module" src="./index.js"', 'script src="./index.js"');
    // var result = data.replace(/script type="module" src="./index.js"/, 'script src="./index.js"');
    fs.writeFile(indexLoc, result, "utf8", function (errWrite) {
        if (errWrite) {
            return console.log(errWrite);
function getDirectories(path) {
    return fs.readdirSync(path).filter(function (file) {
        return fs.statSync(path + "/" + file).isDirectory();
var foldersToKeep = ["lib", "css", "assets"];
getDirectories("./dist").forEach((x) => {
    if (foldersToKeep.indexOf(x) === -1) {
        fs.rmdirSync("./dist/" + x, { recursive: true });

Labels: , , ,

posted by ruffin at 8/12/2021 04:45:00 PM
Saturday, August 07, 2021

There's been a lot of pixels spilt regarding Apple's plans to sniff out pictures of child exploitation on personal devices and, if I understand correctly, silently report someone to the National Center for Missing and Exploited Children if they think their algorithms have found it.

A couple of quick reactions:

First, the rhetorical power of child exploitation as a cover discourse for something else entirely in the last decade or so would be unbelievable to someone from the 1980s. What the absolute heck is going on? Stopping someone accused of exploitation has become akin to a theoretical rhetorical get out of jail free card to justify doing whatever someone wants to be doing. And, in some cases thankfully, like the fellow with the assault rifle at the pizza store, it also still appears to be a practical get into jail quick card if you actually act on that coopted rhetoric. Still, it's a bizarre, collective neurosis.

Second, let's talk about what Apple's doing. It seems antithesis to their "privacy is in or DNA" claim, even though some Pizzagates are tragically real. Why are they taking an anti-privacy stand now?

Let's be frank: Apple has not been doing great looking privacy-minded this year, as they gave up the privacy high ground when they announced just last month that they plan to literally start selling AAA privacy in iOS once iOS 15 ships. You don't pay, you don't get to be fully private on iOS.

Let's also admit that Apple's not going to be able to create a successful system for sniffing evil images for years. If you've been reading this blog for a while, you know I believe Apple can't QA software to save their life (QA is "Quality Assurance", here meaning the ability to test software to make sure it works well even in unanticipated situations). Here's one example:

Things will go wrong. Someone will be suing Apple for a false positive. And one or two of those people may honestly have their lives ruined.

How hashing an image works

To know why someone's going to get charged who shouldn't, I want to describe how hashing and fingerprinting works, though I really don't want to get into the weeds.

So let's grossly oversimplify and say it works like this:

  1. Take a seven digit number. This represents the content of a picture. (try 1234567)
  2. Remember the third, fifth, and seventh digits. That's your "hash" or "fingerprint" (357)
  3. Now any time you get a number, you can compare. If you have XX3X5X7, you know you might have 1234567.

In our case, matching our hash or fingerprint of 357 means there's a 1 in 9,999 chance of actually having 1234567. That's a horribly large chance of a false positive. You could also have 0030507. Or 3335577. Or 2136567. We don't know for sure. Each of those 9,999 matches that aren't 1234567 are collisions. Even so, that's only 10,000 values out of ten million we need to check behind those three hashed digits. Huge potential time savings.

Now when "cyber-fingerprinting" large files like images, the numbers are VERY large (lots over seven digits) and the hashing algorithm, though it will have some collisions, is MUCH more exact. The chances of false positives with a true fingerprinting is, let's guess, about the same or worse than winning the lottery. In any event, false positives are very rare. And you should appreciate that.

But eventually people do win the actual lottery, and, given enough people, someone will have a photo fingerprint collision. Someone will have a picture that, once hashed, matches the fingerprint of a known evil [no hyperbole intended at all] image. And their life could be ruined in a way that will make some identity thefts feel quaint.

Worse, with Apple's software record, there's going to be some bug that says the equivalent of "Any number with a single 3, 5, or 7 in it matches," the National Center is going to receive thousands on thousands of false reports, and we're going to bring down, at least briefly, the very system we're trying to support.

And if someone games the system, well, all bets are off. Someone is going to match a fuzzy fingerprint with a meme image specifically spoofed to match a database image, it's going to get popular, and suddenly there are Pizzagates everywhere! No, really, no joke. It's going to happen.

panda plus invisible filter equals gibbon

Apple's true (and legitimate) motivation

Perhaps false positives are worth it to expose those who do exploit children. Certainly in theory I think a few ruined lives is worth the good that can come out of this if there's any meaningful reduction of exploitative imagery.

And Apple has a clear motivation for doing this, an angle nobody's mentioned yet (that I've heard):

Apple is hosting child pornography on their servers right now.

Not maybe. They are. I can't say that with 100% certainty, but theoretically, given a billion active devices, you know they are. There are too many sickos out there, sickos have phones, they have evil on those phones, and some of those phones are backed up to iCloud. That's a huge issue for Apple.

That has to be Apple's motivation. My guess is that the people with serious problems know other ways to maintain their privacy that Apple won't catch. Apple sniffing Photos (the app) will get some less deliberate criminals. But even at 100% foolproof iCloud sniffing, Apple won't stop exploitation. Should Apple delete apps like those from the App Store too? Maybe! Tough question, but cut from the same cloth.

I mean, what a freaking mess. I can't imagine all the smut people likely have on their phone. Heck, Brett Favre allegedly (almost certainly did, right?) sent pics of, well, you know, to a female reporter while he was with the Jets. Very few have signed him off as a habitual recidivist, and I bet most NFL fans still have a mostly positive view of Favre in spite of having ­and sharing NSFW pics and being a sexual harasser. (Could iOS stop these sorts of pics from being shared? Would that be bad? What if I wasn't a Puritan at heart, would I still think it's bad -- that is, consenting adults can exchange NSFW pictures, right? Right? Ewww.)

It's just that this passive, "We're looking through your phone and taking actions based off of its contents without your involvement" that's scariest to the layperson, I think. To jump all the way from absolute, objective evil, let's go right to the end of the grey area where it's almost harmless:

Wait. Before I venture much further, let me stop completely to say something: If someone has 1000 matches with a database of child exploitation imagery, even at 95% accuracy (insanely low accuracy, I'd think), statistics say that they've definitely got non-trivial amounts of illegal imagery. If they have 100, they have illegal images. If they have 10? I've got to think probably they do.

I have some practical privacy and 5th amendment itches somewhere, but here, they're unimportant. You're using a private company to store illegal goods. Apple sniffed those illegal images just like a storage company could catch a cocaine stash with a drug sniffing dog. You should get turned in with no warning and let the judicial system (at least in the US) figure out where the chips should fall.

Back to the grey area discussion...

What if you have too many pictures of jaywalking?

Movies taken from cars that were speeding?

Should you get fines in the mail as if you'd been caught by a red-light camera?

How many jaywalking pictures before something must be done? It's more than 2. Is it less than 1000?

In all of these cases, what we're talking about is the practical loss of privacy, at least compared to the situation that came before it. This practical, day-to-day loss is starkly different from losing the theoretical right to privacy, which Apple hasn't changed at all without some serious mental gymnastics -- you could argue that today's First World requires a cell phone, and if Android starts doing this photo sniffing too you're trapped in a duopoly, but you also have other options for taking and storing pictures.

Again, this is an argument because Apple is hosting your images on their hardware.

But wow, it feels like a slippery slope, and a dangerous rhetoric of absolute evil attached to not tripping down it.

Labels: , ,

posted by ruffin at 8/07/2021 04:31:00 PM

Support freedom
All posts can be accessed here:

Just the last year o' posts:

URLs I want to remember:
* Atari 2600 programming on your Mac
* joel on software (tip pt)
* Professional links: resume, github, paltry StackOverflow * Regular Expression Introduction (copy)
* The hex editor whose name I forget
* JSONLint to pretty-ify JSON
* Using CommonDialog in VB 6 * Free zip utils
* git repo mapped drive setup * Regex Tester
* Read the bits about the zone * Find column in sql server db by name
* Giant ASCII Textifier in Stick Figures (in Ivrit) * Quick intro to Javascript
* Don't [over-]sweat "micro-optimization" * Parsing str's in VB6
* .ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture); (src) * Break on a Lenovo T430: Fn+Alt+B
email if ya gotta, RSS if ya wanna RSS, (?_?), ¢, & ? if you're keypadless

Powered by Blogger Curmudgeon Gamer badge
The postings on this site are [usually] my own and do not necessarily reflect the views of any employer, past or present, or other entity.