This morning I came across an example of a fake Windows error message advertisement. The web being the shady place it is, I wouldn't have blinked, except that (a) the advertisement was on the site of a respected newspaper, The Sydney Morning Herald and (b) it was advertising a Microsoft web site. Microsoft. Really.
Not only does the advertisement use Windows 2000-like icon sand colours, it also appears approximately in the center of the screen, where you would expect to see a genuine pop up box. (Screenshot, 102k gif, colours aren't great).
The advertisement claims that my computer has an unfixable virus, and - by hijacking Windows UI conventions, begs me to click the OK button. Of course, the advertisement has no way of knowing whether my computer has a virus, and the OK button is not what it appears to be.
It is the moral equivalent of sending someone a letter notifying them, "your bank has foreclosed your mortgage, ring this number to find out more."
I used to think Microsoft treated customers and potential customers with some amount of respect, but this shows that they do not. Using lies in advertising is not OK. Microsoft has dived sharply in my estimation.
So I dashed off a bleary-eyed, half-cogent note (it was early) on the Herald website's feedback form. Lee Stephens - Director of News and Finance, F2 Network - wrote back within a few hours to say that he did consider it a problem, that and would see if he could track it down.
When I hear more from the Herald, I'll let you all know. Meanwhile, the advertisement appears to have been pulled from the rotation.
I was in the Clarence St motor registry on Tuesday, and I couldn’t help but notice that each of the sixteen service counters sported a shiny new iMac. Naturally, I asked about them.
The staff had had them for less than a week. They have Mac mice, but not Mac keyboards. Instead, they use old Olivetti keyboards complete with integrated card stripe readers and ink stains. It looked quite peculiar.
The friendly lady that served me told me that the Macs were running all of their old applications (at least one of which was just a terminal emulator) as well as some new applications that she seemed quite pleased with. They had also been promised some more new applications in time. She was pleased by the change, but obviously a little perplexed as to the reasons for it.
I was wondering… has anybody else seen Macs where they expected to see beige boxen?
I have an hour long train commute to the office, and I work on my own projects in that time. At least one person expressed an interest in hearing my experiences working that way.
I’m pleased to report that that an hour is plenty of time to do useful work. I keep a TODO file to keep track of what I am working on, and what there is left to do. I generally knock over two or three items an hour.
Because I’m working on my project for just two hours a day, I’ve had plenty of time away from the keyboard to think through each problem before I start coding. This makes the time especially productive.
In the afternoon, when trains are more crowded, I find it worthwhile to go to Central and catch an inter-city train. In the mornings, if I’m especially lucky, I get the seat-and-a-half up the back of the top deck a C-class train. 1 A big trick is to get a seat away from the corridor so that my laptop screen is at less risk from the corner of someone else’s briefcase. If I can’t get the right seat, I don’t open my laptop.
Another point to remember is that you can’t mumble curses at your computer while on the train. In the office, people can’t hear over the cubicle walls, but on the train there are six people sitting within a one metre radius.
While sunlight at just the wrong angle can be a problem, the HP NX7010’s screen is readable in most conditions. In terms of size, the HP is about as large a PC as I could regularly use on the train. Depending on how tall you are, the screen’s useful viewing angle and what’s in front of your seat, a big latop can’t be openned fully while holding the machine at a comfortable typing distance. I have seen somebody really struggle with a Dell 8600, which is only 21mm deeper than my HP.
The main drawback to working on the train is getting all excited about my personal project each morning, then having to change gear when I reach the office. In the afternoon, I get it in reverse – my mind is buzzing with real, paid work and it takes a few minutes to “find my groove” again.
1 C-class are the newer kind of silver carriages. Serious commuters study the plans. :)
I've been investigating Java Message Service (JMS) over the last few days. I had been under the impression that it was an arcane, difficult to use API, but and pleasantly surprised when I actually started to use it. Here is some code to illustrate how easy it is.
A JMS program needs two objects before it begins: a QueueConnectionFactory and a Queue. Typically the program would look these up via JNDI, but the JMS products I've looked at (Sun Java System Message Queue1 and Websphere MQ) also allow them to be created 'by hand.'
The program asks the ConnectionFactory for a Connection, and then asks the connection for a session:
import javax.jms.*;
public class MQTest {
public static final String QUEUE_NAME = "AQueueName";
private QueueConnectionFactory qcFactory;
private QueueConnection qConnection;
private QueueSession qSession;
private Queue queue;
public void init() throws JMSException {
qcFactory = new
com.sun.messaging.QueueConnectionFactory();
qConnection = qcFactory.createQueueConnection();
qSession = qConnection.createQueueSession(false,
Session.AUTO_ACKNOWLEDGE);
queue = new com.sun.messaging.Queue(QUEUE_NAME);
}
}
(The com.sun.messaging class is an implementation class from Sun's Java System Message Queue product.2)
A sending program also needs a sender object and a message object, both of which it obtains from the session. When it is time to perform the send, the program loads up the message object with data, and sends it:
public void send(String msg) throws JMSException {
init();
QueueSender qSender = qSession.createSender(queue);
TextMessage textMsg = qSession.createTextMessage();
textMsg.setText(msg);
System.out.println("Sending Message: [" + msg + "]");
qSender.send(textMsg);
close();
}
In a real program, the QueueSender would be created once and reused.
To receive a message, a program uses a Receiver object, which it gets from the session. The receive() method waits for a message to be delivered and returns it:
public void receive() throws JMSException {
init();
QueueReceiver qReceiver = qSession.createReceiver(queue);
qConnection.start();
TextMessage msg = (TextMessage) qReceiver.receive();
System.out.println("Contents:" + msg.getText());
close();
}
Before receiving a message, the connection also needs to be informed that messages can be sent through it, by calling the start() method.
This is how to close connections and release any external resources. Be careful about this - some brands of messaging queuing middleware won't automagically clean up after a closed (or crashed) application.
public void close() throws JMSException {
if (qSession != null) {
qSession.close();
}
if (qConnection != null) {
qConnection.close();
}
}
And for completeness, here is a driver method for the above class:
public static void main(String args[]) {
try {
if ("send".equals(args[0]))
(new MQTest()).send(args[1]);
else if ("receive".equals(args[0]))
(new MQTest()).receive();
} catch (JMSException e) {
e.printStackTrace();
}
}
As you can see, this is not a lot of code to send a simple messages point to point. Even with some error handling code and a JNDI look up, it is still less programming effort than building a one-way, asynchronous message sending component out of TCP sockets or servlets.
1 A big thanks to Craig Day of the ajug mailing list for pointing me to Sun's product. The code here is a very much mangled version of Sun's tutorial code.
2 If you want to avoid any JMS product dependencies, then you need to use JNDI, though that creates other product dependencies.
Of all the email spam I get, the flattering ones are the most amusing. This one had me snickering for half an hour:
I visited your web site earlier today
(www.cardboard.nu/priv_stats/usage_200312.html) and I just wanted to congratulate you on a well presented, and informative web site.
It’s not often that I come across a web site that offers a wealth of quality and hard to find information about Software. I particularly liked your web design.
In order that you might appreciate the full depth and breadth of the insincerity conveyed by those words, I invite you to visit the link to which my spammer refers www.cardboard.nu/priv_stats/usage_200312.html. (Even if you think you can guess what’s there by the URL, click it anyway, because it’s not what you think.)
I’m just so glad that my spammer found that page “well presented, and informative.” I put so much effort into it.
Pages showing images of the Venus Transit today:
More pointers here: http://www.users.bigpond.net.au/heyes/transit.html.
Simon points to computer-driven woe at the Royal Bank of Canada. They have 155 people working on the problem.
In the olden days, I used to work at a bank. They ran their entire transaction processing load on a brand new IBM 4341. One pension day, something really bad happened, and in the space of two minutes, the computer room filled with people.
They arranged themselves thusly:
I know all this because I was visiting some of the other operations staff at the time, and was left to watch the scene unfold through the plate glass windows. Pretty soon, the area I was in filled up too.
I looked around, decided that no good could come from watching a disaster unfold, and made myself scarce.
I watched the Olympic flame downtown at lunch-time. There was a crowd of several tens of thousands. Streets were closed. Barricades were erected. News helicopters hovered overhead. Speeches commemorating the first “truly international” Olympic flame were made.
It would have been exciting, but the sponsorship overpowered the event.
Half the crowd seemed to be holding up blue “Samsung” flags, passed out by cute little PR girlies1 in blue tights. The fact that the torch bearers’ uniforms, the cavalcade of support vehicles and sundry Olympic decorations were almost exactly the same shade of Samsung blue would have made that company’s marketing people very happy indeed.
I couldn’t help but laugh out loud as a Samsung blue truck carrying ten Samsung blue and Olympic logoed people passed by. The truck’s P.A. system blared forth congratulations to the crowd for showing the world “the true Olympic vibe.” Everybody agreed and waved their Samsung flags.
1 Yes, that is sexist term, but that is exactly how they were dressed and made up.
Property descriptors are a powerful tool for building easy to understand APIs. I use read-only properties liberally in my APIs, but it took a few months to arrive at an implementation idiom that I was happy with.
In Kangapy,1 each article is associated with a template, and the template may not change after the article object is constructed. It makes sense for the Article class to have a read-only 'template' attribute.
Based on what I had read of property descriptors, this was my first version of the descriptor code:
def __getTemplate(self):
return self.__template
template = property(__getTemplate, None, None,
"This article's defining Template")
While it provides a neat API for getting the article's template, the implementation is long winded and difficult to read. Compare it with the implementation of the equivalent getter method:
def getTemplate(self):
""" This article's defining Template
"""
return self.__template
Casting around for a better way to write property descriptors, I hit on a methodless idiom that I am still using:
template = property(lambda self: self.__template)
Simple derived value properties also work well:
templateName = property(lambda self: self.__template.name)
This methodless form of a property is simpler to write and read than the original form. On the down side, it doesn't have a doc string,2 and it still isn't as clear as a getter method.
1 Kangapy is my blogging software. It is currently undergoing its third complete rewrite. After this one, I'll release the source, I promise.
2 I found that burying the doc string inside the property function meant that I wasn't using it while I was editing the code. Since I'm not using pydoc, the doc string was useless.
May the fleas of a thousand camels swim to your rescue when you next fall from an ocean cruise-liner.
I have been putting together a static HTML site that has some long pages. It was becoming difficult to find content on some of these pages so I added an automagically generated table of contents.
The table of contents is generated from all H1, H2 and H3 headings on the page, except if there is only one heading, in which case the whole table of contents is removed.
My script is based on this article from quirksmode.org.
Here is the script:
// pageToc.js
//
// Ensure all H1, H2 and H3 headings are added to the page table of contents
//
window.onload = createTOC;
function createTOC()
{
// find the nodes to be added to the Page TOC
var tocTargets = new Array()
nodes = document.getElementById('contentArea').childNodes
for (var i = 0; i < nodes.length; i++) {
nn = nodes[i].nodeName
if (nn == "H1" || nn == "H2" || nn == "H3") {
tocTargets.push(nodes[i])
}
}
tocDiv = document.getElementById('pageToc')
// Remove toc if none or one heading
if (tocTargets.length <= 1) {
tocDiv.parentNode.removeChild(tocDiv)
return;
}
// Add the toc contents
tocDiv = document.getElementById('pageToc')
tocDiv.innerHTML= "<h2>Page Contents </h2>"
tocList = document.createElement('ul')
tocList.className = "pageToc"
tocDiv.appendChild(tocList)
// Insert elements into our table of contents
for (var i = 0; i < tocTargets.length; i++) {
tocTarget = tocTargets[i]
if (tocTarget.id == '') {
tocTarget.id = 'pageToc' + i
}
newItem = document.createElement('li')
newItem.className = "pageToc" + tocTarget.nodeName
newLink = document.createElement('a')
newLink.href = '#' + tocTarget.id
newLink.innerHTML = tocTarget.innerHTML
newItem.appendChild(newLink)
tocList.appendChild(newItem)
}
}
To use it, you need to add a reference to the script in each page header
<script src="/idsproj/theme/pageToc.js"></script>
This DIV element also needs to be added near the top of the body:
<div id="pageToc"> </div>
The script has been tested on Mozilla, Firefox and IE6. Feel free to use as you will, though I would appreciate a comment here if you do.