Wednesday 30 January 2013

Blatant click bait: ColdFusion 10 Updater 8 is...

G'day
OK, this is a cop-out of an "article", and the title is purposely designed to make you go "huh? Update 8?" (they're only up to update 7 so far).

But I notice there's been a bug raised in the installer for update 8 (update: this bug has since been deleted, so the link is dead), so I guess it's due out any day now. After (hopefully) they iron out the bugs, that is ;-)

Friday 25 January 2013

Survey results: turning a string into an array of characters

G'day:
One of my readers pointed out to me if that if I tarry too long before reporting back on my recent survey about turning a string into an array of characters, then people would lose what little interest they have in the topic. And I admit it's not the world's most interesting topic anyhow. Anyway, I've got 35 responses, so I'll summarise the results.

Thursday 24 January 2013

Bring back named params for <cfprocparam>

G'day
I forgot I was annoyed about this, until I was just reminded about it via Twitter & StackOverflow (no, this is not another gripe about S/O ;-).

Back in the good-old pre-CFMX days, <cfprocparam> used to support named parameters via the dbvarname attribute, eg:

Wednesday 23 January 2013

ColdFusion: Adobe's Ugly Step-child

G'day
Here's an ironic observation that I would have made on Twitter rather than a blog article if the former allowed a reasonable size of message.

I was snooping around the ColdFusion docs website for some stuff on CFScript's try/catch, using Google to search the thing as the internal search engine ain't that great. Anyway, as I was closing tabs in my brower, one of those "would you please fill out our pointless survey to help us gather meaningless info which we will then ignore" surveys. For some reason I fill these things out on sites I regularly go to, so I set about filling this one in.

Tuesday 22 January 2013

Quick survey / quiz: turning a string into an array of characters

G'day:
This is a bit of a random article. In conversation a coupla weeks back, a colleague questioned my approach to converting a string into an array of characters. Not questioned in a bad way, but my approach surprised them.

Anyway, this festered in my head for a coupla weeks, and popped back into it this morning on the train on the way into work.

Monday 21 January 2013

Railo website on Raspberry Pi with a public facing domain hosted at home

G'day:

As promised on Twitter last week, here's Chris's article on getting Railo running on Rasperry Pi.

Over to Chris...



So you are a lucky owner of a sweet Raspberry Pi, you have a typical broadband connection, some ColdFusion language skills and you would like to take advantage of all these things and roll out a little Web site hosted at home, independently from any hosting provider, and make it available to your family, friends and the rest of the world? That's exactly what I've done and I thought I'd share a step-by-step guide on how my stack has been set up so you can give it a try, amend it and/or improve it.


The guide is inspired by an excellent article by Glyn Jackson on running Railo on Raspberry Pi that I found very useful when I started this exciting journey. However, the set-up described below differs slightly as the current version of Raspbian does not allow to install the official Oracle Java JDK and for that reason I'm going to opt for OpenJDK instead. And also, we don't need to worry about the SSH configuration as it's enabled by default in more recent versions of Raspbian.
Another deviation from Glyn's config is using a wired Internet connection rather than WiFi.

Prerequisites

  1. Standard broadband connection with a dynamically allocated IP address
    If you are in the UK, it can be BT, Virgin or any other popular async broadband option (and if you are lucky enough to have an Internet connection with a static IP address, you might want to skip the section covering Dynamic DNS).
  2. A router configurable to forward traffic on port 80 to a machine on the local network
    I tested it with an Apple TimeCapsule and a BT HomeHub but other routers should provide that functionality as well.
  3. Raspberry Pi (Model B) with 512MB of RAM
    I haven't tested it on the 256 model but you might like to do it at your own risk.
  4. An SD card with the Raspian GNU/Linux distribution installed on it
    A step-by-step guide covering this topic can be found on the eLinux site. You will need direct or SSH access to the box with root permissions.

Setup summary

Possible alternatives
HardwareRasbperry Pi 512MB RAM
Operating SystemGNU/Linux Raspbian
JREOpenJDK 1.6Oracle Java provided you are running a soft-float ABI distro (e.g. Debian) instead of Raspbian
Web serverLighttpdNginx
Application serverTomcat 7Jetty, Resin etc.
CFML serverRailo 4 jarsEarlier version of Railo, Open BlueDragon (not confirmed). Adobe ColdFusion is unlikely to run on such limited hardware.
Internet domain providerDNS DynamicThere is a number of alternative free and commercial services

Power

One of the great things about Raspberry Pi is its low power consumption which means having it always on should not ruin your home budget. I'm no expert on the electricity stuff but I'm powering my Pi through a USB cable hooked to the Apple TimeCapsule which acts as our home router and is always on anyway so that means there are two devices plugged to one wall socket. Does this configuration mean a decreased power consumption? I honestly don't know but it's certainly nice to have one extra power socket available.
In my case, the Pi is connected to TimeCapsule with two cables as the wired Internet connection is also coming from it (see the picture below).


Saturday 19 January 2013

ColdFusion: 2 - Cameron: nil

G'day:
You know how I say I like being wrong? Well it's a good thing I like it as I get a lot of practise at it.

14 June 2013

I've just updated the score to be 2-0 because this very same problem just caught me out again, and when googling for the answer, came across this very blog post. Sigh. God I'm thick.


Friday 18 January 2013

ColdFusion: makes hard things easy easy things incomprehensible

G'day:
Now this article is being true to the idea of a blog being a "web log". It's not very interesting, but it logs the high pointnadir of my day, yesterday. You will learn very little from reading this article. If that doesn't sell it to you, I don't know what will!

I got undone by how ColdFusion reports exception types.

How cool are the Railo guys?

G'day:
Just a quick one. Check this out. I was chatting with Adam Tuttle last night about some differences we'd noted in how ColdFusion and Railo seem to implement the hashCode() method for their respective struct implementations.  Here's some code (as per the thread I link to above):

Thursday 17 January 2013

Shorthand struct notation is still buggy (follow-up & repro case)

G'day;
Brad Wood has demonstrated that he is a bit of a star, in that he has concocted a repro case for that bug I mentioned a coupla weeks back.  The repro case is buried down in the comments of that article, but here it is:

Regular expressions in CFML (part 8: the rest of CFML's support for regular expressions)

G'day:

[Copy-and-paste-from-the-previous-article alert!]

The previous sixseven entries in this series discuss what a regular expression is:
And the syntax of the regex engine ColdFusion uses:
Now I have moved on to discuss the specifics of how CFML implements regular expression technology in the language:
This article will cover the rest of the functions / tags in CFML which utilise regular expressions.

Wednesday 16 January 2013

Random (unsuccessful) experiment: recursive JSON

G'day:
This quick experiment arose from a comment on Twitter this morning:

@daccf @ntunney the worst part is that relationships don't get serialized either. Apparently recursion is too hard for them? 
(Todd Sharp ‏@cfsilence)
This was a reaction to a bug about serialising entities which was under discussion.

Tuesday 15 January 2013

Floating point accuracy

G'day:
This is not going to be particularly earth-shattering, sorry.

Yesterday someone asked on my favourite source of militant pedantry (Stack Overflow) how to pass a BigDecimal to POI for a spreadsheet cell value. You'll need to take my word for it, as the original question has been deleted (not sure what to make of that). There's a Google-cached version of it here. I dunno how long google caches stuff for though. The gist of the question text is (this is an abridged version of the original:

Saturday 12 January 2013

Not that it will really matter in the bigger scheme of things...

G'day:
After all the shenanigans on Stack Overflow y/day (more of the same as last time, except a more egregious example), I've decided I can't really support Stack Overflow as a venue for the ColdFusion community to seek help. Stack Overflow is more interested in demonstrating how "good" Stack Overflow is (according to a yardstick I don't agree with) than they are in actually helping people - all people - and that's not something I can get behind.

Thursday 10 January 2013

Regular expressions in CFML (part 7: reFind())

G'day:
The previous six entries in this series discuss what a regular expression is:
And the syntax of the regex engine ColdFusion uses:
So far, I've not really mentioned CFML in any of my examples: I've just dealt with the regex syntax. In this article (update: and the subsequent few) I'll look at the CFML tags and functions which use regular expressions.

The most basic operation one can perform with a regular expression in CFML is to simply check to see if the regex matches anything in a string. This is done with reFind() and its case-insensitive counterpart reFindNoCase(). These functions work exactly the same except for the case-sensitivity, so I'll just dwell on reFind(). Similarly for reMatch() and reReplace() later on: their ~NoCase() counterparts work the same, so other than identifying they exist, I'll comment no further on them.

Apologies for my idiosyncratic way of lower-camel-casing the "re" bit on the functions... I cannot bring myself to write a function with an initial capital letter. I know it's a bit odd.

Basics of reFind()

reFind() (see even at the beginning of a sentence... no cap... ;-) works in one of two ways. The most basic is just to work like find() does: return the index of where a match was found:

idx = reFind("\d", "ABC123");

This returns 4 (the position the first digit (\d) - "1" - is at). This operation is not much use beyond that, to be honest. One cannot reliably tell what was matched, because obviously it's a pattern being matched, but also because the length of a match cannot necessarily be inferred from the pattern, so one can't necessarily use mid() to extract the match like one might be able to with a straight string find (one knows the length of the substring being sought, after all). For example, there's no way to infer from a match of "\d*" whether the match was one digit or ten digits. Or indeed zero digits. So it's only good for a throwaway "was it there?" check.

Note that it returns 0 if there was no match (even a zero-width match before the first character of the string results in "1" being returned).

Sub-expressions

Fortunately there's another argument reFind() can take to make it actually useful.

match = reFind("\d{2}", "ABC123", 1, true);

This time, we get back more info:

struct
LEN
array
12
POS
array
14

We get back a struct with keys pos and len, and each of those is an array. The values in the array enable us to extract what exactly was matched, eg:

s = "ABC123";
matches = reFind("\d{2}", s, 1, true);

match = mid(s, matches.pos[1], matches.len[1]);


This results in match having a value of "12": this was the two-digit substring matched by "\d{2}".

The third argument to reFind() is the position in which to start the match (same as the equivalent for find()), and it's not actually relevant here, but because CFML only supports named arguments on a few functions (I'm not sure why some do and some don't?), we need to specify it so as to be able to also specify the argument we're interested in: the true. The fourth argument is a flag as to whether to return subexpression info, and using true means one gets back that struct rather than just the integer index.

On initial take, one might wonder why the pos and len values are arrays, when there's only one element in the array. Well cast your mind back to the discussion on sub-expressions: a sub-expression's match can be "remembered"... remembered for both a back-reference later in the pattern or in a replacement pattern, but also it can be returned from a find operation too. Here's an example.

numbers = "one two three four five six seven eight nine ten";
regex = "\b\w([aeiou]{2})\w\b";

matches = reFind(regex, numbers, 1, true);
match = mid(numbers, matches.pos[1], matches.len[1]);
subexpression = mid(numbers, matches.pos[2], matches.len[2]);

writeDump(variables);

(That pattern matches a four letter word with two vowels in the middle)

struct
MATCHfour
MATCHES
struct
LEN
array
14
22
POS
array
115
216
NUMBERSone two three four five six seven eight nine ten
REGEX\b\w([aeiou]{2})\w\b
SUBEXPRESSIONou

See that the arrays now have two elements:
  • the first element is the overall match;
  • the second element is the match of the sub-expression.
There will be as many elements in the array as there are sub-expressions (plus the first one which is the entire match).

One thing to bear in mind with the "there will be as many elements in the array as there are sub-expressions" is that there will be an element in the array even if the sub-expression could possibly not be matched. Here's an example:

skuPattern = "^(\d{5})([A-Z]{2})?$";

skuBasic = "12345";
matches = reFind(skuPattern, skuBasic, 1, true);
writeDump(matches);

writeOutput("<hr />");

skuVariant = "12345AB";
matches = reFind(skuPattern, skuVariant, 1, true);
writeDump(matches);

Here an SKU can take one of two patterns: nnnnn or nnnnnxx where n is a digit and x is a letter. The pattern matches both of those, and in the case of the nnnnxx version, it also grabs the xx as a sub-expression. We can see this in the results:

struct
LEN
array
15
25
30
POS
array
11
21
30

struct
LEN
array
17
25
32
POS
array
11
21
36

Note how for the "basic" SKU, there's still an array element for the xx part of the pattern, even though it wasn't matched. So bear in mind to check that the pos value is >0 before trying to extract a substring for the sub-expression. Otherwise you'll get this (which will become a very familiar error for you):

The 2 parameter of the Mid function, which is now 0, must be a non-negative integer

The error occurred in D:\websites\www.scribble.local\junk\junk.cfm: line 8
6 : writeDump(matches);
7 : 
8 : variant = mid(skuBasic, matches.pos[3], matches.len[3]);

(nice pidgin English from Adobe there with the error message btw: "the 2 parameter"??)

A variation on this is that a match can be made, but it can be zero length. One needs to be mindful of this too. Consider this example, which shows all four of the possibilities I mentioned:

struct function reFindMatches(required string regex, required string string){
    var result = reFind(regex, string, 1, true);

    result._match = [];
    for (var i=1; i <= arrayLen(result.pos); i++){
        if (result.pos[i] == 0){
            arrayAppend(result._match, "NO MATCH");
        }else if (result.len[i] == 0){
            arrayAppend(result._match, "ZERO-LENGTH MATCH");
        }else{
            arrayAppend(result._match, mid(string, result.pos[i], result.len[i]));
        }
    }
    return result;
}


skuPattern = "^([A-Z]{3})(?:-(?:DEFAULT|(\d*)))?$";

skuVariant = "ABC";
matches = reFindMatches(skuPattern, skuVariant);
writeDump(var=matches, label=skuVariant);

writeOutput("<hr />");

skuVariant = "ABC-DEFAULT";
matches = reFindMatches(skuPattern, skuVariant);
writeDump(var=matches, label=skuVariant);

writeOutput("<hr />");

skuVariant = "ABC-123";
matches = reFindMatches(skuPattern, skuVariant);
writeDump(var=matches, label=skuVariant);

writeOutput("<hr />");

skuVariant = "ABC-";
matches = reFindMatches(skuPattern, skuVariant);
writeDump(var=matches, label=skuVariant);

Here I've added a function reFindMatches() that improves reFind() in that as well as returning the pos and len of what was matched, it also returns what actually was matched. Which it ought to do off the bat, as all one would ever want pos / len for was to extract the matched substring. Indeed I have raised an E/R to augment reFind() and deprecate the mostly useless reMatch(): 3321666.

I've also used a pattern that matches four variations of SKU:
  • Just the basic "three letters" version;
  • Three letters with the "default" variant;
  • Three letters with a custom numeric variant;
  • Three letters with a zero-length numeric variant (this one stretches credulity, I know, sorry).
Here's the results:

123 - struct
LEN
123 - array
10
POS
123 - array
10
_MATCH
123 - array
1NO MATCH

ABC - struct
LEN
ABC - array
13
23
30
POS
ABC - array
11
21
30
_MATCH
ABC - array
1ABC
2ABC
3NO MATCH

ABC-DEFAULT - struct
LEN
ABC-DEFAULT - array
111
23
30
POS
ABC-DEFAULT - array
11
21
30
_MATCH
ABC-DEFAULT - array
1ABC-DEFAULT
2ABC
3NO MATCH

ABC-123 - struct
LEN
ABC-123 - array
17
23
33
POS
ABC-123 - array
11
21
35
_MATCH
ABC-123 - array
1ABC-123
2ABC
3123

ABC- - struct
LEN
ABC- - array
14
23
30
POS
ABC- - array
11
21
35
_MATCH
ABC- - array
1ABC-
2ABC
3ZERO-LENGTH MATCH

This demonstrates various permutations of matches:
  • zero pos and zero len in the first element: no match at all. Equiv to a 0 result from a standard find() operation.
  • Zero pos and len in one of the other elements: no match for that specific sub-expression, but over-all there was still a match. This implies the subexpression was optional.
  • A positive value for both pos and len: there was a substring match.
  • A positive value for pos, but a zero length. There was a match, but it was zero-length.
Hopefully that range of unduly repetitious examples demonstrates the types of matches (or lack thereof) one can expect from reFind().

Starting position

The other argument I glossed over was the "starting position" one - the third argument - there's not much to say about this other than to be aware of it. It works the same as with find(). One thing to note, and kind of demonstrates why not using the fourth argument as true with reFind() isn't very useful, is that if one wants to cycle through all the matches in a string, the normal approach is to do this sort of thing:

// pseudo code
set findStartPos = 1
while (findOperation matches something){
    process the match
    set findStartPos = after last char of this match
}

This step is not really possible with a lot of patterns (ones that don't necessarily match a fixed length substring), unless one returns sub-expressions. Without the sub-expression data being returned, one has only the start position of the match, but one doesn't know how long it is, so one can't skip past it.

reFindNoCase()

This function is kinda redundant, given one can simply specify (?i) in the regex to make it case-insensitive anyhow.



Blimey. I was hoping to cover all the CFML regex functionality in one article, but I'm up to 1800 words on just reFind(). So I'm gonna stop here, before you nod off (if you haven't already), and continue with reReplace() in the next article.

Until the next time...

--
Scheherazade

Wednesday 9 January 2013

Setting a CFAdmin password

G'day:
I despair. I was going to sit down tonight and be all pseudo-intellectual and watch Au Revoir les Enfants (which I have somehow managed to not yet see) on DVD, and otherwise ignore my computer. And ignore ColdFusion.  But here I am.

I had a Twitter exchange with Russ Michaels and Brad Wood about this current slew of security holes in ColdFusion (there are not one but three, apparently), and I mentioned that I couldn't be arsed looking into it to see what the actual issue was. But just like playing The Game, once the topic came up, it intrigued me more and more, so I decided whilst dinner was cooking "ah, it won't take long to find it, I'll have a look". So off I went.

Tuesday 8 January 2013

Weird behaviour with CFHTTP and JSON

G'day:
Here's some useless information to file away wherever it is you file away such stuff.

I was code reviewing some of my colleague Dennis's (who has no online presence that I am aware of, so he doesn't get a link) work yesterday, and when processing an HTTP response, he had this sort of thing:

response = httpResponse.fileContent.toString();

My reaction was along the lines of "whoa there Nelly... it's just some JSON, so it's already intrinsically a string: we don't need to make it into a ReallyReallyString by toString()-ing it".

Well I'm glad I like being proven to be wrong, because that's what happened next.

Friday 4 January 2013

That CFIDE security hole in ColdFusion? It's SERIOUS. So check into it NOW!

G'day:
I didn't bother writing anything about this new security problem with CF, as everyone else seems to have covered the important info already.

If you're not up to speed, read all of this lot:
And there's plenty of other blog articles about it out there (Charlie links to a bunch of good stuff).

I am only commenting now because I have just read about people stating "oh... maybe I should get around to looking at this?"

FFS. It's a really really really serious security hole which is easy to exploit, and a lot of people have found they have been exploited. This is not some esoteric in-theory-only issue.  And now that basically there are instructions of how to do it in the public domain, the risk increases.

If you have not verified you're not exposed, you are being professionally negligent.

So stop whatever you are doing and verify your externally-exposed servers are safe.

Don't piss about, and don't "do it later".

Also, if you know ColdFusion dev / admin people who don't read blogs, follow the community on Twitter and possibly won't know about this: get in touch with them (email, phone, etc).

Cheers.

--
Adam

Thursday 3 January 2013

Regular expressions in CFML (part 6: syntax - flags and the odds 'n' sods that are left )

G'day:
This is part six of the series I started with the introduction article: "Regular Expressions in ColdFusion (part 1: overview)", and followed with a discussion entitled "Regular expressions in ColdFusion (part 2: concepts)". Then I moved onto syntax with:
"Regular expressions in ColdFusion (part 3: syntax - single characters)";
"Regular expressions in ColdFusion (part 4: syntax - repetition, sub-expressions and back-references)";
"Regular expressions in ColdFusion (part 5: syntax - look-arounds, and how the engine parses the string it's matching)".

Flags

There are a few different "modes" the regex engine can use when processing a string. These are summarised as follows:

FlagMeaning
(?x)This flags to ignore whitespace within the pattern, so one can split it across multiple lines and add comments (for clarity).
(?m)This specifies the string being matched within should be treated as multi-line, so the ^ and $ anchors can be used to denote the beginning and end of a line. The \A and \Z characters still denote the beginning and end of the entire string.
(?i)This specifies the pattern should be considered case-insensitve. This is somewhat redundant in CFML as there are separate functions for case-sensitive and case-insensitive operations. This still works though.

Tuesday 1 January 2013

Shorthand struct notation is still buggy in CF10 (it seems)

G'day:
Happy New Year and all that sort of carry-on.

I'm still wading through this ColdFusion Bug Subscriber thing I'm writing using Coldbox. It's slow progress because the "wading" side of things erodes my patience fairly quickly, and I find something else to do. I hasten to add most of the wading is of my own manufacture due to vacillating over how to approach things, but in the early stages of things, Coldbox was being a bit annoying too. Mostly due to me not knowing what I'm doing, that said.

Anyway, I want to get it finished (it's 80% done, I guess), so have been trying to make forward progress with it over the last coupla days whilst I'm off work. With one thing or another, I have made about five lines of code's worth of progress in the last three days or so of sitting at my computer. There was a blog article or three in there, as well as a bit of Skyrim (yes, still playing Skyrim). But a lot of it has been sitting scratching my head and going "why? Just why?".