Archive for the 'coldfusion' Category

Regular Expression Backreferences and the Non-Greedy Modifier

Update: James Allen caught a formatting bug. It seems WordPress doesn't like my coloring, and when present, swaps the double quotes for "smart quotes". I've removed the coloring, and it seem to be fine again.

Someone posted a question on CF-Talk about using backreferences in regular expression search strings. Not the replacement string, mind you, but the search string itself. This is, as you'd expect, perfectly legal and can be incredibly powerful. While contriving an example, the one I came up with also required the non-greedy modifier, so I'll illustrate both. Here's the code in question (copy it to a CFM file to run it):

<cfoutput>
<cfset baseString = "some 'text' with ""quotes an' some apostrophes"" in it" />
<h2>Quoted Strings within #baseString#</h2>
<ul>
<cfset start = 1 />
<cfloop condition="true">
  <cfset result = REFind("(['""])(.*?)\1", baseString, start, true) />
  <cfif result.pos[1] LT 1>
    <cfbreak />
  </cfif>
  <cfset string = mid(baseString, result.pos[3], result.len[3]) />
  <cfset quote = mid(baseString, result.pos[2], result.len[2]) />
  <cfset start = result.pos[1] + result.len[1] />
  <li>#string# (quoted with #quote#)</li>
</cfloop>
</ul>
</cfoutput>

The backreference (the "\1" at the end of the regex) behaves exactly the same as when in a replacement string: it represents the "stuff" matched by the first clause wrapped in parentheses (in this case, "['""]"). Ignoring the middle part, the regex says find me either a single or double quote, then some "stuff", and then the same quote character.

In the middle is the non-greedy modifier (the "?", after the asterisk). Without it the ".*" would match as much as possible while still allowing the regex as a whole to succeed. In this specific case, the quote would match the single-quote before "text", the .* would match "text with "quotes an", and then the backreference would match the single-quote after "an". That's clearly not what we want, so we use the non-greedy operator to tell the .* that we only want it to match as much as it needs to, not as much as it can. Then it behaves correctly. Try deleting the non-greedy modifier and run it.

Why JavaScript (or really, ECMAScript)?

After my last post on CF and JS integration (via Rhino), I got several comments that can be summarized as "why?". I addressed the issue in a rather oblique manner in my last post; here's a more full treatment.

Before I start, I want to make incredibly clear that I'm not talking about a new JS-based application server built on Rhino. I'm talking about using JS as an alternate/supplemental syntax for your CFML applications, which still run on the ColdFusion application server, with all the niceties that the CF server provides.

The first reason is that CFML is incredibly verbose for a lot of common tasks. Consider a function definition in CFML:

<cffunction name="doIt" output="false">
  <cfargument name="param1" />
  <cfargument name="param2" />
</cffunction>

Now the same definition in JS:

function doIt(param1, param2) {
}

The CFML is a lot more verbose, which is both more typing, and more characters to visually parse when you're trying to read the code. Of course, this isn't without downsides. Consider running a parameterized query in CFML:

<cfquery datasource="myDsn" name="get">
  select *
  from my_table
  where id = <cfqueryparam cfsqltype="cf_sql_integer" value="#id#" />
</cfquery>

And now in JS:

var q = new Query("myDsn", "select * from my_table where id = :id");
var get = q.execute({
  id: new QueryParam(id, "integer")
});

The CFML implementation definitely highlights the SQL as a standalone language embedded within the markup, while with the JS implementation, the SQL is just a string; there's nothing SQL-y about it. Is the more concise nature of the JS worth it in this specific case? I'd say it's close to a wash: less SQL delineation, but more concise code, more easily reusable SQL, semantically relevant (instead of positionally anchored) parameters, and reusable parameters. Note that in either case, I'm running my parameterized SQL against a datasource configured in the CF Administrator, and the 'get' variable will be a native CF query object (a 'coldfusion.sql.Table' instance).

Now where I really think JS (really ECMAScript, in general) has a lot to offer over CFML is in the language constructs itself. Nested functions, function literals (and their extension: closures) are a singularly fantastic language constructs. Rather than show a single example implemented in both CFML and JS, I'm going to just illustrate the concepts in JS, and contrast them with CFML. Nesting first:

function doSomething(param) {
  function f(o) {
    // do something ...
  }
  var result = f(param);
  for (var i in result) {
    if (typeof i == "object") {
      result[i] = f(result[i]);
    }
  }
}

So what's happening? I'm packaging up some reusable functionality into a function (named 'f'), but it's an implementation detail of the 'doSomething' function, and is therefore internal to the 'doSomething' function. Do do this same sort of "subpackaging" of functionality in CFML, you'd have to put the 'f' function outside as a peer of the 'doSomething' function (probably named 'doSomething_f' or whatever). That's a leak in encapsulation, as well as unnecessarily crowding the external namespace.

Function literals implicitly require function variables, the latter of which CF already has. A function variable just means you can pass around a function as a variable, and then call it later. A function literal, however, means you can define a function without declaring it. A simple example:

function declaredFunction() {
}
literalFunction = function() {
};

In the former case, there is an actual declaration of the function. It is it's own statement, and is compiled (or interpreted) as such. The latter, however, is a literal. It's an expression, and can be placed anywhere you might want to use an expression. Here's another example of doing something with declarations and then literals:

// declarations
function optionOne(){}
function optionTwo(){}
return (x == y) ? optionOne : optionTwo;

// literals
return (x == y) ? function(){} : function(){};

Assuming this is within another function, the declared functions in the first section could be nested, thereby minimizing their effect on namespace crowding. The second section, of course, doesn't have any extra declarations, though if the functions have any substantial size to them, it can get unreadable very quickly. As such, the latter syntax isn't always the right one, but it is nice to have the option. With CFML, you're again forced to explicitly declare the functions as peers.

And now closures. Closures are nested functions (declared or literal), which execute in the context of their definition location, even if they're executed after that context has gone away. Here's a (somewhat contrived) example:

function getFilter(name, value) {
  return function(item) {
    return item[name] == value;
  }
}
function conditionallyDoSomething(collection, filter) {
  for (var i = 0; i < collection.length; i++) {
    if (filter(collection[i]) {
      // do something ...
    }
  }
}
conditionallyDoSomething(people, getFilter("age", 27));

This is a fairly contrived example, as I said, but it illustrates the concept. By the time the function returned from 'getFilter' is executed, the 'getFilter' function has terminated. However, it (the function literal) still has access to the context it was defined in - namely the 'getFilter' function's context, and therefore it's parameters. Closures are really the crown jewel of ECMAScript, in my opinion. With CFML, the closure is totally undoable, unless you use some sort of synthesis framework like Sean's.

The final advantage, like the querying example above, cuts both ways. JS-based implementations can't use any existing CFML tools (Fusebox, ColdSpring, etc.), but they can use all the myriad JS tools that are available. I happen to be a big fan of Prototype, and I can use the UI-agnostic pieces (like the Object and Array extensions) of Prototype on the server-side. Similarly, if you write some wicked-cool routine for your server-side processing, you can immediately and directly reuse it in your client-side JS (or quite possibly AS).

So between the enormously lighter language syntax and the additional language functionality, I think there's a compelling case for using JavaScript (or ECMAScript) as a language for building apps on the ColdFusion server. In an ideal world, it's be ECMAScript 4th Edition (what ActionScript 3 is based on), but there isn't a mature, Java-based interpreter for it anywhere. Aside from just generally being more modern, the 4th Edition provides strong typing (using colon-postfix notation), real packages and classes, interfaces, object member access levels, and a few other neat things.

One very interesting aspect of all this is that Adobe happens to own an ECMAScript 4 compiler (the AS3 compiler from the Flex SDK), an ECMAScript 4 runtime (the Tamarin project that underlies Flash Player 9 and is now hosted by the Mozilla Foundation), and ColdFusion.  So it seems like using ECMAScript 4 as an alternative to CFML for the CF Server is really not that outlandish.  The pieces are all done, it's just the integration that is lacking, and CF is all about integration.  Rather to rich of a project for me to undertake on my own (hence ECMAScript 2 and Rhino), and the closed nature of CF makes it rather hard as well, but for an entity like Adobe, quite a reasonable undertaking, I'd think.  Here's hoping for CF9!

The Rhino Is Coming … to fix CFML

Show of hands, how many people like CFML? Ok, how many like the ColdFusion Platform? What's the difference, you ask? CFML is a markup language that you do most CF Platform development in. You can use CFSCRIPT (which is ECMAScript-like) for certain things, but CFML is the Platform workhorse. The Platform, on the other hand, is all the stuff that your applications (written in CFML, usually) get because they run on the CF server. Things like datasources, PDF generation, easy file access, etc. That's the platform, not the CFML language.

What if I said you could build applications on the CF Platform but weren't required to use the often-cumbersome CFML? What if it were a language that you already new? What it it was JavaScript? And what does that have to do with rhinos?

Rhino is a free JavaScript implementation from Mozilla. It's what drives Firefox, and is also the base implementation of the new Java scripting framework that is available in Java 6 (the javax.script package). It's entirely implemented in Java, and since ColdFusion is as well, that means that CFML within CF and JS within Rhino can execute in the same context, intermingled with each other.

Here's a simple proof-of-concept contact manager that I build over the weekend (running on my underpowered server). You can download the source as a ZIP archive, or via anonymous SVN (with SVN always being current, of course).  Of perhaps more general interest is the class explorer mini-app, which is included in the distribution. As you might imagine, getting everything wired up took some digging around in the Java internals, and this provides a window to the classes that are actually executing inside the JVM. Helpful for both exploration and troubleshooting classpath issues.

The app is in two parts: the integration core within the 'rhino' subdirectory, and the sample app itself. I'll discuss them separately (and very briefly) below.

The basic architecture of the app is to use JS for the business logic and backend processing, and use CFML only for the view layer (where it excels). 'Application.cfm' and 'index.cfm' can be considered "framework" files; there is no application logic in there, just wiring stuff. The views are all in the 'views' subdirectory, and the backend is in the 'scripts' subdirectory.

The architecture of the Rhino integration is centered around 'rhino.cfc' and it's 'runScript' method. You pass that method a JS file to execute, and before evaluation, it will marshal some CF objects into the JS runtime. Following execution, it will unmarshal the top-level 'model' object back to CF for use in rendering your views. More simply, you pass in your parameters and your JS script, it executes, and you get a 'model' structure back to do something with. There is a special global function named 'loadScript' that can be used at runtime to pull in additional scripts, rather like CFINCLUDE.

As you'd expect, JS files are "precompiled" into in-memory script objects and cached until they update on disk, just like CF does with CFM templates. Unlike CF, however, this doesn't seem to offer a particularly significant performance improvement. I don't have a trusted-cache option at the moment, so there is still the filesystem check per-file, per-request, which is probably part of the reason. This actually happens in two places, once to bootstrap the environment (in 'rhino.cfc') and one for the actual runtime (in 'core/bootstrap.js'). The dichotomy annoys me, but such is life.

So why did I spend 15 or 20 hours putting this together? Because I'd love to be able to write my server-side with ECMAScript (though I'd prefer ActionScript 3 to JavaScript 1.6), and wanted to do a little proof of concept for that. I quite like the CF platform, but I'm not a huge fan of CFML itself. How supremely excellent would it be for CF9 to natively support scripting in ActionScript as well as CFML/CFScript, with equal access to the same underlying platform?

CF8 Structure Literal Gotcha

This one has gotten me several times.  With the new structure literal notation in CF8, you have to use equal signs between the key-value pairs.  In other places where you use key-value pairs (like passing named params to a UDF), you can use equals signs or colons, but not so with structure literals.

I have to say, I was quite excited for structure and array literals in CF8, but man have I been disappointed.  No nesting cripples them to near worthlessness, and this (seemingly random) inconsistency adds further annoyance.  I'd have been happier if they'd just been omitted until they could have been done reasonably.

Cyclic Graph Safe CFDUMP Replacement? Check.

On the Fusebox 5 mailing list this evening, Brian Kotek mentioned the inability to CFDUMP the myFusebox object because CFDUMP can't handle the cyclic nature of the object's internal data structures. While dumping myFusebox (which is a CFC instance) is probably a "silly" thing to do (Sean Corfield from the same thread: "Mind you, since myFusebox is an *object*, I'm not sure why you're dumping it?"), the general problem of CFDUMP overflowing the stack while dumping a recursive data structure is a valid one.

I've been bitten by it a few times in the past, and always worked around it by manually breaking the cyclic references before dumping. That, of course, is error prone and requires an intimate knowledge of the object being dumped, which is often not the case.

Since the kids are in bed and Heather's out this evening, I took it upon myself to create a CFDUMP replacement (or at least the beginnings of one) that handles recursion gracefully. It took about 45 minutes to write, and if anyone on the CF team is out there, please feel free to copy my code into the CFDUMP tag (or send me the source, and I'll patch it myself for no compensation other than the right to blog that I did it).

Here it is, in all it's glory (save it to 'dump.cfm' somewhere). I've comment-wrapped the 13 lines of code (lines 6-11 and 84-89) that deal with cyclic graph protection; the rest is just stock dump stuff.

<cfimport prefix="u" taglib="." />

<cfif thistag.executionMode EQ "start">
  <cfparam name="attributes.var" />
  <!--- cycle protection --->
  <cfif NOT structKeyExists(attributes, "__visited__")>
    <cfset attributes.__visited__ = createObject("java", "java.util.HashMap").init() />
  </cfif>
  <cfif NOT structKeyExists(attributes, "__path__")>
    <cfset attributes.__path__ = "root" />
  </cfif>
  <!--- /cycle protection --->

  <cfset initKey = "__U_DUMP_INITIALIZED__" />

  <cfif NOT structKeyExists(request, initKey)>
    <cfoutput>
    <style type="text/css">
      /* global */
      table.udump th {
        padding: 3px 5px;
      }
      table.udump td {
        background-color: ##fff;
        vertical-align: top;
        padding: 2px 3px;
      }
      /* query */
      table.udump-query {
        background-color: ##848;
      }
      table.udump-query tr.label th.query {
        background-color: ##a6a;
        color: ##fff;
        font-weight: bold;
        text-align: left;
      }
      table.udump-query tr.fields th,
      table.udump-query td.row-number {
        background-color: ##fdf;
        font-weight: normal;
      }
      /* struct */
      table.udump-struct {
        background-color: ##00c;
      }
      table.udump-struct tr.label th.struct {
        background-color: ##44c;
        color: ##fff;
        font-weight: bold;
        text-align: left;
      }
      table.udump-struct td.key {
        background-color: ##cdf;
      }
      /* array */
      table.udump-array {
        background-color: ##060;
      }
      table.udump-array tr.label th.array {
        background-color: ##090;
        color: ##fff;
        font-weight: bold;
        text-align: left;
      }
      table.udump-array td.index {
        background-color: ##cfc;
      }
    </style>
    </cfoutput>
    <cfset request[initKey] = true />
  </cfif>
<cfelseif thistag.executionMode EQ "end">
  <cfset System = createObject("java", "java.lang.System") />

  <cfif isSimpleValue(attributes.var)>
    <cfif len(trim(attributes.var)) EQ 0>
      <cfoutput>[empty string]</cfoutput>
    <cfelse>
      <cfoutput>#attributes.var#</cfoutput>
    </cfif>
  <cfelse>
    <!--- cycle protection --->
    <cfset hashCode = System.identityHashCode(attributes.var) />
    <cfif attributes.__visited__.containsKey(hashCode)>
      <cfoutput>[already dumped : #attributes.__visited__.get(hashCode)#]</cfoutput>
      <cfexit method="exittag" />
    </cfif>
    <cfset attributes.__visited__.put(hashCode, attributes.__path__) />
    <!--- /cycle protection --->

    <cfif isQuery(attributes.var)>
      <cfset fields = attributes.var.columnList />
      <cfoutput>
      <table class="udump udump-query">
      <tr class="label">
        <th class="query" colspan="#listLen(fields) + 1#">query - #attributes.var.recordCount# records</th>
      </tr>
      <tr class="fields">
        <th> </th>
        <cfloop list="#fields#" index="field">
          <th>#field#</th>
        </cfloop>
      </tr>
      <cfloop query="attributes.var">
        <tr>
          <td class="row-number">#currentRow#</td>
          <cfloop list="#fields#" index="field">
            <td><u:dump var="#attributes.var[field][currentRow]#"
              __visited__="#attributes.__visited__#"
              __path__="#attributes.__path__#.#field#[#currentRow#]" /></td>
          </cfloop>
        </tr>
      </cfloop>
      </table>
      </cfoutput>
    <cfelseif isStruct(attributes.var)>
      <cfoutput>
      <table class="udump udump-struct">
      <tr class="label">
        <th class="struct" colspan="2">struct - #structCount(attributes.var)# keys</th>
      </tr>
      <cfloop list="#listSort(structKeyList(attributes.var), 'textNoCase')#" index="i">
        <tr>
          <td class="key">#i#</td>
          <td><u:dump var="#attributes.var[i]#"
            __visited__="#attributes.__visited__#"
            __path__="#attributes.__path__#.#i#" /></td>
        </tr>
      </cfloop>
      </table>
      </cfoutput>
    <cfelseif isArray(attributes.var)>
      <cfoutput>
      <table class="udump udump-array">
      <tr class="label">
        <th class="array" colspan="2">array - #arrayLen(attributes.var)# items</th>
      </tr>
      <cfloop from="1" to="#arrayLen(attributes.var)#" index="i">
        <tr>
          <td class="index">#i#</td>
          <td><u:dump var="#attributes.var[i]#"
            __visited__="#attributes.__visited__#"
            __path__="#attributes.__path__#[#i#]" /></td>
        </tr>
      </cfloop>
      </table>
      </cfoutput>
    <cfelse>
      <cfoutput>[unknown object]</cfoutput>
    </cfif>
  </cfif>
</cfif>

And here is a simple test case (save it to a new file in the same directory as the 'dump.cfm' you just created).

<cfimport prefix="u" taglib="." />

<cfset b = structNew() />
<cfset b.name = "barney" />
<cfset b.age = 27 />

<cfset h = structNew() />
<cfset h.name = "heather" />
<cfset h.age = 27 />

<cfset b.spouse = h />
<cfset h.spouse = b />
<cfset b.anniversary = createDate(2002, 8, 3) />
<cfset h.anniversary = b.anniversary />

<cfset l = structNew() />
<cfset l.name = "lindsay" />
<cfset l.age = 3 />
<cfset l.mom = h />
<cfset l.dad = b />

<cfset e = structNew() />
<cfset e.name = "emery" />
<cfset e.age = 2 />
<cfset e.mom = h />
<cfset e.dad = b />

<cfset c = arrayNew(1) />
<cfset arrayAppend(c, l) />
<cfset arrayAppend(c, e) />

<cfset b.children = c />
<cfset h.children = c />

<cfset q = queryNew("id,name", "integer,varchar") />
<cfset queryAddRow(q) />
<cfset querySetCell(q, "id", 42) />
<cfset querySetCell(q, "name", "brian") />

<cfquery dbtype="query" name="get">
  select *
  from q
</cfquery>

<cfset b.recordSet = get />

<u:dump var="#b#" />

The code (both dump.cfm and the test case) are public domain, so you can use them however you'd like. I'd prefer credit be provided (at least a name and URL) where appropriate, but it's up to you.

Reflection on CF8's Image Tooling

I was really hoping for (though not really expecting) a nice simple solution to centering text on an image to show up as a result of the Wednesday Contest. Sadly, that wasn't the case. As you might guess, the contest was based on a real world use case that I had: gracefully handling the image tooling's inability to generate thumbnails of certain images.  The usual culprit seems to be color profile issues (which cause fatal errors), but I also get a number of thumbnails that come out with horribly screwed up colors (not actual negatives, but close). I should mention that I'm not doing anything special to create the thumbnails, just resizing the image to within certain bounds (usually 150×150 or 100×100).

I hadn't had the resizing problem with my JAI-based solution (which piggy-backed on the Lite/DevNet edition of Alagad Image Component), so I'd never had occasion to drop in error handling until switching to CF8's built-in toolkit. I didn't want to spend much time on it, just wanted it to not throw errors and create unbroken images, so I picked a pretty simple (I thought) task. This was the task I posed as the Wednesday Contest, though my implementation actually uses three lines instead of one (for "Error Generating Thumbnail"). I'd originally wanted to use 12pt bold instead of the default (10pt plain), but after seeing the implementation cost of using a non-default font (default font implementation vs. custom font implementation), I bailed on that and used the default.

I'd be lying if I said I wasn't disappointed. Centering text seems like a fairly basic task, but it's far from simple to do. I went back to the docs several times sure that I'd missed something, but unless I'm an idiot, there's nothing there.

Wednesday Contest Solution (pt. 2)

And here's the extra credit solution:

<cfif NOT isDefined("attributes")>
  <cfset attributes = structNew() />
  <cfset structAppend(attributes, form, false) />
  <cfset structAppend(attributes, url, false) />
</cfif>
<cfparam name="attributes.width" default="100" />
<cfparam name="attributes.height" default="100" />
<cfparam name="attributes.backgroundColor" default="f7f7f7" />
<cfparam name="attributes.borderColor" default="cccccc" />
<cfparam name="attributes.textColor" default="990000" />
<cfparam name="attributes.text" default="Hello!" />
<cfparam name="attributes.textSize" default="16" />
<cfparam name="attributes.textStyle" default="bolditalic" />
<cfparam name="attributes.textFont" default="courier new" />

<cfset fontArgs = structNew() />
<cfif structKeyExists(attributes, "textSize") AND isNumeric(attributes.textSize)>
  <cfset fontArgs["size"] = attributes.textSize />
</cfif>
<cfif structKeyExists(attributes, "textStyle") AND len(trim(attributes.textStyle)) GT 0>
  <cfset fontArgs["style"] = attributes.textStyle />
</cfif>
<cfif structKeyExists(attributes, "textFont") AND len(trim(attributes.textFont)) GT 0>
  <cfset fontArgs["font"] = attributes.textFont />
</cfif>

<cfset image = imageNew("", attributes.width - 2, attributes.height - 2, "rgb", attributes.backgroundColor) />
<cfset imageAddBorder(image, 1, attributes.borderColor) />

<cfset imageSetAntialiasing(image, "on") />
<cfset imageSetDrawingColor(image, attributes.textColor) />

<cfset graphics = imageGetBufferedImage(image).getGraphics() />
<cfset originalFont = graphics.getFont() />

<!--- default the fontArgs struct based on the default font --->
<cfif NOT structKeyExists(fontArgs, "font")>
  <cfset fontArgs.font = originalFont.getFontName() />
</cfif>
<cfif NOT structKeyExists(fontArgs, "size")>
  <cfset fontArgs.size = "" & originalFont.getSize() />
</cfif>
<cfif NOT structKeyExists(fontArgs, "style")>
  <cfif originalFont.isBold() AND originalFont.isItalic()>
    <cfset fontArgs.style = "bolditalic" />
  <cfelseif originalFont.isBold()>
    <cfset fontArgs.style = "bold" />
  <cfelseif originalFont.isItalic()>
    <cfset fontArgs.style = "italic" />
  <cfelse>
    <cfset fontArgs.style = "plain" />
  </cfif>
</cfif>

<!--- create the new font --->
<cfset font = createObject("java", "java.awt.Font") />
<cfif fontArgs.style EQ "bolditalic">
  <cfset style = bitOr(font.BOLD, font.ITALIC) />
<cfelseif fontArgs.style EQ "bold">
  <cfset style = font.BOLD />
<cfelseif fontArgs.style EQ "italic">
  <cfset style = font.ITALIC />
<cfelse>
  <cfset style = font.PLAIN />
</cfif>
<cfset newFont = font.init(fontArgs.font, javaCast("int", style), javaCast("int", fontArgs.size)) />

<!--- get the FontMetrics, this time for the new font --->
<cfset bounds = graphics.getFontMetrics(newFont).getStringBounds(attributes.text, graphics) />

<!--- draw it --->
<cfset imageDrawText(
  image,
  attributes.text,
  (attributes.width - bounds.getWidth()) / 2,
  (attributes.height + bounds.getHeight()) / 2,
  fontArgs
) />

<cfimage action="writeToBrowser"
  source="#image#" />

The implementation is fairly generic, though it contains no error handling, so it's still possible for fatal errors to crop up (particularly with font names). Quite a lot of work for some simple centered text.

CFTHREAD is Sweet!

Just had my first occasion to use CFTHREAD in an app, and it's nice.  As part of rendering an image gallery, I wanted to ensure that the thumbnails (which are generated server-side) exist so that they the user doesn't have to wait for them to be auto-generated as they're requested.  Unfortunately, generating the thumbnails is relatively slow, so I didn't want to do it as part of the page execution.

However, using CFTHREAD I can just put my thumbnail generation loop inside a "throwaway" thread that will execute in the background until it's finished, hopefully after the page goes back to the browser, but before the browser gets very far into requesting the thumbnails.  That way most of the thumbnails should be pregenerated by the time they're requested.

This is nothing that you couldn't do with the Async CFML Event Gateway (or even a throwaway Ajax call), but the CFTHREAD method is much cleaner than either one.  It also provides the capability to rejoin the threads with the main page thread if you need to do that, which is doubly nice, and something that you can't do with the async gateway (nor obviously an Ajax request, as that happens after the generated output is client-side).

Wednesday Contest Solution (pt. 1)

Since I had a whopping zero takers for my contest, I'm thinking it won't be a repeat event. Here's my solution for the first portion of the challenge:

<cfif NOT isDefined("attributes")>
  <cfset attributes = structNew() />
  <cfset structAppend(attributes, form, false) />
  <cfset structAppend(attributes, url, false) />
</cfif>
<cfparam name="attributes.width" default="100" />
<cfparam name="attributes.height" default="100" />
<cfparam name="attributes.backgroundColor" default="f7f7f7" />
<cfparam name="attributes.borderColor" default="cccccc" />
<cfparam name="attributes.textColor" default="990000" />
<cfparam name="attributes.text" default="Hello!" />

<cfset image = imageNew("", attributes.width - 2, attributes.height - 2, "rgb", attributes.backgroundColor) />
<cfset imageAddBorder(image, 1, attributes.borderColor) />

<cfset imageSetAntialiasing(image, "on") />
<cfset imageSetDrawingColor(image, attributes.textColor) />

<cfset graphics = imageGetBufferedImage(image).getGraphics() />

<cfset bounds = graphics.getFontMetrics().getStringBounds(attributes.text, graphics) />
<cfset imageDrawText(
  image,
  attributes.text,
  (attributes.width - bounds.getWidth()) / 2,
  (attributes.height + bounds.getHeight()) / 2
) />

<cfimage action="writeToBrowser"
  source="#image#" />

I'm withholding the extra credit solution until tomorrow, in case anyone wants to take a crack at it.

Contest Update

For those of you who missed it, I posted a little contest this morning and have gotten a whopping zero submissions!  There is still time to submit a solution, but be quick, as my solution (just the base, not extra credit) will be published tomorrow morning.  I'll be posting a full solution (with the extra credit) Friday morning.  If you tried and gave up, you're smart.  ;)  It's really circuitous for how simple it seems on the surface, and way more effort than it ought to be.  That being said, I'm quite interested in how other people have solved, or would approach solving, the problem.

And for my wife's sake, I didn't do this so someone else could do my work for me.  I have my solutions already; I did it because I'm interested in other approaches.