Monday, 29 February 2016

ColdFusion has 2000 new "customers" per quarter. Apparently.

G'day:
I was surprised to read this, from Rakshith:

[...] we get 20000 new customers ever year [...]
My ellision there does not change the context of what he said at all. It was just in the middle of a comment about something else.

This, obviously, raised some eyebrows. This morning Rakshith modified this claim:

@ Everyone: I stand corrected about new customers. I wanted to say 2000 new customers per quarter. We do not add 20000 new customers but rather it is 2000 new customers per quarter or 8000 new customers per year. I apologize for the confusion.

And yes, I am only referring to ColdFusion new customers here.

That is a bit less unbelievable than 20000, but I'm still keen to hear how they measure that.

I have asked for further clarification.

Interesting though, eh?

One thing I'd say about this though is that - if it's true - then... where are the people joining the online / visible community. If we are harsh and say each of those is a licence, and each of those means one developer doing the work... even if only 1% of them were interested in the online side of the community, we'd still see 20 new faces per quarter. Which... we're not, as far as I can tell. More's the pity.

Still: I think this is more a case of Rakshith presenting conveniently described numbers which do not in reality reflect what one might expect "2000 new customers per quarter" to actually mean.

Update:

Rakshith has just updated:

@Adam: New customers in this context are entities or organizations that have never bought ColdFusion from us in the past. Each such customer has bought one or more units of Standard or Enterprise. 8000 new customers will mean more than 8000 new units purchased.

Blimey. Where are they all?


--
Adam

Sunday, 28 February 2016

ColdFusion 2016: improvement to cfloop (of all things)

G'day:
I don't think I'll be able to spin this out very far, but it's another small feature of ColdFusion 2016 which is good, and seems to work properly. Well I say "good", and I call it a "feature", but it's really more "mundane" and just a case of finally implementing something almost correctly, instead of the initial attempt which was ballsed-up.

Back in ColdFusion 8, Adobe added the ability to <cfloop> to loop over an array directly, rather than need to use the <cfloop> tag's equivalent of an index for loop. So prior to ColdFusion 8, we needed to do this:


<cfset rainbow = ["Whero","Karaka","Kowhai","Kakariki","Kikorangi","Poropango","Papura"]>

<cfloop index="i" from="1" to="#arrayLen(rainbow)#">
    <cfoutput>#rainbow[i]#<br></cfoutput>
</cfloop>

This outputs the predictable:

Whero
Karaka
Kowhai
Kakariki
Kikorangi
Poropango
Papura


That's fairly innocuous, but iterating over an array in a view is sufficiently common a task that it made sense to fine-tune <cfloop> to accommodate it more semantically. So in ColdFusion 8 we got this instead:


<cfloop array="#rainbow#" index="colour">
    <cfoutput>#colour#<br></cfoutput>
</cfloop>

Well done, Adobe. This would have been so easy to get right, but they managed to balls it up. Here's a quick lesson in arrays:


rainbow = [];
rainbow[1] = "Whero";
rainbow[2] = "Karaka";
rainbow[3] = "Kowhai";
rainbow[4] = "Kakariki";
rainbow[5] = "Kikorangi";
rainbow[6] = "Poropango";
rainbow[7] = "Papura";

Arrays have two relevant components in this exercise: the element (which contains the value), and the index, which indicates the relative position of the element in the array. This isn't just terminology I'm making up... it's fundamental to how arrays work. And it's simple, and it's a CS 101 sort of thing (maybe CS 102?).

I missed this at the time it went into CFML as I did not bother with the CF8 pre-release, so it was out the door before I was aware of it. How everyone who did show up to the PR managed to not notice is beyond me. I imagine people simply didn't care, or were too busy playing with Flash Forms or whatever was the shiny gewgaw in that release. I mean it's trivial, but it's yet another example of Adobe rushing headlong on their mission of making CFML shit, instead of improving it.

Anyway, that was all a digressive framing exercise. The ColdFusion community finally managed to convince Adobe to set things straight (see 3321646, and 3341256), after only 3.5 years and two ColdFusion releases. We finally now have this:

<cfloop array="#rainbow#" index="i" item="colour">
    <cfoutput>#i#: #colour#<br></cfoutput>
</cfloop>

Notice how if I specify both an index and an item, the array loop actually exposes both the index (and it actually is the index), and the item for the element. We can't blame Adobe for using the term item here rather than element as - for once - they took advice to follow what Railo had already done. And item ain't so bad. And is actually correct-ish, which index never was.

If one specifies only the index in the loop, then it still receives the element value. For the sake of backwards compat. This was supposed to be deprecated, but it doesn't seem to be. I will follow this up (commented added to 3321646, to get it reopened).

And if one specifies only item, then it works as one would predict:

<cfloop array="#rainbow#" item="colour">
    <cfoutput>#colour#<br></cfoutput>
</cfloop>

Adobe have also extended this to list looping and file looping too:

<cfset week = "Rāhina,Rātū,Rāapa,Rāpare,Rāmere,Rāhoroi,Rātapu">

<cfoutput>
<cfloop list="#week#" index="day">
    #day#<br>
</cfloop>
<hr>

<cfloop list="#week#" index="i" item="day">
    #i#: #day#<br>
</cfloop>
<hr>

<cfloop list="#week#" item="day">
    #day#<br>
</cfloop>
<hr>
</cfoutput>

Rāhina
Rātū
Rāapa
Rāpare
Rāmere
Rāhoroi
Rātapu


1: Rāhina
2: Rātū
3: Rāapa
4: Rāpare
5: Rāmere
6: Rāhoroi
7: Rātapu


Rāhina
Rātū
Rāapa
Rāpare
Rāmere
Rāhoroi
Rātapu



<cfsetting enablecfoutputonly="true">

<cfoutput><pre></cfoutput>
<cfloop file="#getCurrentTemplatePath()#" index="line">
    <cfoutput>#encodeForHtml(line)#<br></cfoutput>
</cfloop>
<cfoutput></pre></cfoutput>
<cfoutput><hr></cfoutput>

<cfoutput><pre></cfoutput>
<cfloop file="#getCurrentTemplatePath()#" index="i" item="line">
    <cfoutput>#i#:    #encodeForHtml(line)#<br></cfoutput>
</cfloop>
<cfoutput></pre></cfoutput>
<cfoutput><hr></cfoutput>

<cfoutput><pre></cfoutput>
<cfloop file="#getCurrentTemplatePath()#" item="line">
    <cfoutput>#encodeForHtml(line)#<br></cfoutput>
</cfloop>
<cfoutput></pre></cfoutput>
<cfoutput><hr></cfoutput>

(I'll spare you the output: you get the idea).

Enigmatically, they did not extend this to structs. I'd expect this to work:

<cfset numbers = [
    one = "tahi",
    two = "rua",
    three = "toru",
    four = "wha",
    five = "rima",
    six = "ono",
    seven = "whitu",
    eight = "ware",
    nine = "iwa",
    ten = "tekau"
]>

<cfoutput>
<cfloop index="index" item="item" collection="#numbers#">
    #index# #item#<br>
</cfloop>
</cfoutput>

The analogue here is that when one specifies both index and item, then those receive the key and the value. But... no. We just get a compile error:

The following information is meant for the website developer for debugging purposes.
Error Occurred While Processing Request

Attribute validation error for tag CFLOOP.

It has an invalid attribute combination: collection,index,item. Possible combinations are:





  • Required attributes: 'file,index'. Optional attributes: 'charset,from,to'.
  • Required attributes: 'file,index,item'. Optional attributes: 'charset,from,to'.
  • Required attributes: 'file,item'. Optional attributes: 'charset,from,to'.
  • Required attributes: 'index,item,list'. Optional attributes: 'delimiters'.
  • Required attributes: 'index,list'. Optional attributes: 'delimiters'.
  • Required attributes: 'item,list'. Optional attributes: 'delimiters'.
  • Required attributes: 'group'. Optional attributes: 'endrow,groupcasesensitive,startrow'.
  • Required attributes: 'group,query'. Optional attributes: 'endrow,groupcasesensitive,startrow'.
  • Required attributes: 'query'. Optional attributes: 'endrow,startrow'.
  • Required attributes: None. Optional attributes: None.
  • Required attributes: 'array,index'. Optional attributes: None.
  • Required attributes: 'array,index,item'. Optional attributes: None.
  • Required attributes: 'array,item'. Optional attributes: None. <l...

  • Heaven forbid Adobe do a thorough job here.

    Also note the error messages is actually truncated half-way through a tag, and before the various attribute combos even get around to mentioning structs. Sigh.

    Oh, and one cannot use this syntax to iterate over a query either.



    This all got me thinking, actually. Why do we have different constructs for looping over an array, query, list or struct? Or file for that matter. How come it's not just this:

    <cfset myCollection = getCollection()>
    
    <cfoutput>
    <cfloop collection="#myCollection#" key="key" value="value">
        #key#: #value#<br>
    </cfloop>
    </cfoutput>
    

    Where I'm using getCollection() to be purposely value. That could return anything iterable: an array, a list, a file object, a struct, a query. Anything that implements some notional "Iterable" interface really. But <cfloop> could have one uniform syntax for iterating over said collection. Would that not be better? (Raised as 4122711).

    But anyway. As far as they have implemented this feature: it works. It perhaps shoulda been extended to structs and queries too though, yeah? And perhaps as a unified syntax. Oh well.

    Righto.

    --
    Adam

    Friday, 26 February 2016

    I'm more polylingual than I thought

    G'day:
    (and before I start, I am very very much not polylingual. The only language I notionally speak is English. And don't even do a very good job at that).

    However I had a bit of a surprise when I came to test the sample code for a quick article I'm gonna write on the flight tonight:



    Bloody Swahili? Ha. If only.

    Obviously (?) that's my usual Maori sample text: the colours of the rainbow in this case.

    But apparently "whero" (that's "ferro", btw... Maori "wh" is kinda like a cross between an F and an H...) is "hero" in Swahili.

    Sawa basi.

    --
    Adam




    Thursday, 25 February 2016

    Marc Garner

    G'day:
    We had a bit of a shock at work yesterday: me mate and boss Marc Garner is moving on from HostelBookers (well: we're part of HostelWorld now, but we still mostly work on the HB brand n our London IT dept). This is a bit crap for HB, but good for Marc, so that's cool I guess.

    I've been at HB for closing in on six years now (April is the six-year mark), and when I first sat down I was parked next to Marc. Poor sod (him, not me). At the time he was just a senior developer, as was I. However Marc was the old hand, having been there for a coupla years, and obviously knew the ins and outs and vagaries of how the HB website - and the other projects I came to be working on - all came together. So he was basically my mentor. This was an excellent time as Marc's a bloody good CFML developer, and we shared a lot of commonality in the ways we liked to see things done, so we made a good team. One of Garner's assets is that he's a pretty bloody patient individual, so was also happy to endure my bullshit on a daily basis (well: I say "happy"... perhaps more like "resolved to ~" and he managed to endure it and maintain a positive countenance throughout).

    He was also a good honest bloke who liked to have a pint after work too, which was handy. He was always slightly more sensible with how often was appropriate to go for a pint than I was though. Heh.

    Another thing I'm thankful for is he has a kid slightly older than my own boy, so when my lad was on the way, he was a good sounding board as far as the concept of being a dad goes, which was a completely foreign notion to me.

    Anyway... work stuff... Before too long Marc's technical skill and HR skills meant he was promoted to be our team lead, and I'll always remember he apologised to me when it happened as he didn't want me to think that it was because he was better than me or anything, just had been around longer. Which was bullshit: he was far more able in that sort of role than I'm likely to be. Technically: I could do it, sure; but I'd be a nightmare for HR. Ha.

    Marc also excelled as a team lead, running interference between our lads in the team and the bosses of the department, and always came to bat for us. All whilst still delivering the message down to use from above.

    One thing I deeply respect Marc for is that occasionally I have needed to get  a bit of a ballocking for one reason or another (usually personnel issues, as you can imagine), and he was... well... good at doing it! He was always firm and put his point across, but still always listened, and maintained an approachable demeanor throughout. And then that was that, and we were back to work and there was never any lingering "situation". I think this is a good personal strength to have.

    When HostelBookers was subsumed by HostelWorld, there were personnel changes at the top of HB's IT department, and it was clear to the management at HW that Marc was the right person to step up into the Dept Head role. I will be honest and say I think there were a coupla wobbles initially - but nothing major - and the thing is Garner's a pragmatic person and just refined his leadership as he goes. He's really stepped up into the role, and has the respect of everyone in the department (both down to us bods doing the coding, and up to the big bosses over in Dublin).

    Over the last year or so we've been reimplementing and rebranding the HostelBookers website. I mentioned this went we went live with the new site a few weeks back: "The end of ColdFusion". But now that project is done, and Marc has seen this as a good opportunity to move on again, to tackle someone else's challenges. I can understand why he's moving on.

    Anyway, Marc was a bloody good boss, and I just wanted to put that down "on paper" somewhere.

    Take it easy, fella.

    --
    Adam

    Tuesday, 23 February 2016

    Adobe personnel who are relevant to ColdFusion

    G'day:
    It's bloody difficult to get out of Adobe exactly who is on the ColdFusion Team, and in what capacity. Very few of them are particularly forthcoming about their roles (or indeed, communications in any real way).

    I've done some detective work (read: googling), and these are all the people I can find that have done something to do with ColdFusion over the last year or so, and are currently in Adobe's employ.

    This information is in the public domain, so I don't think it's inappropriate to share it?


    • Akhila K Srinivas - Software Engineer
    • Anit Kumar Panda - Manager Technical Support at Adobe
    • Awdhesh Kumar - Senior Developer
    • Chinoy Gupta - COMputer Scientist
    • Dattanand M Bhat - bugbase
    • Deepraj Jha - bugbase
    • Elishia Dvorak - Solution Consultant at Adobe
    • Hari Krishna Kallae - Lead Software Engineer at Adobe
    • Himavanth Rachamsetty - Software Engineer at Adobe Systems
    • Immanuel Noel - Lead Software Engineer at Adobe
    • Jacob Jayakar Royal - (dunno Jacob's title, but he looks after the ColdFusion docs site)
    • Kailash Bihani - bugbase
    • Kishore Balakrishnan - Senior Product Marketing Manager at Adobe
    • Krishna Reddy - bugbase
    • Mayur Jain - Computer Scientist at Adobe
    • Milan Chandra - bugbase
    • Nikhil Siddhartha - Member of Technical Staff
    • Nimit Sharma - bugbase
    • Paul Nibin K J - Computer Scientist
    • Piyush Kumar Nayak - bugbase
    • Poonam Jain - Software Engineer
    • Priyatharsini K - bugbase
    • Rahul Upadhyay - Product Consultant at Adobe
    • Rakshith Naresh - Product Manager at Adobe Systems
    • Rupesh Kumar - Engineering Manager at Adobe Systems Inc
    • S Preethi - bugbase
    • Sandeep Paliwal - ColdFusion Engineering
    • Sandip Halder - Adobe ColdFusion product Consultant
    • Saurav Ghosh - Community Lead
    • Shambhuling Nashi - Quality Engineering Manager
    • Suchika Singh - Software Engineer
    • Suresh Jayaraman - Senior Engineering Manager
    • Tridib Roy Chowdhury - G.M. & Sr. Director Of Products at Adobe
    • Uday Ogra - Computer Scientist
    • Vamseekrishna Nanneboina - Quality Engineering Manager for ColdFusion, Adobe
    • Kapil Arora - Sr. Computer Scientist (Kapil runs the bugbase, but is not directly on the ColdFusion Team)


    That's a whole bunch of people! Where I have listed job titles, that was from either their own LinkedIn page, or a bio page on the Adobe website. Where I've just listed "bugbase", that's the only place I could find their name. It's quite interesting how a lot of them don't actually mention "ColdFusion" on their LinkedIn profiles. For example even Rakshith doesn't mention it in his initial bio summary! I dunno what to make of that.

    There have been a coupla departures from the ColdFusion Team in the last year: I have not listed those people.

    Anyway... these seem to be the people that bring ColdFusion to you. Cheers all.

    Righto.

    --
    Adam

    Monday, 22 February 2016

    ColdFusion 2016: Unaspirational thinking with session/Redis support

    G'day:
    Disclsoure: this is a reproduction of an observation I made on the ColdFusion 2016 pre-release forums. As it is my own work, and is independent of anyone else's comment or input, I feel it's not breaking the NDA to repeat it.

    ColdFusion 2016 adds a new feature to be able to pass-off session storage to a Redis server. Details here: ColdFusion 2016 Features / External session storage. The allows one to specify in CFAdmin a Redis server to use for session management.

    On the face of it this is a good feature, but I had apprehensions about this since it was announced. To contextualise the first sentence, I had earlier speculated that the implementation would not be very well thought out.

    Right, so here we are, and my suspicions were correct.

    This implementation is somewhat lacking in aspiration.

    [redacted]Adobe have implemented half a solution here.

    What would have been a good approach would be to have provided an interface which one can implement a SessionManager connector. And then have this sort of thing in Application.cfc (or in the CF server config somewhere for instance-wide handling):

    this.sessionManager = new MySessionManager();
    

    This hands off all session management to the SessionManager.

    The interface specifies which methods are needed to use sessions via the abstracted manager, eg:
    • createSession()
    • setProperty()
    • getProperty()
    • hasProperty()
    • getProperties()
    • invalidateSession()
    • expireSession()
    • onSessionStart()
    • onSessionEnd()
    • etc, you get the idea

    I s'pose this interface could be fulfilled either by a Java class or a CFC.

    From there, Adobe could implement a redis-based SessionManager.

    Why? Because there’s more games in town than Redis. A lot more. We have a cluster of Memcached boxes which we could use for this, had Adobe not painted itself (and all of us) into a corner. Again. Even from the perspective of existing CF work... why Redis, when all the rest of the embedded nearline storage has been build on Ehcache? Or, hey... I might wanna put my sessions in a DB, or even have a null implementation.

    But the way Adobe have implemented this we're stuck with their one implementation. And at their mercy for how it’s implemented.

    Also I think - as a general thing - the primary configuration mechanism for a CF server/instance/application needs to move away from the CFAdmin interface. That approach to configuring application server software is a bit out of date. Config should be file based, IMO (and not WDDXed structs, but clear text, human- and code-maintainable config files).
    I removed one sentence from that as it alludes to something else on the PR which I am not in the position to discuss here, I have also corrected two typos I spotted, and added some formatting.

    A coupla notes on this:

    • as I mentioned: seemingly this can only be managed by CFAdmin. I think this should be settable at Application level.
    • As mentioned in the docs: "If you select Use J2EE session variables, you cannot store ColdFusion sessions in Redis". This is not very satisfactory. This was discussed in the pre-release, but I cannot go into that here. erhaps the relevant people from Adobe can reproduce their feedback on this.

    I've not much to add other than that... I have not experimented with or tested this feature, so I don't know how robust or production-ready it is.

    It's certainly not an enterprise solution to the functionality though.

    Righto.

    --
    Adam

    Friday, 19 February 2016

    ColdFusion 2016: toJson() method

    G'day:
    This'll need to be super quick as I only have 15min of lunch break left.

    ColdFusion 2016 added a toJson() method to allmost of its inbuilt types. Here's the biz:

    a = ["tahi"];
    st = {two="rua"};
    ost = {three="toru"};
    q = queryNew("en,mi", "varchar,varchar",[["four","wha"]]);
    cfxml(variable="x"){
        writeOutput("<five><rima/></five>");
    }
    s = "ono";
    ts = now();
    d = 42 * 1;
    b = true == true;
    
    CLI.writeLn(a.toJson());
    CLI.writeLn(st.toJson());
    CLI.writeLn(ost.toJson());
    CLI.writeLn(q.toJson());
    CLI.writeLn(q.toJson(true));
    CLI.writeLn(x.toJson());
    CLI.writeLn(ts.toJson());
    //CLI.writeLn(d.toJson()); // not supported for numerics
    //CLI.writeLn(b.toJson()); // not supported for booleans
    CLI.writeLn(variables.toJson());
    


    And the output:


    C:\src\CF12\other\tojson>cf toJson.cfm
    ["tahi"]
    {"TWO":"rua"}
    {"THREE":"toru"}
    {"COLUMNS":["EN","MI"],"DATA":[["four","wha"]]}
    {"ROWCOUNT":1,"COLUMNS":["EN","MI"],"DATA":{"EN":["four"],"MI":["wha"]}}
    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<five><rima/></five>"
    "ono"
    "February, 19 2016 13:48:38"
    {"OST":{"THREE":"toru"},"B":true,"ST":{"TWO":"rua"},"X":"<?xml version=\"1.0\" e
    ncoding=\"UTF-8\"?>\n<five><rima/></five>","Q":{"COLUMNS":["EN","MI"],"DATA":[["
    four","wha"]]},"D":42.0,"TS":"February, 19 2016 13:48:38","A":["tahi"]}
    C:\src\CF12\other\tojson>

    So all good for arrays, structs, ordered structs, queries (and both modes for queries), XML, strings, dates and scopes. But it fails on numerics and booleans. For the sake of completeness it should work on numerics and booleans too (esp if it works on strings!). I've raised 4119888.

    Anyway... well done: something that's a) useful; b) almost works 100%. And the non-100% it's quite edge-case-y anyone.

    Righto.

    --
    Adam

    ColdFusion 2016: good-bye Akamai

    G'day:
    Two snippets of info from King Anit on Slack this morning:
    Anit Kumar
    [09:34]
    Hi All,
    From now onward, ColdFusion and ColdFusion Builder installers are available without Akamai Download Manager. So, no more download related complaints :simple_smile:
    I've tested this and it's true. Well done.

    And also Adobe have put the Express versions of ColdFusion 2016 back up, and there are direct downloads for them (so circumventing even the Adobe webshite):

    So that's jolly good. Good work, Anit.

    In other Anit-related news, another of his colleagues - Rahul Upadhyay - from the ColdFusion Support Team has joined the CFML Slack channel too. Hopefully Rahul is as solid a bloke as Anit has proven to be.

    --
    Adam

    You need to consider the ColdFusion 2016 release as a public beta

    G'day:
    I've been looking at what Adobe has released as ColdFusion 2016 over the last few days, and I can only conclude that it's really only "first public beta" quality. I figure it's worth making this observation, and warning people to not treat it as production-ready, and - unless you're basically installing it for testing purposes - simply don't touch it yet. Wait for a coupla updates even before trying it.

    Adobe (and Macromedia before them) have always had public betas in the past, but for some reason they chose not to this time. If one looks at the duration of the pre-release cycle, ColdFusion 2016 was released very early compared to other releases. If one also bears in mind there's usually a small-audience alpha even before the wider-audience pre-release, and they didn't have that closed alpha round this time, it demonstrates it's been in a testable environment for an even shorter period than usual.

    Given that... what they have released is pretty much the quality one would expect perhaps half-way through the pre-release cycle, which makes it perhaps 2-3 iterations more untested than the public usually experiences.

    So in effect it's not even a beta. It's an alpha. It's OK for an alpha, but that doesn't make it production ready.

    We also have to bear in mind a few factors contributing to the quality of the product here:

    • the ColdFusion Team's understanding of CFML is poor (ie: that's as distinct from Java, which they might be quite good at; but they don't understand the language they are creating);
    • their attention to detail is notoriously bad;
    • their testing is superficial;
    • they generally ignore input from the community. This was especially bad this time round, as described by Ray in his recent blog article about the ColdFusion 2016 release;
    • and as stated, this was all just a rush job.
    If you bear all that in mind, do you really want to be investing your time trying to get your applications working on something that can only optimistically be referred to as beta? No.

    Also stop to think about what you're gaining here: there is bugger-all in ColdFusion 2016 anyhow, feature-wise. I guess they have fixed a bunch of bugs, but most of those ought to be back-ported into ColdFusion 10 and 11 (as appropriate) anyhow. ColdFusion 10 is supported until mid 2017, and ColdFusion 11 until Q2 2019 (ref: Adobe Support Lifecycle Policy).

    In addition to that there seems to be some question marks over licensing changes which might make ColdFusion 2016 substantially more expensive to run (or upgrade to) than ColdFusion 11, so that's something else to consider. I do not quite understand the details of this, but perhaps ask around.

    Just steer clear of ColdFusion 2016, at least for the time being, until they get their act together. If nothing else, don't reward them for doing substandard work.

    Righto.

    --
    Adam

    ColdFusion 2016: critical regression in scoping

    G'day:
    Thanks to Mingo Hagen for inspiring me today. He brought this to my attention on the CFML Slack channel (all the more reason to subscribe to that, btw... to catch stuff like this).

    ColdFusion 2016 has introduced a serious regression bug when it comes to unscoped references in functions.

    Update (2016-07-23)

    See Wil's comment below. He's confirmed this is fixed in ColdFusion 2016, Update 2. Cheers for letting us know about this, Wil.
    Here's the repro:

    function foo(bar) {
        bar = "test";
        try {
            writeOutput("arguments scope");
            writeDump(var=[arguments.bar]);
        } catch (any e){
            writeDump({message=e.message});
        }
        try {
            writeOutput("local scope");
            writeDump(var=[local.bar]);
        } catch (any e){
            writeDump({message=e.message});
        }
        try {
            writeOutput("no scope");
            writeDump(var=[bar]);
        } catch (any e){
            writeDump({message=e.message});
        }
        try {
            writeOutput("variables scope");
            writeDump(var=[variables.bar]);
        } catch (any e){
            writeDump({message=e.message});
        }
    }
    
    writeOutput("Test with no arg passed:<br>");
    foo();
    
    writeOutput("<hr>Test with arg value passed:<br>");
    foo("arg value");
    

    The conceit here is that we are assigning an un-scoped variable a value within the function.

    On previous versions of ColdFusion (and Lucee/Railo) we get this:



    So CF successfully notices that the unscoped bar is a reference to bar argument, and assigns it appropriately. And the behaviour is uniform irrespective of whether we pass a value for the bar argument or not. This is correct.

    On ColdFusion 2016, we get this instead:





    Here ColdFusion isn't bothering to do a scope look-up to see if the unscoped variable already exists in a scope, it just goes "unscoped = variables scope". Which, in a function, is wrong.

    This is a pretty serious bug. All the more reason to give ColdFusion 2016 a swerve at least for the time being (if not permanently, because it's just not worth the hassle given the lack of any real gain one would get from "upgrading" to it).

    Mingo's not raised a ticket for this yet, but I'll cross-ref once he has. It's 4119653.

    Righto.

    --
    Adam

    Thursday, 18 February 2016

    ColdFusion 2016: the slipshoddiness from Adobe continues with ordered structs

    G'day:
    Hopefully "slipshoddiness" with keep Ron Stewart amused.

    However no-one should be amused by any of this ColdFusion 2016 bullsh!t, which continues to be beta-quality the more of it I look at.

    OK, so I wrote about the sorted/ordered structs coming to ColdFusion 2016 back when Adobe released that info to the public, a few months back: "ColdFusion 2016: ordered/sorted structs". Some of that info is out of date now, because [stuff that went on in the pre-release programme and I can't discuss], but the reasons were reasonably legit (-ish), and we all agreed to the scope reduction.

    One of the changes was that it became clear that there really isn't a difference between the notion of "ordered" and "sorted": they are basically synonyms. Originally the idea was that an ordered struct had its keys in the order they were originally added into the struct; but a sorted struct was one in which one could supply a callback to define a bespoke ordering. It was pointed out that "insertion order" and "alphabetic order" and "bespoke order" are all variation of the same concept, so it was decided to drop the disparate concepts, and just run with ordered structs to cover all bases. Well until they had trouble with the callback-ordered version, and dropped that from ColdFusion 2016. This is correct: the callback option did not ship. It'll come "later". Which might be ColdFusion 2018, I should think. Or never.

    So what's left: there's a new type of struct called an ordered struct. or as Adobe put it using their CFML-yoda-English "structOrdered" (FFS).

    There's two ways of creating a new ordered struct:

    orderedViaFunction = structNew("ordered");
    writeDump(var=orderedViaFunction, label=orderedViaFunction.getClass().getName());
    
    orderedViaLiteral = [=]; // or : for the assignment if you must
    writeDump(var=orderedViaLiteral, label=orderedViaFunction.getClass().getName());
    

    And these dump just like structs:

    D:\src\CF12\structs\ordered>cf creation.cfm
    coldfusion.runtime.StructOrdered - struct [empty]


    coldfusion.runtime.StructOrdered - struct [empty]


    D:\src\CF12\structs\ordered>

    I think perhaps it's a slight glitch there that dump doesn't identify them as ordered structs. I'll raise a ticket for that (4119477).

    Anyhow, and empty ordered struct is a bit of a cop-out. Here's one with something in it, demonstrating the different from a normal struct ("structNormal"?):

    normal = {
        first = 1,
        second = 2,
        third = 3,
        fourth = 4,
        fifth = 5
    };
    writeDump(normal);
    
    ordered = [
        first = 1,
        second = 2,
        third = 3,
        fourth = 4,
        fifth = 5
    ];
    writeDump(ordered);
    

    Result:

    D:\src\CF12\structs\ordered>cf literal.cfm
    struct

    FIFTH: 5
    FIRST: 1
    FOURTH: 4
    SECOND: 2
    THIRD: 3

    struct

    FIRST: 1
    SECOND: 2
    THIRD: 3
    FOURTH: 4
    FIFTH: 5

    D:\src\CF12\structs\ordered>

    So you see that the latter dump has indeed preserved its key ordering. Lovely.

    Oh... literal syntax there uses square brackets rather than curly braces.

    I tested a bunch of other things: each(), map(), filter(), toJson(), for-looping, keyArray() etc, and they all worked. But it's all boring, so I'll spare you.

    As with everything (it seems) in ColdFusion 2016, it's riddled with bugs though.

    First - I did not find this one, Aaron Neff did - the literal syntax is a bit fragile (heaven forbid literal syntax in ColdFusion is brittle... struct- and array-literal syntax in ColdFusion was almost unusable when it was added in ColdFusion 8; almost production ready for ColdFusion 9, and I think by ColdFusion 10 it'll be stable. So with this stuff... maybe by ColdFusion 2020. Or it'll probably be COLDFVSION MMXX or something daft by then. But anyway...

    ColdFusion 2016: half-arse`d-ness from Adobe on a potentially handy feature

    G'day:
    This'll be a lot quicker than I anticipated, given Adobe haven't actually bothered to implement most of the given feature.

    Back in the ColdFusion 10 era, I raised 3597432 ("replaceWithCallback()"). The idea here was to add an option to replace() to make it behave more like JavaScript's String.prototype.replace(), in that it can take a callback to perform the replacement operation. Quite often a replacement operation might be mroe than a simple swap-out for one value for another, beyond the scope that regex operations can facilitate it. So using a callback allows one to handle the replacement anyway one likes.

    Here's an example of the JavaScript version:

    source = "this is a string from which to exchange some matches using a callback to perform the exchange";
    match = new RegExp("exchange", "g");
    replacement = "replace";
    
    result = source.replace(match, function(match, index, source){
        return replacement;
    });
    
    console.log(result);
    

    Which yields:

    C:\src\CF12\strings\replaceWithCallback>node replace.js
    this is a string from which to replace some matches using a callback to perform the replace

    C:\src\CF12\strings\replaceWithCallback>

    Note how this just swaps out all the instances of "exchange" for "replace". This is a daft usage of a callback, but you get the general idea.

    So ColdFusion 2016 implements this:

    source = "this is a string from which to exchange some matches using a callback to perform the exchange";
    match = "exchange";
    replacement = "replace";
    
    result = source.replace(match, function(match, index, source){
        return replacement;
    }, "ALL");
    
    writeDump([
        source=source,
        match=match,
        replacement=replacement,
        result = result
    ]);
    

    Result:



    So that's cool. It works.

    But do you know what's not cool?

    They only implemented it on replace(). They did not implement it on replaceNoCase(). Nor reReplace(). nor reReplaceNoCase().

    Sigh. Useless. Just useless.

    So really... in that they only added it to one of four congruent functions, this represents making CFML (haha, I initially typoed that as "FML"... somewhat fittingly perhaps) just that little bit worse, rather than that little bit better.

    Righto.

    --
    Adam

    ColdFusion 2016: query iteration functions

    G'day:
    In ColdFusion 11, one of the best new features was the addition of collection iteration methods, ie stuff like Array.map(), Struct.each(), List.listReduce() etc. One glaring omission was the lack of these implemented for queries. I have no idea why they were omitted, but there you go.

    Anyway, one of the few decent language features in ColdFusion 2016 is that these have finally been implemented. They mostly work as one would expect, but I'll run through examples of each anyhow.

    each()

    each() simply iterates over the query, calling the callback for each row. The function singature for the callback is:

    void function(struct row, numeric index, query query)
    

    An example of this in action is:

    colours = queryNew("id,en,mi", "integer,varchar,varchar", [
        [1,"red","whero"],
        [2,"orange","kakariki"]
    ]);
    
    colours.each(function(colour, index, colours){
        writeDump(arguments);
    });
    

    And the results:



    Predictable and no surprises.

    map()

    map() is a bit more complicated. I'll start with an example to frame things:

    colours = queryNew("id,en,mi", "integer,varchar,varchar", [
        [1,"red","whero"],
        [2,"orange","karaka"],
        [3,"yellow","kowhai"],
        [4,"green","kakariki"],
        [5,"blue","kikorangi"],
        [6,"indigo","poropango"],
        [10,"violet","papura"]
    ]);
    
    maoriColours = colours.map(function(colour, index, colours){
        return {mi=colour.mi};
    }, queryNew("mi","varchar"));    
    
    writeDump(var=maoriColours);
    



    The function signature for the callback is the same as before except it returns a struct:

    struct function(struct row, numeric index, query query)
    

    Note map() takes a second argument, which is a second query. This query acts as a template for the remapped query returned by map(). The map callback returns a struct with keys that are a subset of the column names in that query. Note here my template query has a column mi, and so does the struct I'm returning from the callback. If I try to return a different column name, I get an error:



    It's important to note that that query is only used for the "schema" of the returned query, any rows in it are ignored. That whole second argument is optional, and if omitted the original query's schema is used instead.

    reduce()

    reduce() holds no surprises. Its callback signature is:

    any function(any carry, struct row, numeric index, query query)
    

    And an example is:

    week = queryNew("id,en,mi", "integer,varchar,varchar", [
        [1,"Monday","Rāhina"],
        [2,"Tuesday","Rātū"],
        [3,"Wednesday","Rāapa"],
        [4,"Thursday","Rāpare"],
        [5,"Friday","Rāmere"],
        [6,"Saturday","Rāhoroi"],
        [7,"Sunday","Rātapu"]
    ]);
    
    shortestMaoriDayName = week.reduce(function(shortest,number){
        if (shortest.len() == 0) return number.mi;
        return number.mi.len() < shortest.len() ? number.mi : shortest;
    }, "");
    
    writeOutput(shortestMaoriDayName);
    

    This simply returns:

    Rātū

    sort()


    The callback for this takes two elements to compare:

    comparison function(any row1, any row2)
    

    Where I say comparison as the return type here, I mean a numeric value that is <0, 0 or >0 indicating whether row1 is less then, equal to or greater than row2, by whatever yardstick is reflected by the callback. Same as any other sort handler. Example:

    colours = queryNew("id,en,mi", "integer,varchar,varchar", [
        [1,"red","whero"],
        [2,"orange","karaka"],
        [3,"yellow","kowhai"],
        [4,"green","kakariki"],
        [5,"blue","kikorangi"],
        [6,"indigo","poropango"],
        [10,"violet","papura"]
    ]);
    
    colours.sort(function(c1,c2){
        return compare(c1.mi, c2.mi);
    });
    
    writeDump(colours);
    

    Note that sort() desn't return the sorted query - it'd be a lot better if it did, TBH, I think I might raise a bug for this (4119099) - it sorts the query inline. This prevents this method being chained, which is disappointing. The output for this is predictable:



    (it's the Maori column that's sorted there... not so obvious given the ubiquity of Ks in Maori words).

    filter()


    Yay, here's the first definite bug. The filter() callback has this function signature:

    boolean function(struct row, numeric index, query query)
    

    And here's an example:
    colours = queryNew("id,en,mi", "integer,varchar,varchar", [
        [1,"red","whero"],
        [2,"orange","karaka"],
        [3,"yellow","kowhai"],
        [4,"green","kakariki"],
        [5,"blue","kikorangi"],
        [6,"indigo","poropango"],
        [10,"violet","papura"]
    ]);
    
    coloursWithoutK = colours.filter(function(colour, index, query){
    writeDump(arguments);abort;
        return !colour.mi.find('k');
    });
    
    writeDump(coloursWithoutK);
    

    This obviously (obviously!) returns a query with only the three rows which don't have the letter K in the Maori colours, right?



    No. It returns an array. How did this get through QA (NB: there's a good reason why this was not fixed in the pre-release, but I cannot disclose why. It's not a good reason though).

    So I'll raise a bug for that (4119103).

    That's about it. There's a fail in sort() in that it does not return the sorted query, leaving the original alone, and an outright bug in the implementation of filter().

    All in all: a good alpha-quality implementation of these functions though. And a good thing about ColdFusion 2016.

    Righto.

    --
    Adam

    Tuesday, 16 February 2016

    ColdFusion 2016: trying to write about one thing; end up writing about another

    G'day:
    I was gonna do an article about ColdFusion 2016's new query iteration functions, but my fondness for using Maori as my sample data language has pointed me in the direction of a possible bug in ColdFusion 2016's CLI.

    I've distilled it down to this:

    CLI.writeln("kuputuhi tauira ki pūāhua nako");
    

    If I run that via the ColdFusion 2016 CLI, I get this:


    D:\src\CF12\cli\utf8>cf
    CLI.writeln("kuputuhi tauira ki pūāhua nako");
    ^Z
    kuputuhi tauira ki puahua nako
    D:\src\CF12\cli\utf8>

    Hmmm... where gone the diacritic marks?

    Initially I put this down to a tweak I've made to the CLI batch file which allows me to put code straight into STDIN instead of a file and run it, so I ran the code old-school:

    D:\src\CF12\cli\utf8>cf cfmlExample.cfm
    kuputuhi tauira ki p┼½─?hua nako
    D:\src\CF12\cli\utf8>

    Yikes! Worse!

    I figured there was a chance that Windows wasn't handling encoding in its own CLI box that well, so decided to see what PHP made of this:

    <?php
    echo "kuputuhi tauira ki pūāhua nako";
    

    And this yields:

    D:\src\CF12\cli\utf8>php phpExample.php
    kuputuhi tauira ki pūāhua nako
    D:\src\CF12\cli\utf8>

    OK, so ColdFusion is doing no different from PHP here when running a file. On a whim I decided to try Ruby too, and this fared better:

    puts "kuputuhi tauira ki pūāhua nako"
    


    D:\src\CF12\cli\utf8>ruby rubyExample.rb
    kuputuhi tauira ki pūāhua nako

    D:\src\CF12\cli\utf8>


    So it wasn't like it was impossible to display the right characters in a Windows CLI box, but I decided to google anyhow.

    I found a PHP answer which said I needed to change the code page in the CLI box to support UTF-8, by doing this:


    D:\src\CF12\cli\utf8>chcp 65001
    Active code page: 65001

    D:\src\CF12\cli\utf8>


    This is a new one on me, but it seemed to sort PHP's issues out:


    D:\src\CF12\cli\utf8>php phpExample.php
    kuputuhi tauira ki pūāhua nako
    D:\src\CF12\cli\utf8>


    But it didn't really help ColdFusion:


    D:\src\CF12\cli\utf8>cf cfmlExample.cfm
    kuputuhi tauira ki pū�?hua nako
    D:\src\CF12\cli\utf8>

    On a further whim, I decided to extend my test bed to Python:

    print("kuputuhi tauira ki pūāhua nako")
    


    Without the chcp call, I got this:

    D:\src\CF12\cli\utf8>py pythonExample.py
    kuputuhi tauira ki pūāhua nako

    D:\src\CF12\cli\utf8>


    Which is exactly the same as ColdFusion's output. But once I make the chcp call:


    D:\src\CF12\cli\utf8>chcp 65001
    Active code page: 65001

    D:\src\CF12\cli\utf8>py pythonExample.py
    kuputuhi tauira ki pūāhua nako

    D:\src\CF12\cli\utf8>

    As you can see: it's fine.

    So my conclusion here is that it's completely legit than ColdFusion might not be able to render UTF-8-encoded characters without the code page being actively changed, but even after that something is not right with the CLI. I supsect that when they load the file in, they don't give any thought to encoding at all, so the source code actually gets "corrupted" before it's run. I have to admit that my understanding of encoding is OK, but not fantastic, but when one throws Windows CLI code pages into the mix too... I dunno what my expectations ought to be. But it ain't working, that's fer sure.

    Could someone please try this on *nix and see what they get when using a more robust shell?

    Now it's too late for me to look at query iterations functions, so that might be a job for before work tomorrow.

    Righto.

    --
    Adam

    ColdFusion 2016: floor()

    G'day:
    OK, so there's a coupla other uninteresting features in ColdFusion 2016 which I'll look at. The first one is in response to a ticket John Whish raised a while back: Deprecate `int` in favour of `floor`.

    SSIA, really, but not the grounds for doing so. The int() function doesn't really do what it's supposed to, as I wittered on about here: CFML: how should int() behave? int() should just return the integer part of a number (hint: it's in the name), but instead it performs a rounding exercise instead. This means with negative numbers, it gets the answer wrong.

    Still: the horse has bolted and it's not like it can be fixed or dropped now. Speaking of fixing it, there is a function fix() which does what int() was supposed to do.

    So what's this floor() function? It does exactly the same as int() currently does, but it's got a more sensible name when taken in conjunction with another already-existing ceiling(). The idea is that we abandon int() as being faulty, and promote floor() and ceiling() for the rounding down/up intergerising functions, and use fix() to just get the integer part. Basically: just forget about int() being a thing, and move on.

    So this ain't much of an enhancement, it just does some language tidy-up.

    Here, btw, is some code demonstrating what I'm on about:

    <cfset numbers = [-3.6,-3.5,-3.4,-2.6,-2.5,-2.4,-0.5,0,0.4,0.5,0.6,1.5,1.6,2]>
    <cfset handlers = [int,floor,ceiling,fix,round]>
    <cfoutput>
    <table border="1">
        <thead>
            <tr>
                <th>x</th>
                <cfloop array="#handlers#" item="handler">
                    <th>#handler.getName()#</th>
                </cfloop>
            </tr>
        </thead>
        <tbody>
            <cfloop array="#numbers#" item="x">
                <tr>
                    <td>#x#</td>
                    <cfloop array="#handlers#" item="handler">
                        <td>#handler(x)#</td>
                    </cfloop>
                </tr>
            </cfloop>
        </tbody>
    </table>
    </cfoutput>
    

    Here's a rare instance of me using tags, eh? Well it's mostly output, and I needed a table to present it, so fair cop.

    This outputs:

    x int floor ceiling fix round
    -3.6 -4 -4 -3 -3 -4
    -3.5 -4 -4 -3 -3 -3
    -3.4 -4 -4 -3 -3 -3
    -2.6 -3 -3 -2 -2 -3
    -2.5 -3 -3 -2 -2 -2
    -2.4 -3 -3 -2 -2 -2
    -0.5 -1 -1 0 0 0
    0 0 0 0 0 0
    0.4 0 0 1 0 0
    0.5 0 0 1 0 1
    0.6 0 0 1 0 1
    1.5 1 1 2 1 2
    1.6 1 1 2 1 2
    2 2 2 2 2 2


    All we see here is that int() (and now floor()) round to the next lowest integer, which might be a different integer from the integer part of the original number if the number is negative. ceiling() does the opposite: rounds to the next highest integer. fix() just returns the integer part of the number, and for good measure I've chucked round() in their too to show rounding to the nearest integer, which is yet another variation.

    One thing Adobe have not done to finish this work is to mark int() as deprecated. That's kinda essential to this, as otherwise floor() is just adding clutter to the language, rather than being a step to tidy it up. I'll remind Adobe about this bit. Again.

    So not very interesting, but a quick one to write up whilst waiting on a call.

    Righto.

    --
    Adam

    ColdFusion 201610.5.1: first attempt at installing...

    G'day:
    So I decided to bite the bullet, install that stupid Akamai download manager (in 2016, seriously?) and grabbed the ColdFusion 201610.5.1 trial.

    Most of the way through the install process, I get this:



    Just for the sake of people googling, I'll put that here again in text:

    The Program can't start because MSVCR110.dll is missing from your computer. Try reinstalling the program to fix this problem.

    I guess this is something to do with a C++ runtime I don't have installed, or something. I mean I do have the 2005, 2008, 2010, 2012, 2013 and 2015 ones installed. But not this one.

    For the record, I'm doing this install on a Windows 10 Home 64-bit laptop.

    One would think if an installer needed a dependency... the installer would know how to get hold of the dependency?

    Oh well. I'll work out WTF, and report back.

    Update:

    Yeah, apparently I didn't have the 2011 redistributable, which is solved by installing the 2012 one. Which I already had installed. But, hey... I'll play their silly games and reinstalled it, and now ColdFusion 2016's installer has completed no worries.

    I remain underwhelmed by ColdFusion 201610.5.1, needless to say.

    Righto.

    --
    Adam

    A more professional CFML blog: Ryan Guill

    G'day:
    (more professional than this one, I mean ;-)

    Good news, CFML community: Ryan Guill has started blogging. It's @ http://ryanguill.com/.

    He's off to a flying start with eight articles already:
    If you don't know Ryan already, I can tell you he really knows his stuff, and is a great bloke, so what he writes will be worth reading.

    Righto.

    --
    Adam

    ColdFusion 2016: Adobe finally abandons CFML

    G'day:
    I should have suffixed that with "for all intents and purposes".

    Today ColdFusion 2016 was released. My executive summary of this release is that it's by far the worst ColdFusion release since CFMX6.0. 6.0 was basically released as alpha quality, and not usable for I think three additional beta patches, finally being usable at 6.1.

    ColdFusion 2016 continues Adobe's increasingly prevalent tendency to aim to appeal more to PHB types, but this time finally decides to completely marginalise the actual CFML developer. If ColdFusion 11's only addition to CFML had been <cfclient>... it'd still be a better ColdFusion release - in terms of CFML - than CF2016 is. That's how crap CF2016 is.

    In this light, I think it's clear that Adobe have pretty much given up on the CFML community, instead thinking their "community" is a bunch of purchase-order-signing IT managers.

    ColdFusion 2016 includes a bunch of non-CFML features, which are varying degrees of relevance and interest to the CFML developer, but there are only... 2 (f***ing two!!)... enhancements to the CFML language. We've been waiting two years for more stuff to go into the CFML language, and that's what we get. This is appallingly cynical from Adobe.

    So what are the CFML features? Let me quote from the release docs:

    Language enhancements

    For safe navigation, “?.” operator has been introduced. Collections support for “ordered” and “sorted” has been introduced. Refer this section to know more about all the language enhancements.

    That's it. Two things.

    I've already written about both of the features they list above:


    Both of these have changed since I wrote about them:
    • the scope of sorted/ordered structs has been pegged back a bit, and there's now only ordered structs, as Adobe realised "ordered" and "sorted" are synonymous terms, and they only really needed the one concept. The implementation they have shipped is a bare minimum to not take the piss, but it's not as good as the alpha version I wrote up. I'll leave it to you to examine the final implementation.
    • the implementation of the safe-navigation operator has been tweaked to also do a null-safety-check on the last right-hand-side operand (read the linked-to article for explanation of this), but it has been released in an incomplete state as it only supports dot notation, not bracket notation.
    They've actually forgotten a coupla small things: there are now iteration methods for queries (.map().reduce() etc), and I heard someone mention there's also a valueArray() method now... I've not tested that.

    I've had a quick look at the query iteration methods, but do't have anything to show for it yet. I'll get onto that next.

    And actually there is another feature: arrays are now "passed by reference" rather than "passed by value", which is long overdue, and more a design bugfix than a feature IMO. And is that really a CFML feature? I guess it's code-centric.

    To be fair there's also some tweaks to PDF functionality, but as the whole concept of PDFs makes me...

    ...zzzzzzzzzzzzzzzzzzz...

    ... sorry, dunno what happened: dropped off there for a second. Um... right... PDFs... yeah, one can do stuff with redaction and comments and metadata, but I have no idea what and intend to keep it that way.

    The other actually good developer-centric feature of ColdFusion 2016 is the CLI, which is a welcome addition, and has been implemented well. But it's not a CFML enhancement. I wrote up the alpha implementation a while back: "ColdFusion 2016: the long-awaited CLI". It's not moved much since then, so I won't go into it more.

    But what about all those tickets Adobe marked "to fix" shortly before and during the pre-release? Nothing, as far as I can tell. I know goalposts change during development of new software, but I really do think Adobe changed the status on those tickets purely to get people off their back, and they never really had any intention of fixing them in ColdFusion 2016. I'm sure someone will come back saying "they just said 'to fix', they never said when". That's just disingenuous. But I'm sure that was the particular combination of smoke and mirrors they were going to fall back on if anyone called them on it.

    What other stuff is there?

    NTLM authorisation has finally been added to I think all features which should have had it from the outset. This is not a new feature IMO, but basically bringing beta-quality features up to release quality. It makes them usable beyond general proof of concept.

    There's a half-baked, feature which allows one to hive session storage off to a redis data store which isn't bad conceptually, but I don't think the realisation is that good. Still: this is an administrative feature, not a language feature.

    The marquee features of ColdFusion 2016 are ColdFusion-administrative sort of stuff, indeed the main feature, the API Manager is a completely separate app, and I'm not sure why it's been shipped as part of ColdFusion. Note it's an API Manager, not a ColdFusion API Manager. SO it's like a separate Adobe product they bunged in with ColdFusion 2016 simply cos they got the same team developing it. Well: developing it at the expense of actually working on ColdFusion itself, it seems.

    ColdFusion Builder has had a code security scanner built into it, but that's CFB not ColdFusion, so who cares about that? It requires using CFB to use it, so that pretty much invalidates it as far as being relevant goes, I think.

    One caution I have here is that the pre-release cycle seemed very short this time around. It's usually about a year, I think; this time it was more like six months. I cannot go into detail about the inner workings of the PR due to an enduring NDA, but I will let the reduced duration speak for itself. As I would always advise: do not upgrade your environments yet. Perhaps put a ColdFusion 2016 server into your test lab and run your tests against it. But do not make plans to go live with it yet. I would usually recommend waiting until the .0.1 or .0.2 release of any new ColdFusion version before running with it, but if one takes the duration of the prerelease, I think one ought to consider this a public beta rather than the release version, so perhaps hold off longer even than usual.

    What an abject disappoint.

    As a footnote to this, Ray's written an article about his thoughts on ColdFusion 2016, as well as pushed the boat out a bit and made some (supposedly) NDA-friendly observations about the ColdFusion 2016 Pre-release programme. You've probably already read his stuff before landing here, but if not: Adobe ColdFusion 2016 Released.

    I'll give those query iteration methods a whirl and report back...

    --
    Adam

    Tuesday, 9 February 2016

    "Adam Cameron is kind of a twat"

    G'day:
    I know it's puerile of me to revel in such things, but this made me laugh: "Adam Cameron is kind of a twat."

    It is, of course, completely true.

    Well done, "TimDuncanTheAlmighty". Well done.

    Righto. All this twattery does not get done by me loafing around here. I better crack on with it.

    --
    Twat