Tuesday, September 16, 2014

Reject the Spoon! Effective Online Technology Training


(To skip the retrospective, jump to The Next Step in the Evolution of Online Training)

The Evolution of Technology Training

In the heady pre-internet days, I would dive into a new language or technology by surrounding myself with dictionary-sized books on the topic. I made sure to use books from different publishers so I would have explanations of a particular topic from different points of view. When one book would come up short, I could usually fill in the gaps with another.

In the mid 90s, boot-camp training exploded. Students pay hundreds to thousands of dollars to spend 3-5 days in intensive, hands-on sessions with a new concept and an experienced instructor. Quality crested, then dropped as training centers learned that they were more profitable using less experienced instructors and reusable mediocre course material. VHS and DVD training experienced a similar birth and devolution in the at-home training market.

Once the internet backbone was robust enough to support video, some enterprising business folk realized that presenting an entire course online would have the same net effect as an in-person course, minus the ability for students to ask questions of the instructor. Moreover, the content providers no longer needed expensive training facilities, and could pay their instructors for a single recorded engagement rather than multiple in-person sessions. Win-win.

Lynda.com rocketed to popularity by creating polished presentations using fresh content and a consistent course format. Early on, Lynda.com focused on the art side of technology, leaving room for other companies to bring the same formula to programming and technology infrastructure like PluralSight, Udemy, CodeAcademy and others. (Lynda has since broadened its catalog to include programming topics, but still focuses on the artistic side of technology.)

This is pretty much the state of online training today. Instructional videos are essentially desktop video capture interspersed with power-point slides - a technique that is clearly effective.


The Next Step in the Evolution of Online Training

Several months ago, I was looking for "instructor led online training". I wanted the benefits of on-demand learning with the extra benefit of having someone to talk to when I had questions. This led me to LearningLine (Link removed as the site is now defunct :/ ). While initially unimpressed, LearningLine employed two techniques that helped me learn far more from their classes than from any other online training class I have taken to date.

Let me stop right here to say: this is not going to be a whitewash review. LearingLine, an offshoot of 20-year classroom training veteran DevelopMentor, is a newcomer to the online training space and it shows. Frankly, their UI is awful. As a long time user of Lynda.com and PluralSight courses, I felt cheated when navigating through the cheap-looking LearningLine interface. It was my actual learning experience that prompted me to write this blog post. For me, the techniques they use make it worth suffering through LearningLine's inadequacies.

Real-World Resources

I took an ASP.NET MVC course through LearningLine. Unlike self-contained training courses I have taken in the past, LearningLine points you to industry sources on the internet like Microsoft Blogs, Microsoft reference pages, YouTube videos, Microsoft Evangelist websites...etc. At first, I thought that this was a cop-out; they were co-opting the work of others instead of creating new content. Then, I realized that these were resources that I could use on my own long after the course was done. For the ASP.NET class, I now had a list of well known industry bloggers to follow and Microsoft resources to use. Introducing this sort of external dependency does make LearningLine's courses fragile. I can only hope they have some sort of robust link checking system in place to ensure critical pieces of their course material don't disappear overnight.

Here is a Concept and How It Works. Now Figure This Out!

The second, most effective learning technique came at the end of the lesson. Each segment of the course starts out in the ordinary way: Present a concept, demonstrate it and close with an exercise for the student to work. The exercise, however, was not what I was expecting. In every course I have taken online, the exercise is identical to the presentation example with a few inputs changed. LearningLine, however, challenged me with an exercise that was related to the topic but required information not presented in the source material to complete.

Again, I scoffed at this, thinking LearningLine threw the course into the wild without a proper review to ensure the questions matched the lesson taught. (In fact, even as I write this, I truly hope this was intentional and not some fortuitous accident.)

While researching a question, I would invariably stumble across really cool related topics that would pull me down the rabbit hole. When Google would come up dry, I was inspired to hack out the answers through trial and error (and occasionally blog about the results.) I didn't realize it until much later, but once I returned to LearningLine to answer the question, I had piles of useful related material that helped me stitch the lessons together into a complete understanding of the topic.

It occurred to me that LearningLine was breaking its students out of the classroom and sticking them into real-world, work scenarios. When solving a coding problem in my job, the answer is never textbook. Often times, you will have experience with a vaguely related scenario, but won't know the best approach. You have to synthesize your answer from bits and pieces of information you find through research and trial and error.

Reject the Spoon!

More than just a dose of reality, not having answers spoon-fed inspires engagement. Instead of trying to figure out how to answer the question correctly, I found myself wanting to understand how to solve the problem. It's the difference between wanting to pass the course and wanting to understand what is being taught.

I hope Lynda.com, PluralSight, Udemy and others take note of this technique. Any teaching method that inspires interest and learning in the self-study education arena should be adopted universally. Speaking to LearningLine, I hope this technique was indeed intentional. Explaining the technique up front will clear up any ambiguity and will put your students in the right frame of mind at the outset.


Friday, August 15, 2014

ColdFusion 9.0.1 Bug: Function Executes Twice & Line Preceding Function Call Not Executed!?

This is just insane. I stumbled on a perfect storm of syntax that will lead to the craziest execution error.


First, write a simple function that accepts a struct and displays some text:
public void function SimpleFunction1 (struct incomingStruct) {
 WriteOutput("This is SimpleFunction1.");
}

Then, Call that function using a named, inline short-hand struct for the parameter:
SimpleFunction1(incomingStruct={item1="ok",item2="go"});

So far, this will work fine. However, wrap this function call in a try/catch block and not only will the function execute twice, but any instruction in the line preceding the function call will be ignored.
try {
    abort; //this line will never execute.
    SimpleFunction1(incomingStruct={item1="ok",item2="go"}); //this function will execute 2x
}
catch {
rethrow;
}

As a workaround, you can either remove the name from the argument in the function call, or make the argument a variable instead of an inline struct... I suppose you could also remove the try/catch block, but that's not really a good idea, is it?

Here is a complete example. Numbers One and Two should work fine. Number Three will fail.

try{
 //one
 WriteOutput("

SimpleFunction1 with inline struct

"); WriteOutput("WORKING!"); SimpleFunction1({item1="ok",item2="go"}); //two WriteOutput("

SimpleFunction1 with var substituted for inline struct

"); tempstruct ={item1="ok",item2="go"}; WriteOutput("WORKING!"); SimpleFunction1(incomingStruct=tempstruct); //three WriteOutput("

SimpleFunction1 inline shorthand struct and named parameter

"); WriteOutput("NOT WORKING!"); //this line will never execute SimpleFunction1(incomingStruct={item1="ok",item2="go"});//this function call is executed twice } catch (any e){ rethrow; } public void function SimpleFunction1 (struct incomingStruct) { WriteOutput("This is SimpleFunction1."); }

OUTPUT:
(I have to apologize. The script formatter I use strips out BR tags, so you'll need to add line breaks to the code above to make the output match the screen shot below.)
You may notice I use a "WriteOutput" command to demonstrate the line that fails to execute. You experienced devs out there are probably thinking "use CFFLUSH to clear the output buffer". I tried, but to no effect. Replace that WriteOutput with an Abort; It won't trigger.
Another thought was that perhaps something about the naming convention or the syntax was causing the try/catch to fire somehow. But, if you remove the try/catch, it executes fine.
If you try using a comment as the 'ignored line' it will skip that and ignore nearest preceding command.

8/15/2014 Update: I have reported this one to Adobe  https://bugbase.adobe.com/index.cfm?event=bug&id=3806526

8/15/2014 Update2: It appears to fail on CF 9.0.1, 9.0.2 and 10, but it is fixed and working properly in CF11!

Friday, July 18, 2014

ColdFusion sFTP and ZLIB

A client last week needed an automated sFTP push. I was able to reach the host, but was receiving the error: "Algorithm negotiation fail". Since Filezilla could connect fine, my first thought was that they were using a cipher that was too advanced for ColdFusion 9 to handle.


To get more information on the connection, I looked to Filezilla's debugging tools. Under [Settings], [Debug] I bumped the logging level to [2 - Info]


In the connection scroll, I saw something interesting. The ciphers were ordinary: SHA1 and Blowfish-128, but zlib stood out. Zlib compresses data at the transmission level, similar to gzip but patently different. ColdFusion doesn't handle gzip natively (though there are clever workarounds), so I suspected that CFFTP was having a problem with zlib.

I searched the internet for Java libraries that could sFTP with zlib enabled and the overwhelming majority of links pointed me to JCraft JSch. To my surprise, I discovered that ColdFusion 9 implements a modified version of JSch 1.41 library (C:\ColdFusion9\lib\jsch-0.1.41m.jar). The zlib functionality is not part of the core JSch, but is part of jzlib.jar (also available free from JCraft). I added jzlib.jar to the classpath and it worked like a charm. Here is my proof of concept code:

<cfscript>
FTPSERVER = "someserver.somewhere.com"; 
FTPPORT = "22"; 
FTPUSER = "someuser"; 
FTPPW = "somepassword"; 

jschObj = createobject('java',"com.jcraft.jsch.JSch"); 
jschSession = jschObj.getSession(FTPUSER, FTPSERVER); 
jschConfig = createObject("java","java.util.Properties"); 
jschConfig.put("StrictHostKeyChecking","no"); 
jschConfig.put("compression.s2c", "zlib,none"); //server to client
jschConfig.put("compression.c2s", "zlib,none"); //client to server
jschSession.setConfig(jschConfig); 
jschSession.setPort(FTPPORT); 
jschSession.setPassword(FTPPW); 
jschSession.connect(); 
jschChannel = jschSession.openChannel("sftp"); 
jschChannel.connect(); 
if (jschSession.isConnected()) { 
 WriteOutput("CONNECTED!");
} 
jschChannel.cd("/Test"); 
FileInputStream = createobject("java", "java.io.FileInputStream").init(expandPath("payload_test.txt"));
jschChannel.put(FileInputStream, "payload_test.txt"); 
WriteDump(jschChannel); 
jschChannel.disconnect(); 
jschSession.disconnect();
</cfscript>

The two commented lines enable zlib for upstream and downstream transmissions. This resolved our connection issues.


Friday, June 20, 2014

ColdFusion Builder 2 and Two Icons in the Taskbar on Windows 7 x64

I installed ColdFusion Builder 2 as a plug-in on my work PC running Windows 7 x64 and Indigo 3.7.1. When I manually created a shortcut on my taskbar to run eclipse, I noticed something odd... a second icon would appear in the task bar for eclipse when the IDE would finish loading.

If you right click the second icon, there is no option to pin it to the taskbar. The biggest nuisance about this is that when you click the first taskbar shortcut, it starts another instance of Eclipse instead of bringing the running instance into focus.
The Solution:
To trick Eclipse/CFB2 into using a single icon, you have to point it to the /bin folder in the JRE.
Here is how:

Find the path to the JVM used by Eclipse?
using Click [Help]-->[About Eclipse]. Click the [Installation Details] button. In the Eclipse Installation Details window, click the [Configuration] tab.

Scroll down a bit until you see "java.home=..." (In my case, it was pointing to "C:\Program Files\Java\jre7".)

Edit eclipse.ini and use -vm to point Eclipse to the \bin folder
The configuration file eclipse.ini should be in the same folder as eclipse.exe. Add the following two lines to the top of the eclipse.ini file to help it find the /bin folder:
-vm{the path to java.home you discovered above plus /bin}
The next time you run Eclipse, right click the task bar icon and pin it.
You should be down to one icon that behaves more like a Windows app should.

Wednesday, May 28, 2014

Sublime Text 3 and ColdFusion

The instructions on the git site for the Sublime Text 3 ColdFusion plugin says that the only way to install the plugin is to use Git. https://github.com/SublimeText/ColdFusion

I had trouble getting it to work on a fresh build of Sublime Text 3 because the build from 22 Sep 2013 appears to be broken. The previous build from 17 Sep 2013 works fine, but after installing the broken build, I had to wipe out the Sublime Text 3 settings entirely to get the previous build to work.

Install Git
Download and install the latest version of Git.

Choose the middle option: "Use Git from the Windows Command Prompt"
(By default, "Use Git from Git Bash only" is checked.)


Accept the defaults for the rest.

Download and Install Sublime Text 3
http://www.sublimetext.com/3

Install the ColdFusion plugin
run CMD.EXE and type the following commands:
The git checkout line above reverts your clone to the Sept 17, 2013 build.

Run Sublime Text 3 and open a ColdFusion page...



The familiar syntax coloring should be there.

Wiping out Sublime Text 3 settings
If you are still having trouble, wipe out the sublime text 3 settings by deleting this folder:
%APPDATA%\Sublime Text 3
It will be recreated the next time you run Sublime Text 3, but be prepared to reinstall all plugins.


Monday, April 21, 2014

Bootstrap 3 HTML Template with CDN Failover for JS and CSS

I wanted to create a nice, simple template for Bootstrap 3.0 that uses a failover technique I learned about at a recent ASP.NET user group meeting (Thanks Alek Davis).

The Getting Started section of http://getbootstrap.com shows a CDN example, but the HTML template that assumes you have local Bootstrap JS and CSS files.  I found lots of examples of Javascript failover techniques, most notably Scott Hanselman’s CDNs fail, but your scripts don’t have to… blog post. A little more Googling turned up this technique to see if Bootstrap loaded properly. I adapted the code from github to the shorthand code from Scott’s blog to create this nice Bootstrap 3 HTML template that attempts to load JQuery and the Bootstrap 3 JS and CSS files from CDN. Should any fail, it loads the files locally.

Note: This template is expecting the following local resources:
js/jquery-1.11.0.min.js
js/bootstrap.min.js
css/bootstrap.min.css

May not be IE compatible!

 <!DOCTYPE html>  
 <html lang="en">  
  <head>  
   <meta charset="utf-8">  
   <meta http-equiv="X-UA-Compatible" content="IE=edge">  
   <meta name="viewport" content="width=device-width, initial-scale=1">  
   <title>Bootstrap 101 Template</title>  
   <!-- Latest compiled and minified Bootstrap 3 CSS CDN-->  
   <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">  
  </head>  
  <body>  
   <h1>Hello, world!</h1>  
   <!-- jQuery (necessary for Bootstrap's JavaScript plugins) CDN Failover -->  
   <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>  
   <script>window.jQuery || document.write('<script src="js/jquery-1.11.0.min.js">\x3C/script>');</script>   
   <!-- Include all compiled plugins (below), or include individual files as needed -->  
   <!-- Latest compiled and minified JavaScript CDN Failover-->  
   <script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>  
   <script>$.fn.modal || document.write('<script src="js/bootstrap.min.js">\x3C/script>');</script>  
   <script>  
   $(document).ready(function() {  
     //CSS CDN Failover (If you change the body color, you will need to change the rgb value below.)  
     $('body').css("color") == 'rgb(51, 51, 51)' || $("head").prepend("<link rel='stylesheet' href='css/bootstrap.min.css' type='text/css' media='screen'>");  
   });  
   </script>  
  </body>  
 </html>  

References:
Scott Hanselman: CDNs fail, but your scripts don't have to - fallback from CDN to local jQuery
GitHub MaxCDN / bootstrap-cdn: Check if Bootstrap is loaded #111
Bootstrap Website: http://getbootstrap.com

Thursday, April 10, 2014

ColdFusion 10 CFLOOP bug with decimal steps

Back in the ColdFusion MX 6.1 era, I stumbled across a bug. A CFLOOP tag with a step of 0.2 would inexplicably skip a number (32.0, I believe) as it counted up. The bug persisted through version 7.x. I had a workaround in place, so I didn’t give it much thought after that.

Recent ColdFusion conversations made me think of this bug, so I decided to code up a quick test to see if it was still an issue with CF10. What I discovered was far worse than I remembered.

Start with a simple loop from 0 to 40 with a step of 0.2. Display each step and add a comma after all but the last number:
<cfloop index="i" from="0" to="40" step="0.2">
      <cfoutput>#i#</cfoutput>
      <cfif i LT 40>, </cfif>
</cfloop>

Hmmm… 40 is missing. When counting up by integers, 40 is included. This was the first hint that something was not quite right.


The list is a bit tough to read, so let’s break it up by inserting a <BR> before each integer (skipping the initial zero).

<cfloop index="i" from="0" to="40" step="0.2">
      <cfif int(i) EQ i and i GT 0><BR></cfif>
      <cfoutput>#i#</cfoutput>
      <cfif i LT 40>, </cfif>
</cfloop>

This should have produced a nice column of integers with each row ending in x.8! 

There is a line break after 0.8, as expected, but no line breaks again until 8.8 and no more again until 37.8? This makes no sense. Since the problem occurs in the first 10 digits, let’s reduce the TO value to 10 and include “int(i)” and the result of the evaluation “int(i) eq i” in the output:
<cfloop index="i" from="0" to="10" step="0.2">
      <cfif int(i) EQ i and i GT 0><BR></cfif>
      <cfoutput>#int(i)# EQ #i#:#int(i) EQ i#</cfoutput>
      <cfif i LT 10>, </cfif>
</cfloop>


So, this output is telling me that when i = 2 , int(i) EQ i evaluatees to 1 EQ 2! Worse, it is saying 4 <> 4, 5 <> 5, 6 <> 6 but 7 = 7? I tried the other rounding functions: FIX, ROUND and CEILING with varying degrees of weirdness. (ROUND appeared to work, but I don’t trust it completely.) I also tried JavaCast() but the results were still off. The string comparison function COMPARE (x,y) had the same problem. When I tried int(2.0) by itself, it did not yield “1”, so I suspect the problem is data type conversion in the processing of the loop steps.

The Workaround
I used the same workaround here that I used years ago with the original problem. Multiply the FROM, TO and STEP by 10 and divide the value as appropriate inside the loop.
<cfloop index="i" from="0" to="100" step="2">
      <cfif i MOD 10 EQ 0 and i GT 0><BR></cfif>
      <cfoutput>#numberformat(i/10,"09.9")#</cfoutput>
      <cfif i LT 100>, </cfif>
</cfloop>

And the results turn out as expected:

Conclusion
Avoid decimal steps.

Thursday, February 13, 2014

ASP.NET MVC5 (Novice) Protecting your site with a login wrapper

The default MVC framework includes login and registration pages. They are functional, but by default the main pages in the site are not configured as login-protected.

 

As with much of MVC, the login wrapper has been abstracted to a configuration component – a filter in this case.

 

In the solution explorer under ~/App_Start, double, double-click “FilterConfig.cs”

 

Add the following lines to RegisterGlobalFilters:

 

filters.Add(new System.Web.Mvc.AuthorizeAttribute());

filters.Add(new RequireHttpsAttribute());

 

I disabled RequireHttpsAttribute during development.

 

The entire site is now protected by the login wrapper with the exception of the account related pages. The account pages are excluded from the login wrapper because of the [AllowAnonymous] attribute.

 

 

For a much more comprehensive treatment, see “Deploy a Secure ASP.NET MVC 5 app with Membership, OAuth, and SQL Database to a Windows Azure Web Site” by Rick Anderson.

 

This is a beginning-to-end explanation of how to create and deploy a site. To skip to the security section, scroll to the middle of the page and look for “Protect the Application with SSL and Authorize Attribute”. He even explains how to create security levels!

 

 

 

 

ASP.NET MVC5 (Novice) Creating different layouts for different views

I’m creating a simple login-protected site. I want to have a main layout for the core site and a separate layout for the login and other account-related pages.

 

It took me a while to stumble on the most ‘elegant’ answer for ASP.NET MVC 5. The easiest/best solution (also restated here) is to copy _ViewStart.cshtml from the View folder root to the view folder that you want to style differently.

 

Create a new layout in ~/Views/Shared … (_Layout-Account.cshtml in my case)

 

and edit ~/Views/Account/_ViewStart.cshtml to point to the new Layout.

 

This will override the main _ViewStart.cshtml in the Views folder. There are many other approaches, like adding conditional logic to the main _ViewStart.cshtml page, but creating a _ViewStart.cshtml page for each view you

 

Shailendra Chauhan made an excellent blog post exploring many different ways of rendering layouts in ASP.NET MVC.