dans.blog


The miscellaneous ramblings and thoughts of Dan G. Switzer, II

Using queryName.columnName shorthand can generate errors with <cfqueryparam />

Yesterday I ran into a very strange bug with ColdFusion 9 and I thought it worth blogging about. I think this probably affects earlier versions of the product, but I haven't tested to confirm.

What was happening is whenever I tried executing a specific query, I was seeing the following error:

Invalid data coldfusion.sql.QueryColumn@540350 for CFSQLTYPE CF_SQL_INTEGER

The error had me very perplexed, because the variable that it was complaining about I knew was an integer. When displayed on screen, it showed as an integer. It would even return true when passed to the isNumeric() function. After spending way to much time on the issue, I finally track down the root problem.

What was happening is the variable's value was coming from a ColdFusion query, that I was converting to a structure. Since the query was designed to return at most a single row, I was using the shortcut notation of queryName.columnName to update the variable. I've used this shorthand plenty in the past, because it will either display the value in the first row (when not inside a <cfoutput query=""> or <cfloop query="">) or it will display an empty string if the query returned no rows. This has generally worked fine for me, but apparently this ends up storing a reference to the query object, instead of copying the value directly—which <cfqueryparam /> did not like.

The fix was pretty straightforward, all I need to do was to change my code to reflect grabbing the value from the first row of the dataset: queryName.columnName[1].

My original code looked like this:

<cfquery name="data" attributeCollection="#Application.dsn.getAttributes()#">
  select
    Name, Email, Phone
  from
    Employee
  where
    EmployeeId = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.EmployeeId#" />
</cfquery>

<!---// get the column names from the query //--->
<cfset columns = getMetaData(data) />

<!---// return the preferences as a struct //--->
<cfloop index="column" array="#columns#">
  <cfset results[column.Name] = data[column.Name] />
</cfloop>

All I did was change the code to:

<cfquery name="data" attributeCollection="#Application.dsn.getAttributes()#">
  select
    Name, Email, Phone
  from
    Employee
  where
    EmployeeId = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.EmployeeId#" />
</cfquery>

<!---// get the column names from the query //--->
<cfset columns = getMetaData(data) />

<!---// return the preferences as a struct //--->
<cfloop index="column" array="#columns#">
  <cfset results[column.Name] = data[column.Name][1] />
</cfloop>
NOTE:
You'll notice the only change is the [1] after data[column.Name].

What I learned from this is that I shouldn't trust using the queryName.columnName shorthand—at least not outside a cfoutput/cfloop query block. Instead I need to make sure to reference an actual row from the query.


Forcing your Application.onError event to run to completion in ColdFusion

A common practice when building applications in ColdFusion is to utilize the onError event in the Application.cfc in order to track and log errors that occur in your application, so that you can track down the problems and resolve them. However, there's one type of error that can often escape your onError event handler—and that's requests that are timing out.

First, just some background information on how ColdFusion handles "request timeouts". If the server (or current page) is designed to timeout after 30 seconds, ColdFusion will not simply stop executing when the length of the running request gets to 30 seconds. Instead there are specific operations in ColdFusion1 that check the current running time to see if the request should be halted. That's why if you have a SQL query that takes 45 seconds to run, the page doesn't simple stop after 30 seconds. Instead the query will finish executing and your code won't halt execution until it tries to execute logic that would check the current execution runtime.

NOTE:
This also why when ColdFusion reports the line that took to long to run, it often isn't pointing to the actual line of code that was the real culprit, but a tag like <cfoutput>—which is just displaying the information.

Now that you hopefully have a better understanding of when request timeouts are thrown, let's examine why the Application.onError might not run.

The problem isn't that the Application.onError event doesn't get fired—it does. The problem is that because your page has already been running longer than the allotted time, as soon as ColdFusion encounters one of the operations that checks to see if the page should timeout, it will throw a second error—which effectively breaks your onError event.

The way you can get around this problem is by tracking the current execution timing in your Application and then having your Application.onError immediately adjust the page's request timeout setting as it's first line of logic. Since the <cfsetting /> tag does not check against the current execution time, this allow you to add a buffer to your onError request so that the event can run to completion.

Here's a sample snippet of an Application.cfc which will allow the Application.onError event to run for another 10 seconds—regardless of how long the current template has been running:

<cfcomponent output="false">
  <!---// track the starting execution time //--->
  <cfset executionStartTime = getTickCount() />

  <!---// onError //--->
  <cffunction name="onError" returnType="void" output="true">
    <cfargument name="exception" type="any" required="true" />
    <cfargument name="eventName" type="string" required="true" />

    <!---// declare local variables //--->

    <!---//
      take the current time the request has been running and add
      10 seconds, to attempt to run the onError handler succesfully
    //--->
    <cfsetting requesttimeout="#(((getTickCount()-executionStartTime)/1000)+10)#" />

    <!---// insert error code handling here //--->
  </cffunction>
</cfcomponent>

I've been using this trick to help make sure any requests that are timing out are fully logged, so I can evaluate the issue and look for ways to fix the root problem.

1 Unfortunately I do not have a list of which operations in ColdFusion do an integrity check on the request lifecycle. I do know that <cfloop>, <cfoutput>, <cfquery> and most complex cf-based tags do check the current running time against the page's request timeout setting.


Merging changes after a successful pull request back into your fork using EGit

Yesterday I finally had the incentive to download Git so I could fork a Github project (Mustache.cfc) and contribute some changes I'd made. Being that Eclipse is my main IDE, EGit seemed to be a logical client to install. The install process was painless and I was able to figure out how to clone a local copy, commit and push changes back to Github. Even the Github pull request process was painless. Much to my chagrin, my pull request was accepted almost immediately and merged back into the main branch.

Naturally the next thing I wanted to do was to sync my fork with the original repository. This is where I got stuck. Whether due to my lack of understanding of Git terminology or just a lack of my Google Search skills, I was not able to easily find instructions for how to sync the original repository back to my fork. After much searching, I was finally able to find some help.

However, I figured I'd clean up the instructions a bit and provide a little more detail on the steps for merging the main repository back into your fork.

The first thing you need to do, is set up a new remote repository linked to your fork:

  1. Open the "Git Repositories" view (Window > Show View > Other > Git > Git Repositories)
  2. Locate your local copy of the fork
  3. Expand the "Remotes" branch (you should see a "origin" entry)
  4. Right-click on "Remotes" and select "Create Remote"
  5. Enter a name representing the master repository, for this example I'll use "mainrepo"
  6. Select the "Configure fetch" option
  7. Click "OK"
  8. Go to the main repository in your browser
  9. Copy the Git URI into your clipboard
  10. Go back to Eclipse
  11. Click on the "Change" button
  12. Paste the URI into the "URI:" field
  13. Click "Finish"
  14. Click the "Add…" button
  15. In the "Source" field, type in the name of the branch you want to import from.

    NOTE: In most cases if you start typing "m", it should show you an auto-complete entry with the "master" branch—just select that option to sync to the master branch.
  16. Click "Finish" (or click "Next" if you want more options)
  17. Click "Save and Fetch"

Now that you have a linked the original repository to your fork, you can merge changes from the original repository to your fork:

  1. Right-click on your project and go to Team > Merge
  2. Under "Remote Tracking", find the "mainrepo/master" (or the appropriate repository/branch based on the remote repository you just configured.)
  3. Click "Merge"
  4. If your repository is up-to-date, there's nothing else to do.
  5. Finally, just commit your changes locally and push back to the upstream

These steps worked for me, so hopefully they'll help guide someone else!


Adding custom callbacks to existing JavaScript functions

This morning I was reading Adding your own callbacks to existing JavaScript functions by Dave Ward—which covers how to overwrite an existing function so you can add some additional functionality (in this case, adding callbacks.) While the article is informative, a couple of improvements can dramatically improve his suggestion.

If you don't want to take the time to read Dave's article, in a nutshell he describes how we can overwrite a JavaScript function by storing a reference to the original function in a variable. So, we can take the following function:

function sayHello(name){
  alert("Hello, " + name + "!");
}

And we can now overwrite that function by storing a reference to the original function in a variable:

var sayHelloOld = sayHello;

function sayHello(){
  var name = prompt("Enter your name");
  sayHelloOld.apply(this, [name]);
}

Now there's a couple of problems with the above code.

  1. As written, this would only work if the original sayHello() function was defined in another <script> tag because of function hoisting.
  2. We're polluting the global name space.

We can solve both those problems by using a closure around our code:

// define a closure and pass in a reference to the global window object
(function (w){
  var sayHelloOld = w.sayHello;

  w.sayHello = function (){
    var name = prompt("Enter your name");
    sayHelloOld.apply(this, [name]);
  }
})(window || {});

(NOTE: You can see a working copy on JSFiddle.)

The other topic Dave discusses is how to add callback hooks to run before and after a the original function code runs. His suggestion is built around using the global name space to declare some function names. Since the example is based around jQuery, I'd suggest a much better method would be to add in custom events to your function. This gives you a way to bind callbacks to run, but your neither cluttering the global namespace nor running into issues if the callbacks aren't needed.

Dave's Original Solution

Here's what Dave's original solution looks like:

var oldTmpl = jQuery.fn.tmpl;

// Note: the parameters don't need to be named the same as in the
//  original. This could just as well be function(a, b, c).
jQuery.fn.tmpl = function() {
  if (typeof onBeforeTmpl === 'function')
    onBeforeTmpl.apply(this, arguments);

  // Make a call to the old tmpl() function, maintaining the value 
  //  of "this" and its expected function arguments.
  var tmplResult = oldTmpl.apply(this, arguments);

  if (typeof onAfterTmpl === 'function')
    onAfterTmpl.apply(this, arguments);

  // Returning the result of tmpl() back so that it's actually 
  //  useful, but also to preserve jQuery's chaining.
  return tmplResult;
};

Improved Solution

Using the two previously mentioned techniques combined, here's how I'd change that code:

(function ($){
  var oldTmpl = $.fn.tmpl;

  // Note: the parameters don't need to be named the same as in the
  //  original. This could just as well be function(a, b, c).
  $.fn.tmpl = function(){
    // trigger the before callback
    // to attach a callback, we just bind() this custom event to our jQuery object
    this.trigger("onBeforeTmpl", arguments);

    // Make a call to the old tmpl() function, maintaining the value 
    //  of "this" and its expected function arguments.
    var tmplResult = oldTmpl.apply(this, arguments);

    // trigger the after callback
    // to attach a callback, we just bind() this custom event to our jQuery object
    this.trigger("onAfterTmpl", arguments);

    // Returning the result of tmpl() back so that it's actually 
    //  useful, but also to preserve jQuery's chaining.
    return tmplResult;
  };
})(jQuery || {});

This gives use a few benefits over Dave's original solution:

  1. We're not polluting the global namespace
  2. We can now attach custom callbacks to each jQuery object separately

To use our code, we can do:

$("#id")
  .bind("onBeforeTmpl", function (){
    alert("before!");
  })
  .bind("onAfterTmpl", function (){
    alert("after!");
  })
  .tmpl(data, options, parentItem);
NOTE:
If your prefer to run the same callbacks for all $.tmpl() calls, you could attach the custom events globally.

Any comments on how to make this solution even better?


jQuery Linkselect Plug-in v1.5 released!

Today a new version of the jQuery Linkselect Plug-in was released. The new version under went a ton of changes from the previous version and includes a much better CSS skinning mechanism (see the Linkselect Example.)

The coolest new feature is probably the "placeholder" support, which allows you to specify an <option /> element in your <select /> box to use as a label/placeholder. The "placeholder" <option /> tag uses the <option /> tag as the title of the dropdown menu that's always visible, but still selectable. Here's an example:

Here's a list of all the changes:

  • Revised CSS naming structure to make it to have multiple visual styles of linkselect elements on the same page. The changes in v1.5 are not backwards compatible, so you will need to update your CSS in order to upgrage to v1.5. You can either replace you existing CSS files with one included in the zip file, or you can modify your existing CSS files to match the new naming syntax (which for the most part is just changing the camel casing from "linkselectLink" to "linkselect-link", "linkselectLinkOpen" to "linkselect-link-open", etc. Also, all CSS classes now using the prefix "linkselect-" by default.
  • Added new "style" option. This replaces all the previous class* options. The default style is "linkselect" and is simply used as the prefix used for all the CSS classes. You can create custom linkselect skins by just copying one of the included CSS files and changing the prefix to match your style option value.
  • Added "text" API call to return the label of the currently selected option.
  • Added "destroy" API call to destroy a linkselect element and return to original select element.
  • Changed the "replaceOptions" API to add a new "includeFilter" argument. The API change is backwards compatible.
  • jQuery.delegate() is now used to monitor event changes
  • Changed <li /> elements to use "data-" attributes for custom attributes
  • Changed <li /> elements to use "data-value" for storing selectable value instead of the "rel" attribute.
  • Fixed issue with Chrome not correctly accepting focus when the linkselect element was clicked.
  • Events related to closing/resizing of the open linkselect element are now registered/unregistered when the menu opens. This helps improve performance when there are many linkselect elements on the page as it reduces the document.click events that fire to see if the menu should be closed.
  • Added ability to use both "name" and "id" attributes on a select element with different values.
  • Added new "placeholder" functionality. You can now give an option element a class of "placeholder" to have it used as a selectable title for the linkselect element. This allows you to use a "Please select..." option element in your select and have it used as the title of the linkselect. Users will be able to select this option, just like any other option element.
  • Fixed various positioning bugs.


Upgrading Trac with integrated SVN to new version of Python

We recently upgraded our version of Subversion from a very old version of Subversion to v1.7.1. We really wanted the newer merging capabilities that arrived in Subversion 1.5 and figured it was worth the energy to upgrade Subversion to the latest version. Fortunately upgrading our Subversion repositories went very smoothly. I even decided to just do a full dump/load to make sure the repositories were fresh 1.7.x repositories. While this process took a little extra time, the upgrade itself went very smoothly.

However, where things really fell apart for us was with our Trac/SVN integration. The problem is we were still running Python 2.4, which include old SVN bindings, so any attempt to do anything with our SVN ended up with an error that looked like:

TracError: Couldn't open Subversion repository c:/path/to/repository: SubversionException: ("Expected FS format '2'; found format '4'", 160043)

In order to get the SVN commit hooks working with Trac, I was going to need SVN bindings that worked with SVN v1.7.1, but also were compiled for my version of Python. While one might think this wouldn't be difficult, I couldn't find any SVN bindings for Python 2.4. This left my options at either trying to compile my own versions or upgrade Python. Since I don't have easy access to tools for compiling my own version of the Windows binaries, I thought the best option was just to upgrade Python—especially since Trac is soon dropping support for Python 2.4.

The problem is there's no easy way to just migrate a Trac install to a new version of Python, because you're going to need to recompile all your Python *.egg files for the version of Python you're using. After spending way too much time getting all this working, I thought it was wise that I compile a list of all the steps you may need to take in order to get Trac migrated to a new version of Python.

Here is the general install instructions. I don't break this down as a true step-by-step instructions, because so much varies based on your environment. However I do break down all the major steps you'll need to take and try to point you to step-by-step instructions for each bullet when possible.

  1. Install the version of Python you intend to run
  2. Make sure to install Python into a new folder (do not install over your old version of Python)
  3. Compile a list of all the Trac plug-ins you're currently running (check both your Trac/path/to/env/eggs folder and the Python/Lib/site-packages folders for EGG packages you currently have installed)
  4. Back up your current Trac environment folder (where all your Trac repository files are)
  5. Follow the instructions for installing Trac (but ignore the steps for creating new repositories—you can use your existing ones)
  6. Delete any old EGG packages from the Trac/path/to/env/eggs folder
  7. Reinstall all your old Trac Plugins
  8. Shut down your Trac server
  9. Follow the Trac guide for upgrading Trac, with the following notes:
    • You don't need to update the Trac Code (you just installed the latest version)
    • Skip the "Resynchronize the Trac Environment Against the Source Code Repository" step—you'll do that after updating SVN
  10. For Trac/SVN Integration, the Trac and Subversion page outlines the basic steps needed, but this is the step that cost me the most pain, so I'm going to break down some extra notes.
    1. Download the SVN binaries from http://alagazam.net. You'll want to download the Windows binaries and Python bindings for the version of Subversion you plan on using.

      NOTE: This site has the largest collection of Python SVN bindings that I could find and also offers the command line SVN binaries you'll also need. While you should be able to use another SVN command line binaries, using the Setup-Subversion-*.msi installer is probably going to be the most forward way to get started.
    2. Install the Subversion binaries.

      NOTE: You may be required to reboot your server. You will also want to confirm that the Subversion/bin path is in your Window PATH environment variable.
    3. If running Apache, you'll want to make sure to replace the mod_authz_svn.so and mod_dav_svn.so in your /Apache/modules with the versions in  the /Subversion/bin folder.
    4. Copy the files in the Python bindings file (e.g. svn-win32-1.7.1_py27.zip) to the Python/Lib/site-packages folder. You'll want to overwrite the existing files or delete the existing directories.
    5. You'll now want to test your Python SVN installation:
      1. Go to your Python folder and type "python"
      2. Verify that you can load the bindings using the Python interactive interpreter by typing:

        from svn import core
      3. If all is successful you should just see a new Python prompt. The only time you should see output is if there is an error.

        NOTE: This is the part where I spent a lot of time troubleshooting. I kept getting a "ImportError: DLL load failed: The specified module could not be found." After much digging and research, this turns out to be related to Trac Issue #665. The fix for me was to copy the following files into the Windows\system32 folder:
        • libdb42.dll
        • libeay32.dll
        • ssleay32.dll
        I'd recommend backing up existing files before replacing them.
      4. If you're still getting errors, see the Trac/Subversion checklist for more tips.
    6. Resynchronize the Trac Environment Against the Source Code Repository, using the following syntax for each repository:

      trac-admin /path/to/projenv repository resync '*'
  11. Check all your SVN hooks and update any paths pointing to the old version of Python to make sure they point to the new install. For example, your trac-svn-post-commit-hook.cmd may point to your old Python path and these need to be updated in order to work.
  12. Check your Windows PATH environment variable and make sure the new version of Python is in the PATH statement. If it's not, update/add it and reboot your server.
  13. Restart your Trac server.

If all goes well, your environment should now be running under your new Python installation.

This process ended up costing me way more time than expected, so hopefully this guide will prevent you from struggling the way I did.


Using simple conditional logic in JsRender

I've been updating some code that was built using jQuery Templates, but since jQuery Templates has been discontinued, I've decided to migrate my code to use JsRender.

The syntax is close enough for the most part that translating existing templates is straightforward enough. For the most part it's updating to the new mustache-like bracket syntax and changing variables from ${var} to {{=var}}. However, there was one thing that was tripping me up—simple conditional statements.

JsRender uses the mustache like "codeless" syntax for conditions:

{{#if varName}}output{{/if}}

This fine if varName is a truthy statement, but what if you need to check if varName  is equal to a specific value? Having gone through all the JsRender sample code, it appeared the only way to accomplish any kind of comparison conditional statement was to use custom code. This syntax ends up being very ugly and verbose. Here's an example of writing an attribute dynamically based on the value of a variable named varName :

<div class="base{{* if($view.data.varName == 'None'){ result += ' none';  } }}">{{=varName}}</div>

This seems overly complicated for such a simple comparison. I figured there had to be a better way.

After digging through the code, I found there's some undocumented features of the if tag. You can actually use the following syntax to do the same thing:

<div class="base{{#if varName eq='None')}} none{{/if}}">{{=varName}}</div>

While this syntax ends up being pretty close to jQuery Templates, it uses the "hash" functionality of JsRender's custom tags. The odd looking part is that you need the equal sign between the conditional operator and the value. Other operators include:

  • eq = equals
  • ne = not equals
  • lt = less than
  • le = less than or equal
  • gt = greater than
  • ge = greater than or equal

I actually would prefer to see "lte" and "gte" used for the "or equal" functions, so I've added that to a ticket.

So, while the syntax isn't ideal, it's certainly better than using using the code syntax. Since the project is still in development, it possible the syntax will change.


iPhone 3GS vs 4S data speed

On Friday I upgraded my iPhone 3GS to the new iPhone 4S. One of the things that's changed in the 4S is that it's supposed to support HSPA+. Well not truly "4G", it should offer faster data transfers on AT&T's network. Before heading into the AT&T store to pick up my new phone, I decided to run a couple of tests on my 3GS in my car while parked in the parking lot.

My initial tests on the 3GS reported data xfer speeds around 970Kbits/s.

Once I had my new 4S in hand, I returned to my car to repeat my performance tests. I immediately saw the numbers jump to somewhere in the 1820Kbits/s—almost double the speed.

While this was not an exhaustive test by any means, it does appear that there is a nice speed jump on AT&T's network—provided your in an area covered by HSPA+.

Here's the screenshot showing my min/max results:

 

iphone_3gs_vs_4s_data_speed


Important! The Olson Time Zone Database has been shut down

There was some disturbing news yesterday—and I'm not talking about the death of Steve Jobs. The "Olson" time zone database was taken offline. While the immediate impact may not be felt, this is a very important open project and shutting it down is potentially going to cause a lot of problems.

For those that don't know, the time zone database has been maintained by a group of volunteers over the years and hosted at National Institutes for Health and contains historical, present day and known future information on day light savings changes around the world. This database is used by a huge of array of platforms to keep accurate time—Java, Unix, *nix, smart phones, etc. If you have an app that can tell you the current time in another location, there's a good bet it's based on this time zone database (either directly or via the underlying language's platform.)

Here are some good articles with more insight:

As many have already commented on, I'm not sure how this law suit can hold up since historical information can not be copyrighted. However, the law suit will have an impact—especially for applications in use by locations where the day light savings is in frequent flux.


Moving data between source and destination tables using the OUTPUT clause in SQL Server 2005+

One of the features introduced in Microsoft SQL 2005 that I think really goes largely unused in the "OUTPUT" clause. It certainly was a feature that went unnoticed by me for a long time and even once I became aware of the feature, didn't really put it to much use. However, lately I've been refactored a ton of old SQL into objects and with this refactoring I've been making high use of the OUTPUT clause in order to help create audit trails. It's been a great way to know which rows were affected in your CRUD operations.

There's really a ton of useful things you can do with the OUTPUT clause, but one thing it allows you to do is to migrate data from one table to another in a single atomic operation.

Let's look at the syntax:

-- the table to move data from
delete
    dbo.SourceTable

-- get the data removed from the "source" table
output
    deleted.column1, deleted.column2, deleted.column3

-- insert the deleted row into the "destination" table
into dbo.DestinationTable

-- your where clause for the "delete" operation
where
    Column1 > 2000
and
    Column2 = 1234

Here's a fully working example that you can run in SSMS:

-- declare temp tables
declare @original table (id int identity(1,1), name varchar(20), company varchar(20), dob datetime)
declare @new table (id int, name varchar(20), company varchar(20), dob datetime)

-- insert some fake data into our "original" table
insert into @original (name, company, dob) values ('Bill Gates', 'Microsoft', '1955-10-28')
insert into @original (name, company, dob) values ('Paul Allen', 'Microsoft', '1953-01-21')
insert into @original (name, company, dob) values ('Steve Jobs', 'Apple', '1955-02-24')
insert into @original (name, company, dob) values ('Steve Wozniak', 'Apple', '1950-08-11')

-- show the results
select 'original' as tableName, * from @original
select 'new' as tableName, * from @new

/*
  here is the core SQL used to do the move
*/
delete
  @original

-- get the data removed from the @original table
output
  deleted.id, deleted.name, deleted.company, deleted.dob
-- insert the deleted row into the @new table
into @new

-- your where clause for the "delete" operation
where
  company = 'Microsoft'


-- show the new results 
select 'original' as tableName, * from @original
select 'new' as tableName, * from @new

If you run this example in SSMS, you'll see the two "Microsoft" records move from the @original table into the @new table.

NOTE:
The @original and @new tables are simple table variables (which are like temp tables.)

There really is a ton of useful things you can do with the OUTPUT clause, so I highly recommend playing around with the OUTPUT clause if you're using SQL Server 2005 or later!


Issues with the throttle() function in Underscore.js and my throttle() fixes

[UPDATED: Wednesday, August 24, 2011 at 3:19:27 PM]

I was looking through the source code of Underscore.js this morning and notice it's implementation of _.throttle() contains two issues that bother me with most JavaScript-based throttle implementations I've seen:

  1. It delays the execution of the first hit until the "delay" has been reached. While this is ideal for debounce type operations, I believe throttle operations should execute immediately and then only execute after the delay for each additional call. Throttling works really well for mouse movement and scrolling operations, but you usually want the behavior to initiate when the operations begins—delaying the first execution until the delay is reach usually ends up with an odd behavior.
  2. The arguments passed to the throttled event are based upon the invoking function that triggered the setTimeout() event. This means you are not dealing with the latest data passed to your throttled event, but dealing with expired data. A perfect example of this is using throttling to monitor mouse movements. The way Underscore.js has implemented the throttle() function, you could end up with coordinates based on where the pointer started—not where it ended.

Let's take a look at an example I posted on JSFiddle: http://jsfiddle.net/MNGpr/

Mouse your mouse from the top left of the "Results" frame to the bottom right. If you do this quickly (under the 1 second delay,) you'll notice that when the function executes it's based upon coordinates in the upper left of the screen—not where your cursor left off.

What I've been doing is using the following throttle() function in my code:

// limit a function to only firing once every XX ms
var throttle = function (fn, delay, trail){
  delay || (delay = 100);
  var last = 0, timeout, args, context, offset = (trail === false) ? 0 : delay;
  return function (){
    // we subtract the delay to prevent double executions
    var now = +new Date, elapsed = (now - last - offset);
    args=arguments, context=this;

    function exec(){
      // remove any existing delayed execution
      timeout && (timeout = clearTimeout(timeout));
      fn.apply(context, args);
      last = now;
    }

    // execute the function now
    if( elapsed > delay ) exec();
    // add delayed execution (this could execute a few ms later than the delay)
    else if( !timeout && trail !== false ) timeout = setTimeout(exec, delay);
  };
};

What this version does that differentiates it from the Underscore.js version is it:

  1. Executes immediately upon first hit and then only after the specified delay. IMO, this provides a more desired effect for most throttled events. If you're really looking to do something when a user stops interacting with the screen, then use a debounce technique.
  2. The last arguments are applied when executing the throttled function. This means that the latest version of the values are used, instead of the values supplied to the initial timed event.

To see the difference in behavior, check out the JSFiddle example using my version of throttle().


jQuery Field, mcDropdown and iButton Plugins Updated!

I'm working on migrating our application to use the latest version of jQuery. In the process of migrating, I've been working on fixing compatibility issues with several of the plug-ins I've worked on to make sure they work with the latest version of jQuery. So, here's a list of updated plug-ins and their release notes:

Field Plug-in v0.9.4

  • Fixed issues with jQuery v1.6.x
  • Fixed file fields not currently supported by getValue or getType
  • Fixed formHash breaks on fields with apostrophes
  • Fixed moveNext() did not work, it have invisible parent

mcDropdown jQuery Plug-in v1.3.1

  • Fixed support for jQuery v1.6.2

iButton jQuery Plug-in v1.0.03

  • Fixed compatibility issues with jQuery v1.6.2
  • Added className option for adding an additional class name to the main container—which is useful for adding alternative styles to the button
  • Revised image sprite to be better organized (handles are now grouped together)
  • Updated CSS to reflect changes to image sprite
  • Fixed bug where iButton behavior could be attached multiple times if code attempts to re-initialize on the same element


My Take on the iOS (aka iPhone) vs Android Debate

[UPDATED: Tuesday, June 21, 2011 at 10:27:35 AM]

About 2 years ago, I decided to take the plunge and see what the iPhone craze was all about. My contract was over with my Windows Mobile phone and I was looking for something to replace it. While I loved the idea of my Windows Mobile phone (WM5,) it's execution was severely lacking and I pretty much had non-stop issues with it. I experienced all sorts of random lockups, services shutting off, etc. in my 2 years of owning the VX-6700 phone. While it tried to combine the power of a PDA and a Phone, it really did neither of them well (but it was probably a better PDA than it was a Phone—it was a horrible phone.)

So, even with some of the negatives I'd read about the iPhone, I was definitely anxious to try a smart phone that seemed to be both a solid PDA and a phone—even if it was tied to iTunes and AT&T's network.

It didn't take long to discover the iPhone was vastly superior to my old WM phone. The UI was intuitive and the device worked. Battery life was excellent and my only real issues with the phone were it's lack of a physical keyboard and it's dependency on iTunes—which I despise.

Fortunately, once I found MediaMonkey I only needed to rely on iTunes for the occasional backup and firmware updates. Using MediaMonkey does end up requiring some patience, because Apple is constantly trying to prevent 3rd party applications from managing songs on the iPhone/iTouch/iPad devices, but if you're willing to wait for the developers of MM to work out the issues w/each firmware revision, the software works well and fits my setup much better than iTunes ever will.

After 2 years of using my iPhone, I've been extremely happy, but there are a few points that have always bothered me:

  • I hate the virtual keyboard – even after 2 years of use, I find I still end up tying "for" as "fir" and the auto-correction never helps me out. I just find it difficult to use and still too often it looks as if I'm pressing the correct key, only to have it register something else. Typing is a real chore for me on this device, so I try to keep typing to a minimum.
  • Notification system – I hate how there's no central screen to see all notifications. This can be a problem if you have several missed calls, e-mails and text that all have occurred since you last looked at the phone.
  • Apple's strict app approval process – I've seen apps ended up needing weeks to get bug fixes online and apps pulled for what seem no good reason. This draconian approach can be irritating—it's your phone, you ought to be able to do with it whatever you want.
  • Lack of Flash – the refusal to include Flash used to really bother me, because it used to be really difficult to watch online videos. However, almost all sites now encode their videos in way you can watch the videos online now. Because of this change, the lack of Flash really hasn't bothered me much in the last year, although every once in a while I'd hit a site that required Flash and wish I had it.

So, in my search to find the best phone I can, I thought I'd try my hands at an Android-based phone. I've known plenty of people who have gone from iPhones to an Android device and they seemed pretty happy. I was also wanting to get off AT&T and get back to Verizon Wireless—since they have without a doubt have a better network than AT&T.

After much research, the wife and I decided on the Samsung Droid Charge. We played around with several phones at the Verizon store, but the wife and I both really dug the display on the Droid Charge and I was really digging Swype when playing around with it at the store. I also wanted to make sure I got a 4G phone, since I was getting locked into another 2 year contract. I ended up buying the phone from Amazon Wireless, because at the time they had the phone for half the price I could buy it directly from Verizon—which means I'd get both phones for the price of one phone directly from Verizon.

The phones took 2 business days to arrive after ordering and I eagerly opened the packages so I could begin charging the phones so I could play with them after work. After playing with the phone for a week, here's how I view the Android experience.

Initial Impressions

My initial opinion of the Android after playing it with it for a day was really poor. I constantly felt lost in applications, not sure how to perform actions that were always very intuitive on the iPhone. I found navigating an app with the separate buttons difficult and not intuitive at all. I had become so accustom to iPhone apps offering all the options onscreen, that go "back" in an app or trying to refresh a listing by hitting the "menu" button was not very intuitive.

Also, actions that were single clicks/actions on the iPhone, generally involved at least 2 operations on the Android. Want to refresh your mail on the iPhone? Click the refresh button on the screen. That's one action. Want to refresh your mail in Android? Press the menu button, click refresh. That's two actions. Pretty much ever application I use frequently on the iPhone is like that. The Android way pretty much always involves more steps—many of them which were not intuitive.

I also started really missing the ability to scroll to the top of a page by clicking in the status bar—which works in pretty much every iPhone app where the page scrolls. I've not found an equivalent operation in Android, and this makes using some Android apps painful—especially the browser.

After the first day, I was really hating the phone, but I was intent on trying to give the phone a fair chance and wanted to use the phone for a week before making any rash decisions. So I kept plugging away, trying to use the phone as my primary device.

I started liking the phone better after the second day of usage as I began to get the hang of how the phone worked. It's still nowhere near as intuitive or as efficient as the iPhone is, but at least I wasn't feeling lost any more. Maybe this Android thing isn't so bad after all!

However, the more I used the phone, the more I realized the many deficiencies in the Android platform. I've yet to find find a program on Android that's better than it's iOS equivalent. The Facebook app for iOS is way better than the one on Android and I'm pretty much seeing that trend across all the applications I've downloaded. The one exception might be Words for Friends—only because it tells you what word is invalid (but the lack of an Ad-free version makes it worse overall.)

The battery life is also abysmal compared to my iPhone 3GS. I know the screen and increase in CPU power both will affect things, but even when the phone is in an idle state the battery drain is incredible. After playing around with some task killer applications, I can at least get a day of moderate use out of the phone, but there's no way the battery would last for 2 days—even if I wasn't using it. My iPhone on the other hand can go a couple of days easy on one charge w/moderate use.

This leads me to my biggest complaint with Verizon. One of the reasons I left Verizon is because their phone selection was always poor. They never had phones that came close to their competitors. However, in the 2 years I've been with AT&T they've actually started getting much better phones. The problem is, they tend to be slow to update the firmware on the phones and their firmware is loaded with Verizon crap that you can't install.

Whenever I run Advanced Task Killer, I constantly see Verizon apps re-spawning that I have no intention of every running (like IM, Daily Briefing, My Verizon Mobile, etc.) Obviously running programs that aren't going to be used affects both battery, but performance. Please let me remove programs I have no intention on using.

The other issue is obviously with outdated firmwares. The Samsung Droid Charge is only like a month old—it's one of Verizon's newest phones. Yet the it's still shipping with Froyo 2.2.1. Why does Verizon always wait so long to release firmware updates? Android 2.3.4 came out in May 2011, but Android 2.3's been out since December 2010. That's not to mention that Android 3.0 was released in February and 3.1 is soon to be released.

So, after a week of using Android I'm really thinking I'm going to abandon the Android device and go back to the iPhone.

The Good

It's not all bad though, there are some things I really do like and love about the Samsung Droid Charge.

  • Swype – Swype simply rocks. It's really great with long words and actually feels like a much more natural way to type on a virtual keyboard. The one downside I can see is that if you're not familiar with the QWERTY keyboard, it might be hard to know where to trace your fingers to form words (since your finger tends to cover the keyboard.) However, any touch typist should have no issues typing with Swype. It's truly a thing of beauty and Apple really needs to look at licensing the technology.
  • Virtual Keyboard – the normal virtual keyboard is much better as well. The issues I have w/the virtual keyboard on the iPhone magically don't exist on the Droid Charge. Maybe this is because of the slightly larger keys, but I find typing the word "for" actually comes out "for" and not "fir" like it does for me on my iPhone. My only complaint is Android needs to remove the period, double the size of the spacebar and make double pressing the spacebar insert a period like in iOS. If they do that, the keyboard is virtually perfect.
  • 4.3" AMOLED display – the display on the Droid Charge is absolutely beautify. If makes my iPhone screen seem dinky and ridiculous small. The screen is actually almost too big for me. I actually find the phone's a little harder to use with one hand because the phone is so big, but it's truly beautiful! My only real complaint is that if the brightness is turned down, the whites can be a little greenish—it gives photos of people a strange tint.
  • Gmail app – the Gmail app really works great. I use Gmail for my personal e-mail and on the iPhone I stick to using the mobile web interface, as I really don't want my personal e-mail polling every time I check my work e-mail. However, the Gmail app on Android is very nice. I real like having a native app that gives me all the great functions of Gmail conversations.
  • Camera – the camera on the phone seems very nice. I really like the HD recording capabilities of the phone and the camera has a lot of options too. I just wish there was a way to map one of the many physical keys to take a picture/record a video.
  • Speakerphone – this thing is loud and crystal clear.

The Not As Good As I Was Hoping

  • 4G (i.e. 4LTE) – well I've seen some areas where Verizon's 4LTE network does indeed appear to be blazing fast (I've seen up to 15Mbps d/l and 6 Mbps u/l in Dublin) in my area (which is a mile from a Verizon store) I'm not seeing speeds any different AT&T's 3G network. Not really a huge deal since I'm mainly at my house on WiFi, but I was hoping to use the 4G network and my phone as a mobile hotspot when out and about. While it'll work, it's not as a good as I was hoping.
  • Lock screen – after reading tons of great things about the Android lock screen, I was thought it would be more useful than it is. I find it very frustrating to get in a new text or phone and not have any insight to what the notification was about when I turn on the phone. Maybe it's just a matter of not finding a good lock screen add-on, but I was really hoping for something better out of the box.
  • Flash in the browser – when I first bought my iPhone, I really thought the exclusion of Flash was a major missing feature. However, since 99% of the time I really wanted Flash on my mobile was to watch a phone, the lack of Flash on iOS has become less and less over time as most sites now offer video in a iPhone compatible format. However, I was really excited finally getting Flash on my phone as it would finally give me the full web experience. After playing with the browser for a week, I'm finding the reality of Flash on a phone isn't nearly as great as the idea of Flash on the phone. Since the vast majority of Flash on the web is ads, I'm actually finding Flash is slowing down my normal browsing experience because it's loading ads I'd never see on my iPhone. I'm not saying Flash is bad, but what I found I really wanted was either better native ad blocking or at least a prompt asking me if I wanted to run Flash on the current site. I think idealistically, the browser would ask me if I want to run Flash on a site the first time Flash tries to run for a site. If you tell it not to run Flash, each Flash element would turn into a button that you could click to enable Flash to run on that element.
  • Widgets – I really thought this would be what set the Android device apart from the iPhone. What I ended up finding was a lack of really good widgets and the good widgets I did find, don't have enough configuration options.
  • Browser – well the browser is ok in general, I find that there's two issues were the iPhone really shines. First, using the status bar to scroll to the top of the page. I find I'm really missing the ability to quickly scroll to the top of a page. The second issue is page rendering in general. For some reason the Android seems to render pages in a wider format and makes the fonts too hard to read. The iPhone seems to do a better job of rendering "desktop" sites and constraining them to a narrow width. This is really mostly an issue with websites that have a fluid layout, which is unfortunately the vast majority of websites out there.
  • Phone layout – I find the layout of the buttons on the Droid Charge a bit of a pain to work with. The power/lock button is in a bad spot. I keep looking for it on top of the screen. It's also in a horrible spot for using the phone in landscape mode—the power button ends up being right where I want to hold my index finger to hold the phone.
  • Music Player – the native music player lacks gapless playback—which is a big problem for me as most of my favorite artists tend to right albums where the music all blends together from track to track (The Beatles, Dream Theater, etc, etc, etc.) PowerAMP is ok, but still left me noticing gaps between tracks on some ablums. Rockbox has been the best music player I've tested for actual playback and gapless playback, but the UI is really lack (and it's still pretty buggy being a beta application.)
  • Only power buttons turns device on – I find myself expecting some of the other physical buttons to turn the phone on like on the iPhone.
  • Front facing camera – the front facing camera seems nice enough, but with a complete lack of good Video Chat applications it makes the front facing camera in essence pointless. I mean I'm not the kind of self indulgent person that takes photos of themselves all the time, so unless you can give me a good Video Chat application, having a front facing camera is pointless. I've tried Fring, but the video quality is poor and the audio volume is horrible—you can't hear the other person at all. Tango has decent video, but the audio is completely broken on the Droid Charge—once you go to video call mode, the sound mutes completely.

The Bad

  • Applications lack polish – even though I used to consider the Apple App Store policies of app approval draconian, after a week of using the Android I can certainly see the benefits. The Apple apps generally have much more polish and generally work much better than their Android counterparts. It's also much harder to find good Android apps—there's a ton of rubbish out there.
  • Application incompatibilities – one of the biggest issues facing the Android platform today, is the compatibility of applications across various devices. It's really frustrating to see that there's an app you want, only to find you can't run it on your particular Android device. It's one thing to not be able to run the application because you don't have the right version of the OS, it's another thing not to be able to run the application because you don't have the right physical device. There's a couple of apps I really want for my phone, but can't download them because my phone is incompatible with the application (I'm speaking to you Netflix.) This is extremely frustrating and the opposite of the experience in the Apple App Store. Granted, Apple can be a bit draconian about which apps make it to the store, but at least you know if the app is there you can run it. (Yes, there are exceptions, such as having a very old iPhone/iTouch, etc, but if you have a modern device, all apps will run.)
  • Verizon's pre-installed apps – I appreciate Verizon giving me lots of applications to choose from and it makes sense to pack the phone full of features for users who may not look in the Android Market, but please, please, please let me uninstall the crap I don't want. I find there's a handful of applications that keep starting in the background that I will never use. I should be able to uninstall the applications I don't want on my phone, without having to resort to the drastic measure of rooting a phone.
  • Poor battery life – you really have to work to get your Android device to make the battery last. This reminds me of my poor experiences with Windows Mobile. Seems like I constantly have to kill apps to improve my battery life. Last week, I unplugged my Droid Charge at 4pm before heading to my golf league. I made one 4 minute phone call (on speaker phone) and then turned the screen on a couple of times (for no more than 3-4 minutes total.) When I finished my 9 holes of golf, I looked at the phone and released my battery was done to 67% charge. My iPhone had been off the charger since 7am, had been used way more and was still at like 94% charge. I've finally got the battery life to the point where I think maybe it's manageable, but I feel like it's work. Unless I have extreme usage of my iPhone, I never need to charge it during the day. However, with the Droid Charge I'm pretty sure I can't be too far from a charger.
  • Mail – other than the Gmail app, there appear to be several major issues with mail on Android devices that are really prohibiting me from using the phone. I have a really complicated mail setup. I use IMAP for work e-mail, ActiveSync for "mobile" push e-mail and Gmail for my personal mail. Other than the lack of a good native Gmail app on iOS, the iPhone handles all this great. Even having to use the mobile web UI for Gmail works ok (but it's not nearly as nice as the Gmail app that comes on Android.) However, there are a few huge issues I'm having with non-Gmail on Android:
    • IMAP – appears to be extremely buggy. I'm having too major issues that are a deal killer for me.
      1. Every time I refresh my IMAP e-mail, all the e-mail shows as unread (even the mail that has already been marked as read.) I might be able to live with this if I could easily select all the message in a folder, but this behavior is extremely annoying. I did some Googling and this seems to be a common problem for some people, but not common enough that there are any fixes—other than using a different e-mail client, like K-9. The problem is, I refuse to use 3 different e-mail programs to check all my mail. I need Exchange/ActiveSync support and only the native Android e-mail client appears to support it.
      2. Starting yesterday, every time I try and pull my IMAP e-mail I'm getting the error: "The application Email (process com.android.email) has stopped unexpectedly. Please try again." This appears to be the problem parsing certain e-mails and the only current fix for Froyo appears to be to wipe the data, remove the corrupted e-mail using another client and then restoring all your mail accounts. This bug appears it may be fixed in Gingerbread, but who knows when Verizon & Samsung will decide to push out Gingerbread to the phone.
    • ActiveSync – while it doesn't happen all the time, a handful of times over the past week I've had issues w/my ActiveSync account telling me the password was corrupted and needed to be re-entered. Since this happens without me being notified, it makes push mail completely unreliable. I need stable push mail, because that's how I have all server notifications, support tickets, etc sent to me. I need to know that push e-mail is reliable and works without random failure.
  • No scroll to top – I find the inability to click on the status bar to scroll to the top of the window a function really missing from Android. You'd think with all these physical buttons, you'd have some way to jump to the top of the page—like with a long press of the menu or back button.
  • Phone layout – well already mentioned in the previous section, I find the placement of the USB charger to be horrible. The phone becomes extremely difficult to use when you're charging the device. I could live with it if the phone didn't need to be charged so much. The USB port should really be on the bottom of the phone.
  • No silent button – I find the lack of switch to mute the phone a problem. The only way to turn off sound is to turn the device on—which means you have to pull the device out of your pocket and light it up. I love that with my iPhone I can just reach in my pocket and turn the phone to silent without having to pull the device out of my pocket. It's a quick one handed operation.

Conclusion

I really, really wanted to love this Android device, but the more I use it the more I realize the iPhone is superior for me. It appears many of my issues may be addressed in newer versions of Android OS, but Verizon and especially Samsung have a bad history of basically abandoning firmware updates after 6 months of a phone being released. I'm sure that Gingerbread will eventually be released for the Charge, but I'm beginning to doubt whether I'll ever see 3.0 or 3.1 officially released for the phone—which is a real shame. These mobile carriers are in such a hurry to release a new crop of phones every 6 months, that they stop improving their existing phones. If the carriers are going to lock you into a 2 year contract, then they out to be guarantee that they will keep the phone up-to-date with the latest firmwares over that 2 year period.

I'm going to touch base with Verizon today to see if they can resolve my issues. I've got another week before my 2 week trial is up and I really want to give the phone a chance—I'm really trying. However, at this point I think I'm going to stick with an iPhone and iOS (and thus, probably staying w/AT&T. As much as I'd love to be on Verizon's network, but it bothers me that Verizon's version of the iPhone doesn't seem to be keeping up with the firmwares.)


Modifying the message in a CFCATCH before rethrowing error

This morning I was working on some code where I wanted to capture an error in side a cftry/cfcatch block and rethrow the message, but I wanted to modify the cfcatch.message key to include more detail without losing the stack trace. I could have just used the <cfthrow /> tag and used the type, message and detail attributes but this would have caused me to lose the stack trace—which I needed.

Idealistically, I could have just modified the "message" key in the cfcatch variable, but the problem is the ColdFusion cfcatch variable is not really a struct—it looks like one—but it's actually an Java exception. Because it's not really a struct, it's not possible to just edit key values—making the cfcatch variable essentially read-only.

This got me looking into a method were I could rethrow the original stack trace, but customize the "message" key. After a few minutes playing around the java.lang.Exception object, I came up with the following:

  <cffunction name="rethrowMessage" access="public" returntype="void" output="false" hint="Rethrow a CFCATCH error, but allows customizing the message key">
    <cfargument name="cfcatch" type="any" required="true" />
    <cfargument name="message" type="string" required="false" />

    <cfset var exception = "" />

    <cfif not structKeyExists(arguments, "message")>
      <cfset arguments.message = arguments.cfcatch.message />
    </cfif>

    <cfset exception = createObject("java", "java.lang.Exception").init(arguments.message) />
    <cfset exception.initCause(arguments.cfcatch.getCause()) />
    <cfset exception.setStackTrace(arguments.cfcatch.getStackTrace()) />

    <cfthrow object="#exception#" />
  </cffunction>

Using this UDF, I can now do something like:

<cfscript>
  // connect and authenticate
   try {
    store.connect(variables.instance.server, variables.instance.username, variables.instance.password);
  } catch(Any e) {
    // throw original message, but append the username to the message
    rethrowMessage(cfcatch=e, message=e.Message & " [#variables.instance.username#]");
  }
</cfscript>

This allows me to throw the original Java error that occurs when connecting to a JavaMail Store occurs, but modify the message to include the mailbox I'm trying to connect to  which is helpful in debugging the root cause.


Fixing "MODIFICATION_FAILED" errors in Thunderbird when using Google CalDAV

For a while now I've been dealing with issues adding/updating events to my Google Calendar from Thunderbird/Lightning. When ever I'd try to update an event, I'd get a very generic "MODIFICATION_FAILED" error message with no detailed message. I could view events just fine and even dismiss alarms, but nothing I tried would allow me to add new events directly from Thunderbird. I ended up resorting to opening up Google Calendar and adding the events via the web interface. While this works, it's no where near as fast as accepting an invite from Thunderbird.

Today I had several GoToMeeting invites that I need to add to my calendar and decided look into the problem again. After doing some searching, I found lots of threads of people having the same issue, but alas no solutions. The one thing that did keep popping up is that Google considers CalDAV support still experimental, so problems may occur.

This got me to look into if there were other solutions other than CalDAV and I came across Provider for Google Calendar 0.7.1 add-on for Sunbird and Lightning. After changing all my calendars to use the new provider, everything seems to be working very well.

So, if you're getting errors updating your Google Calendar using CalDAV, you might try the Provider for Google Calendar to see if it fixes your issues. I'd also recommend taking a look at the Calendar:GDATA Provider wiki page which covers installation/setup of the provider.