Adam Tuttle

Presenting on Adding More Awesome to Your Life at Philly Tech Week 2014

I've agreed to do a short presentation at Philly Tech Week this year. I'll be talking about how I use Node.js and Heroku to integrate and automate "all the things" -- basically, how I make my life easier and more productive, for free.

If you're in the area, it looks like it's going to be a great event, so you should buy a ticket ($25 and up) and come check it out!

Fix: What Are These Ugly and Useless Error Pages on My Fresh ColdFusion 10 Install?

I recently installed ColdFusion 10 on a new server, and of course I followed the CF10 Lockdown Guide [pdf].

Then I started moving sites onto the newly configured box and testing things out. And I got this lovely piece of work:

(Full disclosure: there are two possibilities, a "missing page" error, as shown above because it's easier to reproduce now for the purposes of the blog article, and a "there was an error" error, which is what I was running into at the time. For all practical purposes there is no difference.)

Viewing the source of this error message, it was clear that it was generated by ColdFusion. The references to files inside /CFIDE/ are a dead give away.

        <InvalidTag http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <link href="/CFIDE/administrator/templates/assets/style.css" rel="stylesheet"/>
    <div id="header"></div>
    <div id="spot">
         <image src="/CFIDE/administrator/templates/assets/spot.png" />
        <div id="title">404</div>
    <div id="content">
        The page you are trying to access could not be found. Please try again or notify the administrator.

And as soon as I saw this I knew instantly why the image didn't work and the page was unstyled. Because the lockdown guide instructs you to remove the /CFIDE/ virtual directory from public-facing sites such as this one. I was curious what it would look like styled, so I briefly added the virtual directory to the site to get a look at it. This was the result:

... marginally better, I suppose. And once I knew that these errors were being served up by ColdFusion, I knew it had to be something I had done as part of the lockdown guide... Except that everything there I was familiar with. Except Secure Profile. Secure Profile is a mysterious setting you can enable during the installer that sets a bunch of settings to more secure default values.

Unfortunately, there's no quick "undo secure profile" toggle, to see if it is causing any problems for you. It just twiddles some knobs. You're capable of twiddling them too, but can't just flip them all like a light switch.

Right, so my hunch is that Secure Profile is causing these error pages. How do I turn them off? I puzzled about this for a few minutes, and eventually decided to read every setting it changes, hoping to find the culprit there. And as luck would have it, I found it pretty close to the top. Items #5 and #6 are Custom missing template error, and Custom site-wide error template. And, as much as I like to harp on Adobe for doing a poor job writing documentation, this page very nicely describes where to find the settings in question ("Server Settings > Settings"). So pop open the CF Administrator and find these settings down near the bottom of the general settings page:

Just empty these values out (or replace them with your preferred error pages) and submit, and you're good to go.

A ColdFusion Community Memeber Needs Your Help

Jared Rypka-Hauer has been a long time contributor to the CF Community. He's been writing -- remember FAQU? CFDJ? He wrote for them both -- and teaching for years. He's been a prolific presence in some CF beta releases (e.g. improving the CF product directly). He's contributed to open source CFML projects like Fusebox 4 and 5, Model-Glue, CFEclipse, Transfer, Reactor, and something called Tartan... whatever that is (reminds me of Trantor). And cf.Objective() is his brainchild.

All of this is to say that Jared has given much of his time and energy to the CF Community, without ever asking for anything in return, for many, many years.

And now he could use our help.

If you can spare a few dollars, every little bit will help. I mean seriously... Can you just sit there and let this little girl have her electricity and heat turned off? I hope not.

Corq: Synchronously Asynchronous Item Processing Queue for Node.js, RequireJS, and the Browser

AKA "How I Spent My Friday Evening" -- Yes kids, life is terribly exciting as an adult. Do grow up faster.

Right, so I made this thing. It's not some pretty 3-axis spinning 3d rendered photorealistic image of Tom Cruise's head made with a single <span> tag and CSS3, but I think it's pretty darn great anyway. I once remarked that spreadsheet features were boring, and then the person next to me piped up that she thought spreadsheet features were great because she hated using POI manually -- and as it turns out, she was right. Making complicated things simple is pretty awesome, even if they aren't spinning spans.

I call it Corq, and basically it's just a queue. But don't close the tab just yet! This isn't your grandfather's queue data structure.

Corq is a queue built for the purpose of separating queueing tasks from their execution, for allowing those executions to run asynchronously while still running task processing in a synchronous and slow manner (maybe "controlled" is a better word choice...), and to make tremendous effort to ensure data is never, ever lost. If task processing fails, or if there's a syntax error, or runtime error, or the network / remote server is down, (and so on...) then instead of losing the task you wanted to process, it's requeued -- it goes to the end of the line.

Corq was born for exactly these requirements in one of my Phonegap applications. Network connections can be ephemeral, servers go down. Heck, sometimes you just screw up the code. By keeping the tasks queued, you could push out an app update that fixes the code error, and any queued tasks that were skipped because of the error will now complete.

The simplest way to use Corq is to drop it into your application like so:

<script src="corq.js"></script>

Note: It's also compatible with RequireJS and Node.js module formats.

Once you've got it loaded up, just create a queue:

var queue = new Corq(5000, 30000);

The arguments are the inter-item delay (5s) and the cooldown delay (30s) written in milliseconds. These are the default values, so if you don't want to change them you can simply write: var queue = new Corq();

Once you've got your queue object, you need to add item-type handlers:

//handle items of type `foo`
queue.on('foo', function(item, success, fail){
    /* handle item */

    if (/* item is successfully processed and can be discarded */){

You can register as many item-type handlers as you like. Just call the .on() method once for each type you want to register.

After your handlers are registered, start the queue:


And then you're off to the races. You can push new data into the queue any time:

queue.push('foo', { foo: 'bar', fizz: 'buzz' });

The first argument to the push() method is the item type, the second is the item data. The item data is what will be passed to your handler method as the item argument.

And all public methods are chainable, too:

var q = new Corq()
   .on('foo', function(){ /* ... */ })
   .on('bar', function(){ /* ... */ })
   .push('foo', { /* ... */ })
   .push('bar', { /* ... */ });


Corq can optionally persist the queue every time it changes, so that data won't be lost if the page reloads, your node app crashes, etc. This does have some implications, but is A Good Thing™.

Here's how you might persist data to / load data from localStorage for a Phonegap app:

var queue = new Corq()
        localStorage.setItem('myQueue', JSON.stringify(data))
        var data = JSON.parse( localStorage.getItem('myQueue') );

Notice that even though getting data out of localStorage is synchronous, it is returned to Corq via a callback. This allows you to use async methods like AJAX or an async database call to load the data, if necessary. No matter what, though, you have to set the data into Corq via the callback -- returning it will accomplish nothing.

I hope you find it useful. I enjoyed writing it, at least; and I'm quite happy to have the app from which this idea was born cleaned up.