Technorati has become infamous of late for have severe performance problems, especially their feature that allows weblog authors to see what links back to them, which would often fail to complete. Something’s happened today, though: Technorati is blazing along like never before. Let’s hope it lasts!
The Danish Ministry of Science, Technology and Innovation has a website called Work in Denmark created, they say, because:
Denmark needs foreign knowledge workers to contribute new expertise and thereby strengthen trade and industry, innovation and research in Denmark.
What’s nice about the site is that it isn’t the usual “we’re a world-class destination with leading-edge technology infrastructure that can be leveraged to maximize.” At least not entirely. There’s actually useful information there, like how to register for Kindergarten, how to get divorced and how to get your teeth fixed.
Here on Prince Edward Island, the excellent InfoPEI directory has much the same information; I like the Danish site, however, for its concise text, exclusive focus on foreign workers (like me), and clear organization.
It says here that The Amazing Race: The Family Edition will premiere on September 27, 2005:
This child-friendly season will see a shorter race route, as we see more legs set in the United States of America, with a strong focus on historically significant cities and locations.
The CBS Amazing Race 8 page confirms this date, and has bios for ten teams of four.
Episode 14 of commandN, Amber MacArthur’s tech vidcast has just been posted. This is the episode where Amber interviews me about Plazes.
Intuit offers a free 30-day trial of their QuickBooks for Mac. To download this, you “purchase” the product, for $0, from their web store. At which point you get the following “error” message:

Read the whole thing.
My friend Stephen Regoczei is stoking the fires of his new weblog. I never knew that Stephen was so great at pith:
Terrorists are relatively harmless. They do very little damage when compared to other hazzards such as food poisoning, malaria, or car accidents. Looking at the damage that the inaction of the US Government caused in New Orleans after Katrina, I can not see why why we bother with, or even notice, so-called “terrorists” at all.
Oliver and I have come to the office this Sunday morning to get out of Catherine’s hair while she puts down a couple of dozen cobs of corn for the winter. We stopped at Timothy’s on our way in for a bagel with swiss and tomato, a cup of tea and a glass of orange juice. And as I type Oliver is out front in the lounge playing with the mysterious Lego that appeared there this spring. And I am blogging, at least for this minute.
And suddenly I’m flooded with memories of CCIW, where my Dad worked for more than 30 years, and visits there with him on Sundays. I remember signing in with the Commissionaire at the front desk, the “sciencey” smell of the place, getting to draw with pencils and pens on reams of old line printer paper (with lines and lines of discarded sedimentological data on the other side), and taking a walk down to the hydraulics lab to see the giant water tanks.
And, if the moon was in the right place, getting to stop at Tim Horton Donuts on the way home for a Dutchie.
I decided this afternoon that it was time to try my hand at creating an OS X Dashboard widget to show me live sales information from one of my client’s online stores. To my surprise, I found that this was a lot easier than I thought it was going to be: everyone should be making Dashboard widgets! So here’s how I did it.
Getting the Sales Information
First, I needed a way of getting sales and revenue information for the current day. My client’s online store is a custom PHP application, so it was easy to extract this from a database. I created a little PHP script to do this and called it dashboard.php. Here’s the important part of the PHP code:
<?php
$today = strftime("%Y-%m-%d");
if ($return == "sales") {
$query = "SELECT count(*) as sales from onlinesales where
saledate between '$today 00:00:00' and '$today 23:59:59'";
$result = MYSQL_QUERY($query);
$currentrecord = 0;
$sales = trim(MYSQL_RESULT($result,$currentrecord,"sales"));
$retval = sprintf("%3.0f",$sales);
}
else if ($return == "revenue") {
$query = "SELECT sum(amount) as revenue from onlinesales where
saledate between '$today 00:00:00' and '$today 23:59:59'";
$result = MYSQL_QUERY($query);
$currentrecord = 0;
$revenue = trim(MYSQL_RESULT($result,$currentrecord,"howmuch"));
$retval = "\$" . sprintf("%6.2f",$revenue);
}
$retval = str_replace(" "," ",$retval);
print $retval;
This script returns the number of sales if it’s called like this:
http://www.example.com/dashboard.php?return=sales
Similarly, it returns total revenue if it’s called like this:
http://www.example.com/dashboard.php?return=revenue
What gets returned is a pre-formatted number, ready for magical insertion into my Dashboard widget.
Designing the Widget
Apple provides excellent documentation on how to create widgets, including a Hello World! application. If you have the OS X 10.4 Developer Tools installed, you’ll also find some handy sample code at:
/Developer/Examples/Dashboard/Sample Code/
To start out, I copied the contents of the “Blank Widget” example widget into a new folder called Online Sales:
mkdir "Online Sales"
cd "Online Sales"
cp "/Developer/Examples/Dashboard/Sample Code/Blank Widget/"* .
sudo chown peter:peter *
The last step is required because the permissions on the sample code don’t allow it to be modified; changing ownership to my user and group (peter) let me make changes.
Next, I renamed the sample files for my new widget:
mv BlankWidget.css OnlineSales.css
mv BlankWidget.html OnlineSales.html
mv BlankWidget.js OnlineSales.js
Then I edited the HTML file OnlineSales.html — it’s where the widget gets “drawn” — so that it looks like this:
<html>
<head>
<style type="text/css">
@import "OnlineSales.css";
</style>
<script type='text/javascript' src='OnlineSales.js' charset='utf-8'/>
</head>
<body onload='setup();'>
<img src="Default.png">
<span id="sales" class="salesText"></span>
<span id="revenue" class="revenueText"></span>
</body>
</html>
I now had a simple HTML file with a hole for the sales figure (the span called sales) and a hole for the revenue figure (the span called revenue). The CSS file called OnlineSales.css is used to style the HTML, and I modified it so that it looks like this:
body {
margin: 0;
}
.salesText {
font: 40px "verdana";
font-weight: bold;
color: black;
position: absolute;
top: 7px;
left: 25px;
}
.revenueText {
font: 18px "verdana";
font-weight: normal;
color: black;
position: absolute;
top: 53px;
left: 29px;
}
I dropped some “dummy” values into the HTML file and then loaded it up in Safari to see what it would look like; then I tweaked the CSS until it looked like I wanted:
Now I had my widget designed. All that remained was a way of getting the sales and revenue data from the webserver into the widget.
Getting the Web Data
Although Apple has a number of ways to get external data into a widget, the simplest one, and the one that required no learning curve for me, was to use the System Method, a Javascript function available automatically to widgets that allows OS X command line scripts to be run and their results returned to JavaScript.
By default, OS X includes a handy utility called cURL that can act as a sort of “command line browser,” connecting to web servers and retrieving what they return. To run cURL from the command line to grab my sales data is as simple as:
/usr/bin/curl http://www.example.com/dashboard.php?return=sales
This script simply returns something like:
14
…the current number of sales, ready for popping into the hole I’ve created in the widget for this piece of information. The glue that binds all this together lives in the JavaScript OnlineSales.js, that looks like this:
function setup()
{
UpdateData();
return 0;
}
if (window.widget)
{
widget.onshow = UpdateData;
}
function UpdateData () {
sales = widget.system("/usr/bin/curl
http://www.example.com/dashboard.php?return=sales",
null).outputString;
revenue = widget.system("/usr/bin/curl
http://www.example.com/dashboard.php?return=revenue",
null).outputString;
document.getElementById("sales").innerHTML = sales;
document.getElementById("revenue").innerHTML = revenue;
}
The JavaScript function UpdateData uses cURL, through the widget.system method, to grab the sales and revenue data from the server, and then updates the widget’s sales and revenue spans with what it retrieved. This is automatically updated whenever Dashboard is activated by gluing the method to the widget.onshow property.
Modifying the Property List
The final step in creating the widget is to modify the Info.plist file, that contains some important settings information. If you double-click on this file in OS X, the Property List Editor will load the file. Here are the settings I set for my widget:
In addition to customizing the defaults already in Info.plist, I added the AllowSystem setting, that, as explained here, you must specify if “your widget requires access to command-line utilities using the widget script object.” I saved the modified Info.plist, and then I was ready to test my widget out.
Testing the Widget
After all of the above, I was left with six files in my Online Sales folder:
- Default.png
- Icon.png
- Info.plist
- OnlineSales.css
- OnlineSales.html
- OnlineSales.js
To turn these into a widget is as simple as renaming the Online Sales folder to Online Sales.wdgt. This automagically bundles the files together into a “widget package” that will look like this:
To ease the debugging process, the best way to proceed from here, I found, is to make a duplicate of the widget (select it in the Finder and press “Command+D”) and then double click on the duplicate. If all goes according the plan (and, amazingly enough, it actually did for me), you’ll be prompted to choose whether to install the widget or not, and if you say “Yes,” then the widget should appear on the Dashboard, with live sales information:
A couple things you might want to note:
- It’s a good idea to thoroughly test each step of the process, especially the server-side script, before assembling and testing the widget itself; although there are debugging assists built in to Dashboard, it’s much easier to debug earlier, especially the widget.system call.
- In my real world implementation, my sales data talks to a secure webserver using SSL; to encode username and password data into a cURL call is as easy as modifying the JavaScript to use the form /usr/bin/curl -u username:password.
- I didn’t do any customizing of the icon or the default “Blank Widget” look and feel; obviously if I was going to make a widget for distribution, I would do that.
Following the steps I went through, it should be easy to make a Dashboard widget to display almost any sort of “up to the minute” kind of data. If you go ahead and do this, please post a comment with your experiences.
From today’s Jane Siberry email newsletter:
I just put Calling All Angels on my website for free. People have been contacting me recently wondering how the song could be sent out in a wider way in these difficult times. One person wanted to burn copies for relief workers. I said yes. Then I thought that feels so right. And better yet, if i also make it available as a free website download the gesture would be more Earth-loving with no plastic created. Then I thought, heck, why don’t i just make everything free (that I have rights to). Something feels forced about withholding (music) until one gets something (money). People could pay what they want or not pay at all. That would be more authentic, pure. And probably bring more positivity to all. I think the music would be happier, too.
Grab the MP3. It’s a good song.
Okay, so I admit it: I’m aurally crossing the picket lines for an hour or so every morning and using Shelagh Rogers to wake me up (I’ve been sleeping later than usual, and her “involuntary self-scabbing” archival presence, starting at 9:00 a.m., syncs with my slovenly lifestyle).
I just can’t face the notion of waking up to Great Lite Rock Hits.
And you know what? The CBC is a much more pleasant listening experience without all the self-promotion and “lifestyle assistance” accessory crap that’s sprung up over the past 4 or 5 years.
There’s no Promo Girl telling me that I absolutely must not miss the great episode of Quirks and Quarks that’s coming right up. Gone to is the bottom of the hour “90 second news break,” designed primarily, I’m told, to feed the need for traffic information in urban centres and left here in the hinterlands to inform us of the WI pie bake-off that’s coming up on the weekend. The expensive theme music to “Sounds Like Canada” is gone — it just starts up with Shelagh.
In short, it is the CBC unadorned. And I like it.
There’s some significant irony here: I’ve only come to to truly appreciate how good Shelagh Rogers is when she’s not actually there. But I think what I’ve really discovered is that if left to their own devices and free from management dictates to “pump up the promos to increase cross-promotional demographic shift balancing,” CBC radio people just making good radio is pretty compelling all on its own.
By the way, if you want to get a 100% unvarnished, no punches pulled locked out view from a well-spoken locked out CBC reporter, listen to this Winnipeg podcast — about 5 minutes in there’s a scathing commentary from Kirk Petrovich.