Most apps tell the user to check this and that when there's a network problem, any network problem. The web browsers I've seen offer the same evasive blah-blah for any problem except a failing TLS certificate.
I have an app that's mine alone, though. It shares my values and its behaviour is guided by my pet peeves, including being annoyed by messages that just say can't reach server
. So for it I wrote a class to analyse a network problem and offer a less generic message.
My analysis is quick and will offer a diagnosis after at most 2.5 seconds. My reasoning here is that when something takes a little longer than usually, there may or may not be a problem, and it's reasonable to start analysis while continuing to try. After a couple of seconds more, there very likely is a real problem, and the app should offer the user a decent explanation. That gives a couple of seconds from when a problem appears likely until the explanation must be ready.
It's cheap, in particular it doesn't cause a lot of network traffic. It sends and receives packets, but not so many as to slow down existing up/downloads. This is because I want to start the analysis before I'm certain that there is a problem.
It's more liberal about sending packets on the local WLAN than about packets across the internet.
It performs all analysis locally. The local device is the only one that is known to be reachable when there's a network problem, so that's where I do all the work.
This implies that if you want to access a URL containing sensitive or personal information, that URL stays in your app, and you comply with all current and future data protection rules.
It also doesn't try to access the URL, because who knows what might happen? It simply trusts your assertion that there's a problem, and finds the most likely type of problem. If nothing is wrong, then the analysis won't make sense.
It recognises the main types of problems and I accept that it may be wrong and definitely won't spot the exact problem. This is a good-versus-best issue. I can deliver a good analysis and promise to have the result ready within 2.5s, but the best possible analysis might take longer. I decided for speed and low cost, and decided that every message to the user, in every language, must convey probability rather than certainty.
Here's what it does, at the time of writing: If a resource isn't reachable from a device, then that's either
- because the device is offline,
- because the device has IPv4 or -6 and the resource requires the other,
- because the device's upstream router is unreachable,
- because that router cannot reach the general internet,
- because the device's local DNS resolver doesn't do its job,
- because your connection works but is too flaky,
- because the resource isn't reachable from the general internet,
- because of a problem at the site where the resource is hosted,
- or for some indecipherable reason.
Eight plus uh, not sure
. My code does some quick checks to find out which kind looks most likely.
Usage: Include the code in your app's build.gradle using compile(''), import no.priv.gulbrandsen.anpa.NetworkProblemAnalysis;, and at the appropriate spot in your code you start analysis using NetworkProblemAnalysis.forHost(string).timeout(millis).onConclusion((problem) -> {…}).start(); A small example app shows exactly how to do it.
The host may be a DNS name or an IPv4/6 address, timeout() is optional, and if you don't call start() nothing happens. The result is usually available long before the timeout (even instantly, if the problem is that the device is in airplane mode). start() returns quickly; the work is done in background threads. You can save a reference to the analysis object just before you start() and call cancel() at any time. The callback from onConclusion() occurs in a thread of its own, and its argument has this enum type.
If there is no problem and you don't cancel() the analysis, your lambda will be called when the timeout is reached, and the argument will not make any sense.
How does it work? If you tell it the problem relates to www.example.com, it will do DNS lookups for www.example.com, example.com, and .com, as well as run a few ping commands with the -c, -i and -t options. Classifying the problem is simple given that data.
Have fun. Serve the users. Send me mail if you have questions or comments. Or raise an issue, or submit a PR.
Update, many years later: I wrote the above on my desktop while I also wrote the code on my then laptop. Later that day I saw a flash, a fuse blew and the laptop was thoroughly dead.
I thought I'd rewrite that code but somehow that didn't happen. The whole thing was surrounded by bad karma. Until now, with Claude's help. Claude used about a dozen files where I used three (two classes and one enum), but there's no denying it, the result is better. I told Claude what to do, we measured and discussed, Claude wrote code, we tested, measured and discussed again, after a few iterations the result's good. We are in a new phase of software development.
I reread both No Silver Bullet and The Mythical Man-Month recently, when Claude changed my world. They're both perceptive, both hold up well in this new age IMO, and I don't think Claude is a 10× silver bullet, but Claude does seem to be a 2× change overall, and sometimes more, as in this case. 2× on average is fantastic. Have fun. Serve the users.
I was searching for something else when a really old mail message caught my eye.
It was a message from dtrump@tpalace.com
, with whom I was not previously familiar. That dtrump
address sent me two messages in July and August 1997, both about an income opportunity
with which I could get rich
.
I'm not sure the messages are genuine. They're unsigned, of course, and the chain of Received fields is difficult to analyse reliably at this point. I also don't know to whom tpalace.com belonged at the time (the oldest information I could find is from 2008).
If there existed a host named tpa-us14d4.tpalace.com with IP address 111.243.5.2 in 1997, I would guess that the spam really came from, uh, tpalace, whatever tpalace was.
I buy less and less hardware as time passes. But I couldn't resist the See.sense Icon3 bike rear light. It's really, really bright and has fancy features: It should be able to brighten when a car approaches from behind, answering the car's headlights as it were, without wearing out its battery.
The light charges via USB C, badly. None of my cables can charge it from a USB C port, it only charges from USB A ports using A-C cables. This may be due to faulty use of the CC1 and CC2 lines in the Icon3. My Anker 737 says it charges at 1.1W from USB A.
It shone very nicely when I used it on a transalpine bike trip this summer, and wasn't at all bothered by rain. The car drivers behaved as if they could see me well.
Update: The charging problem is clearly due to a hardware error in in the Icon3. I bought a USB-Chyna adapter and when I use that, the Icon3 charges correctly from all of the USB C chargers I've tested.
I implemented the IMAP UIDONLY extension in Archiveopteryx a while ago. A couple of notes:
It was really simple; two lines of code changed to six lines starting at line 1154, plus a few lines to announce the extension etc.
It didn't bring any any performance improvement, because generating the EXISTS response is mandatory. With UIDONLY Archiveopteryx counts messages in order to report how many there are in an EXISTS response. Without it, Archiveopteryx makes a list of messages. The loop is the same.
It ought to improve performance for the case where a connection opens a large mailbox and another connection already has opened that. This seems rare with Archiveopteryx. It's more important than it seems though: Opening really large mailboxes can take many seconds. I decided to leave the code in.
There's so much new text on the web that the valuable old writing is difficult to find. I know that Ali Davis wrote an excellent description of various kinds of answers, with a very lucid example of how some answers open the space of possible conversations and others restrict it. I'm 99% sure she posted it to improvisation.ws, and while archive.org has others of her postings, that one is gone and I can't find it.
Sigh.
So I want to quote this little gem before it becomes impossible to find, from a blog mostly about economics:
The one revelation for me was Austria, especially rural Austria. At first I wondered if what I was seeing was an unrepresentative sample—tourist areas that looked richer than usual. But no, the whole of rural Austria looks extremely impressive—like a Swiss travel poster. It’s makes America’s built environment look shoddy by comparison.
Everything looked high quality and attractive. The trains, trams and buses all looked brand new. The roads had no potholes and were well designed. The drivers were all skilled and the traffic flowed smoothly. Doors and windows seemed as solid as a bank vault, not the flimsy Home Depot crap you get in America.
Yes, I know that America is richer than Austria. I know that there is more to GDP than the quality of the built environment. Services matter (don’t ask about their food). Size of houses matters. But I’d also argue that quality counts for something, and probably gets overlooked in GDP comparisons. If an Austrian (or German) told me that America seemed poorer than their home country, I would not argue with them. It’s all subjective.
The residential buildings in rural Austria were quite attractive, quite unlike the ugly new houses being built in America. I can’t blame America for lacking the beautiful baroque buildings of Vienna and Salzburg; we are too new to have any of those. But why is even the modern architecture in Austria so much better.
At some point I'm going to take my office chair to Salzburg to get about half of it replaced. An long-day bicycle trip each way, with the chair on a trailer. No doubt I will stay at my favourite hotel there, one that's a perfect example of the attitude he describes in that blog posting: Money was spent on something good and while the goodness somehow counts for something, counting it is difficult and not done.
That hotel is just pleasant. There's a bourgeois solidity that isn't visible in photos (on booking sites or here) and isn't visible in economic statistics either.
Meanwhile, here's a photo from a chain hotel in a rich American city. The door looked like plastic to my eyes, the frame too, and then there's the door handle.

debconf: cannot find a question for
means that the package database and debconf's database have lost sync. Packages are supposed to add and remove questions when they're installed/uninstalled, and mistakes can happen.
The solution is simple: Run /usr/share/debconf/fix_db.pl as root. fix_db.pl deletes any questions that related to deleted packages.
I liked Pivotal Tracker. I liked the tracker Abhijit and I used for aox. That's all. Of all the task trackers I've used over the years, those are the only two I liked.
So of course I had to write my own eventually.
Mine is a single file, easily edited, in almost this format, except that mine has special support for links.
I need to keep an eye on bugs in remote trackers, issues, pull requests, etc. and look at them every few weeks, so I wrote code that acts like a compiler. When I run that in the editor as though it were a compiler, the task tracker inspects the links, and if one needs attention, two things happen:
- It opens the relevant link in a browser.
- It shows an
error message
and the editor moves the cursor to the note containing that link.
That's it. That's really the only feature. I like it. git handles everything else. If I want to know when I added something, git blame tells me. If something is done, I delete that note and git commit.