I Don’t Want Flying Cars; I Just Want Working Bluetooth

I love Bluetooth. I love that it’s supported on all my various electronic gadgets, and lets them talk to each other and exchange information, be it streaming audio data, or a text note, or what have you.

Or at least I love the idea of Bluetooth. The unfortunate reality is that the implementations that I’ve seen never quite live up to the ideal.

For instances, it often takes several attempts to pair two devices, even when they’re two feet from each other. Sometimes devices disconnect for no obvious reason, or seem to become unpaired without me doing anything.

And then there’s the stuttering, which might be related. I have yet to find a Bluetooth headset, speaker, or other audio receiver that doesn’t stutter for five minutes until it finds it groove. In fairness, after the initial five minutes, things tend to stay pretty stable (at least until I, say, move my phone five feet further from the speaker, at which point, they need to resync). But if it’s a matter of the two devices negotiating, I don’t know, frequencies and data throttling rates and protocols, why don’t they do it at the beginning? Or is it a TCP thing, where the two start out using little bandwidth and ramping up over time?

Lastly, there are the tunnel-vision implementations. From what I’ve seen, the Bluetooth standard defines roles that each device can play, e.g., “I can play audio”, “I can dial a phone number”, “I can display an address card”, “I can store files”, and so forth. But in practice, that doesn’t always work: my cell phone sees my desk phone as an earpiece, and earpieces can’t handle address cards, don’t be silly, so I can’t copy my cell phone’s contact list to my desk phone.

In the age of the Internet of Things, my desk phone can store contacts, my TV can run a browser, and pretty soon my toaster will be able to share its 5G hotspot with the neighborhood. There’s no reason to be limited by a noun on the box it came in.

I understand that most of the above is likely caused by bad implementation of a fundamentally decent protocol. But Bluetooth has been around for, what, a decade or more? And I still regularly run into these problems. That points to something systemic in the software community.

Fun With Barcodes

If you have an Android phone, odds are that you have the Barcode Scanner app. And if you’ve looked in the settings, you may have noticed one called “Custom Search URL”.

This is, as the name says, a URL you can fill in. Once you do, you’ll get a “Custom search” button at the bottom of the screen when you scan a barcode. A “%s” in the URL will be replaced by the numeric UPC value, and “%f” with its format (which is displayed next to the code when you scan one).

It seems to me that this can be used as a poor man’s plugin API. You can use http://www.mydomain.org/barcode?f=%f&s=%s, and make barcode be a CGI/PHP/whatever script that looks at the format and code and decides what to do.

For instance, $EMPLOYER has barcoded asset tags on all inventory items. So today I was able to scan a machine’s code and be redirected to the inventory web page for that machine.

Likewise, if it’s an EAN-13 code that begins with 978 or 979, then presumably it’s an ISBN or ISMN, and you can look it up at Amazon, your library, or wherever.

As far as I know, you can’t recognize that a UPC corresponds to a CD or DVD, without having a table of every CD/DVD publisher, but there’s nothing that says your script has to only do redirection; you can present a list of links to the user. So anyway, for CDs, you can construct MusicBrainz or Discogs lookup URLs. Or perhaps you can parse the code, get the manufacturer, and based on the user’s choice, remember what sort of item that manufacturer corresponds to. Over time you can build up a “good enough” database of the things you scan most often.

I wouldn’t mind having a properly organized library of books, CDs, etc. Which is kind of the point of looking this data up on the net in the first place. But while a phone may make a serviceable barcode scanner, it’s no good for lengthy data input. So really, what I’d like would be for the script to remember what I’ve scanned, along with a quick and dirty readable reference (e.g., “ISBN such-and-such: The Wee Free Men by Terry Pratchett) and stash that someplace so that I can later go back and import the data into Koha or whatever I’m using.

Of course, since it’s a web page, I’m guessing you have access to the full range of goodies that people put in browsers these days. I’m thinking of geographical location, in particular. So the script could in principle behave differently based on where you’re located at the moment (e.g., at home or at work).

There are lots of possibilities. Must. Explore.

A Couple of Shell Quickies

Since I got asked several sh-related questions, I might as well get a post out of them.

One person asks:

I’m writing a portable shell script to download a file from the web, and then compare it to a locally-stored version of the same file, using diff.

My first version of the script used mktemp to download the web-file to temporary file, run the diff command, and then delete the temporary file afterwards. e.g.

TEMPFILE=$(mktemp)
wget -q $ONLINEFILEURL -O $TEMPFILE
diff $TEMPFILE $LOCALFILE
rm $TEMPFILE

However I later discovered that the BSD version of mktemp has an incompatible syntax to the GNU version of mktemp. So then I got rid of the usage of temporary files completely, by using input-redirection, e.g.

diff <(wget -q $ONLINEFILEURL -O -) $LOCALFILE

However while this works fine under bash and ksh, it fails under ash and sh with

Syntax error: "(" unexpected

to which I replied:

The first obvious problem here is that “(wget -q $ONLINEFILEURL -O -)” isn’t a filename, it’s a subprocess. So the shell sees “<” and expects a filename, but finds “(” instead.

It looks as though the way to get diff to read from stdin is the standard way: specify “-” as the filename, and give it input on stdin. Since you’re feeding it the output from a process, you want to use a pipe:

wget -q $ONLINEFILEURL -O - | diff - $LOCALFILE

I also suggested that he could try to figure out which version of mkfile he was using:

# Wrapper function for GNU mktemp
gnu_mktemp() {
	mktemp /tmp/tmpfile.XXXXXX "$@"
}

# Wrapper function for BSD mktemp
bsd_mktemp() {
	mktemp -t /tmp/tmpfile.XXXXXX "$@"
}

# Try to figure out which wrapper to use
if mktemp -V | grep version >/dev/null 2>&1; then
	MKTEMP=gnu_mktemp
else
	MKTEMP=bsd_mktemp
fi

mytmpfile=`$MKTEMP`

And, of course, if race conditions and security aren’t a big concern, there’s always

mytmpfile=/tmp/myprogramname.$$

Another person wanted to write a bash script that would do one thing when run by him or root, and another thing if run by anyone else (basically, die with an error message about insufficient privileges and/or grooviness).

He asked whether the following two expressions were equivalent:

  • if [[ ( `whoami` != "root" ) || ( `whoami` != "coolguy" ) ]]
  • if [[ ! ( `whoami` = "root" ) || ( `whoami` = "coolguy" ) ]]

They’re not, but maybe not for obvious reasons, because propositional logic is a harsh mistress.

In the first expression,

if [[ ( `whoami` != "root" ) || ( `whoami` != "coolguy" ) ]]

let’s say that the user is joeblow. In this case, “`whoami` != "root"” is true, and so the shell can short-circuit the rest of the “||“, because the entire expression is true.

If the user is root, then the first part, “( `whoami` != "root" )” is false. However, the second part, “( `whoami` != "coolguy" )” is true (because rootcoolguy), and so the entire expression is “false || true”, which is true.

The second expression,

if [[ ! ( `whoami` = "root" ) || ( `whoami` = "coolguy" ) ]]

is closer to what he wanted, but doesn’t work because of operator precedence: “!” binds more tightly than “||“, so the expression is equivalen tto “(whoami ≠ root) || (whoami = coolguy)”.

In this case, if the user is joeblow, the first clause, “whoami ≠ root“, is true, and so the entire expression is true.

Worse yet, if the user is root, then neither the first nor second clause is true, so the entire clause is false.

What he really wanted was something like:

if [[ ( `whoami` = "root" ) || ( `whoami` = "coolguy" ) ]]; then
	# Do nothing
	:
else
	# Do something
	echo "Go away"
	exit 1
fi

Except, of course, that since the if-clause is empty, it can be cut out entirely. Then all we need to do is to negate the condition and only keep the code in the else-clause:

if [[ ! ((`whoami` = "root" ) || ( `whoami` = "coolguy" )) ]]

Note the extra pair of parentheses, to make sure that the “!” applies to the whole thing.

(Update, May 18: Fixed HTML entities.)

Countdown to Backpedaling Widget

Over on the right, in the sidebar, you should see a countdown clock entitled “Countdown to Backpedaling”. (If not, then something went wrong.)

If you’ve been listening to Ask an Atheist, then you should recognize this as a widget version of the Countdown to Backpedaling clock. And if not, then you should definitely be listening to them. Because they’re cool.

At any rate, it’s a clock that counts down to May 22, the day after Jesus’ return and the Day of Judgment, when the backpedaling and excuses begin.

So anyway, now you want to know a) where to download this, b) how to install it, and c) how to complain to me about all the problems you’ve had with (a) and (b).

Download

The main download page is .

If you’re using WordPress, you can download , put it in your wp-content/plugins directory, and with any luck, a “Countdown to Backpedaling” widget should magically show up in your “Widgets” control panel. You can then drag it into position, and it should work.

If you’re using some other software, you’ll want . Installation depends on what you’re using, of course, but you should be able to insert it anywhere that takes HTML.

Configuration

The main configuration option is the “show_secs” variable at the top. If you want to see seconds in the countdown, set it to true. If you find the seconds’ flashing annoying, set it to false.

You can also look through the CSS part, and edit as you please. You might need to change the width.

I might improve on this, if time permits and I don’t get raptured before getting around to it.

If you have any comments or complaints, leave a comment. Bug reports accompanied by a rum and Coke will get higher priority. Bug reports accompanied by a patch will get even higher priority.

Bourne Shell Introspection

So I was thinking about how to refactor our custom Linux and Solaris init scripts at work. The way FreeBSD does it is to have the scripts in /etc/rc.d define variables with the commands to execute, e.g.,

start_cmd='/usr/sbin/foobard'
stop_cmd='kill `cat /var/run/foobar.pid`'

run_rc_command "$1"

where $1 is “start”, “stop”, or whatever, and run_rc_command is a function loaded from an external file. It can check whether $stop_cmd is defined, and if not, take some default action.

This is great and all, but I was wondering whether it would be possible to check whether a given shell function exists. That way, a common file could implement a generic structure for starting and stopping daemons, and the daemon-specific file could just set the specifics by defining do_start and do_stop functions.

The way to do this in Perl is to iterate over the symbol table of the package you’re looking for, and seeing whether each entry is a function. The symbol table for Foo::Bar is %Foo::Bar::; for the main package, it’s %::. Thus:

while (my ($k, $v) = each %::)
{
	if (defined())
	{
		print "$k is a functionn";
	}
}

sub test_x() {}
sub test_y() {}
sub test_z() {}

But I didn’t know how to do it in the Bourne shell.

Enter type, which tells you exactly that:

#!/bin/sh

# List of all known commands
STD_CMDS="start stop restart status verify"
MORE_CMDS="graceful something_incredibly_daemon_specific"

do_start="This is a string, not a function"

do_restart() {
	echo "I ought to restart something"
}

do_graceful() {
	echo "I am so fucking graceful"
}

for cmd in ${STD_CMDS} ${MORE_CMDS}; do
	if type "do_$cmd" >/dev/null 2>&1; then
		echo "* do_$cmd is defined"
	else
		echo "- do_$cmd is not defined"
	fi
done

And yes, this works not just in bash, but in the traditional, bourne-just-once shell, on every platform that I care about.

So yay, it turns out that the Bourne shell has more introspection than
I thought.

Pre-Compressing Web Content

This was definitely a “D’oh!” type of problem.

One thing I’d been meaning to figure out for a while was how to send gzip-compressed files to a browser. That is, if I have a large HTML file, it’d be nice if the server could compress it to save bandwith and transmission time. Yes, Apache has mod_deflate which takes foo.html and gzips it on the fly, setting all the appropriate HTTP headers. But for static content, I should just be able to compress the file in advance. If the browser asked for foo.html, I wanted Apache to see that there’s a foo.html.gz and send that instead, with headers saying that it’s a text/html file that happens to be compressed.

mod_mime seemed like just the thing: just add

AddEncoding x-gzip .gz

to .htaccess. But every time I did that, Apache sent back “Content-Type: application/x-gzip“, so my browser treated it as a random file of unknown type that happened to be compressed.

Then I noticed that my vanilla-ish site-wide Apache config had

AddType application/x-gzip .gz .tgz

so that when Apache saw foo.html.gz, it ignored the .html extension, and saw only the .gz one.

The fix was to add RemoveType to my .htaccess:

RemoveType .gz
AddEncoding x-gzip .gz

And voilà! .gz stops being a file type and becomes an encoding, allowing .html to shine through.

I’ll add that this plays nice with AddLanguage as well. In my test setup, I have foo.html.en.gz, for which Apache returns the headers

Content-Type: text/html
Content-Encoding: x-gzip
Content-Language: en

I.e., it’s an HTML file, it’s gzip-encoded, and it’s in English.

Just as importantly, this works with other file types (e.g., CSS files and JavaScript scripts), and XMLHttpRequest does the Right Thing with them on all of the browsers I care about.

Evil Hack of the Day

MacOS plist XML files are evil; even more so than regular XML. For instance, my iTunes library file consists mostly of entries like:

<key>5436</key>
<dict>
	<key>Track ID</key><integer>5436</integer>
	<key>Name</key><string>Getting Better</string>
	<key>Artist</key><string>The Beatles</string>
	<key>Composer</key><string>Paul McCartney/John Lennon</string>
	<key>Album</key><string>Sgt. Pepper's Lonely Hearts Club Band</string>
	…
</dict>

You’ll notice that there’s no connection between a key and its value, other than proximity. There’s no real indication that these are fields in a data record, and unlike most XML files, you have to consider the position of each element compared to its neighbors. It’s almost as if someone took a file of the form

Track_ID = 5436
Name = "Getting Better"
Artist = "The Beatles"
Coposer = "Paul McCartney/John Lennon"

and, when told to convert it to XML in the name of buzzword-compliance, did a simple and quarter-assed search and replace.

But of course, what was fucked up by (lossless) text substitution can be unfucked by text substitution. And what’s the buzzword-compliant tool for doing text substitution on XML, even crappy XML? XSLT, of course. The template language that combines the power of sed with the terseness of COBOL.

So I hacked up an XSLT template to convert my iTunes library into a file that can be required in a Perl script. Feel free to use it in good or ill health. If you spring it on unsuspecting developers, please send me a photo of their reaction.

Monthly Reports with Org-Mode

Like a lot of people, I have to submit a monthly “bullet” report, listing the things I’ve done in the previous month.

Since I use Org-Mode for planning, scheduling, and organizing tool (or rather: I tend to throw a bunch of notes into a file and tell this love child of a day planner and a wiki to tell me what I should do next), I figured I should use that.

I could use the timeline feature (C-c a L), but that only works for the current buffer, and I want a report that covers all buffers, just like the agenda.

What I’ve done in the past is to use C-c a a to get the agenda view, go back a month, toggle displaying completed/archived/whatever items, and go through that to make my bullet list.

But I finally got around to encapsulating that into a single M-x bullet command:

; Make it easier to generate bullets for $BOSS
(defvar bullet-entry-types
  '(:closed)
  "Org-mode agenda types that we want to see in the monthly bullet report
See `org-agenda-entry-types'."
  )

(defun bullets ()
  "Show a list of achievements for the past month, for monthly reports.
Uses `org-agenda'.
"
  (interactive)
  (require 'org-agenda)
  ; All we're doing here, really, is calling `org-agenda' with
  ; arguments giving a start date and a number of days. But to do
  ; that, we need to figure out
  ; - the date of the first of last month
  ; - the number of days in last month
  (let* ((now (current-time))
	 ; Figure out when last month was. Assuming that I run this
	 ; close to the beginning of a month, then `now' minus two
	 ; weeks was some time in the previous month. We can use that
	 ; to extract the year and month that we're interested in.
	 (2weeks-ago
	  (time-subtract now
			 (days-to-time 14)))
	 ; We'll also need to know when the first of this month was,
	 ; to find out how long last month was. If today is the 12th
	 ; of the month, then the first of the month was `now' minus
	 ; 11 days.
	 (1st-of-this-month
	  (time-subtract now
			 (days-to-time
			  (- (nth 3 (decode-time now))
			     1))))
	 ; Ditto to find the first of last month.
	 (1st-of-last-month
	  (time-subtract 2weeks-ago
			 (days-to-time
			  (- (nth 3 (decode-time 2weeks-ago))
			     1))))
	 ; The length of last month is the difference (in days)
	 ; between the first of last month, and the first of this
	 ; month.
	 (len-last-month
	  (time-to-number-of-days
	   (time-subtract 1st-of-this-month
			  1st-of-last-month)))
	 (start-date (decode-time 1st-of-last-month))
	 (start-year (nth 5 start-date))	; Year number
	 (start-mon (nth 4 start-date))		; Month number
	 ; Restrict the agenda to only those types of entries we're
	 ; interested in. I think this takes advantage of dynamic
	 ; scoping, which is normally an abomination unto the lord,
	 ; but is useful here.
	 (org-agenda-entry-types bullet-entry-types)
	 )
    ; Create an agenda with the stuff we've prepared above
    (org-agenda-list nil
		     (format "%04d-%02d-01"
			     start-year
			     start-mon)
		     len-last-month)
    ))

I hope this proves useful to someone.

Network Problems Fixed?

As far as I can tell, FreeBSD 8 tickled something in the driver for my ethernet card, and caused it to behave unreliably. Rather than muck around with half-tested kernel patches or ifconfig settings, I slapped a $30 Whatevertheyhadontheshelf-3000 (read: common chipset that’s been debugged by a lot of people), and as far as I can tell, things are now working as they should. If the site stays up for a year, I guess we’ll know.

I also took the opportunity to add some memory. So whoo-hoo all around.

And while I’m at it, I should point out that FreeBSD is like a VW Bug: not the prettiest thing to look at, especially compared to various Apple or Linux offerings, but in a crunch it’s nigh-indestructible. Wanna run with a root partition that’s over 100% full? Sure thing. Boot a 7.2 kernel with a 8.0 /usr? No problem.

Quick and Dirty Perl Hack: Is Foo::Bar Installed?

Every so often, I need to find out whether I have a certain Perl module installed. Usually it’s either because of a security alert, or because I’m wondering how much of a pain it would be to install some package that has Some::Obscure::Module as a prerequisite.

I don’t know how y’all do it, what with the plethora of package-management utilities out there, but one way that works for sure is simply:

perl -MSome::Module -e ''

If this command succeeds, that means Perl successfully loaded Some::Module, then executed the (empty) script, printing nothing. If Some::Module is missing, it’ll print an error message and fail.

This is short enough that it should be aliased, but I haven’t gotten around to that yet.