dO-BoY

console.log(‘Blues’)

In web development, the first 90% of development time is devoted to all the other browsers, and another 90% of the time is devoted to Internet Explorer. Thanks to Firebug in Firefox and Safari’s excellent developer tools, I’ve given up hideous “alert-debugging” in favor of logging informative messages to the console with console.log('a message'). You can even get a little fancy with printf-style formatted output, e.g., console.log("var i: %s",i).

But then development moves to IE, and I get bitten by the forgotten console.log() left in the code somewhere. Presumably, IE9 will have some kind of console, but we’ll be testing back to IE6 for years, so this is a problem that’s not going away.

I’ve seen a lot of “solutions” that create new jQuery functions–and we’re all using jQuery now anyway, right?–like $.log() and then you’re supposed to stop using console.log() in favor of this new function.

But I’m a stubborn old man, and my arthritic old fingers won’t soon forget the keystrokes, so I find this approach a little unworkable. What I really want is to leave console.log() alone if it’s available, and if not, drop a DIV into the page to send output to. So I used the code from the above link as a point of departure, and worked it into something that does what I want:


jQuery.extend({
log: function(msg) {
$("body").append("<div style=\"width:600px;color:#fff;background-color:#666;\">" + msg + "</div>");
return true;
}
});

// create object and define method if not present
if ( !window.console )
{
window.console = new Object;
window.console.log = $.log;
}

The strategy is, define a jQuery function $.log() (or jQuery.log() if you prefer) and then assign it to console.log() if it doesn’t already exist. The last block is the key: create an object window.console and assign $.log to a method in the object.

Now I can continue leaving console.log() in my code to debug. If window.console exists, $.log() is defined but never used; if window.console does not exist, it is created and passed $.log and uses that.

Now I just have to remember to include a file debug.js which contains this mess, but to me that’s easier than learning a whole new function which also requires the extra code to define it anyway.

bc Extensions

More often than not, if I have to do any calculations from my laptop, I eschew the very fine GUI application PCalc in favor of bc on the command line. I also like to use the extended version, bc -l to get decimal places in my result.

Like most bc enthusiasts, I have this aliased in my .bash_profile file like so:

alias bc='bc -l'

But if you’re a bc nerd, this probably isn’t enough; you also want to pre-define functions and have a bunch of scientific constants, too. There’s a pretty standard extensions.bc file out there, and you can get it from the straight from the open-source project: first a buncha functions, then the scientific constants.

The usual way is to include these when you run bc, so your alias in .bash_profile becomes

alias bc='bc -l /PATH_TO/extensions.bc /PATH_TO/scientific_constants.bc'

After a while, I know I’ll forget where my bc extensions files are, so I include a message in my alias:

echo "Using bc -l with extensions in /PATH_TO/"

So my alias is

alias bc='echo "Using bc -l with extensions in /PATH_TO/";bc -l /PATH_TO/extensions.bc /PATH_TO/scientific_constants.bc'

Now every time I run bc, I see

Using bc -l with extensions in /PATH_TO/
bc 1.06
Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.

And that way I can remember why it works just the way I want it to.

Cats: hack,unix

Don’t Drop That Shadow

As a coder, I spend way more time worrying about how something works, or how someone might break it, than on how it looks. I leave it to the designers to fret about that sort of stuff, and just make sure it’s usable and won’t crash when fed crazy input. (What my high-school physics teacher called “monkey-proofing.”)

A recent project is a classic case in point: tons of UI stuff going on, and the flow isn’t completely worked out, so I built a somewhat functional prototype. It’s nowhere near finished, but the parts we’re focused on right now are working. The designer had included some drop-shadows along the edges of these elements, but as they had nothing to do with how they work–they’re sliders that can be “tossed” and animate to a stop–I omitted said drop-shadows.

Guess what the designer’s very first comment was? “The drop-shadows are missing.” Even though we both knew they were completely extraneous to the actual issue of how the animation works, he just couldn’t get past it. It was like an air horn blasting over a gentle harpsichord melody off in the distance; in your ear, it’s all air horn.

Tonight, as I continued working on the prototype, I figured I’d spare him the visual agony and put the drop-shadows in. It took about five minutes.

So I figure I saved five minutes last night only to spend five minutes tonight, plus several minutes lost today discussing the damn thing. In overall time, I lose, but I lost even more: it also took time to get the designer to focus on what really matters about the UI, which remains a not insignificant issue. But for all I know, his brain is clouded even now by drop-shadow absences.

I guess the moral is, for the designer’s sake, and your own,  make even the prototype look as much like his design as you can. Evidently it’s a corner you just can’t cut.

Catching Up to Snow Leopard

Even part-time freeware developers look forward to new OSX releases, but our software doesn’t always make the transition very smoothly. My screensaver “The Tube” is a bit of a CPU and RAM hog, so when OSX 10.6 broke it, I kind of bid it adieu and got on with other projects. After some prodding, though, I considered that faster CPUs and plentiful RAM nowadays mean this five-year-old resource hog might have new life yet.

Tube Map screensaver previewBut it wasn’t as simple as just opening the old Xcode project and clicking “Build”. This is probably because the old build designations “Development” and “Deployment” don’t really have a place in Xcode these days. (Now it’s simply “Debug” and “Release”.) Curiosity led me to create a brand new project and then add the resources and classes from my old project, then simply click “Build”. And it worked…sort of.

I also had  to adapt the default class files (declaration and implementation) to match the old versions. It might have worked to add a modern build target to the old project, but in a way it was easier to do the rote work of going method by method pasting code into place. Once the resources were included, we were off to the races.

Now I’m reminded of the pleasantly hypnotic movement of the London Underground map and its gently flickering train. If you have OSX 10.6 (Snow Leopard) you can check it out here.

One Two Three

At a high level, all software development–perhaps all invention–breaks down into three steps:

  1. Build it the way you thought it should work
  2. Do it from scratch the way you should have done it to begin with, as you learned during the previous step
  3. Optimize step 2 from scratch so you can actually ship it.

And of course, loop on steps 2 and 3 from then on.

Sometimes you’ve done step 1 so often, you hit the ground running with step 2, but not if it’s a new technology. And I can’t say I’ve always gone through all three steps for every project, but I’ve always wished I could.

Tip for 1Password-Using iPhone Devs

As if there aren’t enough other details to worry about, developing for iPhone has been doubly difficult for me because my provisioning certificate kept getting lost by Xcode. Exasperated, I’d delete/revoke/regenerate/reinstall, and it would work. Problem solved.

For a while. Then it would break again.

Even this Apple Developer Q&A article doesn’t mention it, but my friend Todd did: your login keychain must be the default in the Keychain Access utility’s list of keychains. And just now, when my provisioning failed yet again, I checked Keychain Access to discover that 1Password’s keychain is the default.

This is evidently a known issue, even to the application developers. The linked article mentions a new keychain format that solves the problem.

Also, it looks like new users won’t have the same trouble now as they’ll be using the new Agile Keychain format, in a file stored at ~/Library/Application Support/1Password/1Password.agilekeychain. Existing users–especially iPhone developers–should switch to this format; see the “Keychain” tab of 1Password’s preferences window.

For a lot of applications, this kind of crap would earn a one-way ticket to the Trash. But I really like 1Password, and have probably recommended it to people more than any other. I’m glad I’ve found a way for 1Password to peacefully co-exist with Xcode and iPhone provisioning.

Cats: osx,Xcode

Managing File Downloads

My friends’ band Surrender is heading off on a European tour. (Yes, I’m jealous.) In addition to their other merchandise, they wanted to be able to include MP3 downloads with their vinyl records, or even just sell the downloads directly. This is a service United Record Pressing offers but it’s a little, ah, invasive, and not available a la carte, as it were, if they don’t also press your record.

My band played a show with The Measure [SA] this year, and their record came with a download option as well, and it’s pretty DIY. But Surrender wanted something DIYer, with more control over things. I had been intrigued by the VinylDownloads.com style, and figured it wouldn’t be too hard to build something similar, at least for one band. So I tried.

First is the db: one table with a list of unique download keys and how many times each was used:

+----------+-------------+------+-----+-------------------+
| Field    | Type        | Null | Key | Default           |
+----------+-------------+------+-----+-------------------+
| id       | int(11)     | NO   | PRI | NULL              |
| key      | varchar(16) | NO   |     | 0                 |
| used     | tinyint(1)  | NO   |     | 0                 |
| mod_date | timestamp   | NO   |     | CURRENT_TIMESTAMP |
+----------+-------------+------+-----+-------------------+

I generated the keys–16 alphanumerics–and the MySQL commands for inserting each one into the table in a PHP script. Here are the lines of interest:

$key = substr(md5(rand()),0,16);
$query = "INSERT INTO file_keys (`key`,`used`,`add_date`) VALUES('$key','0',NOW());";
mysql_query($query,$DB_CONNECTION);

I didn’t explicitly check for uniqueness of the key values. What can I say? I have faith in MD5, even if collisions have been found.

The last part is getting the file to download without actually providing direct access to it. PHP makes this pretty easy, although there are some gotchas related to IE and Safari:

// Stuff only IE seems to need
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false); 

// We'll be outputting a ZIP
header("Content-type: application/zip");
// It will be called surrender.zip
// (double-quote file name in header or Safari will be sad)
header('Content-Disposition: attachment; filename="surrender.zip"');

header("Content-Transfer-Encoding: binary");
header("Content-Length: " . filesize($DL_FILE_PATH) ); 

// The ZIP source is in $DL_FILE_PATH
readfile($DL_FILE_PATH);
The problem is the step between checking the DB and allowing/disallowing the download. How do you authorize the download page conditionally, without passing along information easily intercepted by nefarious types? A session variable seemed reasonable–theoretically hackable, but kudos to anyone who does it.

So after checking for whether the download key can be used–each one can be used up to three times–a session variable is set:

$_SESSION['downloadfile'] = 'secret';

Another issue is how to message the user about what’s happening. If a code is valid, we redirect to the “downloading now” page, or else the user sees the “sorry” page. To actuate the download, I went back to some 20th century web technology: a META tag to “refresh” the page to the page that does the download:

<meta http-equiv="refresh" content="2;url=getfile.php">

This sends the user to getfile.php, which doesn’t actually display in the browser but just starts a file download (solving the problem of triggering both the download and a message to the user to let him know what’s going on). The download happens and everybody’s happy.

The last step is to unset the session variable:

$_SESSION['downloadfile'] = '';

I’m working on more generic code to share, or maybe this would be a good SourceForge project?

Cats: experiment

iPhone Post

I guess you really can post to a blog from an iPhone. I’m not sure how valuable this is, though. Yet?

Cats: experiment
Tags:

Form Field Backgrounds

At the Day Job I was called upon to make form fields with rounded corners. There’s a lot of approaches out there, but most of them are a bit too complex for my liking. Generally, it’s some variation on the old-tymey technique of putting something in the center of a 3×3 table, but with DIVs or what-have-you.

Forget that, I want something simple, just a bit of CSS I can tack onto text input objects. The simple approach seemed to work:

input{
   width: 90px;
   height: 26px;
   background: url(/images/text-field.png)
     no-repeat;
}

…at first. It turns out Internet Explorer anchors the background image to the text field, and if you type beyond the border, the image scrolls off to the left as you type.

Well, that’s okay, you can just anchor the background with “background-attachment: fixed;” like so:

input{
   width: 90px;
   height: 26px;
   background: url(/images/text-field.png)
     fixed no-repeat;
}

Ah, but there’s a slight problem now: Firefox and Safari respond to this new attribute by not showing the background image at all. I have to say, and this could be a first for me, my opinion is that IE gets this one right. Scrolling makes sense, and a “fixed” background is the right solution.

But such is the life of a web developer, making things work the way they are, not the way they ought to be. So, alas, I left the “fixed” attribute out of the CSS–works for Safari and Firefox–and used jQuery’s “document ready” function for IE:

$(document).ready(function(){
if ( $.browser.msie )
    $('input').css('background-attachment','fixed');
});

It’s a little weak, I know, but sometimes quick and dirty is the best solution. Besides, without JavaScript, the rest of the site will fail much worse than this form field.

Not Spam

My friend is embarking on a tour to promote his new book. He’ll be on the road so email is going to be the best way to announce what’s going on to interested parties. However, sending email from his Yahoo! account to multiple recipients proved problematic: emails addressed To: a complete list of recipients raised some ire from people not wanting their emails revealed to other recipients.

The next attempt went a little better: he addressed it to himself and BCC’ed actual recipients. But so do spammers, and a lot of people never even saw this one. The alternative is to send the email over and over to each individual, which is even more work than the tedium of adding all email addresses to a BCC field with Yahoo!’s address book.

Obviously, this is something where a computer should be doing the heavy lifting, but the options out there are either not free, or contain intrusive ads. (Which, come to think of it, Yahoo! Mail also does.) Given the nature of the book, this is undesirable.

I wanted to help, so I threw together a little three-page web app to store email addresses and names, and loop over each item to send an individual email to every person. We also want to do the right thing by sending a MIME multi-part style email, so email clients do the right thing based on each user’s preferences. PHP’s mail() function, with some custom headers, to the rescue.

These lines set up the headers:

$to = "\"$rname\" <$remail>"; # recipient
$from = "\"$sname\" <$semail>"; # sender
$headers = 'From: ' . $from . "\n";
$headers .= 'To: ' . $to . "\n";
$headers .= 'Return-Path: ' . $from . "\n";
$headers .= 'MIME-Version: 1.0' ."\n";
$headers .= 'Content-Type: multipart/alternative; boundary="'
. $boundary . '"' . "\n\n";
$headers .= $body_simple . "\n";
$headers .= '--' . $boundary . "\n";
$headers .= 'Content-Type: text/plain; charset=ISO-8859-1' ."\n";
$headers .= 'Content-Transfer-Encoding: 8bit'. "\n\n";
$headers .= $body_plain . "\n";
$headers .= '--' . $boundary . "\n";
$headers .= 'Content-Type: text/HTML; charset=ISO-8859-1' ."\n";
$headers .= 'Content-Transfer-Encoding: 8bit'. "\n\n";
$headers .= $body_html . "\n";
$headers .= '--' . $boundary . "--\n";


Each section of a multi-part email is set off by a unique boundary string, defined in this case as follows:

$boundary = md5(uniqid(time()));

 

Now “abuse” mail() as follows:

mail('', $subject,'', $headers);
Even though ‘to’ and ‘content’ params are empty, the headers contain everything needed to properly deliver each message. So far, it works.
Lots of the code above is based on some sample code from php.net
Cats: experiment
Tags: , , ,