I'm Back!

The move is over, I've got an internet connection again, and life is
returning to normal.  All in all, the move went pretty well, and
we've pretty much got the house unpacked.  There's some boxes
still lingering, but most of them are stuff that we don't really need
(Christmas decorations, LEGOs, etc.).

I'll eventually fall back
into a routine, hopefully blogging more often, and at least joining in
on the mailing lists again.  But for now, it's playing catch up
for a week and a half of being disconnected from the office.

The Move is Official

Well, the move is officially underway.  Our current house
closed yesterday, we move to Portland tomorrow, and take custody of the
new house Saturday.  Unfortunately we can't get Internet access
until Thursday, so I'll be offline until then, but it's finally
happening, and then we'll be done with this god-forsaken packing
s**t.  ;)

Hope all had/are having good December-ish holidays, and happy new calendar year.  Gotta love PC.

Until next week…

Damn the DevNet META Tag

Once again, I've wasted an appreciable amount of time because of the
friggin' CF7 DevNet META tag, and basically come to the conclusion that
my DevNet subscription was a waste of cash.  I don't use Studio,
just the DevNet licensed CF, and I can't use CF7 in that capacity
because it makes non-HTML requests impossible without building in
special processing to remove the META tag it "helpfully" adds to the
content.

I know that DevNet's dead, but that doesn't change the
fact that I forked out a chunk of change for software that cannot be
used for what I bought it for: a use well within the licensed
functionality.  Not to be a whiner, but this really bugs the heck
out of me.

Quote of the Day

From Sean Corfield's .sig: 

"Progress isn't made by early risers. It's made by lazy men trying
to find easier ways to do something."
– Robert Heinlein

Amen to that.

CFTIMER for CF6

Ever wanted CFTIMER support on CF6?  I hadn't either until this
evening when I needed to some some code and it wasn't going to work to
do my standard start = gettickcount() ... #gettickcount() - start# routine.  So I wrote my own, and thought I'd share.

Drop this in timer.cfm inside your $cfwebroot/WEB-INF/cftags directory:

<cfif NOT thistag.hasEndTag>
    <cfthrow type="MissingClosingTagException"
        message="You must provide an end tag for CFTIMER" />
</cfif>
<cfparam name="attributes.label" />
<cfif thistag.executionMode EQ "start">
    <cfif NOT structKeyExists(request, "__cftimer")>
        <cfset data = structNew() />
        <cfset data.stack = arrayNew(1) />
        <cfset data.results = arrayNew(1) />
        <cfset request["__cftimer"] = data />
    <cfelse>
        <cfset data = request["__cftimer"] />
    </cfif>
    <cfset s = structNew() />
    <cfset s.label = attributes.label />
    <cfset s.depth = arrayLen(data.stack) />
    <cfset arrayAppend(data.results, s) />
    <cfset arrayAppend(data.stack, gettickcount()) />
<cfelse>
    <cfset stoptime = gettickcount() />
    <cfset length = arrayLen(data.stack) />
    <cfset elapsed = stoptime - data.stack[length] />
    <cfset arrayDeleteAt(data.stack, length) />
    <cfset s.elapsed = elapsed />
</cfif>

Next add this block to your $cfwebroot/WEB-INF/debug/classic.cfm
file, around line 450 or so.  It really doesn't matter where, but
I wanted it just above the 'exceptions' block, so that's where I put it:

<!--- fake CFTIMER results --->
<cfif structKeyExists(request, "__cftimer")>
<cfoutput>
    <p class="cfdebug"><hr />
    <b class="cfdebuglge"><a name="cfdebug_cftimer">CFTIMER</a></b>
    </p>
    <table border="1" cellspacing="0" cellpadding="3">
    <tr>
        <th>Label</th>
        <th>Time</th>
    </tr>
    <cfset results = request["__cftimer"].results />
    <cfloop from="1" to="#arrayLen(results)#" index="i">
        <tr>
            <td style="padding-left: #results[i].depth + 1#em;">#results[i].label#</td>
            <td align="right">#results[i].elapsed# ms</td>
        </tr>
    </cfloop>
    </table>
</cfoutput>
</cfif>

That's it.  Just start using CFTIMER in your code, keeping in
mind that only the 'label' attribute is supported, and that it's
required.  I'm not sure about the real CFTIMER, but mine handles
nesting of CFTIMER tags in a graceful manner, indenting child tags like
the 'tree' execution times display does.  Nesting needn't been in
the same file, just any time a CFTIMER is enclosed in another,
regardless of template structure. 

As you can tell, the tag and debugging output make use of a request-scope variable named __cftimer
Hopefully that won't collide with any other variable names in any
applications, but if you get weird results, that might be what's
happening.

edit:
I should note that the tag and debugging output will work equally as
well installed in the custom tag directory of choice.  There's no
real reason to install the tag in the WEB-INF/cftags
directory other than a) for the tag insight in your editor to work
without having to set up a custom tag in it's dictionary and b) to
allow it to work server-wide without interfering with any existing
CF_TIMER tags that may be installed already.

ClearSilver

I'm currently in the process of rebuilding my main app using ClearSilver,
and it's really slick. In a nutshell, it's a presentation layer (view)
for an MVC-style application.  Your controller (the 'C') uses the
model/backend (the 'M') to create a dataset that it passes to
ClearSilver (the 'V') to render the actual page.

This is a good idea for several reasons, the main one being that it
forces a complete separation between your view and your
controller.  It also allows you to hand off your view to some
non-programmers to build using ClearSilver.  They needn't learn
CF, or anything about your application.  All they need is to
understand how to access data from the dataset using a couple very
simple tags.  ClearSilver is also entirely platform neutral. 
It's written as a native C library, with bindings for Java, Ruby,
Python, Perl, C#, and CGI, so you can seamlessly move templates between
any of those environments without needing any changes.  Finally,
it's a good way to allow users of an application to have a very high
level of control over page formatting, without exposing the app to
malicious CF code.  Since ClearSilver templates can only recall
data out of the dataset, the wost they can possibly do is create a
template that is time consuming to process.

In my particular case, it's the last point that really
differentiated it from it's competitors (such as Velocity).  Our
app includes a web CMS as part of it's functionality, and exposing
complete control over the site layout makes for better integration with
existing infrastructure for our clients, without mandating a
significant amount of custom development work.

But enough of that, how does it work?

<cfsavecontent variable="data">
page.title = "My Title"
page.content << EOM
<h1>Hello, World!</h1>
<p>here's a paragraph
</p>
EOM
</cfsavecontent>
<cfsavecontent variable="template">
<html>
<head>
<title><?cs var:page.title ?></title>
</head>
<body>
<?cs var:page.content ?>
</body> 
</html>
</cfsavecontent>
<cfset hdf = createObject("java", "org.clearsilver.HDF").init() />
<cfset hdf.readString(data) />
<cfset cs = createObject("java", "org.clearsilver.CS").init(hdf) />
<cfset cs.parseString(template) />
<cfoutput>#cs.render()#</cfoutput>

Of course, your data sets get a lot more complex than that, as do
your templates.  You can load data sets from files, create them
from strings (as I did above), or build them a field at a time using hdf.setValue(path, value)
Templates are usually stored on the filesystem (so they can include one
another), and you define a template path (like your $PATH at the
shell), which makes customization a snap.  Provide default
templates, and allow people to add custom templates to a directory
that's earlier in the path.

All in all, ClearSilver is a very
functional presentation engine.  Some of the syntax is a bit
obtuse because of all the extra "<?cs" and "?>" bits in there,
but it's very easy to work with.  And best of all, it's
ludicriously fast.  Even with the overhead of having to convert
native CF datatypes (structs, arrays, queries) into HDF, using
ClearSilver instead of CF templates to generate the HTML is still
faster.

If that sounds interesting, I highly recommend checking
it out.  The Java API is somewhat lacking compared to the Python
and C interfaces, but after I implemented a couple of the missing bits,
the guy who wrote it said that he'd put in a bunch of missing stuff
into the next release.  So it should be even more capable when
that rolls out.  Of course, if you don't mind getting your hands a
little dirty, the API is simple to augment on your own.

Moving…

My family and I are finally moving to Portland.  As some of you
know, I've been pursuing gainful employment in Portland for a while
now, and have found it.  Surprisingly, I don't even have to switch
jobs.  I'll continue to work for my current employer, AudienceCentral,
just remotely.  This will work well for them, since I'm a very
valuable asset to the company, and for me, since it'll give me a more
understanding employer during the move and no transition into a new job
during an already chaotic time.

So good news all around, aside from the fact that we now have to
frantically prepare the house for sale, and go through the whole
process of selling, buying, and moving.  But in a few months, we
should be all settled in, and life should return to something akin to
normal.

As a result, don't expect to see to much of my digital
self for a while.  I'll still be inhabiting the CF mailing lists
to some extent, but side projects and the blog (as if I posted much
anyway) will pretty much fall by the wayside.  If anyone does need
me for some reason, a direct email will always get a response, of
course.

Apache/SSL on OSX

I've been running Apache 2 from Server Logistics
on my PowerBook for quite a while now, and never had issues.  But
tonight I needed to set up an SSL host for some testing, and couldn't
get it to work.  Turns out there some weirdness with the SSL mutex
stuff, and there's an easy fix.  Just add

AcceptMutex    flock

to your httpd.conf, and it magically works.  I'm thinking
something to do with the threading and/or cross-process communication
libraries in the OSX kernel, but I really have no idea. 
Regardless, that will allow you to run non-SSL and SSL hosts without
issue. 

cfusion_encrypt/cfusion_decrypt UDFs

I was using cfusion_encrypt and cfusion_decrypt today, and decided that even though they don't appear to be going anywhere, they might at some point, and dealing with it shouldn't be a big deal. I'm also pretty sure that BD doesn't have the functions. So I thought why not write my own?

<cffunction name="fusion_encrypt" output="false" returntype="string">
  <cfargument name="string" type="string" required="true" />
  <cfargument name="key" type="string" required="true" />
  <cfset var i = "" />
  <cfset var result = "" />
  <cfset key = repeatString(key, ceiling(len(string) / len(key))) />
  <cfloop from="1" to="#len(string)#" index="i">
    <cfset result = result & rJustify(formatBaseN(binaryXOR(asc(mid(string, i, 1)), asc(mid(key, i, 1))), 16), 2) />
  </cfloop>
  <cfreturn replace(result, " ", "0", "all") />
</cffunction>
<cffunction name="fusion_decrypt" output="false" returntype="string">
  <cfargument name="string" type="string" required="true" />
  <cfargument name="key" type="string" required="true" />
  <cfset var i = "" />
  <cfset var result = "" />
  <cfset key = repeatString(key, ceiling(len(string) / 2 / len(key))) />
  <cfloop from="2" to="#len(string)#" index="i" step="2">
    <cfset result = result & chr(binaryXOR(inputBaseN(mid(string, i - 1, 2), 16), asc(mid(key, i / 2, 1)))) />
  </cfloop>
  <cfreturn result />
</cffunction>
<cffunction name="binaryXOR" output="false" returntype="numeric">
  <cfargument name="n1" type="numeric" required="true" />
  <cfargument name="n2" type="numeric" required="true" />
  <cfset n1 = formatBaseN(n1, 2) />
  <cfset n2 = formatBaseN(n2, 2) />
  <cfreturn inputBaseN(replace(n1 + n2, 2, 0, "all"), 2) />
</cffunction>

The binaryXOR is a requirement for both functions, but it could easily be inlined out of existance if the extra UDF is a problem. Here's some code to illustrating:

<cfset key = "test" />
<cfoutput>
<table>
<cfloop list="barney,is,damn cool!" index="i">
  <tr>
    <td>#i#</td>
    <td>#cfusion_encrypt(i, key)#</td>
    <td>#fusion_encrypt(i, key)#</td>
    <td>#cfusion_decrypt(cfusion_encrypt(i, key), key)#</td>
    <td>#fusion_decrypt(fusion_encrypt(i, key), key)#</td>
  </tr>
</cfloop>
</table>
</cfoutput>

I'm Back!

Much thanks to Bob Clingan, who pointed out a seemingly unrelated
setting in GMail, my email woes seem to have vanished.  The
culprit was choosing UTF-8 as my outgoing mail encoding, rather than
'default' (which is ISO-8859-1 for me).  Of course, the charset
has nothing to do with the problem, but Google decided UTF-8 messages
should be sent base-64 encoded, while 'default' messages go in plain
text.  No idea why, but fortunately my issue seems to be solved,
as long as I don't need to send any non-latin-1 characters in my email.

Thanks
to everyone who helped me in troubleshooting the issue over the past
few days, and especially to Bob who came up with solution (even though
it was backwards).