29 December 2010

2,000 calculations per second

3-minute TV spot for Remington Rand's Univac (inserted into an episode of What's My Line?, if I'm not mistaken).

Why does the script for every live TV commercial from that era use "You see," as a transition?

24 December 2010

Plastic fantastic

Andy Carol has built an emulator of some elements of the Antikythera Mechanism out of LEGO bricks. A slick video by John Pavlus shows an exploded view of the contraption's operation. Carol's own page explains how to make a gear ratio of 19 when all you have are gears of 1, 3, and 5.

Seems like everyone is on the Antikythera Mechanism bandwagon. Soon, I expect to see an emulator based on a North Korean card section, filmed as part of an OK Go video.

15 December 2010

A candidate for the WTF HOF

At a previous job, one of our initial screens for a job applicant was to throw her or him a Code SOD from The Daily WTF (with the explanatory setup removed) and to ask to applicant to explain what the code did and how to improve it. Today's snippet would be perfect for that exercise. You don't even need to understand much PHP to see that the algorithm is crazy mean bull bad, and that there are so many ways to make the code better.

06 December 2010

Is more

Dmitry Fadeyev reports on several CSS preprocessors, including LESS. On my current assignment, we've had specialists to take care of everything but the most trivial CSS, so I don't need one of these tools right away. But I expect that a project will come up in the future where I'll have to do my stylesheet fiddling.

03 December 2010

Revolution

Looks like there are some new goodies on display as part of the Computer History Museum's first "permanent" exhibition. Harry McCracken follows Steve Wozniak on a sneak preview tour.

(Link via The Code Project.)

30 November 2010

Regex mystery, once more

I spent some quality time with Friedl's Mastering Regular Expressions, and I'm beginning to get a better understanding of JavaScript's NFA regular expression engine. I dimly understand how the case I described in an earlier post sent the engine into backtracking perdition. I tested (but did not commit to the codebase) this version. It addresses the specific bad data case, but I don't think it's a comprehensive solution.



var PROBE_REGEX = /client\.org/;
var URL_REGEX = /^(http:\/\/)?(\w+\.?)*client\.org(.*)$/i;

stripUrlPrefix = function (url) {
var regex = new RegExp(URL_REGEX);
var result = jQuery.trim(url);
if (result.search(PROBE_REGEX) == -1) {
return result;
}
var matches = regex.exec(result);
if (matches) {
return matches[3];
} else {
return result;
}
}



It's one or both of the quantified expressions (\w+\.?)* and (.*) that are responsible for the performance issues.

Bronze metaphor

New research by James Evans suggests that the artisans who built the Antikythera Mechanism suggested epicycles to the Greek astronomers as an explanation of planetary motions, and not the other way around. Jo Merchant reports.

11 November 2010

Friendly is good

Joanne Garlow reports on a just-released increment of software to which I contributed, broad support of semantic URLs at npr.org.

15 October 2010

Might come in handy again

The table amgp_release associates UPC codes (amgp_upc) with album IDs (amgp_a_id). You'd think that this would be a one-to-one relationship, but apparently multiple IDs can share the same UPC code. Question: What are the UPCs that are associated with multiple IDs? Query:



select count(*), amgp_upc
from (select distinct amgp_upc, amgp_a_id from amg.amgp_release) tbl
group by amgp_upc
having count(*) > 1

13 October 2010

'N Sync

At this shop, a developer uses a Windows laptop to shell into a virtualized machine running Linux where the source code is compiled into a web application. Most of us use Eclipse as a development studio. I had set up my Eclipse to edit my working copy of the code base directly on the virtual machine, mounting it as an SMB network drive. But over time, I found that some serious latencies would occur sporadically--Eclipse would take several minutes to open a short file of JavaScript, that sort of hassle. So, after some cajoling from colleague Jared, I followed his lead and moved my setup so that my working copy is on my laptop's hard drive. So now, instead of an edit-build-test-think cycle, I have an edit-rsync-build-test-think cycle, but the edit step is much faster.

But I was faced with a new annoyance. Every rsync or ssh to the VM required me to type my password. (The other way with SMB, I just left a shell window open already logged in to the VM.)

(Hunh. I suppose I could have set up rsync to pull from the VM rather than push from the laptop. Never thought of that.)

Anyway, the team's wiki links to a helpful crib on how to make RSA keys to perform an automatic login with ssh, but my first efforts failed. Colleague Harold provided the missing piece. He checked /var/log/auth.log on the VM and found an error message that indicated the file permissions on my home directory were too open. We did a chmod 755 on my home directory, and I was in!

17 September 2010

Work in progress

I started to draw these page flow diagrams with the tool that's integrated with our wiki. But sometimes there's just no substitute for a whiteboard and a camera.
work in progress

16 September 2010

Not to mention shortening URLs


W (double U) has, of all the letters in our alphabet, the only cumbrous name, the names of the others being monosyllabic. This advantage of the Roman alphabet over the Grecian is the more valued after audibly spelling out some simple Greek word, like ἐπιχοριαμβικός. Still, it is now thought by the learned that other agencies than the difference of the two alphabets may have been concerned in the decline of "the glory that was Greece" and the rise of "the grandeur that was Rome." There can be no doubt, however, that by simplifying the name of W (calling it "wow," for example) our civilization could be, if not promoted, at least better endured.

—Ambrose Bierce, The Cynic's Word Book (1906)


24 August 2010

Measure twice, cut once

A simple, brilliant idea: README Driven Development.

...you're giving yourself a chance to think through the project without the overhead of having to change code every time you change your mind about how something should be organized or what should be included in the Public API.


(Link via The Code Project.)

19 August 2010

Post-modern obsolescence

I don't know whether to be tickled or appalled: USB Typewriter.

(Link via IEEE Spectrum's iCandy.)

Empirical observation

Gorsline's Corollary to Osborn's Law ("Variables won't; constants aren't."): Temp directories aren't.

17 August 2010

Small victories

This is a puzzle I had failed to solve a few weeks ago; I finally figured out how to do it. Given a modal that you've opened with jQuery's dialog(), and given that it has some buttons (like "Save" and "Cancel") that you've added as options, how can you programmatically disable or hide a button? dialog() doesn't give the buttons IDs or distinguishing classes. And you don't want to look at everything in the DOM, just the row of buttons on your modal.

I already have as part of our framework the DOM ID of the <div> that makes up the body of the modal: it's in a variable called overlay.context. The trick is to walk up two levels of the DOM to the common ancestor of the body and the buttons. So, to hide the button with a label of "Cancel":



var grandParent = $(overlay.context).parent().parent();
$(":button:contains('Cancel')", grandParent).hide();

02 August 2010

Primality test

kottke.org pointed out this egregious abuse of regular expressions some time ago, but the page he referenced never made it into my post, and I can't find Kottke's post in his archives. In the course of trying to track down the page, I found several variations and amplifications of /^(11+)\1+$/ as a regular expression to find prime numbers in Perl, Python, or what have you.

See posts from Brontosaurus, Peteris Krumins, Neil Kandalgaonkar, Avinash Meetoo, and this Stack Overflow thread. There is a Perl one-liner by Abigail (last name?) from a 1997 Perl Journal that perhaps takes historical priority.

24 July 2010

COBOL grouse

I dug out some of my old technical books from storage, looking for blog fodder. One of them was the book I really learned COBOL from, Greg Lupfer's DTSS COBOL: Introduction (1974), published by Dartmouth College's Kiewit Computation Center (DTSS is Dartmouth Time-Sharing System, and was an online environment that shared roots with Multics). There was a shelfload of copies of this book available to new programmers like me at Greg and Gary's consultancy in the early 1980s. For the most part, the presentation is no-nonsense, focusing on the features of COBOL 68 that you'd actually use to write business applications (with the exception of the Report Writer module, which has always been no more than a historical curiosity to me). The book is set throughout in a Courier-like font, and it looks like it was laid out with RUNOFF.

Using the example of an order entry system for a consumer audio store in Minnesota (with customers like R. Zimmerman from Hibbing!), Greg walks you through how an indexed-sequential file works, he explains figurative constants and the REDEFINES clause, and he touches on a few points of good programming practice. Early on is this deadpan gem:
The first program to be described is ORDER11. This program will accomplish the first step described above, which is to create a working data record that contains three additional fields used as the record progresses through the order edit module. The functions of these three fields are defined in the comments included in the IDENTIFICATION DIVISION of the program.

The name ORDER11, which seems to a rather unimaginative name for a program, is the result of an overall file naming convention that is used throughout the system described in this text.

Greg spells out a convention for naming source, object, transaction data, and master files within the constraints of eight (8) alphanumeric characters and no extensions. He then expostulates:

Most COBOL application systems use dozens of programs and files, so a consistent file naming convention is essential, and is to be preferred over assigning "meaningful" names to the files. These meaningful names often have meaning only to the programmer who wrote them. One actual system of seven programs used the names DOC, HAPPY, BASHFUL, SNEEZY, GRUMPY, SLEEPY, and DOPEY, and the programmer was not Ms. White. Any experienced programmer can probably recall similar instances of absurd names for programs. (pp. 22-23)

Greg didn't always follow his own advice. There was a legendary one-off that he wrote for a customer to scrub out unwanted control characters and other fluff. As the story goes, he named it REMOSHIT.

22 July 2010

Return of the regex mystery

The little one-off function that I wrote to extract the file name from a URL still continues to baffle. Rekha, in the course of reviewing some other code and functionality, threw a random string of letters (no punctuation) at it, which caused the browser's script engine to time out. I rewrote the code somewhat, but even this version takes about 30 seconds to complete, when given a string like "asdfghjklasdfghjklasdfghjkl":



var URL_REGEX = /^(http:\/\/)?(\w+\.?)*client\.org(.*)$/i;

stripUrlPrefix = function (url) {
var regex = new RegExp(URL_REGEX);
var result = jQuery.trim(url);
var matches = regex.exec(result);
if (matches) {
return matches[3];
} else {
return result;
}
}

20 July 2010

More songs about buildings and slugs

I wrote about slugs as naming technology some weeks ago. It seems that in the direct mail industry the term has a slightly different meaning. And somewhere out there, if there is justice, there's a requirements analyst that got slugged.

10 July 2010

Carrying on for Adm. Hopper

Via The Code Project, Emily Goligowski surveys five programs designed to give girls and women an extra boost in technology training.

In 2008, girls made up just 17% of Advanced Placement test takers in computer science (the lowest percentage of any subject) and held less than 20% of CS degrees.


Too bad about the annoying widgets salted into the text of Mashable's pages; also, the demo for this article apparently skews female, so the ads are all about shoes.

09 July 2010

There's a plugin for that

I recently went through this exercise: for a form submitted by Ajax, disable all the controls on the form until the Ajax update completes. The code to perform the disabling is nothing particularly complicated:



CLIENT.Utilities.disableJQueryDialog = function (jq) {
try {
$(":input", jq).attr("disabled", "disabled");
//NOTES: Disabling other clickable elements (<a>, <span>, etc.)
//is the responsibility of the specific resource overlay.
} catch (e) {
CLIENT.Utilities.postWarnMessage('', 'Utilities.js disableJQueryDialog()', e);
}
};



Call this function with anything that can be a jQuery context, and all the one-line text boxes, dropdowns, checkboxes, and radio buttons in that context are disabled. As the notes indicate, we have other UI elements that the user can interact with (like hyperlinks), so I worked out a simple pattern so that a dialog overlay can register a callback function to disable other HTML elements. I also used this callback to disappear any popups from the date picker plugin and to remove TinyMCEs attached to <textarea>s.

Well, it turns out that there is a jQuery plugin that will do most of what I needed to do, and throw up a "Loading..." message as well, according to Dino Esposito. If I have some extra time this afternoon I'm going to check out the BlockUI plugin for jQuery.

31 May 2010

Depends on how you look at it

Tom Malzbender's presentation to the Smithsonian Associates on the Antikythera Mechanism focused on Polynomial Texture Mapping. PTM has its roots in computer graphics techniques for rendering artificial surfaces (in game applications, for instance), but in this case it's used to enhance surface detail of physical artifacts.

The process starts with high-resolution image acquisition from multiple POVs: the object to be imaged is mounted in a domed frame fitted with dozens of digital cameras. (The contraption looks something like the Trinity device, to me.)

Once the images are captured, software apps can manipulate the apparent direction of the light source (to realize the artist's "raking light"), and more astonishingly, the apparent surface characteristics (e.g., reflectivity) of the artifact.

The application of this technology to recovering lost surface detail on chunks of bronze that have been sitting in saltwater for two millennia is a natural. Mazlbender and John Seiradakis report that the metal plates that comprise the Antikythera Mechanism's "user's manual" have revealed an additional 2,200 characters, thanks to PTM techniques.

28 May 2010

Breaking the C-note

And first looks at a prototype XO-3 from Seth Weintraub and Nick Bilton. I like the little key ring thing at the corner, though I suspect that's not its intended purpose.

Plans are for at least one version of the box (how can you call anything that slim a box?) to run Android.

[Nicholas] Negroponte also stressed the importance of the open source nature of the project, pointing out that every aspect of the the project would still be open source. "We're going to go totally open," he said. "In some sense it's the complete opposite of the Amazon bookstore or iTunes, where we'll run anything, including viruses and Flash."


(Weintraub link via The Code Project.)

Make another compartment in the toobox

Colleague Harold passes along a notice about Chrome extensions for web development. Not enough there to move me away from Firefox and Firebug just yet, but it's good to know that there are some options.

In a bind

Yesterday I did some refactoring of the JavaScript that manages jQuery Datepickers and the event handlers attached to them. Several of the modal dialog boxes of the application use the following pattern: a text box that permits direct entry of a date (as 'MM/DD/YY'), a Datepicker tied to the text box that allows the user to point and click at a date, and 3 hidden fields for the month, day, and year portion of the date. It is this set of 3 fields that is persisted.

So we have an event handler that takes care of direct input (hdlChange) and one that takes care of the point-and-click selection (hdlDatePickerSelect). The difficulty I had to overcome was establishing an execution context for the event handlers so that they could access member variables that identified the date being processed (several of the app's modals [managed with a jQuery Dialog] collect 2 or 3 dates).

Another complicating factor was this unfortunate behavior of the Datepicker object: as we use it, the Datepicker's text boxes on each modal must have distinct IDs, even modals that have been closed and destroyed. Hence the variable overlayAffix (we call the modals "overlays" in this app) that is appended to the ID-based selector for the Datepicker.

Anyway, back to the problem of establishing context. The nut of it is passing some sort of extra information to the event handler that identifies the this that you want to use, because the event handler's this is the text box DOM element.

I experimented with jQuery's .bind() method, and that worked just fine for the change handler. (Mike West's article is helpful background.) Using .bind(), you can pass whatever you like into an event handler—say, a pointer to your execution context—and retrieve it through the event object. But, unfortunately, I did not find a way to make this technique work for the select handler. The Datepicker doesn't have a .bind() analogue: rather, the handler is specified as the option onSelect; furthermore, the signature of the handler doesn't include the event (AFAIK).

So I resorted to what I consider trickery, taking advantage of JavaScript's expando properties: I simply attached the execution context as a an additional property of the text box (date control).

Here's the completed script, lightly edited for presentation. Wording note: context in the code below refers to the jQuery DOM context, not the execution context that we've been discussing.



// Helpers for managing a datepicker, the associated text box, and hidden fields.

CLIENT.Utilities.DatePicker = function (context, overlayAffix, dateAffix) {
this.context = context;
this.overlayAffix = overlayAffix; //identifies the overlay we're on (e.g., 'GeneralJournal')
this.dateAffix = dateAffix; //identifies the date (e.g., 'invoice')
this.datePickerSelector = '#' + dateAffix + 'Date' + overlayAffix;
this.monthSelector = '#' + dateAffix + 'Month';
this.daySelector = '#' + dateAffix + 'Day';
this.yearSelector = '#' + dateAffix + 'Year';

this.setDate = function (date) {
try {
$(this.monthSelector, this.context).val(date.getMonth() + 1).change();
$(this.daySelector, this.context).val(date.getDate()).change();
$(this.yearSelector, this.context).val(date.getFullYear()).change();
} catch (e) {
CLIENT.Utilities.postWarnMessage('', 'DatePicker.js setDate()', e);
}
};

this.clearDate = function () {
try {
$(this.monthSelector, this.context).val(0).change();
$(this.daySelector, this.context).val(0).change();
$(this.yearSelector, this.context).val(0).change();
} catch (e) {
CLIENT.Utilities.postWarnMessage('', 'DatePicker.js clearDate()', e);
}
};


this.setupControls = function () {
try {
$(this.datePickerSelector, this.context).change(this.hdlChange);

$(this.datePickerSelector, this.context).datepicker({
showOn: 'button',
buttonImage: '/new_cms/images/calendar.png',
buttonImageOnly: true,
onSelect: this.hdlDatePickerSelect
});

//give the date control a reference to the 'this' DatePicker object,
//so that event handlers can access the DatePicker object
$(this.datePickerSelector, this.context)[0].theThis = this;
} catch (e) {
CLIENT.Utilities.postWarnMessage('', 'DatePicker.js setupControls()', e);
}
};

//event handlers for which 'this' is the date control, not the DatePicker object
this.hdlChange = function () {
try {
//retrieve the object reference from the date control
var myThis = this.theThis;

var dateText = $(myThis.datePickerSelector, myThis.context).val();
if ($.trim(dateText).length > 0) {
var date = CLIENT.Utilities.parseDateString(dateText, $(myThis.datePickerSelector, myThis.context));
if (date) {
myThis.setDate(date);
} else {
$(myThis.datePickerSelector, myThis.context).val('');
myThis.clearDate();
}
} else {
myThis.clearDate();
}
} catch (e) {
CLIENT.Utilities.postWarnMessage('', 'DatePicker.js hdlChange()', e);
}
};

this.hdlDatePickerSelect = function (dateText, inst) {
try {
//retrieve the object reference from the date control
var myThis = this.theThis;

CLIENT.Utilities.clearValidationMessages($(myThis.datePickerSelector, myThis.context).parent());
if ($.trim(dateText).length > 0) {
var date = new Date(dateText);
myThis.setDate(date);
} else {
myThis.clearDate();
}
} catch (e) {
CLIENT.Utilities.postWarnMessage('', 'DatePicker.js hdlDatePickerSelect()', e);
}
};
};



Example HTML:



<div id="divGeneralJournal">
* * *
<label for="invoiceDateGeneralJournal">Invoice date</label>
<input type="text" id="invoiceDateGeneralJournal" value="" class="datefield" />

<input type="hidden" id="invoiceMonth" />
<input type="hidden" id="invoiceDay" />
<input type="hidden" id="invoiceYear" />
* * *
</div>



Initialization script would go something like this:



var invoiceDatePicker = new CLIENT.Utilities.DatePicker('#divGeneralJournal', 'GeneralJournal', 'invoice');
invoiceDatePicker.setupControls();

21 May 2010

Alpha bravo charlie

Every software development effort more complex than an accountant bashing away with Excel macros divides itself into phases. Practitioners sometimes assign simple sequential numbers to the phases of a project, but number-based designators often don't work out because phases overlap, get rescheduled, subdivided, and cancelled—who wants to explain to management that Phase 3.7 will be completed after Phase 6.2? And numbers don't have much sizzle. While they do have the advantage of being arbitrary, they still imply a precedence.

Temporal designators ("the fall '09 release") are even worse, because we all know that sometimes the fall release is completed the following summer.

And so we use code names, and the more arbitrary but transparent the better. They function in much the same way that journalists use slugs to identify stories. A slug doesn't tell you what's in a news story—the headline and teaser do that. It's just enough of an identifier so that you know which story you're talking about in an page space budget meeting. Monday's story on a key Senate floor action might be slugged HEALTHCAREVOTE. In fact, you need the slug in order to conceptually manipulate the story even before you know the story's outcome. Not unlike many software projects I've known.

Choosing the pattern for a group of code names is an important decision, and one best left not to the group, but rather to one person. Group-chosen patterns are rather bland and uninteresting. At a previous job, the whole company voted on the pattern and we ended up with "Caribbean resort islands." And so I worked on Aruba, and Barbados, and Coba, etc. Blah. Or way too pretentious: names from Greek mythology was another popular pattern there.

Much better is the approach that my current client uses. Each January, the code names start following a new pattern at the beginning of the alphabet, but the pattern is left a mystery known only to the project management office, which doles out the names a few letters at a time. The first team member who susses out the pattern—and mind you, this is an honor system thing, no search engines allowed—gets to choose the pattern for the next year.

And so phases for this year were named Abby, Biff, Claribelle (a tantalizingly distinctive spelling), Domby, and so on. One of us, Kate, eventually cracked the code at Kami. I wonder what Kate will give us next year?

01 May 2010

Tik tok

D.C. area residents interested in the Antikythera Mechanism have an opportunity to learn more at a lecture to be given by John Seiradakis (professor of astronomy, Aristotle University of Thessaloniki) and Tom Malzbender (senior research scientist, Hewlett-Packard Laboratories) later this month.

23 April 2010

Moving on

Shain Miley links to the video archive of presentations at this year's MySQL conference, including a presentation on migration from Oracle to MySQL by Joanne Garlow, tech lead/architect for the development team at my client site.

18 April 2010

One Mouse Per Child?

Randall Stross checks in with Matt Keller of the OLPC Foundation, and discusses some technological alternatives offered by other players in the development-through-childhood-computing space. Microsoft's MultiPoint, developed by a team in India, puts multiple cursors on the screen, each controlled by a particular student.

15 April 2010

A little cheesecake

Greg Ferrara posts a publicity photo, ca. 1958, of a Ramo-Wooldridge RW-300 process control computer (a product line completely unknown to me) at (the deliciously-named) If Charlie Parker Was a Gunslinger, There'd Be a Whole Lot of Dead Copycats. Ramo-Wooldridge was a predecessor company to TRW. Computer History Museum materials indicate that the RW-300 was marketed in the early 1960s as a controller for nuclear reactors. More marketing materials at bitsavers.org describe the assembly of A-to-D modules in subframes to make up an RW-300. Stout and Williams, in a 1995 paper, chronicle the pioneering work of Ramo-Wooldridge in computerized process control.

07 April 2010

And did you control for color?

This article turned up in a sidebar in the text of a statistics textbook that I'm recording: Smith and Pell, "Parachute use to prevent death and major trauma related to gravitational challenge: systematic review of randomised controlled trials." I think the conclusion pretty much covers it:
As with many interventions intended to prevent ill health, the effectiveness of parachutes has not been subjected to rigorous evaluation by using randomised controlled trials. Advocates of evidence based medicine have criticised the adoption of interventions evaluated by using only observational data. We think that everyone might benefit if the most radical protagonists of evidence based medicine organised and participated in a double blind, randomised, placebo controlled, crossover trial of the parachute.

24 March 2010

Onward and upward

The team that I've been a member of for the past six months or so achieved a milestone today: integration of three of the client's blogs with the in-house CMS. As Daniel Jacobson explains, this means that blog posts are first-class content, available through an API, on emerging platforms, and via the "mother ship" web site. One of the small but important features of this work is that posts now carry a "semantic URL" permalink, rather than an URL with nothing but a cryptic "&id=zqx3".

17 March 2010

Like, random

Kyle VanHemert introduces the IBM RAMAC 305, the first commercial computer to use magnetic disk storage (and one of IBM’s last systems to use vacuum tubes). The 305 was announced on 13 September 1956, my one-month birthday.

The post embeds a really sweet 5-minute industrial from IBM promoting the system: check out the access panels that swing out and down to afford access to the copperage. The post conflates the 305 (the model number of the entire system) with the 350 (the model number of the 50-platter hard disk subsystem), but no matter.

(Link via The Code Project.)

12 March 2010

DISP=(NEW,CATLG,DELETE)

Along time ago, when I was just getting started in this career, back in the days when an interviewer would take you to lunch at the Capital Hilton on 16th Street, I was trying to schmooze my way into a COBOL job. My interviewer knocked me around with some basic principles questions (like, "what's a pointer?") and then he went in for the kill:

Do you do your own JCL?


I understood the question, at least. And I answered truthfully that, no, I wasn't equipped for that, not yet. But what I kept to myself was, "JCL? How hard can that be? It's just a command language for batch jobs." (I had already mastered one DEC command shell and thought I knew nearly everything.) Dan Wohlbruck illustrates how naive I was.

I didn't get the job, of course, but nearly ten years later I finally made my acquaintance with OS JCL. We have since parted, but we have agreed to remain friends.

22 February 2010

Another regex issue

For a bit of code designed to block all HTML tags from an input string, I picked up the following regular expression from Friedl, Mastering Regular Expressions, 3/e:



<("[^"]*"|'[^']*'|[^'">])*>



As in:



if (inputString.match(/<("[^"]*"|'[^']*'|[^'">])*>/)) {
CLIENT.Utilities.addValidationMessage($(this), 'No HTML tags, please.');
isValid = false;
}



Unfortunately, colleague Jared points out that ill-formed HTML tags will pass this validation, and colleague Jason demonstrated that browsers (at least some, under certain conditions) will (more or less) render the ill-formed HTML. Jared's examples:



<a href="bad link" attr'>click me</a attr=">



Since this code is used for an internal app where users aren't actively trying to clobber things, we've chosen to live with the situation that the fishy markup can slip through.

28 January 2010

Fun with jqGrid

We've recently started using jqGrid, a jQuery-based data grid tool, for presenting search results. I picked up a tip for adding a custom caption to the rows-per-page dropdown (which is controlled by the rowlist[] array). Unfortunately, that bit of code is subject to a one-off bug in that it is not idempotent. So when it's used in a loadComplete event handler (which fires each time the grid is [server-side] sorted or otherwise reloaded), I found that I had to write some first-time-only guard logic. Here's an abridged version of my code that sets up the grid, with a few other hacks to work around some deficiencies in jqGrid.



var dataGrid;
var firstTime = true;

jQuery(document).ready(function(){

//set up our own grid wrapper
dataGrid = new CLIENT.DataGrid.DataGrid('#postList');

//set up the main grid
jQuery('#postList').jqGrid({
url: BASE_URL,
datatype: 'xml',
mtype: 'GET',
colNames: ['Status', 'Headline', 'Byline(s)', 'Date'],
colModel: [
{name: 'status', width: 80, sortable: false},
{name: 'headline',width: 290, index: 1},
{name: 'bylines', width: 148, sortable: false},
{name: 'date', width: 150, index: 2},
],
rowList: [10,20,30,50],
pager: '#postPager',
pgbuttons: true,
rowNum: 20,
loadonce: false,
viewrecords: true,
recordtext: 'Posts {0} - {1} of {2}',
pgtext: 'Page {0} of {1}',
emptyrecords: 'No posts to display',
* * *
loadComplete: function () {
jQuery('select[class="ui-pg-selbox"]').attr({title: 'Posts per page'}); //label for rowList-based dropdown
if (firstTime) {
jQuery('#postPager .ui-pg-selbox').closest('td').after('Posts per page');
firstTime = false;
}
jQuery('#postPager_center').attr({style: 'white-space: pre; width: 450px;'}); //override jqGrid's width
jQuery('#jqgh_status').attr({className: 'nosort'}); //sortable: attribute doesn't clear the ui-jqgrid-sortable class for us
jQuery('#jqgh_bylines').attr({className: 'nosort'});
}
});
});

10 January 2010

R-squared

Junk Charts provides some how-I-did-it code in the statistical programming language R. The inline application of scalars to matrices reminds me a little of APL, which was popular in the 1970s (at least at Wharton, it was) for exactly this same kind of application.