Thursday, 2 August 2007
Single Quotes & Query of Query
"Query of Query" really doesn't cope very well with that.
CF automagically escapes them with 2 single quotes ('') and then any where clause doesn't find them. Not very useful.
If you use preservesinglequotes, the query is syntactically incorrect. So you get an error. Also, not very useful.
However, if you replace each single quote with 2 single quotes you end up with a param that looks like this 'O''''Reilly'. Somewhat bizarrely, that works a treat.
So, if you want to search for O'Reilly and his mates (from parameter searchValue) using Query of Query, you need to do this: -
#replace(ucase(searchValue),"'","''","all")#
That's rather horrible to read, isn't it. So to make it readable (by adding a bunch of spaces): -
#replace(
ucase(searchValue),
" ' ",
" ' ' ",
"all"
)#
But obviously, you don't want the spaces there in reality.
So there you go. Query of Query is completely mental.
Dave
Wednesday, 18 July 2007
Boy sent £44,000 in eBay parcel
"Result", you might think.
But no! He phoned the police instead. I bet he does always his homework and is never home late either!
More here -> bbc news article
Wednesday, 11 July 2007
Fun with Helium Balloons - Economy Class
Sounds like fun...
more ->
Tuesday, 10 July 2007
It's Snowing in Buenos Aires!
Temperatures plunged to -22C (-8F) in parts of Argentina's province of Rio Negro, while snow fell on Buenos Aires for several hours on Monday.
Two deaths from exposure were reported in Argentina and one in Chile."
I'd just like to take a moment to say "huh?"
See full article on BBC News
Thursday, 5 July 2007
Live in a cave. Missed opportunity!
After all the times I've threatened to give it all up and go live in a cave somewhere I really missed the ball there *sigh*
Hermit heaven.. Photo's here :-
The £25,000 cave home
Big garden too... (according to the Beeb it sold for 100k)
Wednesday, 4 July 2007
It's a bit irritating in many ways (mostly the "I didn't think of it first" way) but kinda funky. It may steal your life though...
Want to find me on Facebook? Just search for Dave Cozens - I'm the one with the smoking monkey.
Missing, presumed missing...
I'll try to remember...
Dave
Strong Encryption in MX7
I needed to encrypt some data to transfer a user to another system using a specified encryption algorithm where the service provider has supplied both the key and the initialisation vector.
Documentation is limited at best, but after beating my head against ColdFusion and Google I finally got it to work.
And it's good to share, so here we go...
1. First you need to get the Sun Unlimited Strength Jurisdiction Policy Files for Java (SUSJPFJ?)
You can get these from http://java.sun.com/j2se/1.4.2/download.html. Unzip jce_policy-1_4_2-1.zip into {jre}\lib\security\ - but it's probably a plan to back it up first. Restart CF. You'll have to restart it again in a minute, but softly softly catchy monkey...
2. Next Stop - BouncyCastle
Go and get the latest 1.4 release of the BouncyCastle service provider files from http://www.bouncycastle.org/latest_releases.html
Now you have to edit runtime\jre\lib\security\java.security to include the new service provider. Assuming that you currently have the default 5 service providers, add the following immediately below: -
security.provider.6=org.bouncycastle.jce.provider.BouncyCastleProvider
Restart CF again. You should be ready to go.
3. An Example
It would be mean to get you this far without some example code. So here goes.
Inline CFML:
<cfset encryptionKey =tobase64("1BF03AB0CEF0AB4A7E793CE0")>
<cfset algorithm ="AES/CBC/PKCS7Padding">
<cfset initialisationVector = "C7D9769F6F261A41">
<cfset encrypted = Encrypt(stringToEncrypt, encryptionKey, algorithm, "Hex", initialisationVector)>
CFSCRIPT
stringToEncrypt = "ooh, ooh, it's a bit secret";
encryptionKey = tobase64("1CF03CF0CEF1CF4A7E733CE0");
algorithm = "AES/CBC/PKCS7Padding";
initialisationVector = "C6D3799F1F111A41";
encrypted = Encrypt(stringToEncrypt, encryptionKey, algorithm, "Hex", initialisationVector);
Tuesday, 20 February 2007
Using GetTickCount() More Effectively in ColdFusion
I needed something to measure performance of sections of code, possibly sections spanning multilpe templates. I needed it to report in a helpful way. So I knocked together Daves Tick Counting Machine (tm).
It enables you to drop 2 lines of code in with existing code to start performance measuring (first line=start, 2nd lin=stop, like a stopwatch).
It gives you a nice sequential, nested output at the end. And it lets you display the results either on screen, to a log file, or both.
Here's the code: -
In application.cfm: -
<cfset request.tcm=createObject("component","DavesTickCountingMachine").init(enabled=true,outputToScreen=true,outputToLog=false)>
To start/stop monitoring: -
<cfset request.tcm.toggleCounter("Counter Name")>
To view output: -
<cfoutput>#request.tcm.report()#</cfoutput>
DavesTickCountingMachine.cfc: -
<Cfcomponent name="davesTickCountingMachine" hint="Provides a method of recording performance data">
<cffunction name="init" hint="creates the tick counting machine">
<cfargument name="enabled" default="true" type="boolean" hint="Turns the TCM on (true) and off (false)">
<cfargument name="outputToScreen" default="true" type="boolean" hint="Turns the TCM screen output on (true) and off (false)">
<cfargument name="outputToLog" default="false" type="boolean" hint="Turns the TCM csv file output on (true) and off (false). File is saved in root of calling file.">
<cfset this.enabled=arguments.enabled>
<cfset this.outputToScreen=arguments.outputToScreen>
<cfset this.outputToLog=arguments.outputToLog>
<!---holds performance data--->
<cfset this.TCM=structNew()>
<cfset this.seq=0>
<Cfreturn this>
</cffunction>
<cffunction name="toggleCounter" hint="Start or Stop timing an item">
<Cfargument name="counterName" hint="The unique identifier for the section of code being analysed">
<cfset var whatTimeIsIt=getTickCount()>
<cfif this.enabled eq "true">
<cfset request.seq=this.seq+1><!--- increment seq no--->
<Cfif not structKeyExists(this.TCM,arguments.counterName)>
<!--- if the counter doesn't exist, create a new struct--->
<cfset this.TCM[arguments.counterName]=structnew()>
<cfset this.TCM[arguments.counterName].start=whatTimeIsIt>
<cfset this.TCM[arguments.counterName].seq=this.seq>
<cfset this.TCM[arguments.counterName].name=arguments.counterName>
<cfset this.TCM[arguments.counterName].stop=0>
<Cfelseif this.TCM[arguments.counterName].stop eq 0>
<!--- it's an existing counter, so this must be the end time--->
<cfset this.TCM[arguments.counterName].stop=whatTimeIsIt>
</Cfif>
<Cfelse>
<!--- it's turned off. return fast--->
<Cfreturn "">
</cfif>
</cffunction>
<cffunction name="report" hint="Returns the analysis report" output="true">
<cfif this.enabled eq "true">
<style>
.tcm{
background:##eeeeee;
padding:5px;
margin:5px;
background-repeat:no-repeat;
border:1px solid navy;
}
</style>
<!--- calculate total times --->
<Cfloop collection="#this.tcm#" item="fn">
<Cfif structKeyExists(this.tcm[fn],"start") and structKeyExists(this.tcm[fn],"start")>
<cfset this.tcm[fn].time=this.tcm[fn].stop-this.tcm[fn].start>
<Cfelse>
<cfset this.tcm[fn].err=true>
</Cfif>
</Cfloop>
<cfset tickData=arrayNew(1)>
<Cfloop collection="#this.tcm#" item="fn">
<!--- build an array so we can sort the data --->
<cfset log="">
<cfset log=structNew()>
<cfset log.fn=fn>
<cfset log.seq=this.tcm[fn].seq>
<cfset log.time=this.tcm[fn].start>
<cfset log.action="start">
<cfset arrayAppend(tickData,log)>
<cfset log="">
<cfset log=structNew()>
<cfset log.fn=fn>
<cfset log.seq=this.tcm[fn].seq>
<cfset log.time=this.tcm[fn].stop>
<cfset log.action="stop">
<cfset arrayAppend(tickData,log)>
</Cfloop>
<cfset MovedSomething=1>
<!--- now sort the data so it can be represented in the order it actually happened--->
<Cfloop condition="MovedSomething eq 1">
<cfset MovedSomething=0>
<Cfloop from=2 to="#arraylen(tickData)#" index="i">
<cfset leftItem=tickData[i-1]>
<cfset rightItem=tickData[i]>
<cfif leftItem.time gt rightItem.time>
<!--- if first item started after 2nd, then swap --->
<cfset arraySwap(tickData,i-1,i)>
<cfset movedSomething=1>
<Cfelseif leftItem.time eq rightItem.time>
<!--- They started at same time. --->
<cfif leftItem.action eq rightItem.action>
<!--- they are both the same action --->
<Cfif leftItem.action eq "stop">
<!--- they are both EOF --->
<Cfif leftItem.seq lt rightItem.seq>
<!--- assume that the item that started first, stopped last - i.e. nested --->
<cfset arraySwap(tickData,i-1,i)>
<cfset movedSomething=1>
</Cfif>
<Cfelse>
<!--- they are both SOF --->
<Cfif leftItem.seq gt rightItem.seq>
<!--- move to start seq order--->
<cfset arraySwap(tickData,i-1,i)>
<cfset movedSomething=1>
</Cfif>
</Cfif>
<Cfelseif leftItem.seq gt rightItem.seq>
<cfset arraySwap(tickData,i-1,i)>
<cfset movedSomething=1>
</cfif>
</cfif>
</Cfloop>
</Cfloop>
<!--- display it. nest child processes --->
<cfif this.outputToScreen eq "true">
<div class="tcm" >
<div style="background:navy;color:white;padding:5px;">Dave's TickCounting Machine (tm)</div>
<div style="float:left;">
<Cfif arrayLen(tickData) neq 0>
<cfset base=tickData[1].time-1>
<cfset depth=0>
<TABLE>
<Cfloop from=1 to="#arrayLen(tickData)#" index="i">
<Cfif tickData[i].action eq "start"><cfset depth=depth+1></Cfif>
<tr>
<td>#repeatString(" ",depth)##tickData[i].fn#</td>
<td>(#tickData[i].action#)</td>
<td align=right>#tickData[i].time-base#ms</td>
</tr>
<Cfif tickData[i].action eq "stop"><cfset depth=depth-1></Cfif>
</Cfloop>
</TABLE>
<Cfelse>
No data was recorded for this request
</Cfif>
</div>
<div style="float:left;padding-left:20px">
<strong>How's It Work?</strong>
<br><br>
Simple.
<br><br>1. Drop a ##request.tcm.toggleCounter("ID String")## at the point you want to start timing.
<br>2. Drop a ##request.tcm.toggleCounter("ID String")## at the point you want to end timing.
<br>3. Relax - Dave's TickCounting Machine (tm) does the rest...
<br><br>
</div>
<br style="clear:both">
</div>
</cfif>
<cfif this.outputToLog eq "true">
<div class="tcm" >
<div style="background:navy;color:white;padding:5px;">Dave's TickCounting Machine (tm)</div>
<cfset date=dateformat(now(),"dd-mmm-yyyy")>
<cfset time=timeformat(now(),"HH:MM:SS")>
<cfset path_trans=cgi.path_translated>
<cfset url_path=url.path>
<Cfif arrayLen(tickData) neq 0>
<Cfloop from=1 to="#arrayLen(tickData)#" index="i">
<Cfif tickData[i].action eq "start"><cfset depth=depth+1></Cfif>
<cfset logrow="">
<cfset logRow=listAppend(logRow,date)>
<cfset logRow=listAppend(logRow,time)>
<cfset logRow=listAppend(logRow,depth)>
<cfset logRow=listAppend(logRow,path_trans)>
<cfset logRow=listAppend(logRow,url_path)>
<cfset logRow=listAppend(logRow,tickData[i].fn)>
<cfset logRow=listAppend(logRow,tickData[i].action)>
<cfset logRow=listAppend(logRow,tickData[i].time-base)>
<Cffile action="append" file="#expandpath("tcm.log.csv")#" output="#logRow#" addnewline="true" mode="775">
<Cfif tickData[i].action eq "stop"><cfset depth=depth-1></Cfif>
</Cfloop>
TCM Data logged to: <a target="_new" href="tcm.log.csv">#expandpath("tcm.log.csv")#</a>
<Cfelse>
No data was recorded for this request
</Cfif>
</div>
</cfif>
</cfif>
</cffunction>
<cffunction name="deleteLog" hint="Deletes the log file">
<Cffile action="delete" file="#expandpath("tcm.log.csv")#">
</cffunction>
</Cfcomponent>
Monday, 19 February 2007
Rant About The Royal Mail
I ordered a bunch of stuff for my lovely wife for Valentines last week (hello lovely wife!). One of the things was a box with some balloons and some other bits and pieces (just novelty stuff). For fun.
The supplier (http://www.balloonsbypost.com/ - who incidentally have some great gift balloon packages and will bend over backwards to be helpful - and they're a charity too!) duly posted everything off in plenty of time.
Whereupon the Royal Mail decided the best thing to do with a "Next Day, Before Midday" package would be to ship it to the wrong hub, leave it in a corner and deliver it almost a week later.
They finally managed to deliver the package this morning. Rather than the requested last Wednesday. So maybe when they say "next day" they really mean "next monday".
So well done Royal Mail. Thanks very much.
/rant
Website Habits...
This is my daily list... just in case anybody cares...
www.thedailywtf.com
www.ajaxian.com
www.theregister.co.uk
www.bbc.co.uk/news
www.slashdot.org
Right. I'll be off. I've got a bunch of other CF and JS stuff to post later, but I'm going to ration it. If I post it all at once I'll have nothing to talk about...
Cut, Copy & Paste the ColdFusion PageContext Buffer
I've been messing about with some localisation stuff lately and I wanted a way to intercept the ColdFusion output buffer so I could mess with it.
Now I know you can sort of use <CFSAVECONTENT> for that. But it's mildy irritating since it only lets you use it on a single page. You can’t (for example) start it on one template and end it on another. Tsk!
So what I needed was a solution. After much poking things with sticks (metaphorical sticks) I found the answer I was looking for.
I’ve knocked up a CFC that gives the ability to manipulate the contents of the output buffer of ColdFusion exposing the following methods: -
- Cut(item) – Write the buffer contents to variable named item and clear the buffer.
- Copy(item) – Write the buffer contents to variable named item.
- Paste(item) – Past the contents of variable named item into the buffer.
- Get(item) – Get the contents of variable named item
- Put(item) – Update the contents of variable named item
- Clear() – Clear the buffer.
Here’s the code: -
Buffer.cfc
<cfcomponent name="buffer" hint="Tools for messing with the ColdFusion string buffer"> |
So, how do I use this buffer.cfc thing? - Here’s an example
<!--- create the cfc ---> <cfset bufferObj=createObject("component","buffer").init()> <!--- clear the buffer ---> <cfset bufferObj.clear()> <!--- output some text ---> Lorem ipsum dolor sit amet, consectetuer adipiscing elit. <!--- cut the text from the output buffer ---> <cfset bufferObj.cut("firstBit")> <!--- output some more text ---> Lorem Ipsum is simply dummy text of the printing and typesetting industry. <!--- cut the text from the output buffer ---> <cfset bufferObj.cut("secondBit")> <!--- Retrieve the "secondBit" from the cfc, bold all the e characters, update the cfc data---> <cfset tmpText=bufferObj.get("secondBit")> <cfset tmpTextp=replace(tmpText,"e","<strong>e</strong>","all")> <cfset bufferObj.put(tmpText,"secondBit")> <!--- Paste secondBit and firstBit back into the stream - but in reverse order ---> <cfset bufferObj.paste("secondBit")> <cfset bufferObj.paste("firstBit")> |