Chris Adams

I found this review of the latest VW Jetta TDI curious:

But like many new clean diesels, which meet even California’s tough emissions rules, the Jetta scoffs at its sticker. Hoarding fuel like a mobile Scrooge, I averaged a remarkable 48 m.p.g. over more than 150 miles of freeway driving. That’s the best mileage of any American-market car I’ve tested — gas, diesel or hybrid. I never knew that driving a steady 60 m.p.h. could be so gratifying, and I vowed to try it more often.

Back when I bought my TDI in 1999 48 MPG would have seemed like a bigger deal but it's actually lower than the 52 MPG I averaged on the ~270 mile round-trip from San Diego to Pasadena and back, with an average speed over 70MPH (other trips weren't as precisely measured . I'm curious whether this is simply due to the extra power or the tighter emissions standards - intriguingly, the 42 MPG average for mixed driving matches the more or less constant value I measured for the last couple of years of mixed highway / city commuting. I know Volkswagen tweaked things to favor power-hungry American drivers for years - I'm curious whether we'll see that switch back now that everyone has rediscovered budgeting.

A great take-down for the recent “Elcomsoft made WPA obsolete” freak–out by people who should know better, pointing out that adding a single character to the password will cancel out the attacker's new-found boost. The part which I find scary and my reason for blogging is the frequent recommendation that you use a VPN instead: this is Ronco Spray-On Security and it's downright hazardous because it puts the focus on the network rather than on the insecure systems and applications which have caused almost every security problems you've ever heard about.

I first talked about this back in 2003 and it wasn't a new idea (or original to me) back then that trusting the network is a really bad idea. Unless used with more discipline than most places manage, a VPN simply enables people to continue ignoring their insecure applications. The underlying problem is that a VPN is convenient but very broad: your salespeople will start using one because you told them they couldn't access the fileserver otherwise — and pretty soon your internal network is getting scanned by the malware installed on their home PC and your network admin is getting DMCA notices because of their kids P2P habit. Worse yet, that one user with a habit of opening malware now has the ability of attacking everyone else in the organization over your mistakenly-trusted network.

There's an easier way to configure your wireless network: treat it like the internet and provide protocol-level security for the resources your users need to access, enforced by firewall rules blocking insecure protocols. This enormously reduces the support cost of VPNs, avoids the significant performance and reliability hits and gets you out of the business of trusting the network at all — which is good, because that trust was almost certainly misplaced.

Like many people, I have a few relatives who have persistent honesty problems when it comes to politics. I'm not talking about things like disagreeing over the best way to deal with poverty or trade but people who consider things like “Liberals are driven by Satan and lie constantly” to constitute a legitimate description of the opposition party. This election, I've been receiving these entirely in the form of multiply-forwarded smears directed at Hillary Clinton and now Barack Obama and it's been getting a bit repetitive listening to the same “Cryto-Muslim-terrorist-eats-babies-hates-America” tirade over and over again. Unfortunately, these are also the people who consider forwarding urban legends their best way to combat the dread menace facing our country and they tend not to listen to either fact-checking or requests not to forward unsourced rumours.

It turns out, however, that there's a way to both lower the volume of crap received and do some good: take a page from the people at Planned Parenthood who started the Pledge-a-Picket program and set a bounty for vicious slander: I picked $50 donated to the target (Obama, the ACLU, etc.) — $500 later and my inbox has remained clear for the first time in recent memory.

Update: the flood has gone down but not dried up. At the conservative inability to stick to facts and logic has raised ~$750 for something better…

Recently the topic of enhancing web pages came up at work. It's a lot easier than it used to be thanks to two trends: the rise of modern JavaScript libraries and public CDNs hosting those libraries. This makes a lot easier to enhance content which you can't easily alter (e.g. the forms used by various big companies with marginal web competency) or in situations where you're worried about compatibility with existing code (some squirrelly vertical apps in our case).

Updated 2008-10-14: there's a very similar jQuery-lovefest on Sam Ruby's weblog with plenty of useful tips.

To illustrate just how little code this can require, here's an example which uses jQuery to install a function which sanitizes input (we have a legacy app chokes on smart-quotes and people paste text in from Word), copies the submit buttons from the bottom of the form to the top and adds a graphical datepicker for every date field on the page:

jQuery(":text,textarea").bind("change", sanitizer);
jQuery("form").bind("submit",
    function() {
        jQuery(":text,textarea").each(sanitizer);
    }
);

var submit_buttons = jQuery('input[type="submit"]');
submit_buttons.parent().clone(true).prependTo(
    submit_buttons.parents().filter('form')
);

jQuery('input[id*="DATE"]').datepicker();

That's the complete, ready-to-go, “even works with crotchety old Internet Explorer” guts of the code (the take-home lesson is that jQuery is awesome for busy developers). The downside is that this requires a little but of work: you need to have jQuery (and possibly dependencies like the UI plugin I used above) available and you need to jump through some hoops to load jQuery into an existing page efficiently and without conflicts.

Didn't we used to pay for hosting?

One drawback to all of this is that you need somewhere to host your external libraries since you can't fit the core jQuery into a URL, much less UI components or the less svelte libraries. This meant setting up a server, getting an SSL certificate if you need to work on HTTPS sites, etc. Not that much work but it's now a lot easier and quite noticeably faster because Google makes it trivial to get the popular AJAX libraries from their CDN.

Developing with Bookmarklets

The deployment scenario for the major projects where I've used these techniques is a situation where you have some limited access to the page source: perhaps inserting a single script tag into a template or using something like MonkeyGrease or an Apache proxy with mod_substitute to rewrite the generated HTML as it passes through. This is great for making minimal changes but a bit cumbersome to develop and test with, particularly if you need to work on a production site or your instructions begin something like “Go change your browser's proxy settings…”

If I was only working in Firefox I could use GreaseMonkey but I need to test in Safari and Internet Explorer, too. The portable solution is a simple bookmarklet. I use a simple template (bookmarklet-template.js) which loads jQuery from the Google CDN and, after everything is ready to go, runs either a simple function or the external script of my choosing. This makes it easy to prepare an injector bookmarklet which can be used to pull my code into the current page, after which I can run and debug it using Firebug.

Useful Examples

This is also a useful technique for fixing other people's pages. Here are two bookmarklets and the commented source for tools which I use often:

  1. Enable autocomplete - changes autocomplete="off" to on throughout the page (Source: enable-autocomplete.js)
  2. Resizable Textareas - makes all textareas resizable (alá Safari 3) using jQuery UI Resizable (Source: resize-textareas.js)

I keep both of these in my Firefox & IE bookmark toolbar since they come in handy throughout the day and I've created more any time I find myself regularly needing to deal with a cranky legacy site. The process is simple: copy bookmarklet-template.js, add the code which does whatever fixups the target page needs, run the entire thing through JSLint and, finally paste it into Ted Mielczarek's very handy Bookmarklet Crunchinator.

Good Code Injection Practices

Use Anonymous functions

What's the difference between this bit of code and the first example above?

(function(){
    jQuery(":text,textarea").bind("change", sanitizer);
    jQuery("form").bind("submit",
        function() {
            jQuery(":text,textarea").each(sanitizer);
        }
    );

    var submit_buttons = jQuery('input[type="submit"]');
    submit_buttons.parent().clone(true).prependTo(
        submit_buttons.parents().filter('form')
    );

    jQuery('input[id*="DATE"]').datepicker();
})();

It looks almost identical but there's a key difference: this code is inside an anonymous function and that means that all of my variables are local to the function itself, which means that they won't be visible to other JavaScript on the page and I don't have to worry about conflicting variable or function names. Note that this is only true for variables declared using "var" - if you leave that out or do something like window.foo you can still touch the rest of the page if you need to - for example, replacing the broken validation logic on Comcast's forms.

Reliably detecting when external code has loaded

When jQuery has loaded, it's easy to say "Load this .js file and run this function when it's ready" - here's how the text-area resizer works:

jQuery.getScript(document.location.protocol + "//ajax.googleapis.com/ajax/libs/jqueryui/1.5.2/jquery-ui.js",
    function() {
        jQuery("textarea").resizable();
    }
); 

Loading jQuery itself requires you to do this the hard way: generate a script tag on the fly, insert it into the document and listen for the load events to tell when it's safe to run code which depends on the library you're loading. This is easy for Safari, Firefox, etc. which support the standard W3C DOM addEventListener: simply run your code after the script tag fires a "load" event. Unfortunately, it's not that simple for Internet Explorer: in theory attachEvent("onload") would be equivalent but unfortunately load events are quite unreliable for script tags with IE and so we need to use an onReadyStateChange handler as seen below and check for either of two events which may be fired:

var s = document.createElement('script');
s.type = "text/javascript";
s.setAttribute('src', document.location.protocol + '//ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js');

if (s.addEventListener) {
    s.addEventListener("load", loader, false);
} else if ("onreadystatechange" in s) {
    s.onreadystatechange = function() {
        if (this.readyState == 'complete' || this.readyState == 'loaded') {
            loader();
        }
    };
} else {
    // Chances are if your browser is this old jQuery won't even work but just in case:
    window.setTimeout(loader(), 2500);
}

document.getElementsByTagName('head')[0].appendChild(s);

It's conceivable that a buggy browser could fire the same event twice in an unusual scenario and if you have any sort of user-driven or timer-based code, you'll want to prevent your payload from being run multiple times using a guard like this which allows the function to check whether it has executed before without using the more common approach of relying on a global variable. Besides cleanliness, this also makes it easy if you might inject multiple things onto a page and don't want to have to rely only on a global variable naming convention to prevent chaos:

// Avoid executing this function twice:
if (arguments.callee._executed)  return;
arguments.callee._executed = true;

Avoid HTTP/HTTPS conflicts

If you're injecting code into pages which may or may not use SSL, you have a problem: if you hard-code a URL in your code and the protocol doesn't match you'll either incur the extra overhead of starting an SSL session (which isn't a major problem) by using https even when you don't need to or encounter Internet Explorer's popular mixed-mode security warning. This is easy to avoid by using the current page's protocol for your scripts as long as you're using a server which can handle either protocol (Google's CDN does; Yahoo's does not):

document.location.protocol + '//path.to.example.com/something.js'

Let's be honest: I had already ruled out voting for McCain over his integrity deficit but I was amused by the rather in-character faces of the two major campaign websites this morning:

John McCain's campaign homepage on Sept 13

Barack Obama's campaign homepage on Sept 13

Unsurprisingly, both Obama and the Red Cross got my dollar, along with the ACLU in honor of their new Constitution Voter campaign.

Two interesting interviews with an American protester who was held for a week by the Chinese government's in case some Western reporters were feeling particularly motivated to do their job and detract from the Olympics' warm totalitarian glow:

Powderly said that prison guards believed — correctly — that he was the man who assembled the laser but not the protest’s organizer. They accused him of trying to “murder China,” he said. “We know that you didn’t murder China, but you made the knife and you’re going to take credit for it — unless you show us the hand,’ they said,” in an apparent bid to learn the leader’s identity, Powderly said. Safely back in his Grand Street apartment, Powderly told The Brooklyn Paper how he was deprived of sleep, water, food and medicine, cuffed into painful positions, and had $2,000 stolen from his bank account — “non-lethal methods of waging war on people” that he considers “just as insidious as waterboarding.” After hours without sleep and threats against their lives and the lives of their loved ones, Powderly and the other Americans began to crack. “That’s when I started to realize that I’m really good at being a douche-baggy art star, but I’m really bad at this secret agent business,” he said.

A few years ago we'd have raised a huge fuss over stifling dissent, abuse of an American citizen (remember the Singapore caning?), etc. Now we're quiet, in no small part because the Chinese tactics described are less than those which our government considers standard operating procedure. This isn't to equate the two governments or deny that China has engaged in worse but … they also think they're protecting their country from outside threats. Once we've allowed torture and murder under that guise, who are we to say that their threats are less real than the minimally supported “threats” our government has claimed were deadly serious in the past?

I'm somewhat curious how many conservatives are conflicted between their desire to raise a fuss in service of the long-standing goal of promoting China as the new Evil Empire and the deep, abiding belief that liberal performance artists could do with a little waterboarding.

Of particular interest in this regard is McCain's latest reversal: now that he's secured the GOP nomination he's less enthusiastic about ordaining torture than he was earlier this year and, quite unusually for a key player, he isn't lying or resorting to euphemism to describe what we've been doing:

During an assessment of the Bush presidency on "Fox News Sunday," McCain discussed the administration's use over "waterboarding," a technique that has been used to interrogate terrorist detainees. "Waterboarding to me is torture, okay? And waterboarding was advocated by the administration, and according to a published report, was used," McCain said. "I obviously don't want to torture any prisoners."

2008-9-1 16:40

Looks like MI5 is reluctantly giving up on profiling:

MI5 has concluded that there is no easy way to identify those who become involved in terrorism in Britain, according to a classified internal research document on radicalisation seen by the Guardian. The sophisticated analysis, based on hundreds of case studies by the security service, says there is no single pathway to violent extremism. It concludes that it is not possible to draw up a typical profile of the "British terrorist" as most are "demographically unremarkable" and simply reflect the communities in which they live. The "restricted" MI5 report takes apart many of the common stereotypes about those involved in British terrorism. They are mostly British nationals, not illegal immigrants and, far from being Islamist fundamentalists, most are religious novices. Nor, the analysis says, are they "mad and bad". Those over 30 are just as likely to have a wife and children as to be loners with no ties, the research shows.

One key point which doesn't get enough attention is that why profiles don't work they also cause problems by making easier for people who don't fit the profile to avoid the attention of the police who are over-worked investigating profile victims

2008-7-21 18:32

Awhile back I posted a kicker replacement which was also a PyObjC promo. Since then, kicker-replacement has advanced and gained the ability to handle filesystem events and workspace notifications and is now available on Google Code:

http://pymacadmin.googlecode.com

Kok-Yong Tan was kind enough to suggest a new name: crankd. I've updated the repository and even engaged in (gasp) random acts of documentation by adding a wiki page describing how to use crankd for policy-based proxy settings, in this case by enabling an OpenSSH SOCKS proxy when on a remote network as demoed at WWDC.

Older Entries