<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/rss2full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><!-- generator="wordpress/2.3.3" --><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">

<channel>
	<title>Orange is my favorite color » My Software</title>
	<link>http://www.ghidinelli.com</link>
	<description />
	<pubDate>Fri, 02 May 2008 03:07:46 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.3.3</generator>
	<language>en</language>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/OrangeIsMyFavoriteColorTech" type="application/rss+xml" /><feedburner:emailServiceId xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">467980</feedburner:emailServiceId><feedburner:feedburnerHostname xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">http://www.feedburner.com</feedburner:feedburnerHostname><item>
		<title>SQL [NOT] EXISTS Goes Zoom</title>
		<link>http://www.ghidinelli.com/2008/05/01/sql-not-exists-goes-zoom/</link>
		<comments>http://www.ghidinelli.com/2008/05/01/sql-not-exists-goes-zoom/#comments</comments>
		<pubDate>Fri, 02 May 2008 03:07:46 +0000</pubDate>
		<dc:creator>brian</dc:creator>
		
		<category><![CDATA[PostgreSQL]]></category>

		<category><![CDATA[Web/Internet]]></category>

		<guid isPermaLink="false">http://www.ghidinelli.com/2008/05/01/sql-not-exists-goes-zoom/</guid>
		<description><![CDATA[I use fairly vanilla SQL most of the time so I was shocked to read this post on the PostgreSQL list when I ran into some slowness with a NOT IN query.  While my experience is with Postgres, apparently this works with most databases.
If you have a NOT IN with a subquery that returns [...]]]></description>
			<content:encoded><![CDATA[<p>I use fairly vanilla SQL most of the time so I was shocked to read <a href="http://archives.postgresql.org/pgsql-performance/2002-12/msg00185.php">this post</a> on the PostgreSQL list when I ran into some slowness with a NOT IN query.  While my experience is with Postgres, apparently this works with most databases.</p>
<p>If you have a NOT IN with a subquery that returns lots of rows, an EXISTS or NOT EXISTS will usually be faster.  And not just a little bit.  Like by a factor of 200:1 in my NOT EXISTS case!  I am doing batch modification to a new schema and used this query to get a count of the remaining records while I was running my conversion scripts:</p>
<pre><code>SELECT count(*) as total
FROM tblLookupAuthenticateOld
WHERE uidMember NOT IN (SELECT uidMember FROM tblLookupAuthenticate)</code></pre>
<p>The EXPLAIN looks like:</p>
<pre><code>"Aggregate  (cost=9033491.00..9033491.01 rows=1 width=0)"
"  -&gt;  Seq Scan on tbllookupauthenticateold  (cost=1772.98..9033453.73 rows=14910 width=0)"
"        Filter: (NOT (subplan))"
"        SubPlan"
"          -&gt;  Materialize  (cost=1772.98..2304.14 rows=29816 width=36)"
"                -&gt;  Seq Scan on tbllookupauthenticate  (cost=0.00..1510.16 rows=29816 width=36)"</code></pre>
<p>Look at that cost: 9033491.00!!  This took about 100 seconds to run on my laptop.  It&#8217;s because the query is effectively doing a sequential scan for every record in the first table.  Ugh.  Then I swapped it to NOT EXISTS:</p>
<pre><code>SELECT count(*) as total
FROM tblLookupAuthenticateOld
WHERE NOT EXISTS (select * FROM tblLookupAuthenticate WHERE uidMember = tblLookupAuthenticateOld.uidMember)</code></pre>
<p>The EXPLAIN looks like:</p>
<pre><code>"Aggregate  (cost=247542.82..247542.83 rows=1 width=0)"
"  -&gt;  Seq Scan on tbllookupauthenticateold  (cost=0.00..247505.54 rows=14910 width=0)"
"        Filter: (NOT (subplan))"
"        SubPlan"
"          -&gt;  Index Scan using tbllookupauthenticate_pkey1 on tbllookupauthenticate  (cost=0.00..8.28 rows=1 width=298)"
"                Index Cond: (uidmember = $0)"</code></pre>
<p>This query ran in about 500ms.  That&#8217;s a &#8220;decent&#8221; improvement of 200:1.  I&#8217;m planning to run a search in Eclipse tonight for &#8220;NOT IN&#8221; to see if there are any places where NOT IN once made sense but not [NOT] EXISTS is more appropriate as the subquery returns more and more rows.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?a=woCgQH"><img src="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?i=woCgQH" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?a=0tXA9H"><img src="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?i=0tXA9H" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.ghidinelli.com/2008/05/01/sql-not-exists-goes-zoom/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Three Great Thunderbird Extensions</title>
		<link>http://www.ghidinelli.com/2008/04/19/three-great-thunderbird-extensions/</link>
		<comments>http://www.ghidinelli.com/2008/04/19/three-great-thunderbird-extensions/#comments</comments>
		<pubDate>Sun, 20 Apr 2008 02:22:18 +0000</pubDate>
		<dc:creator>brian</dc:creator>
		
		<category><![CDATA[Web/Internet]]></category>

		<guid isPermaLink="false">http://www.ghidinelli.com/2008/04/19/three-great-thunderbird-extensions/</guid>
		<description><![CDATA[I know I have my patterns - I get my computer set up and for the next 2 years I leave it nearly as-is.  Then I get a new machine (Lenovo X61) and it&#8217;s time to see what&#8217;s new out there.
I did that search four weeks ago when installing Thunderbird and came across some [...]]]></description>
			<content:encoded><![CDATA[<p>I know I have my patterns - I get my computer set up and for the next 2 years I leave it nearly as-is.  Then I get a new machine (Lenovo X61) and it&#8217;s time to see what&#8217;s new out there.</p>
<p>I did that search four weeks ago when installing Thunderbird and came across some really great plug-ins.  With a month of daily use under my belt, I want to recommend the top three for your consideration:</p>
<ol>
<li><a href="https://addons.mozilla.org/en-US/thunderbird/addon/2487">Nostalgy</a> - Despite the goofy name, this plugin is genius for people who love keyboard shortcuts.  If you&#8217;ve ever used Eclipse&#8217;s Ctrl-Shift-R shortcut that lets you just start typing any filename in your workspace with an as-you-type filtered list of available files to select from, you will fall in love with this.  With any message(s) selected, Nostalgy lets you hit &#8220;S&#8221; and then start typing a folder name and select from a list of matching email folders.  Hit enter and all of the selected messages will be moved to that folder.  Need to open a folder quickly?  Hit &#8220;G&#8221;, start typing the name of a folder and hit enter as soon as it&#8217;s the first match in the dynamic list.  It&#8217;s so simple, yet so sweet.  For organized folder-users, this is a dream plugin.</li>
<li><a href="https://addons.mozilla.org/en-US/thunderbird/addon/4839">Recipients Overview</a> - One downside to the X61 is it has a low resolution of 1024&#215;768 when mobile.  While I spend most of my time docked, screen real estate becomes a real issue on the road.  Thunderbird has a nice feature that lets you condense the header information on a message to take up less space but it doesn&#8217;t list all of the people on the TO and CC list.  I consider this important information for deciding how to handle and/or reply to an email.  Recipients Overview simply enables listing all of the recipients in the condensed view saving you space when you need it without cutting out important details.</li>
<li><a href="https://addons.mozilla.org/en-US/thunderbird/addon/2307">Slideshow</a> - This one is a little simple but so many times that&#8217;s all it takes to make your life easier.  If you receive a message with images attached, Slideshow will give you a one-click option to open them in a slideshow format for viewing.  This is usually much easier than trying to view them in the confine of the message window but doesn&#8217;t require an external image editor.  Sweet and simple!</li>
</ol>
<p>Try them and let me know if you find them as helpful as I do!</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?a=WV8yVGG"><img src="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?i=WV8yVGG" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?a=WYB3TcG"><img src="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?i=WYB3TcG" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.ghidinelli.com/2008/04/19/three-great-thunderbird-extensions/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Lightning strikes faster</title>
		<link>http://www.ghidinelli.com/2008/04/08/lightning-strikes-faster/</link>
		<comments>http://www.ghidinelli.com/2008/04/08/lightning-strikes-faster/#comments</comments>
		<pubDate>Tue, 08 Apr 2008 21:15:17 +0000</pubDate>
		<dc:creator>brian</dc:creator>
		
		<category><![CDATA[Web/Internet]]></category>

		<guid isPermaLink="false">http://www.ghidinelli.com/2008/04/08/lightning-strikes-faster/</guid>
		<description><![CDATA[Mozilla just released Sunbird and Lightning 0.8, the calendar project of the Mozilla Group.  I&#8217;ve been using the combination of Thunderbird, Lightning/Sunbird and a GTD tool called ThinkingRock for over a year now.  The problem is that my calendar files have grown and the calendar would take sometimes as long as 5-10 seconds [...]]]></description>
			<content:encoded><![CDATA[<p>Mozilla just released <a href="http://www.mozilla.org/projects/calendar/">Sunbird and Lightning 0.8</a>, the calendar project of the Mozilla Group.  I&#8217;ve <a href="http://www.ghidinelli.com/2006/11/07/end-to-end-thunderbird-and-lightning-synchronization/">been using</a> the combination of Thunderbird, Lightning/Sunbird and a GTD tool called <a href="http://www.thinkingrock.com.au/">ThinkingRock</a> for over a year now.  The problem is that my calendar files have grown and the calendar would take sometimes as long as 5-10 seconds to switch from month to month.  A real usability drag.</p>
<p>But I just installed Lightning 0.8 into Thunderbird 2.0 and fired it up and not only is the new task pane and conversion between mail, tasks and events really neat, the thing FLIES.  I can switch between months now in less than a second and the visual design of the application continues to be polished.  The speed has been my only complaint about what is otherwise a great piece of software.  Kudos to the team for making big strides over the past year.</p>
<p>If you&#8217;re looking for a well-integrated <a href="http://www.davidco.com/what_is_gtd.php">GTD</a> solution, my combination of Thunderbird (mail), Lightning/Sunbird (calendar) and ThinkingRock (GTD tasks/projects) has worked really well.  ThinkingRock exports an iCal file of your appointments and tasks which I load into Thunderbird as a remote calendar.  Then <a href="http://www.birdiesync">BirdieSync</a> pulls the appointments and tasks from Thunderbird into my Windows Mobile 5 phone so I have full access to everything at all times.  This is, unfortunately, read-only access from the mobile but there is a <a href="http://beagle.u-bordeaux4.fr/yildi/trppc/">Pocket PC extension</a> for ThinkingRock that I have not yet tried.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?a=tIP08hG"><img src="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?i=tIP08hG" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?a=1TxE5kG"><img src="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?i=1TxE5kG" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.ghidinelli.com/2008/04/08/lightning-strikes-faster/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Built-in Ant Properties</title>
		<link>http://www.ghidinelli.com/2008/04/01/built-in-ant-properties/</link>
		<comments>http://www.ghidinelli.com/2008/04/01/built-in-ant-properties/#comments</comments>
		<pubDate>Tue, 01 Apr 2008 19:42:31 +0000</pubDate>
		<dc:creator>brian</dc:creator>
		
		<category><![CDATA[Web/Internet]]></category>

		<guid isPermaLink="false">http://www.ghidinelli.com/2008/04/01/built-in-ant-properties/</guid>
		<description><![CDATA[I couldn&#8217;t find this easily with TEH GOOGLE so I present to you here, a complete list of the built-in properties that you can access using Ant.  If you don&#8217;t know what Ant is and you&#8217;re a developer, then you probably don&#8217;t use deployment scripts and should be whipped.  Check out Jim Priest&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>I couldn&#8217;t find this easily with TEH GOOGLE so I present to you here, a complete list of the built-in properties that you can access using <a href="http://ant.apache.org">Ant</a>.  If you don&#8217;t know what Ant is and you&#8217;re a developer, then you probably don&#8217;t use deployment scripts and should be whipped.  Check out Jim Priest&#8217;s <a href="http://www.thecrumb.com/wiki/Ant">Ant Wiki</a> for a boatload of information and helpful links.</p>
<p>You need do nothing else other than wrap these values in with a ${} inside of a build file to use their values.  They are a combination of built-in Ant properties and all of System.getProperties():</p>
<pre><code>basedir		the absolute path of the project's basedir (as set with the basedir attribute of &lt;project&gt;).
ant.file	the absolute path of the buildfile.
ant.version	the version of Ant
ant.project.name	the name of the project that is currently executing; it is set in the name attribute of &lt;project&gt;.
ant.java.version	the JVM version Ant detected; currently it can hold the values "1.2", "1.3", "1.4" and "1.5".
ant.home	home directory of Ant
java.version	JRE version
java.vendor	JRE vendor
java.vendor.url	Java vendor URL
java.home	Java installation directory
java.vm.specification.version	JVM specification version
java.vm.specification.vendor 	JVM  specification vendor
java.vm.specification.name 	JVM specification name
java.vm.version	JVM implementation version
java.vm.vendor	JVM implementation vendor
java.vm.name	JVM implementation name
java.specification.version	JRE specification version
java.specification.vendor	JRE specification vendor
java.specification.name		JRE specification name
java.class.version	Java class format version number
java.class.path	Java class path
java.ext.dirs	Path of extension directory or directories
os.name		Operating system name
os.arch		Operating system architecture
os.version	Operating system version
file.separator	File separator ("/" on UNIX)
path.separator	Path separator (":" on UNIX)
line.separator	Line separator ("\n" on UNIX)
user.name	User's account name
user.home	User's home directory
user.dir	User's current working directory</code></pre>
<p>If you want to test these, just use echo:</p>
<pre><code>&lt;echo&gt;OS: ${os.arch}&lt;/echo&gt;
&lt;echo&gt;VM: ${java.vm.name}&lt;/echo&gt;
&lt;echo&gt;Username: ${user.name}&lt;/echo&gt;</code></pre>
<p>Finally, you can also get at your environment variables for your system by using the following syntax:</p>
<pre><code>&lt;property environment="env"/&gt;

&lt;echo&gt;Hostname: ${env.COMPUTERNAME}&lt;/echo&gt;
&lt;echo&gt;Path: ${env.Path}&lt;/echo&gt;</code></pre>
<p>Note that the environment variables are case-sensitive even if your OS is not (e.g., Windows).  So for Windows, the variable is env.Path but on Unix (I believe) it would be env.PATH.  env.PATH at any rate doesn&#8217;t work on Windows so watch your case!</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?a=eb13VgG"><img src="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?i=eb13VgG" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?a=KV8S31G"><img src="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?i=KV8S31G" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.ghidinelli.com/2008/04/01/built-in-ant-properties/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Finding the row and cell index of a clicked table cell with jQuery</title>
		<link>http://www.ghidinelli.com/2008/03/27/finding-the-row-and-cell-index-of-a-clicked-table-cell-with-jquery/</link>
		<comments>http://www.ghidinelli.com/2008/03/27/finding-the-row-and-cell-index-of-a-clicked-table-cell-with-jquery/#comments</comments>
		<pubDate>Fri, 28 Mar 2008 01:19:23 +0000</pubDate>
		<dc:creator>brian</dc:creator>
		
		<category><![CDATA[Web/Internet]]></category>

		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://www.ghidinelli.com/2008/03/27/finding-the-row-and-cell-index-of-a-clicked-table-cell-with-jquery/</guid>
		<description><![CDATA[I needed to find where I was at in a table so I could report back the row and cell position for another function.  There aren&#8217;t any easy-to-find answers from the Google so I set about doing my standard Javascript DOM exploration:
for (var ii in this)
  console.info(" ii = " + ii);
I explore [...]]]></description>
			<content:encoded><![CDATA[<p>I needed to find where I was at in a table so I could report back the row and cell position for another function.  There aren&#8217;t any easy-to-find answers from the Google so I set about doing my standard Javascript DOM exploration:</p>
<pre><code>for (var ii in this)
  console.info(" ii = " + ii);</code></pre>
<p>I explore this way because I don&#8217;t know any better.  After much debugging with the .bind() on my <a href="http://www.tablesorter.com">TableSorter</a> table, I cobbled together references to the row and cell so I could update a single value in the table cache when a form element is changed as a performance boost for large tables.  This assumes a SELECT box but it works for any element inside of a TD:</p>
<pre><code>&lt;table&gt;
...
&lt;tbody&gt;
...
&lt;tr&gt;
	&lt;td&gt;...&lt;/td&gt;
	&lt;td&gt;
		&lt;select name="foo"&gt;
			&lt;option value="100"&gt;Blow, Joe&lt;/option&gt;
			&lt;option value="200"&gt;Mack, Jane&lt;/option&gt;
			&lt;option value="300"&gt;Zanker, John&lt;/option&gt;
		&lt;/select&gt;
	&lt;/td&gt;
&lt;/tr&gt;
...
&lt;/tbody&gt;
&lt;/table&gt;</code></pre>
<p>And the corresponding Javascript event handler:</p>
<pre><code>$("table#tblNumbers select").change(
	function()
	{
		// get row, cell, value
		var cell = $(this).parent("td");
		var row = $(cell).parent("tr");
		var cellValue = [[row[0].sectionRowIndex, cell[0].cellIndex, $(this).find("option:selected").text()]];

		// update table cache
		$(this).parents("table").trigger("updateCell", cellValue);
	}
);</code></pre>
<p>The trick is that jQuery&#8217;s .parent() returns a single-item array that you must access through the [0] identifier.  If you drop into the [0] item, you have full access to the DOM node including the properties for rowIndex and cellIndex.</p>
<p>In addition to sectionRowIndex, you can also use rowIndex.  It depends on whether or not you want the position absolutely in the table or relative to the TBODY you&#8217;re inside.  I wanted to exclude the THEAD from the row count so  I used sectionRowIndex.</p>
<p>Hope that helps someone&#8230; or more likely, helps me when I forget how to do this again next week. <img src='http://www.ghidinelli.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?a=ecCCbxF"><img src="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?i=ecCCbxF" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?a=e108YYF"><img src="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?i=e108YYF" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.ghidinelli.com/2008/03/27/finding-the-row-and-cell-index-of-a-clicked-table-cell-with-jquery/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Minimizing memory damage from bot-created sessions in ColdFusion</title>
		<link>http://www.ghidinelli.com/2008/03/26/minimizing-memory-damage-from-bot-created-sessions-in-coldfusion/</link>
		<comments>http://www.ghidinelli.com/2008/03/26/minimizing-memory-damage-from-bot-created-sessions-in-coldfusion/#comments</comments>
		<pubDate>Thu, 27 Mar 2008 01:52:20 +0000</pubDate>
		<dc:creator>brian</dc:creator>
		
		<category><![CDATA[ColdFusion]]></category>

		<guid isPermaLink="false">http://www.ghidinelli.com/2008/03/26/minimizing-memory-damage-from-bot-created-sessions-in-coldfusion/</guid>
		<description><![CDATA[A really interesting thread on CFGURU today discussing how to minimize the impact of clients that don&#8217;t accept cookies from rapidly creating &#8220;phantom&#8221; sessions that eat up memory.  Because the client doesn&#8217;t accept a cookie, each request will appear to be a new client and ColdFusion will generate a new session along with any [...]]]></description>
			<content:encoded><![CDATA[<p>A really interesting thread on CFGURU today discussing how to minimize the impact of clients that don&#8217;t accept cookies from rapidly creating &#8220;phantom&#8221; sessions that eat up memory.  Because the client doesn&#8217;t accept a cookie, each request will appear to be a new client and ColdFusion will generate a new session along with any objects you create in onSessionStart() or Application.cfc.  Bots from most search engines behave exactly like this and while most of them have some throttling on their request rate, there are many that will canvas your site quickly generating hundreds of empty sessions.  If your session timeout is not very short, this could lead to out of memory errors.</p>
<p>There have been some discussions about this previous on <a href="http://www.bennadel.com/blog/154-ColdFusion-Session-Management-Revisited-User-vs-Spider-III.htm">Ben Nadels blog</a> as well as <a href="http://www.coldfusionmuse.com/index.cfm/2005/11/28/session.bots">Mark Kruger</a>.  Ben&#8217;s solution is reported as effective but it is a moving target in that it tests the User-Agent.  But <a href="http://www.sumoc.com/blog/">Cameron Childress</a> posited testing for the existence of cookies as a check for, well, a client that accepts cookie.  If sessions are enabled in an application, ColdFusion will automatically set CFID and CFTOKEN for every page request which seems to be the perfect test!  Johan Steenkamp put it to the test and reported back with a working code snippet (that I&#8217;ve slightly modified to make simple here):</p>
<pre><code>&lt; !-- this code goes in the Application.cfc in the psuedo-constructor outside of any function declaration ---&gt;
&lt;cfif structKeyExists(cookie, "CFID")&gt;
    &lt;cfset this.sessionTimeout = createTimeSpan(0,0,5,0) /&gt;&lt; !--- 5 minutes ---&gt;
&lt;cfelse&gt;
   &lt;cfset this.sessionTimeout = createTimeSpan(0,0,0,5) /&gt;&lt; !--- 5 sec short session for agents like bots that do not accept cookies ---&gt;
&lt;/cfif&gt;</code></pre>
<p>Brilliant - good on you mate!  Now the bots will be a very short 5 second session that will quickly time out and return memory to ColdFusion while real users will get a 5-minute session.  Obviously you can set those values, particularly the real-user version, to be whatever is appropriate for your application.  Personally I use 1 hour for my session timeouts to afford a good user experience and avoid the &#8220;oops, you were logged out&#8230;&#8221; disappointment.</p>
<p>I can&#8217;t take any credit for the solution - I just thought this was a very clever mod to make your public ColdFusion app more resistant to dodgy clients.  I use J2EE sessions so I modified it to check for jsessionid instead but otherwise it seems to be working properly in my testing with and without cookies enabled.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?a=o9tPEcF"><img src="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?i=o9tPEcF" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?a=RCRLpPF"><img src="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?i=RCRLpPF" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.ghidinelli.com/2008/03/26/minimizing-memory-damage-from-bot-created-sessions-in-coldfusion/feed/</wfw:commentRss>
		</item>
		<item>
		<title>TableSorter 2.0.3++ Universal Sorting plus cool Grouping Widget</title>
		<link>http://www.ghidinelli.com/2008/03/25/tablesorter-203-universal-sorting-plus-cool-grouping-widget/</link>
		<comments>http://www.ghidinelli.com/2008/03/25/tablesorter-203-universal-sorting-plus-cool-grouping-widget/#comments</comments>
		<pubDate>Wed, 26 Mar 2008 01:10:12 +0000</pubDate>
		<dc:creator>brian</dc:creator>
		
		<category><![CDATA[Web/Internet]]></category>

		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://www.ghidinelli.com/2008/03/25/tablesorter-203-universal-sorting-plus-cool-grouping-widget/</guid>
		<description><![CDATA[Christian and I collaborated the other day on a new feature for the excellent jQuery plugin, TableSorter.  I can only take credit for the idea as Christian made the magic happen.  This addition makes it now possible to sort any content, whether it be a form field, inside markup, etc.
The Situation
For simple data [...]]]></description>
			<content:encoded><![CDATA[<p>Christian and I collaborated the other day on a new feature for the excellent jQuery plugin, <a href="http://www.tablesorter.com">TableSorter</a>.  I can only take credit for the idea as Christian made the magic happen.  This addition makes it now possible to sort <em>any</em> content, whether it be a form field, inside markup, etc.</p>
<h2>The Situation</h2>
<p>For simple data or markup, TableSorter can normally just grab the data and sort but there are cases where that won&#8217;t work.  Take for example a table with a form field in it. Tables in forms???  Yes, validator-weenies, I have no problem putting a form into a table for tabular editing.  The problem is that TableSorter doesn&#8217;t know the value of the form element so sorting fails.  Furthermore, in my case, I wanted to sort on the display value of a select box since the value was a 35-character UUID.</p>
<p>My &#8220;tableform&#8221; looks like this:</p>
<div style="overflow: auto;"><img src='http://www.ghidinelli.com/wp-content/uploads/2008/03/tablesorter_form.gif' alt='Shot of tablesorter with a form in it' /></div>
<p>I wanted to be able to sort on the select boxes, make changes, and sort again.</p>
<h2>The Change</h2>
<p>I am a relatively clueless Javascript hacker so I asked Christian if he thought a custom extractor or parser was the best way to go about getting at the value and he suggested parsers, because they&#8217;re more powerful.  Then I asked how you get a reference to the content of the cell and he said, &#8220;Oh, hold on&#8230;&#8221;  A few minutes later, he had a new revision checked into subversion that changed the API from:</p>
<pre><code>	is: function(s) {
		// returning false prevents auto-detection; we manually assign this
		return false;
	}

	format: function(s) {
		s += ', ' + new Date().getYear();
		return $.tablesorter.formatFloat((new Date(s)).getTime());
	}
});</code></pre>
<p>where the is() and format() functions just return the HTML content of the node to accepting multiple arguments that include a reference to the table and the table cell like so:</p>
<pre><code>	is: function(s, table, node) {
		// returning false prevents auto-detection; we manually assign this
		return false;
	}

	format: function(s, table, node) {
		s += ', ' + new Date().getYear();
		return $.tablesorter.formatFloat((new Date(s)).getTime());
	}</code></pre>
<p>With this API change, I could now write a parser to pull out the display value from the select box with just a little jQuery sugar:</p>
<pre><code>$.tablesorter.addParser({
	id: 'selectBox',
	is: function(s, table, node) {
		if (!node.childNodes[0].tagName) return false;
		return (node.childNodes[0].tagName == 'SELECT') ? true : false;
	},
	format: function(s, table, node) {
		// use new node argument to get the display value of the select box
		return $(node).find("option:selected").text();
	},
	type: 'text'
});

$("#tblAssignments").tablesorter({
	,headers: { 3: { sorter: 'selectBox' }
			,4: { sorter: 'selectBox' }
	}
}); </code></pre>
<p>As you can imagine, with a jQuery object available, there isn&#8217;t anything you can&#8217;t sort in a table.  Very cool!</p>
<h2>Update</h2>
<p>For efficiency, TableSorter caches the formatted data to make sorting quick.  But when value of a form field changes, TableSorter needs to be told about it with the update() function:</p>
<pre><code>$("table#tblAssignments select").change(
	function()
	{
		$(this).parents("table").trigger("update");
	}
);</code></pre>
<p>Now every time you change a select box, the data is refreshed.  In a smallish table, this only takes 10-30ms.  I haven&#8217;t tested yet on a large dataset but it&#8217;s sufficiently fast.  If performance becomes a problem, we could find a way to update a single item in the cache.</p>
<h2>Grouping/Collapsing</h2>
<p>I also wanted to be able to add grouping and running tallies for groups using TableSorter and came across a <a href="http://code.google.com/p/grouping/">groups widget</a> on Google code.  The comments and variable names are all in some Slavic language meaning I can&#8217;t make head nor tail of it, but the good news is that this plugin does work!  I&#8217;ve updated it a bit to always show a running tally and so forth so contact me if you&#8217;d like my more-hacky version.  The project description <a href="http://code.google.com/p/grouping/wiki/Description">is pretty clear</a>.</p>
<div style="overflow: auto"><img src='http://www.ghidinelli.com/wp-content/uploads/2008/03/tablesorter_grouped.gif' alt='Shot of tablesorter with grouping plugin collapsed' class='aligncenter' /></div>
<p>This screenshot shows several of the groups collapsed into a thin bar with a tally of how many items are in each group.   Thanks goes out to Christian for the new feature and for revving the version number against his will! <img src='http://www.ghidinelli.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?a=FM1cc1F"><img src="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?i=FM1cc1F" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?a=m5ymaHF"><img src="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?i=m5ymaHF" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.ghidinelli.com/2008/03/25/tablesorter-203-universal-sorting-plus-cool-grouping-widget/feed/</wfw:commentRss>
		</item>
		<item>
		<title>The Ultimate ColdFusion Email Validation Regular Expression</title>
		<link>http://www.ghidinelli.com/2008/03/15/the-ultimate-coldfusion-email-validation-regular-expression/</link>
		<comments>http://www.ghidinelli.com/2008/03/15/the-ultimate-coldfusion-email-validation-regular-expression/#comments</comments>
		<pubDate>Sat, 15 Mar 2008 21:23:30 +0000</pubDate>
		<dc:creator>brian</dc:creator>
		
		<category><![CDATA[ColdFusion]]></category>

		<category><![CDATA[Web/Internet]]></category>

		<guid isPermaLink="false">http://www.ghidinelli.com/2008/03/15/the-ultimate-coldfusion-email-validation-regular-expression/</guid>
		<description><![CDATA[I love crazy long titles that make highly qualified claims.  So as the title says, this is, in my humble opinion, the best available regular expression for ColdFusion developers who validate email addresses of everyday English-speaking users.  Here is what I used to use, from cflib.org.  This one is good because the [...]]]></description>
			<content:encoded><![CDATA[<p>I love crazy long titles that make highly qualified claims.  So as the title says, this is, in my humble opinion, the best available regular expression for ColdFusion developers who validate email addresses of everyday English-speaking users.  Here is what I used to use, from <a href="http://www.cflib.org/udf.cfm?ID=216">cflib.org</a>.  This one is good because the function also wraps tests on the length of the local and domain parts of the email:</p>
<pre><code>^['_a-z0-9-]+(\.['_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*\.(([a-z]{2,3})|(aero|coop|info|museum|name|jobs|travel|mobi))$</code></pre>
<p><small><em>Note that this assumes case-insensitive matching</em></small></p>
<p>However, it&#8217;s missing a few characters that I know to be OK like a + in the username part of the address.  Then I thought I would give ColdFusion 7&#8217;s isValid() a try:</p>
<pre><code>isValid("email", someEmailAddress);</code></pre>
<p>It&#8217;s certainly easier to use!  But I am cynical and went sniffing <a href="http://www.bennadel.com/blog/265-ColdFusion-Email-Validation-IsValid-And-CFMail-Errors.htm">for the details</a> and found its regexp to be a little loose.  In particular, it allows any TLD extension at the end from 2-7 characters:</p>
<pre><code>^[a-zA-Z0-9-'\+~]+(\.[a-zA-Z0-9-'\+~]+)*@([a-zA-Z_0-9-]+\.)+[a-zA-Z]{2,7}$</code></pre>
<p>This is one of the most common places to see typos in real-world addresses.  &#8220;.co&#8221; or &#8220;.como&#8221; are very common errors from users who are oh-too-used to typing in their email address 100 times a day.  However, I noticed that the Sun regexp allowed a few more (valid) characters than the cflib.  So I mashed them together and added support for all <a href="http://en.wikipedia.org/wiki/List_of_Internet_top-level_domains">current TLDs</a> and created the ultimate regexp for ColdFusion developers (as of March 15, 2008):</p>
<pre><code>^['_a-zA-Z0-9-\+~]+(\.['_a-zA-Z0-9-\+~]+)*@([a-zA-Z_0-9-]+\.)+(([a-zA-Z]{2})|(aero|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel))$</code></pre>
<p>Ok, maybe it isn&#8217;t <strong>the</strong> ultimate regexp because there are things it does not allow or test.  Such as an IP address in place of a domain. Or a maximum of 64 characters in the local part of the address.  Or full support for <a href="http://haacked.com/archive/2007/08/21/i-knew-how-to-validate-an-email-address-until-i.aspx">quoted literals</a>.  But we&#8217;re talking about addresses that common web applications must validate.</p>
<h2>Truly Ultimate RegExp, without a Qualifier</h2>
<p>If you want the true ultimate, you&#8217;ll need one created by Jeffery Friedl from the <a href="http://search.cpan.org/src/RJBS/Email-Valid-0.179/lib/Email/Valid.pm">Perl::Email Valid.pm</a>:</p>
<pre><code>[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\
xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xf
f\n\015()]*)*\)[\040\t]*)*(?:(?:[^(\040)&lt;&gt;@,;:".\\\[\]\000-\037\x80-\x
ff]+(?![^(\040)&lt;&gt;@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n\015
"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\
xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80
-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*
)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\
\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\
x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)&lt;&gt;@,;:".\\\[\]\000-\037\x8
0-\xff]+(?![^(\040)&lt;&gt;@,;:".\\\[\]\000-\037\x80-\xff])|"[^\\\x80-\xff\n
\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[\040\t]*(?:\([^\\\x
80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^
\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040
\t]*)*)*@[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([
^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\
\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)&lt;&gt;@,;:".\\\[\]\000-\037\
x80-\xff]+(?![^(\040)&lt;&gt;@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-
\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()
]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\
x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\04
0\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\
n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\
015()]*)*\)[\040\t]*)*(?:[^(\040)&lt;&gt;@,;:".\\\[\]\000-\037\x80-\xff]+(?!
[^(\040)&lt;&gt;@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\
]]|\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\
x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\01
5()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*|(?:[^(\040)&lt;&gt;@,;:".
\\\[\]\000-\037\x80-\xff]+(?![^(\040)&lt;&gt;@,;:".\\\[\]\000-\037\x80-\xff]
)|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[^
()&lt;&gt;@,;:".\\\[\]\x80-\xff\000-\010\012-\037]*(?:(?:\([^\\\x80-\xff\n\0
15()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][
^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)|"[^\\\x80-\xff\
n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015"]*)*")[^()&lt;&gt;@,;:".\\\[\]\
x80-\xff\000-\010\012-\037]*)*&lt;[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?
:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-
\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:@[\040\t]*
(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015
()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()
]*)*\)[\040\t]*)*(?:[^(\040)&lt;&gt;@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\0
40)&lt;&gt;@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\
[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\
xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*
)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80
-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x
80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t
]*)*(?:[^(\040)&lt;&gt;@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)&lt;&gt;@,;:".\\
\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])
*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x
80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80
-\xff\n\015()]*)*\)[\040\t]*)*)*(?:,[\040\t]*(?:\([^\\\x80-\xff\n\015(
)]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\
\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*@[\040\t
]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\0
15()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015
()]*)*\)[\040\t]*)*(?:[^(\040)&lt;&gt;@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(
\040)&lt;&gt;@,;:".\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|
\\[^\x80-\xff])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80
-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()
]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x
80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^
\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040
\t]*)*(?:[^(\040)&lt;&gt;@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)&lt;&gt;@,;:".
\\\[\]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff
])*\])[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\
\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x
80-\xff\n\015()]*)*\)[\040\t]*)*)*)*:[\040\t]*(?:\([^\\\x80-\xff\n\015
()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\
\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)?(?:[^
(\040)&lt;&gt;@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)&lt;&gt;@,;:".\\\[\]\000-
\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\xff\
n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|
\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))
[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff
\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\x
ff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(
?:[^(\040)&lt;&gt;@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)&lt;&gt;@,;:".\\\[\]\
000-\037\x80-\xff])|"[^\\\x80-\xff\n\015"]*(?:\\[^\x80-\xff][^\\\x80-\
xff\n\015"]*)*")[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\x
ff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)
*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*)*@[\040\t]*(?:\([^\\\x80-\x
ff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-
\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)
*(?:[^(\040)&lt;&gt;@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)&lt;&gt;@,;:".\\\[\
]\000-\037\x80-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\]
)[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-
\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\x
ff\n\015()]*)*\)[\040\t]*)*(?:\.[\040\t]*(?:\([^\\\x80-\xff\n\015()]*(
?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]*(?:\\[^\x80-\xff][^\\\x80
-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)*\)[\040\t]*)*(?:[^(\040)&lt;
&gt;@,;:".\\\[\]\000-\037\x80-\xff]+(?![^(\040)&lt;&gt;@,;:".\\\[\]\000-\037\x8
0-\xff])|\[(?:[^\\\x80-\xff\n\015\[\]]|\\[^\x80-\xff])*\])[\040\t]*(?:
\([^\\\x80-\xff\n\015()]*(?:(?:\\[^\x80-\xff]|\([^\\\x80-\xff\n\015()]
*(?:\\[^\x80-\xff][^\\\x80-\xff\n\015()]*)*\))[^\\\x80-\xff\n\015()]*)
*\)[\040\t]*)*)*&gt;)</code></pre>
<p><em>Note, I doubt this works with CF</em>  Cal from Flickr also has <a href="http://www.iamcal.com/publish/articles/php/parsing_email/">a pretty long one</a> (and therefore, certainly accurate!) for PHP based on the RFC.</p>
<h2>Ultimate<sup>2</sup></h2>
<p>Of course, the most ultimate email validation is just sending the user an email and making them click a link.  It confirms the email address was valid (after all, they received it!),  they can actually receive email from you, that it bypasses real-time blackhole lists, spam filters and junk folders and reaches their inbox.  It&#8217;s actually really easy.  And doesn&#8217;t have any edge cases you can&#8217;t catch with a single regexp.</p>
<p>Personally, that&#8217;s where I&#8217;m headed with my application.  In the mean time, I&#8217;ll settle for second most ultimate status. <img src='http://www.ghidinelli.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?a=XivVyiF"><img src="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?i=XivVyiF" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?a=vBTMosF"><img src="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?i=vBTMosF" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.ghidinelli.com/2008/03/15/the-ultimate-coldfusion-email-validation-regular-expression/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Quick rounded corners in Photoshop</title>
		<link>http://www.ghidinelli.com/2008/03/10/quick-rounded-corners-in-photoshop/</link>
		<comments>http://www.ghidinelli.com/2008/03/10/quick-rounded-corners-in-photoshop/#comments</comments>
		<pubDate>Mon, 10 Mar 2008 19:49:55 +0000</pubDate>
		<dc:creator>brian</dc:creator>
		
		<category><![CDATA[Web/Internet]]></category>

		<guid isPermaLink="false">http://www.ghidinelli.com/2008/03/10/quick-rounded-corners-in-photoshop/</guid>
		<description><![CDATA[While I&#8217;m not a designer, I do need to pop open Photoshop on a regular basis and save off graphics or make small changes.  I often need to create a rounded corner rectangle when processing customer logos for theming and I never remember how to do it quickly.  This tutorial shows the best [...]]]></description>
			<content:encoded><![CDATA[<p>While I&#8217;m not a designer, I do need to pop open Photoshop on a regular basis and save off graphics or make small changes.  I often need to create a rounded corner rectangle when processing <a href="http://patroon.motorsportreg.com/">customer logos for theming</a> and I never remember how to do it quickly.  <a href="http://matthom.com/archive/2004/09/10/fast-rounded-corners-in-photoshop">This tutorial</a> shows the best method I&#8217;ve seen yet and also taught me a neat feature in Photoshop: Edit &gt; Copy Merged.  It&#8217;s like flattening the image and then copying the current selection which is a major time saver and much safer than flattening, copying and undoing the flatten.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?a=CsVkAyF"><img src="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?i=CsVkAyF" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?a=Kw4AKRF"><img src="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?i=Kw4AKRF" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.ghidinelli.com/2008/03/10/quick-rounded-corners-in-photoshop/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Cloning Transfer Decorators</title>
		<link>http://www.ghidinelli.com/2008/03/05/cloning-transfer-decorators/</link>
		<comments>http://www.ghidinelli.com/2008/03/05/cloning-transfer-decorators/#comments</comments>
		<pubDate>Wed, 05 Mar 2008 22:58:46 +0000</pubDate>
		<dc:creator>brian</dc:creator>
		
		<category><![CDATA[ColdFusion]]></category>

		<category><![CDATA[Web/Internet]]></category>

		<guid isPermaLink="false">http://www.ghidinelli.com/2008/03/05/cloning-transfer-decorators/</guid>
		<description><![CDATA[I have been tempted, and even used successfully, the Transfer.clone() method to duplicate an existing Transfer object.  But Mr. Corfield told me today that I was insane for relying on such a thing which is apparently well documented.  So I began looking for another way to easily duplicate a transfer object. 
Why I [...]]]></description>
			<content:encoded><![CDATA[<p>I have been tempted, and even used successfully, the <a href="http://www.transfer-orm.com/transfer/documentation/clone.html">Transfer.clone() method</a> to duplicate an existing Transfer object.  But <a href="http://corfield.org">Mr. Corfield</a> told me today that I was insane for relying on such a thing which is apparently <a href="http://groups.google.com/group/transfer-dev">well documented</a>.  So I began looking for another way to easily duplicate a transfer object. </p>
<h2>Why I want to clone()</h2>
<p>To take over the world, of course.  Seriously, I have functionality in my application that allows you to clone an existing object changing just a few properties of it as a way to jumpstart data management.  The easy way is to get the existing object and then do get/set on every property.  But that kind of sucks.  So I went about looking to write a generic object cloner.  </p>
<h2>First Attempt</h2>
<p>Here was my first attempt, beginning with my Transfer definition:</p>
<pre><code>&lt;object name="event" table="events" decorator="event"&gt;
	&lt;id name="EventID" type="UUID" generate="true" /&gt;
	&lt;manytoone name="EventType"&gt;
		&lt;link column="EventTypeID" to="event.eventtype" /&gt;
	&lt;/manytoone&gt;
	&lt;manytoone name="Track"&gt;
		&lt;link column="TrackID" to="track.track" /&gt;
	&lt;/manytoone&gt;
	&lt;manytoone name="Club"&gt;
		&lt;link column="ClubID" to="club.club" /&gt;
	&lt;/manytoone&gt;
	&lt;property name="RegistrarID" type="UUID" nullable="true" /&gt;
	&lt;property name="NotifyOnEventReg" type="boolean" /&gt;
&lt;/object&gt;</code></pre>
<p>And here is the first pass of my Transfer decorator:</p>
<pre><code>&lt;cfcomponent displayname="event" output="false" extends="transfer.com.TransferDecorator"&gt;
	&lt;cfproperty name="EventID" type="string" default="" /&gt;
	&lt;cfproperty name="Club" type="string" default="" /&gt;
	&lt;cfproperty name="Track" type="string" default="" /&gt;
	&lt;cfproperty name="EventType" type="string" default="" /&gt;
	&lt;cfproperty name="RegistrarID" type="string" default="" /&gt;
	&lt;cfproperty name="NotifyOnEventReg" type="string" default="" /&gt;

	...
&lt;/cfcomponent&gt;</code></pre>
<p>And the clone routine in my model:</p>
<pre><code>&lt;cffunction name="clone" access="public" output="false" returntype="any"&gt;
	&lt;cfargument name="object" type="any" required="true" /&gt;

	&lt; !--- get properties as defined in the decorator that we can use to get/set ---&gt;
	&lt;cfset var props = getMetaData(arguments.object).properties /&gt;
	&lt; !--- get a new version of whatever we've passed in ---&gt;
	&lt;cfset var obj = variables.transfer.new(arguments.object.getClassName()) /&gt;

	&lt;cfset var prop = "" /&gt;
	&lt;cfset var value = "" /&gt;
	&lt;cfset var len = arrayLen(props) /&gt;

	&lt; !--- copy values from prior obj ---&gt;
	&lt;cfloop from="1" to="#len#" index="ii"&gt;
		&lt;cfset prop = props[ii] /&gt;
		&lt;cfinvoke component="#arguments.object#" method="get#prop.name#" returnvariable="value" /&gt;
		&lt;cfinvoke component="#obj#" method="set#prop.name#"&gt;
			&lt;cfinvokeargument name="#prop.name#" value="#value#" /&gt;
		&lt;/cfinvoke&gt;
	&lt;/cfloop&gt;

	&lt;cfreturn obj /&gt;
&lt;/cffunction&gt;</code></pre>
<h2>So Close, but So Far&#8230;</h2>
<p>It seems to work at first, until you realize that any relationships (many2one, one2many, many2many) don&#8217;t work!  While you normally do something like setRelationship(object), the CFINVOKEARGUMENT syntax passes a named parameter and Transfer expects an argument named &#8220;transfer&#8221;.  So I went back to meddling with my metadata and came up with the following convention:</p>
<pre><code>&lt;cfcomponent displayname="event" output="false" extends="transfer.com.TransferDecorator"&gt;
	&lt;cfproperty name="EventID" type="string" default="" /&gt;
	&lt;cfproperty name="Club" type="any" default="" /&gt;
	&lt;cfproperty name="Track" type="any" default="" /&gt;
	&lt;cfproperty name="EventType" type="any" default="" /&gt;
	&lt;cfproperty name="RegistrarID" type="string" default="" /&gt;
	&lt;cfproperty name="NotifyOnEventReg" type="string" default="" /&gt;

	...
&lt;/cfcomponent&gt;</code></pre>
<p>And the corresponding generic cloner:</p>
<pre><code>&lt;cffunction name="clone" access="public" output="false" returntype="any" hint="takes any Transfer object and clones it"&gt;
	&lt;cfargument name="object" type="any" required="true" /&gt;

	&lt; !--- get properties as defined in the decorator that we can use to get/set ---&gt;
	&lt;cfset var props = getMetaData(arguments.object).properties /&gt;
	&lt; !--- get a new version of whatever we've passed in ---&gt;
	&lt;cfset var obj = variables.transfer.new(arguments.object.getClassName()) /&gt;

	&lt;cfset var prop = "" /&gt;
	&lt;cfset var value = "" /&gt;
	&lt;cfset var len = arrayLen(props) /&gt;

	&lt; !--- copy values from prior obj ---&gt;
	&lt;cfloop from="1" to="#len#" index="ii"&gt;
		&lt;cfset prop = props[ii] /&gt;
		&lt;cfset obj["set" &amp; prop.name]&gt;
		&lt;cfinvoke component="#arguments.object#" method="get#prop.name#" returnvariable="value" /&gt;
		&lt;cfinvoke component="#obj#" method="set#prop.name#"&gt;
			&lt;cfif prop.type EQ "any"&gt;
				&lt;cfinvokeargument name="transfer" value="#value#" /&gt;
			&lt;cfelse&gt;
				&lt;cfinvokeargument name="#prop.name#" value="#value#" /&gt;
			&lt;/cfif&gt;
		&lt;/cfinvoke&gt;
	&lt;/cfloop&gt;

	&lt;cfreturn obj /&gt;
&lt;/cffunction&gt;</code></pre>
<p>Now we use the proper variable name of &#8220;transfer&#8221; for any CFPROPERTY with a type of &#8220;any&#8221;.  By convention, my decorators will use &#8220;any&#8221; for my Transfer relationships and &#8220;string&#8221; for everything else.  This seems to be working so far but I would appreciate input!</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?a=6gE3IoF"><img src="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?i=6gE3IoF" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?a=aqaJIbF"><img src="http://feeds.feedburner.com/~f/OrangeIsMyFavoriteColorTech?i=aqaJIbF" border="0"></img></a>
</div>]]></content:encoded>
			<wfw:commentRss>http://www.ghidinelli.com/2008/03/05/cloning-transfer-decorators/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
