Thursday, October 6, 2016

More Date Masking

I'm a bit ashamed of myself. I've been a member of the ColdFusion Community for over 15 years, yet I just submitted my first bug to the BugBase yesterday. And I'm not even really sure that it's a "bug" per se; just an inconsistency in behavior of similar functions.

https://bugbase.adobe.com/index.cfm?event=bug&id=4194962
(Lucee bug added: https://luceeserver.atlassian.net/browse/LDEV-1025)

Basically, it touches on what has become a pet-peeve of mine: Date Masking. I know I've ranted about it before, but I wish that everyone could just agree on what a proper date mask was for all of the common date parts.

In the latest update to ColdFusion, Update 3, one of the things Adobe announced in the release notes was that you can now use lower- or upper-case letters in DateFormat() masking. My issue with this is that it is completely different behavior from DateTimeFormat(), which seems to make a bit more use of Java's case-sensitive SimpleDateFormat. Granted, I don't agree with Java's way of using "M" to mean "months" and "m" to mean "minutes" (I like CF's "n" minutes), but I still think the two CF functions should be consistent with each other. It's feasible that a dev would have to switch between a date format with and without a time component or have multiple types of date masks on the same page. And the natural assumption would be that the mask from one should work as the mask for the other. At least I would think so.

Last year, I got bit by this behavior when it came to the Year mask. December 29, 2015 was being displayed as 12/29/2016. ???? FYI: DateFormat(someDate,"MM/DD/YYYY") may not return the same thing as DateTimeFormat(someDate,"MM/DD/YYYY"). This is where I learned about the slight difference between a Calendar Year and a Week Year. Not to mention the fact that it will only happen at most on the last few days of a year.

And to make matters worse, we also used moment.js, which expects the year to be formatted as a capital "Y". :-/

I've never made it a secret that I'm not a fan of silent errors. And, yes, this would be an error on the developer's part for not using the proper mask, but it's an easy error to make (especially when using different masks) and even easier to completely miss.

I would like to see Adobe make the date formatting functions be a bit more consistent with each other.


THANK YOU, TRYCF.COM! http://trycf.com/gist/78a374effc62c05330cd33030da265cd/acf2016?theme=monokai

Adobe ColdFusion 2016
Adobe ColdFusion 10

And Lucee just gets wonky with its CFMXish behavior of kinda passing through masks it can't interpret.
Lucee 4.5

Monday, October 3, 2016

ColdFusion 2016 Update 3 Is Live!

http://blogs.coldfusion.com/post.cfm/updates-for-coldfusion-2016-and-coldfusion-builder-2016-is-available-now

ColdFusion 2016 Update 3 is now live. There were quite a few bugs fixed. https://helpx.adobe.com/coldfusion/kb/bugs-fixed-coldfusion-2016-update-3.html

Boolean Girl - STEM Teaching With RaspberryPi

I should have shared this last week when I saw it. STEM education, especially when it comes to bringing more young girls into the dev community, is one of my soap boxes. And as a geek (and lover of Erector sets and those old "Build Your Own Radio" kits with springs and wires from the 80s), the RaspberryPi is one of the coolest inventions of my lifetime. So when I saw the Kickstarter for the Boolean Box, I ordered one for my niece (and to be honest, one for myself, too). Please, if this interests you, back it. 

Boolean Box Kickstarter  (https://www.kickstarter.com/projects/71092263/boolean-box-a-technology-discovery-kit-for-girls)

Boolean Girl Website (http://www.booleangirl.org/)

DON'T PANIC!

Before I was a code monkey, I flew airplanes. I never realized how the lessons I learned then could apply to regular life. I've always said I can teach someone to fly a plane in just a few hours; it's the hours after those first few that teach you to be ready for the unexpected. You learn early that when things go sideways, you only make it worse if you panic.

I was driving back to North Carolina from Nashville on Sunday, and I had a tire-disintegrating blowout. I drive a Silverado, so it wasn't a small tire. I was in traffic, doing about 75 mph, when my front passenger tire decided it was time to let go. I'm sure anyone who's ever had a blowout can attest that it's somewhat of an adverse situation. And I know we've all seen news reports of serious road accidents caused by a high-speed blowout.

So how does this relate to piloting? First and foremost, as I said above, when bad things happen, you learn to stay calm and deal with the problem. More directly, when flying multi-engine aircraft, one of the first things you learn is how to deal with an engine failure and the resulting tendency to "pull" to one side. When bad things happen, like an engine failure or a blowout, they don't usually give you a lot of warning. So you learn that, rather than be surprised, you STAY CALM and KEEP OPERATING YOUR VEHICLE.

When my tire blew, my truck immediately started pulling me to the right. But there was a car there who probably wasn't too keen on sharing space with me. So I couldn't let my truck take me there. I let off the gas and, when I was clear, moved over to the shoulder. I didn't panic.

As I write this, I'm sitting in NTB having a new tire mounted. This isn't how I wanted to spend my lunch break today, but it could have been much worse. I could have been one of those stories on the nightly news. But instead, when a bad situation suddenly developed, I kept my head and dealt with the problem. My old training (even though it was in airplanes and not cars) kicked in.

A quick Google search shows that my lessons weren't exactly unique to piloting. They were based in some common sense steps for disaster preparedness found in many fields. Operate, Communicate, Mitigate. In that order. Whether you're flying a plane, driving a car, or dreaming peacefully in bed, you should be prepared for the engine failure, the blowout, or the 3am call that lets you know the website is down. If you know what you're going to do when a problem happens, you won't have to think about how to handle it when it finally does.


NOTE TO OTHER DRIVERS: If you see someone on the side of the road, PLEASE PLEASE PLEASE show a little bit of courtesy and move over. It's rather unsettling to have a car zip past you at 70+ mph. Especially when they're only a few feet from you.

Sunday, September 25, 2016

NCDevCon 2016

http://ncdevcon.com/
Saturday and Sunday, Sept 17-18, 2016

I got home from NCDevCon last Sunday night. It's been a week, and they've already released the videos online (https://textiles.online.ncsu.edu/online/Catalog/catalogs/ncdevcon-2016). I've procrastinated long enough, so here's my write up.

First off, I want to say a big THANK YOU to the organizers and the sponsors. This was the first year I've attended. I've heard before that it was a great conference, and I definitely wasn't disappointed. It was good to see some of the people that I met before, and it was also good to meet new people. There are some very bright individuals in this community.

As always seems to be the case at conferences, I run into a conflict of having multiple talks scheduled at the same time. I'm glad these sessions were recorded. When they're released, I'll definitely be going back to watch some of the ones I missed.

Anyway, off I go...

I arrived in Raleigh, NC on Friday night. It's only supposed to be about a little less than 3 hour drive from Charlotte, but traffic was HORRIBLE. It took over 4, and I got there later than I expected. But I was still able to meet up with a few others at the hotel, with enough time for a cold beer. Thank you, Dan! After an hour or so of catching up and general yapping, it was time to hit the sack for the conference the next day.

The conference was at NC State University Centennial Campus, College of Textiles (THANKS TO YOU, TOO!). The conference hotel was the Sheraton, right downtown, where quite a bit was going on. I was cheap, and stayed down the road at the Red Roof Inn. All I can say is Thank Goodness for Uber and Lyft. Next year, I think I'll stay closer to everyone else.

DAY 1

Registration began at 8am. I got there around 815, still somewhat sleepy-eyed. Time for a quick, simple breakfast and more yapping, before Adobe's opening remarks.

Elishia Dvorak from Adobe spoke a bit about the recent rise of APIs. Though it wasn't really the focus of her opening, it should be noted that ColdFusion 2016 includes a new API Manager feature, which makes it very convenient for API development. I don't do a lot of API development, but I probably should focus a bit more attention on it.

For my first session, I attended Dependency Injection 101 by Anant Pradhan. He went over the basics of what it is. How the concept is framework and language agnostic. The difference between the "normal" way of an object finding its dependencies and calling them vs inversion of control, with an object being provided with the objects it needs. He talked about a couple of the main frameworks used in ColdFusion, DI/1 and Wirebox. I don't currently do a lot of direct, DI. It's definitely something I need to learn more about.

Session 2 - Taking Your Searches to the Next Level with Solr and Elastic Search by Mary Jo Sminkey

Solr and ES are both full text search engines. ES is better at analytics (like log analysis) and Solr is very good at text search. Solr has been a part of CF since CF9, and is based on Apache Lucene. With CF11, Adobe upgraded Solr to V3, and then again in CF2016 to v5. For a good breakdown, look at solr-vs-elasticsearch.com. Things to watch out for with Solr: searching multiple documents, standard issue with CF serializing a number string like "0123" as a numeric value like 123, and "sea biscuit" problem (multi-term synonyms). Results can be returned in multiple formats with JSON and CSV being most common. Filters are the most basic way of restricting the documents to search. fq = filter query. A simple search => /select?q=front+bumper.

After Session 2, we broke for Lunch (thanks Adobe for sponsoring). The lunch breaks were a bit too long, but the food was very good. Now that we're all fed, time to start the afternoon sessions.

Session 3: MVC With and Without a Framework by Nolan Erck

I first saw this Nolan's presentation at CFSummit 2015, and this is by far one of my favorite presentations I've seen at any conference. If you get the opportunity to see this live, DO IT. Otherwise, check a recording of it. It's definitely worth it.

Nolan demonstrates a good use case for the MVC Pattern by taking common spaghetti code and demonstrating how MVC can benefit it. He starts with some basic definitions:
Design Pattern = "$6 word for 'a common problem solved by organizing objects in a certain way".
View = The App that users see; minimal CF logic; NO business logic or SQL. "Like the Menu at a Restaurant".
Model = Sorta short for "data model"; where ALL of your SQL lives; business logic. "Like the Kitchen / Chef at a Restaurant".
Controller = Sits between Model and View; No HTML output or SQL; Small bits of logic controlling the app flow. "Like the Waiter in a Restaurant".

View <> Controller <> Model

Factory Design Pattern = solves the problem of a change in database ( ie MS SQL to Oracle ).

MVC Pros:
- Promotes code reuse
- Allows multiple people to work on code at the same time
- Pattern is non-framework and non-language specific
- Very common pattern / nomenclature (things mean the same thing in other languages)
MVC Cons:
- Learning curve
- "more typing" (just use hotkeys then)

Use a Framework
- Same design patterns
- FW/1, ColdBox, ModelGlue, MachII, etc
- FW/1 uses a naming pattern of folders to find files

Open Session Sponsored by StrongLoop - Building APIs
I am not even remotely familiar with StrongLoop, so I skipped this one.

Session 4: Less Hate, More Love With ColdFusion ORM by Masha Edelen
She recommended www.coldfusionORMBook.com
ORM = Hibernate first introduced in CF9.
It reduces time by eliminating CRUD and reducing about 95% of common data tasks.
To setup, in Application.cfc >> this.ormenabled=true; then map tables to objects.
IT'S ALL ABOUT RELATIONSHIPS.
Entity names are CASE SENSITIVE.
Watch out for SQL Injection in HQL.
ORMExecuteQuery(hql,params[,unique][,query options]);

To be honest, I don't currently use a lot of ORM. I'm also a fan of letting the database do its job rather than coding the job for the database. I know it's almost a religious debate, but I'm not overly fond of ORM. But that's likely because I just don't know a whole lot about it.

Session 5: ES6 Web Components by Ben Farrell
By two biggest takeaways from this one:
1) I don't know a whole lot about ES6 or Web Components.
2) Ben Farrell is a WONDERFUL presenter! He was very entertaining and engaging, even though most of his preso flew over my head.

As Day 1 drew to a close, Adobe sponsored a networking event for attendees. They catered it with some good finger foods, and drinks with beer provided by a local brewery, Raleigh Brewing Company. What can I say, the brew was excellent!

Several of us headed out for some dinner. Apparently Chicken and Waffles at Beasley's downtown is a conference tradition. The food was excellent, and the company was great. I'm glad I participated.

DAY 2

Session 1: CFML Features For More Modern Coding by Dan Fredricks

This is another one that I saw previously at CFSummit 2015. It too is an excellent presentation and definitely one with some good, applicable content. Dan updated this with some of the new features in CF2016.

Session Notes:
As of CF11, we have full script support for the language.
"Do what is best for you, but try to be CONSISTENT."
Some of the tags have multiple implementations ( ie thread() and cfthread() ).
QueryExecute() is liked much more than previous implementations of script queries. queryExecute(sql[,queryParams][,queryOptions])
MEMBER FUNCTIONS!!! Added as of CF11 and make things more oriented to OOP.
  Old: ArrayAppend(empArray[],empID) ;
  New: empArray.append(empId) ;
  This allows method chaining.
  Watch out because some member functions may drop into underlying Java if build incorrectly.
Elvis Operator added in CF11 ?:
  Like a ternary operation: isNull(x) ? y : x and x?:y
Closures: Added in CF10 with more added in CF11 and 2016
  == functions that bind variable references at declaration-time instead of use-time. Callbacks are not closures. The inner function has access to outer function variables.
  There are several closure functions built into CF.
  Testbox uses closures (that's why it requires CF10).1
  Mark Mandel = Sesame ; Adam Tuttle (fusiongroker.com) = preso on closures.
Map, Reduce, Each and Filter
  Map() iterates over a collection and returns the whole collection with values changed (not key/index)
  Reduce() more complex than map(). Iterates over a collection and from each element derives one value as the result.
  Filter() similar to map() and reduce(). Iterate over object and return a new object without affecting the original.
  Each()
  In CF2016, map() and reduce() can be used on queries.
First Class Functions == object that could be passed as an argument. (see list of available functions = arrayLen, lcase, etc) First introduced in CF11.
  Callback functions = function passed into another function.
2016 Additions:
  Safe Navigation Operator (?.)
    Used to access members of a struct when one of them is NULL or not defined.
writeOutput(employee?.name?.firstName?.lcase());
  Ordered collections = structNew("ordered") >>
  ArrayPassByRefence -- speed up passing arrays. Used to be passed by value.
    Application.cfc = PassByReference='true'
  SearchImplicitScopes -- Don't scope hunt unscoped variables.

There was a lot of good info in this presentation.

Session 2: Git Source Control For The Rest Of Us by Nolan Erck

I noticed during this presentation, that this was actually the first one I attended that wasn't part of the ColdFusion track. That was totally unintentional; I just saw more applicable sessions in that track, I guess.

Nolan has some good presentations, and this one is another. He covered some of the basics of using a source control system, particularly Git on a Windows system through the SourceTree gui client. He talked about some of the more common commands (like "add", "commit", "revert", "branch", etc) and why you should use a Master branch to be your source for Production-ready code. He recommended Brad Wood's presentation on What's a Pull Request, which is available at https://experts.adobeconnect.com/_a204547676/p7dwzsxehq1/?launcher=false&fcsContent=true&pbMode=normal or https://vimeo.com/175768635 or https://www.youtube.com/watch?v=dTlEFQxlrrQ He also recommended Tim Cunningham's CFHour (118) preso.

Session 3: ......

It was supposed to be W3C Content Security Policy & HTTP Headers for Security by David Epler. I attended his and Pete Freitag's Security session at CFSummit2015, and it made a bit of an impression. I really wanted to attend Dave's talk about Content Security Policy, but I have to admit, I missed it. I sat outside his door yapping with Nolan and a couple of other people about Git. Sorry I missed it, Dave. That'll top my list of preso videos to watch this evening.

Which brings us to Lunch time, catered by Moes!

Session 4: CFML: Code Security Best Practices by Trip Ward

This presentation was supposed to be given by Denny Springle, but due to some unfortunate issues with Denny getting to Raleigh, Trip stepped in very late in the game to give this preso, and it's good that he did. There was a ton of good information in this talk.

Session Notes:
Who writes these insecure apps? Us.
Real threats are silent.
We must protect PII.
When it comes to data protection, you can have too much of a good thing. Do not hash and encrypt everything. Pick and choose the important data.
Hash() KEYS and Encrypt() VALUES before looping.
However, remember that it's better to have SOME security than NONE. If you have to, fall back to ECB/128bit keys if performance is an issue.
Attack vectors: SQL Injection, XSS, CSRF, Cookies, Tidbits (cflocation, file upload validation, form methods, file injection, application naming...)
Code Curmudgeon site.
Cookies >> httponly="true" secure="true"
HTTP Headers >> Check your headers (cyh.herokuapp.com/cyh). Check Dave Epler's Content Security Policy preso.
Security Objects >> This is the first thing you should implement in a new project.
If you have to create your own, cache it in the Application scope.
Hide all errors on external apps.
HPP = HTTP Parameter Pollution.

Final Group Session: Virtual Reality Wants You: How developers fit into the new VR landscape by Jason McGuigan and Jason Cooper

Once again, I was yapping with other conference attendees and missed this last session. I don't currently work with VR, but it seemed to be well-liked: it was in the same room as the Closing Remarks, and there were still long lines waiting to check out the VR headsets.

And NCDevCon2016 comes to a close. The organizers drew for some prizes and made some closing remarks. Again, it was great to see some of the people I previously met, and I really enjoyed meeting some new people. NCDevCon was a blast. There were very good presentations. The presentations were recorded, so I'll be going back to watch the presos that I missed.

Once again, thank you to the organizers and the sponsors. I'll see everyone again at NCDevCon2017.




Sunday, July 3, 2016

About Application.cfc

Pet Peeve: Proper Capitalization Of Application.cfc --- It's kinda nitpicky, but I hate seeing people write application.cfc/cfm. On a windows machine, it won't hurt. But putting that on a case-sensitive system, like Linux, will quickly teach you the difference between application.cfc and Application.cfc. I'm all for consistency. If you make it a habit to write Application.cfc, even when you don't have to, you won't accidentally mis-name the file when you create it.

That said, this is a topic that has been written about ad nauseam over the years, but it's VERY important to grasp the underlying framework of the Application.cfc file.

https://helpx.adobe.com/coldfusion/cfml-reference/application-cfc-reference/application-variables.html

/**
@title "Application.cfc reference in CFScript for Coldfusion 9"
@description "This component includes all Application.cfc methods and variables, set to their default values (if applicable). Please note that default values are not always desirable, and some methods or variables should be modified or removed depending on the situation."
@author "Russ S. (http://cfruss.blogspot.com)"

@dateCreated "November 29, 2009"
@licence "This work is licensed under the Creative Commons Attribution 3.0 United States License. To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/us/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA."

@hint "You implement methods in Application.cfc to handle ColdFusion application events and set variables in the CFC to configure application characteristics."
*/


component output="false" {

/* **************************** APPLICATION VARIABLES **************************** */

// The application name. If you do not set this variable, or set it to the empty string, your CFC applies to the unnamed application scope, which is the ColdFusion J2EE servlet context.
THIS.name = "";

// Life span, as a real number of days, of the application, including all Application scope variables.
THIS.applicationTimeout = createTimeSpan(0, 1, 0, 0);

// Whether the application supports Client scope variables.
THIS.clientManagement = false;

// Where Client variables are stored; can be cookie, registry, or the name of a data source.
THIS.clientStorage = "registry"; //cookie||registry||datasource

// Contains ColdFusion custom tag paths.
THIS.customTagPaths = "";

// The Google Maps API key required to embed Google Maps in your web pages.
THIS.googleMapKey = "";

// Name of the data source from which the query retrieves data.
THIS.datasource = "";

// Whether to store login information in the Cookie scope or the Session scope.
THIS.loginStorage = "cookie"; //cookie||session

// A structure that contains ColdFusion mappings. Each element in the structure consists of a key and a value. The logical path is the key and the absolute path is the value.
THIS.mappings = {};

// Whether to enable validation on cfform fields when the form is submitted.
THIS.serverSideFormValidation = true;

// Whether the application supports Session scope variables.
THIS.sessionManagement = true;

// Life span, as a real number of days, of the user session, including all Session variables.
THIS.sessionTimeout = createTimeSpan(0, 0, 30, 0);

// Whether to send CFID and CFTOKEN cookies to the client browser.
THIS.setClientCookies = true;

// Whether to set CFID and CFTOKEN cookies for a domain (not just a host).
THIS.setDomainCookies = false;

// Whether to protect variables from cross-site scripting attacks.
THIS.scriptProtect = false;

// A Boolean value that specifies whether to add a security prefix in front of the value that a ColdFusion function returns in JSON-format in response to a remote call.
THIS.secureJSON = false;

// The security prefix to put in front of the value that a ColdFusion function returns in JSON-format in response to a remote call if the secureJSON setting is true.
THIS.secureJSONPrefix = "";

// A comma-delimited list of names of files. Tells ColdFusion not to call the onMissingTemplate method if the files are not found.
THIS.welcomeFileList = "";

// A struct that contains the following values: server, username, and password.If no value is specified, takes the value in the administrator.
THIS.smtpServersettings = {};

// Request timeout. Overrides the default administrator settings.
THIS.timeout = 30; // seconds

// A list of ip addresses that need debugging.
THIS.debugipaddress = "";

// Overrides the default administrator settings. It does not report compile-time exceptions.
THIS.enablerobustexception = false;

/* ORM variables */

// Specifies whether ORM should be used for the ColdFusion application.Set the value to true to use ORM. The default is false.
THIS.ormenabled = false;

// The struct that defines all the ORM settings. Documentation: http://help.adobe.com/en_US/ColdFusion/9.0/Developing/WSED380324-6CBE-47cb-9E5E-26B66ACA9E81.html
THIS.ormsettings = {};

// note: THIS.datasource applies to cfquery as well as ORM. It is defined on line 31.


/* **************************** APPLICATION METHODS **************************** */


/**
@hint "Runs when an application times out or the server is shutting down."
@ApplicationScope "The application scope."
*/
public void function onApplicationEnd(struct ApplicationScope=structNew()) {

return;
}


/**
@hint "Runs when ColdFusion receives the first request for a page in the application."
*/
public boolean function onApplicationStart() {

return true;
}


/**
@hint "Intercepts any HTTP or AMF calls to an application based on CFC request."
@cfcname "Fully qualified dotted path to the CFC."

@method "The name of the method invoked."
@args "The arguments (struct) with which the method is invoked."
*/
public void function onCFCRequest(required string cfcname, required string method, required string args) {

return;
}


/**
@hint "Runs when an uncaught exception occurs in the application."
@Exception "The ColdFusion Exception object. For information on the structure of this object, see the description of the cfcatch variable in the cfcatch description."
@EventName "The name of the event handler that generated the exception. If the error occurs during request processing and you do not implement an onRequest method, EventName is the empty string."

note: This method is commented out because it should only be used in special cases
*/
/*
public void function onError(required any Exception, required string EventName) {
return;
}
*/


/**
@hint "Runs when a request specifies a non-existent CFML page."
@TargetPage "The path from the web root to the requested CFML page."
note: This method is commented out because it should only be used in special cases
*/
/*
public boolean function onMissingTemplate(required string TargetPage) {
return true;
}
*/


/**
@hint "Runs when a request starts, after the onRequestStart event handler. If you implement this method, it must explicitly call the requested page to process it."
@TargetPage "Path from the web root to the requested page."
note: This method is commented out because it should only be used in special cases
*/
/*
public void function onRequest(required string TargetPage) {
return;
}
*/


/**
@hint "Runs at the end of a request, after all other CFML code."

*/
public void function onRequestEnd() {
return;

}


/**
@hint "Runs when a request starts."
@TargetPage "Path from the web root to the requested page."
*/
public boolean function onRequestStart(required string TargetPage) {

return true;
}


/**
@hint "Runs when a session ends."
@SessionScope "The Session scope"

@ApplicationScope "The Application scope"
*/
public void function onSessionEnd(required struct SessionScope, struct ApplicationScope=structNew()) {

return;
}


/**
@hint "Runs when a session starts."
*/
public void function onSessionStart() {

return;
}

}

Tuesday, June 14, 2016

CF_PublicServiceAnnouncement: Updates Galore!

First off, Adobe has released new patches for the ColdFusion products.This includes a Security Hotfix for CF2016, 11 and 10 for a potential XSS issue, so it would probably be a good idea to update.

http://blogs.coldfusion.com/post.cfm/updates-for-coldfusion-2016-coldfusion-builder-2016-coldfusion-11-and-coldfusion-10-released

Also today, Lucee 4.5.3 has been released with a heap of fixes.

http://lucee.org/blog/lucee-4-5-3-release.html


Wednesday, June 8, 2016

ColdFusion Scopes: Part Deux - "Mutually Exclusive" LOCAL and ARGUMENTS

While playing with LOCAL and ARGUMENTS scopes and the scope order bug, I also came across a behavior that I didn't really know about - LOCAL and ARGUMENTS scopes in a CF function are supposed to be "mutually exclusive". Maybe I misunderstand what that phrase means.

https://gist.github.com/shawnoden/ef494ef92ccd3821a189 http://help.adobe.com/en_US/ColdFusion/10.0/Developing/WSc3ff6d0ea77859461172e0811cbec09af4-7ff1.html http://help.adobe.com/en_US/ColdFusion/10.0/Developing/WSc3ff6d0ea77859461172e0811cbec0a66e-7fe2.html http://help.adobe.com/en_US/ColdFusion/10.0/Developing/WSc3ff6d0ea77859461172e0811cbec09af4-7fdf.html

Friday, May 27, 2016

Security+ Certification!

After weeks of study, I am now officially CompTIA Security+ Certified!



This is my happy face >> :-)

Wednesday, May 4, 2016

Monday, May 2, 2016

Testing: A Confession

I have a confession to make. In the software world, this confession probably ranks right up there with kicking kittens or believing that Firefly deserved to be cancelled, but it's one that I still feel I should make. I've been a developer for over 15 years, and almost all of that time has been spent NOT WRITING TESTS. I have always done the traditional developer QA and smoke testing, but I have spent years making all sorts of excuses as to why I don't actually write tests: I don't have the time to do it. My company's infrastructure isn't set up for it. We have a QA team that does our testing. Or my favorite: We have a mass of legacy code and it's too hard to test.

Those may be some valid "reasons", but they're really just excuses.

I'm a hypocrite, too. I've known the value of testing for most of my career. I've preached that it should be done. But I've never really strongly advocated for it where I've worked. I'm changing that.

I work on a fairly significant code base that doesn't currently have any tests. We constantly make changes and we deploy often. In the last couple of weeks, I've been bitten twice by code that I just created that affected other pieces of my site in ways that I didn't expect. Proper Unit Tests would have picked up those regressions before I ever even checked in my code. So this has given me a bit of a kick to actually start doing something about it. I'm fortunate in that I have a few allies at work who see this need, too. I don't have to be the new guy bucking the system.

We work mostly with ColdFusion and jQuery, so a large hurdle has been just figuring out what the best way to test is. I've chosen Ortus' TestBox for my CF code. It's got great support. It's fairly easy to setup and use. I like it a lot. I've only got a couple dozen tests in place, but I already see several ways that I should have written my code better. I'm seeing some things that appear to be hard to test, but I think that's because I'm just not well-versed in actually testing software like this. I'm determined to get much better at it.

I've confessed my sin. I don't really feel that much better, but let the adventure begin.

Tuesday, April 26, 2016

[REVIEW] Guess What Came In The Mail: Pine64


I am fascinated with tiny computers and the things that a unit like the popular RaspberryPi enables. And when I saw the Pine64 on Kickstarter, I was intrigued. A 64-bit computer for $15!!!! No way!!! I became a backer at the original $15 price (+shipping, but really, at this price shipping doesn't matter).

I watched the Kickstarter move to become a successfully funded project, and then watched some people get frustrated that they didn't get their P64 in February when originally told. Apparently they didn't think about what would happen to an unexpectedly popular and successful Kickstarter campaign. Plus, I guess I value my $15 pledge much less than some of them do. The way I look at Kickstarter, I fund the dreams of other people. When I tell them I'm gonna give them some $, it's a dream that I like, but still a DREAM. If their dream fizzles, then that sucks. I'm still glad I could help them realize their dream. But if they succeed and I get to be part of something cool, then Bonus For Me! I helped make a Veronica Marrs movie, and now I've helped make a $15 computer become a reality. Even if I saw nothing, it was all money well spent.

All that said...  I got a package in the mail today. Guess what it was.....

Guess what came in the mail!
Yup, I am now a proud owner of a 64-bit hand-sized computer with 2gb of memory!

When I first became a web monkey, I was building enterprise-level apps on a Pentium server that wasn't even in the neighborhood of thinking about multiple cores. I still have some "large" 256 MEGABYTE memory chips from those machines. I could build my entire system architecture in virtual machines on my laptop. The power that is now able to be packed into a palm-sized machine is crazy.

Anyway.... back to my mail.

I was an early backer of this thing, and more importantly, a believer. I was a bit giddy when I opened up my mailbox today. I knew what it had to be, but I still felt like a kid in a candy shop. So what did I get....

A PINE64!!! <shamelessPlug>www.pine64.org</shamelessPlug>

For those who haven't hear about this one, it's a VERY tiny computer, a lot like a RaspberryPi, but it's only about 15 bucks. You just can't beat that price. I saw it; I backed it; I bought some accessories: I have it now.
The Package Contents!

Here's my review:

In my former life as a Fulfillment Guy, I would have wanted to use sturdier packaging to prevent damage in transit. I received this thing, with the accessories I ordered, in a normal padded envelope. I would have preferred heftier packaging, but nothing was even remotely damaged, and most importantly, let's not forget that this is essentially A $15 COMPUTER!!!

When I unpacked everything, I assumed that the larger box was the actual unit. WRONG. That was the acrylic case that I ordered. The unit is TINY. To be fair, it's larger than my older model RaspberryPi, but if I hold it up next to another motherboard, I'm not sure this scale is much of an issue.


After getting everything unpacked, I began putting it all together. I bought the acrylic case from the site, and it's a little bit bigger than I thought it would be. I expected something more commensurate with the form-factor of the unit itself. But the size isn't really an issue, because the case looks AWESOME!

Pine64 Acrylic Case
To this point, putting the thing together has been dead simple. The hardest part I've found so far is WHERE ARE ALL MY POWER STRIPS???

Now that I've found power, I need to crank this thing up. But a computer won't do much without some sort of operating system. I was lazy. I went for the first option on the Pine64 Wiki (wiki.pine64.org): Debian Linux with Mate GUI by lenny.raposo. Thank you, Lenny!

  • I used my RasPi tools to prep the SD card for the OS: SDFormatter to prep the disk and then Win32DiskImager to write it. It was a 1.4gb download, but it extracted to an 8gb image. Make sure you have enough SD card for it.
  • Pine64 vs Mobo
  • One very big difference between this and the RasPi is in the size of the card the OS runs on. RaspberryPi runs on a full-sized SD card. The Pine64 runs on a micro-SD card. Many modern SD cards already come with an adapter for a micro-SD to a full-size SD port, but we don't need the adapter here.

RasPi vs Pine64
This unit is tiny. But it's still larger than my older RaspberryPi. However, to put it into perspective, it's not even worth comparing the size to a full motherboard.

Now that we're all hooked up, it's time for the moment of truth: Does this thing power on? Fewer things in life are more disappointing than spending time to carefully put together a computer only to have nothing happen when you finally push the power button.


FLASHY LIGHTS == POWER!!!

Ladies and Gentlemen, here we go......







AND..... BOOTED!!!

WE HAVE SUCCESS!!!!







CONCLUSION: In my very limited experience with small boards like the Pine64 or Raspberry Pi, I can't really give much of a valid comparison yet. However, I will say that I REALLY like the Pine64 so far. The unit itself was $24 for the 2gb model, and all-in-all, I think I spent a grand total of around $80 on this entire setup. And that includes two additional power supplies for my other RasPi units and two HDMI-to-DVI and -VGA adapters. The case is large, but it looks very nice. All-in-all, I am VERY pleased with this purchase.

Now the fun begins... what do I make with this thing?

Monday, April 25, 2016

Adobe ColdFusion Developer Week 2016

For those of you who haven't heard yet:

http://blogs.coldfusion.com/post.cfm/adobe-coldfusion-developer-week-2016-april-24-29

Adobe Developer Week is currently going on. Two sessions per day. Good info. David Epler's Security Enhancements in ColdFusion 2016 is about to start. 

For the other sessions (from Adobe): 


Monday, April 25, 2016
9:00 - 10:00 am
ColdFusion 2016 Overview
12:00 - 1:00 pm
Security Enhancements in ColdFusion 2016
Tuesday, April 26, 2016
9:00 - 10:00 am
Mobile Applications Made Easy with ColdFusion
12:00 - 1:00 pm
Exploring PDF Capabilities in ColdFusion
Wednesday, April 27, 2016
9:00 - 10:00 am
Protecting APIs using CF 2016 API Manager
12:00 - 1:00 pm
MVC With and Without a Framework
Thursday, April 28, 2016
9:00 - 10:00 am
Realtime with WebSockets
12:00 - 1:00 pm
ColdFusion Performance Tuning and Caching
Friday, April 29, 2016
9:00 - 10:00 am
Extending PDF capabilities using DDX
12:00 - 1:00 pm
CFML Features for More Modern Coding
Follow their link and sign up.

Monday, February 29, 2016

Date Masking Inconsistency

What better way to celebrate Leap Day than with a Date Masking post? It's been cooking in my noggin a while and has been in some form of draft for a month, but better late than never, right? :-/

TL;DR: ALWAYS VERIFY YOUR DATE MASKS ARE DOING WHAT YOU THINK THEY'RE DOING!

I originally encountered this at the beginning of February and while digging for the cause, came across the issue in the CFDocs site (https://github.com/foundeo/cfdocs/issues/266). I played a bit with some of the masking and learned that some of my old ways were smacking me. I've been in the habit of masking a DateTime object with "MM/DD/YYYY..." or something like that. I absolutely hate date math and manipulation, but that hatred has led me to learning more than I ever wanted to know about the bazillion different epoch times and how 12:59:59.998 can sometimes be the same as 00:00:00.000. There's a bit of a rabbit hole there, and I've fallen down it more than I care for.

But I digress. The CFDocs site referenced an Adobe bug for CF10 (https://bugbase.adobe.com/index.cfm?event=bug&id=4105828) reported by Alexander Kwaschny, and as I was playing with this, I began to realize how big of an issue this actually could be for us. FORTUNATELY I didn't find anywhere in our code where we were using dateTimeFormat(), just dateFormat(), but we _were_ using the "YYYY" mask. I'm a firm believer in consistency (that may be a holdover from my piloting days), and I think that if you're going to do something, you should always try to do it the same way to minimize the opportunity for error. Date Masking is a big area that has a lot of potential to cause hard-to-detect problems, and we were setting ourselves up for a big one here. Though I can't really fault anyone, since pretty much every example of date masking or formatting that I've ever seen uses capital letters. I think it's insane for a language (THANKS JAVA, and maybe even ISO8601) to treat "Y" and "y" as two different things for such a narrow edge case. Until this issue, I had never even heard of a Week Year ("Y") (https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html). And to make the issue more fun, it would only even come into play at most about 6 days out of an entire year. You probably wouldn't even notice the problem.

So, my solution.... make sure my date masks reflect the proper things in the languages that I'm using. My years now are formatted with "yyyy" instead of "YYYY", though most of the time, it doesn't make a difference either way. Grrrr.....

======= MY RESEARCH ========
First, I wanted to verify that Oracle is documented to behave as I expect it to. https://docs.oracle.com/cd/B28359_01/server.111/b28286/sql_elements004.htm#CDEHIFJA Oracle 11g Datetime Format Elements

Yup, Oracle treats "Y" and "y" as the same thing in its formatting. Note: even the Oracle examples show "Y" for the date mask.

One other cool thing I discovered about Oracle... the capitalization of the Month mask will determine the capitalization of the output.
'' Months : To_Char(myDate,'MONTH') AS CAPDATE, To_Char(myDate,'Month') AS Casedate, To_Char(myDate,'month') AS lowdate ''
I guess it's not something I've ever used nor paid attention to, but it's still kinda cool to know.

Now, back to ColdFusion:

For the Year difference, DateFormat() doesn't seem to have the problem, but DateTimeFormat() does. Interesting. And Lucee/Railo gets even weirder. http://trycf.com/gist/908f3b1ed6d7490bc470/acf11?theme=monokai

<cfscript>
myDate = CreateODBCDateTime('12/30/2015 12:34:56.789') ;
writeDump(dateFormat(myDate,'mm/dd/yyyy')) ;
writeDump(dateFormat(myDate,'mm/dd/YYYY')) ;
writeOutput('<br>') ;
writeDump(dateTimeFormat(myDate,'mm/dd/yyyy')) ;
writeDump(dateTimeFormat(myDate,'mm/dd/YYYY')) ;
</cfscript>

Will return "12/30/Y'Y'Y'Y" for the dateTimeFormat(), but the proper date for simple dateFormat(). Isn't that old pre-CFMX behavior?

The other mask that bugs me is "S" and "s". "s" is Seconds and "S" is milliseconds, except for when "l" or "L" are milliseconds. And, "S" returns Seconds in dateTimeFormat() and timeFormat(), where it returns the milliseconds in dateFormat(), which technically doesn't even specify a time component to return. ARGH!!!!

Once again, CONSISTENCY CONSISTENCY CONSISTENCY. And the case of a mask shouldn't affect its functionality. There's just too much room for a silent error.

Anyway, that's enough for tonight. I guess these things are semi-documented in various places, but I still don't like it. It just seems way too common to not be an issue. The Adobe ticket says the documentation in CF was fixed to be clearer. I'll check that. And I need to pull down CFDocs and change the date function masks to note these differences in behavior. But this post became the rabit hole that I warned about earlier.


===== OTHER NOTES ========================================================

CF > DateFormat() vs DateTimeFormat()
DateFormat -
 9 = http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7ff4.html
 10+ = https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-functions/functions-c-d/DateFormat.html

TimeFormat - http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-6de0.html
DateTimeFormat - CF10+ - https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-functions/functions-c-d/DateTimeFormat.html
 "The function also follows Java date time mask. For more information, refer to Date and Time Patterns topic in SimpleDateFormat Java API page."

--------------------------

<cfscript>
myDate = CreateODBCDateTime('12/30/2015 15:16:17.19') ;
writeDump(dateFormat(myDate,'s')) ; // 17
writeDump(dateFormat(myDate,'S')) ; // 190
writeDump(timeFormat(myDate,'s')) ; // 17
writeDump(timeFormat(myDate,'S')) ; // 17
writeOutput('<br>') ;
writeDump(dateTimeFormat(myDate,'mm/dd/yyyy hh:nn:ss.l')) ; // 12/30/2015 03:16:17.190
writeDump(dateTimeFormat(myDate,'mm/dd/YYYY HH:NN:SS.L')) ; // 12/30/2016 15:16:17.190
writeOutput('<br>') ;
writeDump(datePart('yyyy',myDate)); // 2015
writeDump(datePart('YYYY',myDate)); // 2015
writeOutput('<br>') ;
writeDump(dateAdd('yyyy',1,myDate)); // {ts '2016-12-30 15:16:17'}
writeDump(dateAdd('YYYY',1,myDate)); // {ts '2016-12-30 15:16:17'}
</cfscript>
>>>>>>>>>>>>

http://trycf.com/gist/5a4209466ccf5e5ea854/acf11?theme=monokai
http://trycf.com/gist/ef686d4c4bf45fb85619/acf11?theme=monokai
http://trycf.com/gist/b24b9c91e6cee5e3c12e/acf?theme=monokai
http://trycf.com/gist/9db92000bb204a561edd/acf?theme=monokai

Links:
Original CFDocs Issue: https://github.com/foundeo/cfdocs/issues/266
http://www.sql-server-helper.com/tips/date-formats.aspx
http://www.java2s.com/Tutorial/Java/0040__Data-Type/SimpleDateFormat.htm
https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-functions/functions-by-category/date-and-time-functions.html
https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-functions/functions-c-d/DatePart.html
http://www.petefreitag.com/cheatsheets/coldfusion/dateformat/
https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-functions/functions-c-d/DateFormat.html




Friday, February 26, 2016

ColdFusion Scope Precedence

A while back (August 2015), Himansu Sekhar Khuntia logged a bug for ColdFusion 10 that dealt with the scope precedence of LOCAL and ARGUMENTS scopes within a function, and specifically how unscoped variables were effected with CF's scope hunting. Current behavior of ColdFusion 10 has ARGUMENTS taking precedence over LOCAL, and I really don't know how far back this problem goes, but apparently the behavior should be LOCAL over ARGUMENTS.

Original bug report for CF10: https://bugbase.adobe.com/index.cfm?event=bug&id=4031746
Possibly related for CF2016: https://bugbase.adobe.com/index.cfm?event=bug&id=4119653

Inside a function, LOCAL scope SHOULD take precedence over ARGUMENTS scope. This is fixed in 2016 (need to try it out) and planned to be fixed in 10/11. We'll see which patch it makes it into.

To make things interesting, I decided to play with the function scopes in CF10 (pre-scope order fix), and got some interesting results. See below.

Moral of the Story: ALWAYS SCOPE YOUR VARIABLES!!!!! To be extra safe, it probably wouldn't be a bad idea to try to keep from naming a variable the same in multiple scopes. ARGUMENTS and LOCAL are SUPPOSED to be mutually exclusive, but they aren't always.

Anyway, thank you to Adobe for actually clarifying that. Now I need to start reporting the discrepancy when I see it documented incorrectly, ie http://www.learncfinaweek.com/week1/Scopes/.

========================================================================


Where Did I Come From?

It's a little late, but since my sidebar gadget text became a bit verbose, I chose to put a quick "Who Am I?" over here. Or rather "Where Did I Come From?"

In a nutshell, I'm a plane jockey turned code monkey. I've been fascinated with computers since I was young. I taught myself BASIC on a Commodore 64 (which I still have) with Family Computing magazine and learned that you could double the space on your floppy disk with a hole punch. My first exposure to "networked" computing involved CompuServe and a modem that was only a couple of generations past a phone cradle. If you don't know what a handshake sounds like, you can't fully appreciate the speed jump from 300 to 12oo baud, much less the "blazing" speed of a 56K modem.

Even though I initially didn't follow my love of computing to a career, through an accidental twist of fate, I left my airline search and ventured onto my coding path. I was working with Access databases and writing basic HTML/CSS/JS back around 1997. In late 1999, I took some time off from trying to figure out what kind of airline pilot I wanted to be, and I went to work for my brother as a ColdFusion developer. I haven't looked back.

In that time, I've done quite a bit of different things. I've installed and repaired computers. I've set up small company and home networks. I've had nightmares about wiring Cat-5 cable and can still remember the wire order (even though I haven't had to do it in almost a decade). I've illustrated and laid out magazines, billboards and even a map of an airport ramp. I configured and sold tablet computers to pilots before they were even called "tablets", and once helped a guy troubleshoot his computer while he was flying at 45,000 ft over the ocean. I've written software for tablets, for the Web, for business reporting and even a good bit of SQL. I've spent the last several years of my life immersed in highly sensitive personal background, medical and military data. I spent several years as a SQL developer, but I'm back to being a web developer.

When I moved to Nashville, TN in 2005, I became a member of my first technology user group, the Nashville ColdFusion User Group (mostly because we hosted the group and I helped with setup and teardown). I met some brilliant and talented people though that group. Sadly, the NCFUG quieted down and went dormant for a while, until a few years ago when my friend Brett rebooted the group. He asked me to be his co-manager (even though I was mostly a SQL guy at that time), and I agreed. He passed away in early 2015, and I took over the group. Since then, I've come back over to ColdFusion development, and made a move out of state. I left the group in some very capable hands, but I still have a desire to see a resurgence of the group that I was a part of for so long.

I'll be the first person to admit that I'm not the fastest coder in the world. But when my stuff goes out, it doesn't come back. I pride myself on a fairly low bug-rate. I hate writing code more than once, and I tend to be hard on my earlier self. I've looked at code I wrote a few years ago and wondered a) who wrote this crap and b) after realizing that I did, how does it still work. 

Being a self-taught code monkey, I know there are more than a few holes in the things I think I know. I've learned a lot, but there are always more things to learn and plenty of ways to do things better. Fortunately (though this blog tends to prove that I procrastinate more than I'd like) I enjoy learning. I enjoy reading. I know a lot of stuff about a lot of stuff. I just hope it's useful stuff to know. The current world is a fascinating place. Between RaspberryPi, IoT, <insertJavascriptFlavorOfTheMonthHere> and all of the other things I'd like to do, I wish there was more time for all of it. :-/

I'll likely eventually move this vanity page to its own spot, but for now it gets to live as a blog post. 

Friday, February 19, 2016

ColdFusion 2016 Has Officially Dropped!

I meant to post this a few days ago when it actually happened, but I'm slacking again. The newest iteration of Adobe's ColdFusion has been released! They went away from their previous numbering scheme: this isn't ColdFusion 12, this is ColdFusion 2016. Interesting. And I'm not sure I like it much. By 2017, we'll already sound out-of-date. Can you imagine what CF2012 (CF10) or CF2014 (CF11) would sound like? And CF10 is still a HUGE part of the ColdFusion landscape. Besides, we really need a more positive impression of ColdFusion.

Anyway, I doubt work will get to this new version any time soon, and I'm kinda glad for that. I can already see a lot of things that will need to be refactored to function correctly. Hopefully some of these issues are on the roadmap to be fixed.

The safe navigation operator (?.) is kinda cool, and a built-in CLI is interesting (though I don't yet know how I'd use it). And moving the default install for CFIDE and the CFAdmin is LONG overdue. Hopefully that will cut down on some of the "security problems" that resulted from bad installations and not locking down servers.

I'll play with this one at home some more when I make some time to get a VM for it up and running again.

Here are some announcement links:

http://blogs.coldfusion.com/post.cfm/announcing-the-launch-of-the-newest-version-of-coldfusion-adobe-coldfusion-2016-release

https://helpx.adobe.com/coldfusion/whats-new.html
https://helpx.adobe.com/coldfusion/release-note/coldfusion-2016-release-notes.html


Wednesday, February 10, 2016

Oracle Number Formatting

This may be something you all already know, but it had me scratching my head for a minute. On the one hand, Oracle’s analytic functions like LAST_VALUE make some things kinda cool, but then Oracle smacks me with not handling number masking like pretty much every other language.

Even if you specify a decimal place mask, if the number ends with a 0 in the decimal, it will drop it.

Example:
1) To_Number(44.50,’99.99’) >> 45.5
2) To_Number(100/10.0,’99.99’) >> 10  <<< This one even drops the decimal and returns an integer 10, which leads to a whole different philosophical discussion about the differences between 10 and 10.00.

To get the decimal places mask that we want in Oracle, we have to use To_Char(44.50,’99.99’). But then that value is a string, so you won’t be able to do math on it. Except in ColdFusion, where it’s a numberish string. So to actually format it, we have to remask it in whatever code we use to output the value – ie in ColdFusion = NumberFormat(44.5,’99.90’) >> 44.50 and NumberFormat(100/10.0,’99.00’) >> 10.00

Add this to ColdFusion’s method of determining how to parse a value into JSON, and it makes things super fun. :-/

Moral of my story: If you need a number to be in a specific  format, don’t assume the database will give it back to you the way you thought you told it to.

Tuesday, February 2, 2016

Happy Brettuary!

This past March, Brett "BSmuv" Davis passed away. I've known him for almost 10 years. He was very dedicated to the coding community, and he worked hard to bring back the Nashville ColdFusion User Group. He brought me along to help. Brett had heaps of charm. He was funny. He loved a good office prank. He was larger than life itself. He was an inspiration to me. He was my friend.

I started working with Brett in September of 2007, and when his birthday began to roll around in February of 2008, he quickly made it clear that a single day of celebration wasn't enough. So he declared his birthday to be the month of Brettuary. Every year that I've known him, even after I no longer worked with him, I always wished him good cheer on his birthday. I'm a few days early this year, but I'd still like to offer my customary greeting. 

Happy Brettuary!

And Bonus Points if you can guess one of the highlights of Brett's life.