Author Archive

Using Bootstrap UI pagination links with jQuery Cycle Plugin

Written by jbriccetti on . Posted in App Dev

jQuery Cycle Plugin is a very popular “slider” widget that’s been around for many years. So long, in fact, that many of my old apps use it. Like, they’re pretty old now.

In those old days, I used jQuery UI for styling and while that had it’s challenges, it was easy to make the pager controls take on the themed “button” look:

 

jquery-cycle-jquery-ui-styling

<script type="text/javascript">
  $(document).ready(function() {
    $('.slideshow').cycle({
      fx: 'fade' // choose your transition type, ex: fade, scrollUp, shuffle, etc...
      ,pager:  '#pager'
      ,activePagerClass: "ui-state-highlight"
    });
    $("#pager a").addClass("ui-button ui-state-default");
  });
</script>

The ease of this, as you can see is that you simply have to setup all the link items that the cycle plugin builds in the pager div as “ui-button” and “ui-state-default” and then specify the active class for each one to be “ui-state-highlight”. An important thing to note is that structurally, the pager is just a bunch of anchor tags inside a div. That is as simple a structure as you can cook up. The pager div just starts out like this:

<div id="pager"></div>

For Bootstrap, the Pagination Widget is sweet, but requires a (better) more structured DOM – the link items have to be constructed using <li>’s; That’s not how jquery Cycle works, by default, but that’s easy enough to configure with the option (callback) pagerAnchorBuilder:

jquery-cycle-bootstrap-styling-1

<script type="text/javascript">
  $(document).ready(function() {
    $('.slideshow').cycle({
      fx: 'fade' // choose your transition type, ex: fade, scrollUp, shuffle, etc...
        ,pager:  '#pager'
        ,activePagerClass: "active"
        ,pagerAnchorBuilder: function(idx, slide) { 
          return '<li><a href="#">'+(idx+1)+'</a></li>'; 
        } 
      });
    });
</script>

So here, we’re “manually” constructing each pager item to take on the structure of an anchor tag inside of  a list item. With this, we setup the pager with a little more structure:

<div class="pagination pagination-small">
  <ul id="pager"></ul>
</div>

So far, so good. But here is the tricky part. We want to now use the bootstrap styles to make the “active” slide in the pager look, well, active (like we used “ui-state-highlight” in the jQuery UI example). That’s a little harder to do. as you can see from the above code & screenshot, just setting the activePagerClass option isn’t enough. The reason why this doesn’t work is because the cycle plugin will apply that style to the anchor tag, not the <li> tag. With Bootstrap’s Pagination widget, we need to apply it to the <li>.

{Enter Sandman Music} Checkout the option listed (1) up from the bottom on the jQuery Cycle options reference page. The updateActivePagerLink callback allows us to tweak how the class is applied, just like we were able to tweak how the pager link was built using the pageAnchorBuilder. The result?

jquery-cycle-bootstrap-styling-2

<script type="text/javascript">
  $(document).ready(function() {
    $('.slideshow').cycle({
      fx: 'fade' // choose your transition type, ex: fade, scrollUp, shuffle, etc...
        ,pager:  '#pager'
        ,pagerAnchorBuilder: function(idx, slide) { 
          return '<li><a href="#">'+(idx+1)+'</a></li>'; 
        }
         ,updateActivePagerLink: function(pager, idx){ 
          $(pager).find('li').removeClass('active').filter('li:eq('+idx+')').addClass('active'); 
        }
      });
    });
</script>

2 Important (Overlooked) Features of ColdFusion 9

Written by jbriccetti on . Posted in App Dev

Recently I was chatting with someone on our dev team and I realized that not everyone is as heads-down, buried in ColdFusion every day like I am. New features come and go (do they go?) and we latch on to what we can, when we need it. But depending on what you were doing back when CF9 released, you may have missed these. Yes.  these are old features already (4 years)  but real nice features just seem to slip through without being harnessed. these are (2) big deal items I see overlooked that you really should use:

local variables in functions

We all know about using the var keyword to declare local variables. if you don’t already know, look it up. In CF8, we had to do all these var declarations at the top of the function. Pain in the ass. someone kick the compiler guy/gal.

Leave it to our CF community to come up with a brilliant solution that is one of the more elegant “standards” I’ve seen evolve in the CF world (along with init() pseudo-constructors). All ya gotta do is add this code at the top of every function:


var local = {}; // structNew()? get hip, use the squirrelly brackets!

Then, in your function code when you need a local variable, just use local.

what sucked? well, you have to use local. prefixes on all your local variables which is particularly lame with an lcvs (loop control variables), like i,j,k etc… sometimes you’d see folks declare these as local separately just so they could reference it using #i# or the like.

Overall, nice solution. but that was pre 2009; (eh hem, 4 YEARS AGO) – what’s the gig with CF9?

First of all, in CF9 we can declare a var anywhere in the function. ’bout time. the compiler guy/gal got the message. but that’s only half the story.

Them Adobe folks also made an implicit local scope in all functions, called… (wait for it, wait for it… drumroll) local. Yea, they scarfed the “standard” and rolled it in. nice job Adobe (i don’t say those words too often these days, so I had to throw it in). Well, anyway, what are the perks to this new scope? (2) things:

  1. You don’t have to declare the local structure at the top of the function. it’s already there (but if you do, it’s backwards compatible, so no worries)
  2. You don’t have to reference the local variables using local. once they are initially set in the local. scope, you just reference them directly and they are found in the scope chain

thus:


for(local.i=1;i<10;i++){
writeOutput(i); // works like a charm
}

Implicit setters and setters

Here’s one i didn’t figure out until i had to teach a class in ColdFusion 9 – ColdFusion allows you to add implicit getters and setters with one easy attribute to the <cfcomponent> tag: accessors=”true”

of course Ben Nadel crawled behind the dashboard to check the wiring on this – pretty cool experiment he did too. At the end of the day it’s not a huge deal, but here’s whay I like it. If forces me to do things “the right way” and it makes it easy. That’s pretty much what CF is all about.

Mike Pacella, one of our CF/Java ninjas got me in the habit of using getters() and setters() a lot – it seems a bit uptight sometimes and quite frankly, you dont have to do it for everything – but if your talking about instance properties on an object, well, yeah, you probably should. but it’s a hassle to write getters and it feels like a waste of time when those methods just get and set. I write enough code, i dont need to do more. shut up, I know i can use snippets or generators, or whatever. I do. it’s still a pain in the ass.

so here’s the layup – you add accessors=true to the <cfcomponent tage and all your properties have getters and setters available by default. AH BUT WAIT how the hell does the compiler know what the run-time instance properties will be. this is ColdFusion, we don’t declare those things to our compiler. This is the other thing i love about this feature – we  actually use <cfproperty and now, its a tag that’s actually used by the compiler ISO just being a documentation scrap. I’m a bit of a documentaiton nut, so I like the idea that if I create this tag and thereby write documentation for my doc engine parser, I’m also writing code that is doing something – in this case defining properties for the implicit getters and setters. putting this all togther,  here’s a little cfc code you might see:


<cfcomponent accessors="true">
<cfproperty name="Globals" type="struct" hint="the global variables, by reference." />

<cffunction name=”init” access=”public” returntype=”obj”>
<cfargument name=”globals” required=”no” default=”#{}#” hint=”reference to global variables” />
<cfscript>
setGlobals(globals);
</cfscript>
<cfreturn this>
</cffunction>
</cfcomponent>

so that’s it. if you wanna mess around with it, here’s some code.

Singletons Business Objects in CFWheels

Written by jbriccetti on . Posted in App Dev

Like many application development frameworks, there is lots of plumbing within that you don’t have to use, but hey, it makes a ton of sense. Singleton object management is a good use case.

Now let’s be clear, I could add something like ColdSpring to offload my object factory pattern to a separate  framework – that often makes sense, but depending on the client and how encapsulated you want to keep things, sometimes just a good clean way to do it on your own makes the most sense.

So we want to make instances of a component and keep these instances around beyond a request. In CFWheels, what’s the best way?

As it turns out, the answer is mind-bogglingly simple – but we have to consider (2) things:

  1. Where do we create the object instances?
  2. How will we be able to reference them?

In straight-up ColdFusion (no framework), we have Application events like onRequestStart, onSessionStart, OnApplicationStart & onServerStart that answer question#1. As for how to reference them, well, that’s easy too – we can just use the “scope” of choice for the persistence – “request, session,application or server” and your done. Of course you may need a trigger to “refresh” the cached instances (now you’re adding some plumbing). Here’s the “old school” way of handling this (or at least the non-framework way)

<cffunction name="onApplicationStart" returntype="boolean" output="false">
	<cfset buildCache() />
	<cfreturn true />
</cffunction>

<cffunction name="onRequestStart" returntype="boolean" output="false">
	<cfif structkeyExists(url,"reload")>
		<cfset onApplicationStart() />
	</cfif>
	<cfreturn true />
</cffunction>

<cffunction name="buildcache" hint="I'll build the app cache of singletons">
	<cflock scope="application" type="exclusive" timeout="10">
		<cfset util = createObject("component","lib.util.widget").init() />
	</cflock>
</cffunction>

But with CFWheels, we really should leverage the framework and not worry about micro-managing these events (although we certainly can if we want to get that granular) – so check it out. Answer #1: config/settings.cfm Answer#2: use the CFWheels set() function:

<cfscript>
	set(util= createobject("component","lib.util.widget").init());
</cfscript>

The Beauty of this solution is that settings.cfm only fires when the application loads (or reloads) – essentially (but not identical to) the onApplicationStart event. Secondly, to provide visibility of our variable anywhere in the application, using the set() function allows us to access the variable by using the get() function

<cfscript>
	util = get("util");
</cfscript>

please note: This solution is specifically for application singletons – behind the scenes, CFWheels is using the application scope for these settings – in fact, the documentation on config/settings.cfm explicitly states this file is for configuration – which is in fact a good use case for application level persistence, but not the only use case. Singleton (Business) Objects are also perfectly viable candidates for this same sort of persistence.

 

User Input, Part 1 – Encoding

Written by jbriccetti on . Posted in App Dev, Gotchas

The Problem

Security 101 – ensure you are implementing input validation to prevent XSS. From the OWASP Top 10 Attack Vector #2

You need to ensure that all user supplied input sent back to the browser is verified to be safe (via input validation), and that user input is properly escaped before it is included in the output page. Proper output encoding ensures that such input is always treated as text in the browser, rather than active content that might get executed.

Example 1: outputting request parameters

<cfset form.name = "Jon" />
Thank You, <cfoutput>#form.name#</cfoutput>

In the above example we are setting the form field “Jon” But if we collect the value from a user (like forms normally do), AND if  the user supplied the name as follows:

<cfset form.name = "<script>document.location='http://en.wikipedia.org/wiki/Cross-site_scripting'</script>" />
Thank You, <cfoutput>#form.name#</cfoutput>

What happens when the output gets “displayed” to the screen? What happens is an instruction is executed by the browser! The script instruction redirects the browser to wikipedia. Imagine if that website was Evil. Really Evil. We’re not talking “the diet coke of evil” or the “margarine” of evil, we’re talking Real Evil. Bad news for your browser.

So we have to figure out a way to tell the browser not to treat these characters as instructions? But before we try to figure out how to do that, what characters are we talking about?

 

character encoding
 <  &lt;
 >  &gt;
 “  &quot;
 ‘  & #39;
 &  &amp;

The bracket characters you already know are characters that can embed a <script> tag into a page. These are big naughty characters. Big. Naughty.

But what about the ” and the ‘ character? Well, checkout this example:

<cfset form.name = 'Jon" onMouseOver="javascript:alert(document.location);"' />
<input name="name" type="text" value="<cfoutput>#form.name#</cfoutput>" />

So it’s pretty obvious where this is going. Any characters that are used for markup should be encoded, lest they be used for big naughty things. Or small naughty things for that matter.

The solution (or at least a solution)

The simplest of solutions is encoding the data on the way out (when sent to the browser). So in the above examples, if we were to simply squeeze our output through the built in ColdFusion function xmlFormat(), we’re good to go:

<cfset form.name = "<script>document.location='http://en.wikipedia.org/wiki/Cross-site_scripting'</script>" />
Thank You, <cfoutput>#xmlformat(form.name)#</cfoutput>

<br />
<cfset form.name = 'Jon" onMouseOver="javascript:alert(document.location);"' />
<input name="name" type="text" value="<cfoutput>#xmlformat(form.name)#</cfoutput>" size="100" />

 

Next Steps:

In part duex, we’ll look at a slight drawback to using the xmlFormat() function. Also, we’ll examine an approach to encode the input on the way in. Finally, we’ll look at filtering input to wipe out any other characters that are used for naughty purposes, such as tabs, carriage returns and other non printable characters. Until then, stay safe…

 

 

Distracto-boy meets layout=plain

Written by jbriccetti on . Posted in App Dev, Architecture, Misc Ramblings

I’m a huge fan of UI frameworks – particularly Twitter Bootstrap and jQuery UI – and I love making things look great – these frameworks really help me do that. Basically, I’m a wannabe designer. I admit it.

A simple bootstrap-infused login form

a bootstrap styled list view

Some days, i just spend way too much time on getting those buttons, just right, or the right table or grid layout – it can be a time-sucker and I sometimes find myself behind on a deadline because I spent too much time pushing around the UI and not enough time building the “application” code. Enter: layout=plain.

In the CF Wheels framework, a Rails-like approach to CFML development, the base controller class (/controllers/Controller.cfc) has an init method where most folks handle all the pre-processing needed for all requests. We scaffold our CF Wheels apps from our  TroyWeb1 base-build – which includes a “filter” in the base controller to handle  initialization and cleansing of request parameters as well as setting up defaults for the built-in params used by wheels for layout and format.

<cfscript>
	firewall();
	cleanseAndStrip(params);
	param name="params.format" default="html";
	param name="params.layout" default="";
	switch(params.layout) {
		case "plain":
			usesLayout("/plain");
			break;
		default:
			usesLayout("/bootstrap");
	} //end switch
	if(params.format EQ "xml" || params.format EQ "json"){
		get("cfsetting").setEnablecfoutputonly(true);
		get("cfsetting").setShowdebugoutput(false);
		set(showDebugInformation=false);
	}
</cfscript>

Like most app dev frameworks, CF Wheels leverages a front controller design pattern. That means all requests get routed through the same initial channel and that means certain things can easily be managed in that initial routing – like format and layout, which in CF Wheels are parameterized so the request can dictate what format needs to be returned. This is really great in the world of JSON feeds or other syndication streams. Thus, add ?format=json to the url and the plumbing to route your call to a json generating view is all built in. [checkout provides()] Layouts are managed this way too when combined with the usesLayout() controller method.

If you too are mesmerized by the shiny, candy-like buttons, join Distracto-boy in the fight. Create /views/plain.cfm with one line of code:

<cfoutput>#includeContent()#</cfoutput>

and simply change the default for params.layout to “plain”

	param name="params.layout" default="plain";

and there ya go. Badabing! all those distractions are gone and you can focus on creating the app without all that glitter.

layout=plain rendering of the same form

layout=plain on the same list view

No daddy

Written by jbriccetti on . Posted in Gotchas, Misc Ramblings

I was in the fray when a few clients called me today to say “help, the website is down” – it seemed odd a few sites were down, others weren’t. of course trying to get o the websites that were experiencing problems, well i just got nuthin’ – no error message back from the webserver or anything. seemed odd.

I saw the webserver instances were up so i added host headers for the IP quickly, just to see if i could get traffic routed there – and it worked – so i knew immediately it was a dns issue – and that’s when i discovered go daddy was down for the count.

 

$createNestedParamStruct is a cfwheels badass

Written by jbriccetti on . Posted in Misc Ramblings

One of the nice things about the cfwheels framework is the ability to build forms that map directly to a model object using form helpers. On the “receiving” end (in your controller), you have access to a key in the params scope that is a nested structure of data that’ll line right up with your model. This stuff makes scaffolding CRUD forms a serious layup.

#select(label="org", objectName="contact", property="org_id",options=orgs, valueField="org_id", textField="org_name",includeBlank="Select an Org")#

Recently, I have been working on a standard set of scaffolding templates to take the CRUD generation to a whole new level. Along with a few methods in the base controller (and some helper methods for the view) I’ve worked in generic code to include pagination, column header sorting and filtering in all the generated templates. While I was working on the filter controls, I realized I’d seriously like to have a nested param structure with all the filter fields contained within. But the form helpers are specifically for mapping fields to a model object, and I’m not doing that. So I looked further into how wheels constructs those nested params for the form helpers and low-and-behold, i found a simple little function that when used with the right naming convention, tears it up on the form-field parsing front. And, it’s called on every request automagically, so you aint gotta do nuthin to make it work. Schvinnnng!

Looking inside /wheels/dispatch/request.cfm i found the $createNestedParamStruct() method. After discovering how it expects and parses field names, i then reverted back to my filter form and started naming fields like this:

#selectTag(label="type",name="filters[label_id]", options=labels,textfield="label_description",valueField="label_id")#
#selectTag(label="org",name="filters[org_id]", options=orgs,textfield="org_name",valueField="org_id")#
#selectTag(label="contact",name="filters[contact_id]", options=contacts,textfield="full_name",valueField="contact_id")#

Notice I’m not using the objectName or property arguments to the selectTag function (like we did in the select(0 function for the model object mapping) – selectTag doesn’t tie the form field to a model “object” But, by using the [] notation on the field name, wheels automatically creates a sub-structure in the params scope when the post occurs… so by the time I can even get my hands on these any of these params in the controller, it’s already neatly encapsulated in a sub-structure named “params.filters”

dump of params.filters

cfsetting in cfscript

Written by jbriccetti on . Posted in App Dev

Obsessed with converting much (but not all) of my CFML to <cfscript />, I recently discovered there is no <cfscript /> equivalent for the <cfsetting /> tag.  Of course, there is always a way…

CFML

<cfsetting enablecfoutputonly="true" />
<cfsetting requesttimeout="60" />
<cfsetting showdebugoutput="false" />

<cfscript />

<cfscript>
    createObject( "java", "coldfusion.tagext.lang.SettingTag" ).setEnablecfoutputonly(true);
    createObject( "java", "coldfusion.tagext.lang.SettingTag" ).setRequestTimeout(javaCast( "double", 60 ));
    createObject( "java", "coldfusion.tagext.lang.SettingTag" ).setShowdebugoutput(false);
</cfscript>

 

More Fun with ColdFusion & Spreadsheets

Written by jbriccetti on . Posted in App Dev

I do like spreadsheets. They’re basically glorified csv files and talk about the lowest-common-denominator for data – I’m pretty sure after the nuclear holocaust, the last two things left on earth will be cockroaches and data stored in spreadsheets…

There are many ways to work with spreadsheets, but it’s not uncommon to be pulling data into ColdFusion queries, massaging the data, and then stashing it. This is the sort of utility script work that I get asked to do on client sites like it’s my job. Oh, wait… yeah yeah…

Like most data structures, ColdFusion queries are great for some jobs and stink for others. But then there are things about queries that should work well but they simply don’t. If you have ever tried to generically output a query and you used the “queryname.columnlist” property, you know what I’m talking about. That column list is in alphabetic order, not in the order it appeared in a select statement, or in this case, in the order of the spreadsheet columns. Oh, and its translated to upper case, which is seriously ugly. This is not always a problem, however, when working with spreadsheets, it often is. Spreadsheet users usually put their columns in an order for a reason – and if you are working with a script to read a spreadsheet into a query, do a little dance and then write a new spreadsheet back out, generically (i.e. without hard-coding the column names in your script) – then using that columnlist property for the headers in the output spreadsheet is trouble.

Solution? use the getmetadata function on your query to get an array of structs that describe the columns in the query – and yes, that’s an array, which means ordered, in this case from left-to-right in the spreadsheet. Nice! Also, the case of the values is completely preserved. Extra Nice!

One trick is that you now have an array of structs and what you usually want (for your output to the spreadsheet) is just a common-delimited list of the column names. The column names are all in the key “name” in each structure item in the array. Oh, look what i found (and by found i mean wrote)  http://www.cflib.org/udf/arrayofStructsToList

So, drop that <cffunction /> into a page and sprinkle in some of this sample code:  note, you’ll also need a source xls file

<cfscript>
    fpath = expandPath(".");
    sep = request.vars.sep;
    source = listappend(fpath,"source.xlsx",sep);
    dest = listappend(fpath,"dest.xls",sep);
</cfscript>
<!--- pull the source spreadsheet into a query object --->
<cfspreadsheet action="read" src="#source#" query="q" headerrow="1" rows="2-9999" />

<cfoutput>ugly stuff:#q.columnlist#</cfoutput><br />
<cfoutput>much better:#arrayofStuctsToList(getmetadata(q),'name')#</cfoutput><br />

<!--- image you wanted to modify the data and do some calculations --->
<cfset queryAddColumn(q,"check",[]) />
<cfloop query="q">
    <cfscript>
      isok = "BAD";
        // do whatever you need to do here
        if (true) isok = "OK";
        querySetCell(q,"check",isok,currentrow);
  </cfscript>
</cfloop>

<!--- note the newly created column comes back in both calls. thats good! --->
<cfoutput>ugly stuff:#q.columnlist#</cfoutput><br />
<cfoutput>much better:#arrayofStuctsToList(getmetadata(q),'name')#</cfoutput><br />

<!--- create an output spreadsheet for the new data  --->
<cfset out = spreadsheetNew()>
<!--- Add header --->
<cfset spreadsheetAddRow(out, arrayofStuctsToList(getmetadata(q),"name"))>
<!--- format header if you like --->
<cfset spreadsheetFormatRow(out,{bold=true},1)>
<!--- drop in the data --->
<cfset spreadsheetAddRows(out, q)>
<cfset spreadsheetWrite(out, dest, true)>

Bugs with reading spreadsheets from ram:// disk

Written by jbriccetti on . Posted in App Dev

So this week I had to create a utility to whip together a few spreadsheets, zip them up and provide a download link.There are (2) good reasons (and probably more) to use the RAM disk for storing the files during the processing ISO traditional disk:

  1. Disk bloat: One of the challenges with these sorts of utility apps is orphaned files on the server and after a few months, years, disk space gets scarey. Of course we can clean up the files with a <cfdirectory action=”delete” /> but there are times when you simply can’t rely on that – an error may halt processing, the code to cleanup may not fire and there are those nasty little orphans again! Oh, and then there is the “I’m really lazy” part of programming that, during development, when I’m aborting processing all over the place (for debugging purposes) – well, i just don’t want to see all those files getting orphaned…
  2. Performance: Disk I/O is slow, memory allocation is fast. ’nuff said.

ColdFusion 9 introduced the ram disk – basically, a “virtual”disk drive that CF treats like a regular disk system: You can write, read, delete,  even <cfinclude />. Anyway, use “ram://” as the “drive” specification and create *nix style paths and you are all set.

What are the cons? Well, the ram disk is volatile – if the server reboots it’s all gone. There are some other limitations, like how much ram it will tie-up and the (lack of) restrictions on who can access what (it doesn’t use traditional O/S ACLs). But for what i needed, it was perfect.

And so life was good. I was cranking out the spreadsheets (by copying existing templates) and was able to zip them up and deliver them through <cfcontent /> just fine, and dang fast. Then I went back and tried to actually access the spreadsheets after i copied them, to update some data in them before creating the zip. That’s when I hit this little snafu.

It appears that when you write a spreadsheet to the ram disk, ColdFusion cannot access it through the spreadsheet functions or the <cfspreadsheet /> tag. I guess I’m not surprised – I’m not sure what (java) utility CF is using under the covers to access the spreadsheets, but i suspect the drivers cannot accept a ram disk file path. Bummer.

Back to using disk and hoping like hell my cleanups do their thing…

here is a sample code you can run to see it yourself:

<cfscript>
sep = createObject("java", "java.lang.System").getProperty("file.separator");
folder = "AF2E3351-1422-52FB-568E3B79A02D455F";
disk = {"dir" = "#expandpath('./')##folder#","list"="","fname"="","spreadsheet"="","err"="no errors"};
ram = {"dir" = "ram://#folder#","list"="","fname"="","spreadsheet"="","err"="no errors"};
if(NOT directoryExists(ram.dir)) directoryCreate(ram.dir);
if(NOT directoryExists(disk.dir)) directoryCreate(disk.dir);
source = listAppend(expandpath("./"),"template.xlsx",sep);
disk.fname = listAppend(disk.dir,"spreadsheet.xlsx",sep);
ram.fname = listAppend(ram.dir,"spreadsheet.xlsx","/");
fileCopy(source,disk.fname);
fileCopy(source,ram.fname);
ram.list = directoryList(ram.dir);
disk.list = directoryList(disk.dir);

try{
	disk.spreadsheet = spreadsheetRead(disk.fname);
}
catch(any e){disk.err = e.message;}

try{
	ram.spreadsheet = spreadsheetRead(ram.fname);
}
catch(any e){ram.err = e.message;}

writedump(disk);
writedump(ram);
</cfscript>