Scripting an interactive service intermediary

The recent discussion about active intermediaries ( Sam Ruby, Phil Windley) sent me in an unexpected direction. What I meant to do was revisit some earlier writing on web proxies, email proxies, and SOAP routing, and try to draw some conclusions. Instead, I invented another bookmarklet.

Here was the problem. It's nice that I can now look up a book in my local library, but what if it's not in the collection? My library's OPAC (online public access catalog) enables you to ask the library to acquire a book, but the required fill-in form creates an activation threshold that I am rarely motivated to leap over.

The basic LibraryLookup bookmarklet is a kind of intermediary. It coordinates two classes of services -- Amazon/BN/isbn.nu/AllConsuming and your local library's OPAC -- to facilitate a lookup. I couldn't resist trying to create another intermediary that would facilitate a purchase request.

The solution I'll present here is less general than the basic lookup in several ways, but also interesting in several ways. Here are the ways in which it is less general:

Nevertheless, here are the reasons I find the solution interesting.

Intermediating a library purchase request

Here is the bookmarklet you can drag to your link toolbar: Please Acquire

Here is an Amazon page against which to test it: The Eighth Day of Creation: Makers of the Revolution in Biology.

Clicking the bookmarklet's link should bring up a screen like the one shown here. It's OK to click the button. I've neutered the script so it will just pop up a message rather than send the request. To unneuter it, rewrite the form's action= attribute to specify your OPAC's acquisition-request URL.

A few points to note in the code that follows:

All in all, an instructive little exercise. This sort of technique won't replace active intermediaries, including the local kind that work at the level of HTTP or SMTP. Rather, it will complement them. Users need to be able to see, and approve, what intermediaries propose to do on their behalf. I like the idea of an interactive intermediary that prepares a connection between two services, previews it for the user, and then makes the connection.

Update

The script below contains a privacy bomb which, after a few minutes of reflection, I removed from the live version invoked by the bootloader. It's a fascinating scenario, actually:

  1. You don't want Amazon to see your library-card number.

    1. Don't store/send it at all. This, of course, eliminates most of the convenience of the solution.

    2. Store/send an encrypted version.

  2. You do want Amazon to see your library-card number. Does that sound crazy? Maybe not. Reasons I might trust Amazon with that information:

    1. Because it could use it to co-ordinate my library activity with my Amazon activity, and make better-informed Amazon recommendations. In particular, Amazon could emphasize books known not to be available to me in my local library. This would certainly seem to be a fair quid-pro-quo for the use of that handy ISBN in its URI!

    2. Because it could use it to offer me an email-notification service alerting me to overdue library books.

I find (2b) especially intriguing. It's not really in Amazon's interest for me to be aware of what's available in the local library, and it's not really in the library's interest for me to be made promptly aware of fines accumulating there. By yoking them together, I might be able to play the two services off against one another to my benefit -- and to theirs.


The bookmarklet's bootloader

javascript:void((function() {var%20element=document.createElement('script'); element.setAttribute('src', 'http://jonudell.net/udell/gems/acquire.js'); document.body.appendChild(element)})())

The script loaded by the bootloader

var setCookieScript = 'function setCookie(Name1, Value1) { var expires = new Date(); expires.setFullYear(expires.getFullYear()+1); var cookie = Name1 + \'=\' + escape(Value1) + \';domain=amazon.com;path=/;expires=\' +expires.toGMTString(); alert(cookie); document.cookie = cookie; }';

function getCookie(Name)
{
var s = '; '+document.cookie+';';
var i = s.indexOf('; '+Name+'=');
if (i == -1)
{ return ''; }
else
{
i += 3 + Name.length;
var j = s.indexOf(';', i);
return unescape(s.substring(i, j));
}
}

var myLibraryUserID = getCookie('MyLibraryUserID');
var myLibraryUserName = getCookie('MyLibraryUserName');
var m0 = document.getElementsByTagName('META')[0];
var titleAuthor = m0.getAttribute('content');
var re = /(.+),\s*([^,]+)$/;

re.test(titleAuthor);
var title = RegExp.$1;
var author = RegExp.$2;

var win = window.open('','LibraryAcquisitionRequest', 'resizable=1,scrollable=1,width=600,height=400');

win.document.write('<html><head><title>Request acquisition of: ' + titleAuthor + '</title><scr' + 'ipt>' + setCookieScript + '</scr' + 'ipt></head><body>');

win.document.write('<p>Request acquisition of: ' + titleAuthor + '</p>');

win.document.write('<form name="acquire" method="post" action="javascript:alert(\'Demonstration only!\');"><table><tr><td align="right">Author: </td> <td><input name="author" value="' + author + '" size="40" maxlength="255"></td> </tr><tr><td align="right">Title:</td> <td><input name="title" value="' + title + '" size="40" maxlength="255"></td> </tr><tr><td align="right">Where/when published:</td> <td><input name="publish" value="See Amazon: ' + location.href + '" size="60" maxlength="255"></td> </tr><tr><td align="right">Where mentioned:</td> <td><input name="mention" value="Amazon" size="60" maxlength="255"></td> </tr><tr><td align="right">Other info:</td> <td><input name="other" value="Intermediated by the LibraryLookup project" size="40" maxlength="255"></td> <tr><tr><td align="right">Your name:</td> <td><input name="name" value="' + myLibraryUserName + '" size="40" maxlength="255" onChange="javascript:setCookie (\'MyLibraryUserName\',forms[0].name.value);"></td> </tr> <tr><td align="right">14-digit library card #:</td> <td><input name="barcode" type="text" value="' + myLibraryUserID + '" size="40" maxlength="40" /* use with caution! onChange="javascript:setCookie (\'MyLibraryUserID\',forms[0].barcode.value);" */></td> </tr><tr><td align="left" colspan="2"><br><input name="submit" type="submit" value="Ask library to acquire this book"></td> </tr></table></form><p></body></html>');

win.document.close();


Former URL: http://weblog.infoworld.com/udell/2002/12/30.html#a558