<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss'><id>tag:blogger.com,1999:blog-18636729</id><updated>2010-01-14T10:18:55.734-08:00</updated><title type='text'>Nick Burwell Designs - Blog</title><subtitle type='html'>My thoughts on Ruby on Rails, JavaScript, photography, web design, user interfaces and all other web development topics</subtitle><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default?start-index=26&amp;max-results=25'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.nickburwell.com/blog/atom.xml'/><author><name>Nick</name><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>48</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-18636729.post-5070288322579920018</id><published>2009-10-02T11:03:00.000-07:00</published><updated>2009-11-21T19:31:40.955-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='tech'/><title type='text'>Fireworks CS4 automated scripting with Javascript</title><content type='html'>Finding any information on command line scripting for Fireworks CS4 was difficult. Below is an example script to get you started, along with some hard-to-find resources below. Feel free to add other examples / links to the comments section, so that hopefully this page can become a helpful resource to others.&lt;br /&gt;&lt;br /&gt;This script goes across all layers in a Fireworks animated GIF source file (PNG format). It replaces all text layers of a specific name with specific text. I used Ruby to dynamically generate the "process_image( ... )" calls, as a way to iterate through many source files and save animated GIF's with variable text in them.&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;try&lt;br /&gt;{&lt;br /&gt;    process_image( "hello world" );&lt;br /&gt;    process_image( "konichi wa sekai")&lt;br /&gt;}&lt;br /&gt;catch(e)&lt;br /&gt;{&lt;br /&gt;    alert(e);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// this will insert text into every text layer (of every state, if an animated GIF) called "dynamic_text"&lt;br /&gt;function process_image( text )&lt;br /&gt;{&lt;br /&gt;    var dom = fw.openDocument( "foo.png" );&lt;br /&gt;    &lt;br /&gt;    if ( dom == null )&lt;br /&gt;    {&lt;br /&gt;        alert( "Could not open fireworks file: foo.png" );&lt;br /&gt;        return;&lt;br /&gt;    }&lt;br /&gt;     &lt;br /&gt; if ( !iterate_and_replace_layers( dom, text ) )&lt;br /&gt; {&lt;br /&gt;     alert( "Did not find a layer to replace in " + source_file + ". Be sure you have the updated source files." );&lt;br /&gt;     return;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt;    var opts = new ExportOptions();&lt;br /&gt;    opts.exportFormat = "GIF animation";&lt;br /&gt;    &lt;br /&gt;    var output = save_directory + source_file_name + '_' + phone_number + '_' + creative_id + '.gif';&lt;br /&gt;    var save_result = fw.exportDocumentAs( dom, output, opts );&lt;br /&gt;&lt;br /&gt;    fw.closeDocument( dom, false );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function iterate_and_replace_layers( dom, text )&lt;br /&gt;{&lt;br /&gt;    var layer_replaced = false;&lt;br /&gt;    &lt;br /&gt;    for(var i = 0 ; i &lt; dom.frames.length ; i++)&lt;br /&gt; {&lt;br /&gt;  for(var j = 0 ; j &lt; dom.frames[i].topLayers.length - 1 ; j++)&lt;br /&gt;  {&lt;br /&gt;   var topLayer = dom.frames[i].topLayers[j];&lt;br /&gt;   var elems = topLayer.elemsandsublayers;   &lt;br /&gt;   for(var k = 0; k &lt; elems.length; k++)&lt;br /&gt;   {    &lt;br /&gt;    // add to layer&lt;br /&gt;    if ( elems[k].name == "dynamic_text" )&lt;br /&gt;    {&lt;br /&gt;        set_text( elems[k], number );&lt;br /&gt;        layer_replaced = true;&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; return layer_replaced;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;function set_text( element, number )&lt;br /&gt;{&lt;br /&gt;    var runs = element.textRuns;&lt;br /&gt;    var runsArray = new Array();&lt;br /&gt;    runsArray[0] = { changedAttrs: {}, characters: number };&lt;br /&gt;    runs.textRuns = runsArray;&lt;br /&gt;    element.textRuns = runs;    &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;Save the file with a .jsf extension, and to call it from a Ruby command script, simply do:&lt;br /&gt;&lt;pre&gt;system( "open script_fw.jsf" )&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Article with some information, and a few helpful links to resources:&lt;br /&gt;&lt;a href="http://www.adobe.com/devnet/fireworks/articles/demo_current_document_command.html"&gt;http://www.adobe.com/devnet/fireworks/articles/demo_current_document_command.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Link to PDF API documentation:&lt;br /&gt;&lt;a href="http://help.adobe.com/en_US/Fireworks/9.0_Extending/fireworks_cs3_extending.pdf"&gt;http://help.adobe.com/en_US/Fireworks/9.0_Extending/fireworks_cs3_extending.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Fireworks Help&lt;br /&gt;&lt;a href="http://help.adobe.com/en_US/Fireworks/10.0_Using"&gt;http://help.adobe.com/en_US/Fireworks/10.0_Using&lt;/a&gt; - (Automating Tasks)&lt;br /&gt;&lt;br /&gt;Javscript source of existing Fireworks plugins found here (on a Mac machine using CS4). This is a good way to learn the scripting language by viewing plugins' source code:&lt;br /&gt;&lt;blockquote&gt;~/Applications/Adobe Fireworks CS4/Configuration/commands/&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-5070288322579920018?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/5070288322579920018/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2009/10/fireworks-cs4-automated-scripting-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/5070288322579920018'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/5070288322579920018'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2009/10/fireworks-cs4-automated-scripting-with.html' title='Fireworks CS4 automated scripting with Javascript'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-6801041064956671921</id><published>2009-09-16T23:12:00.002-07:00</published><updated>2009-09-27T20:02:19.046-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby on rails'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><title type='text'>Call controller action from script console in rails app</title><content type='html'>An easy way to call an action in script/console of your Ruby on Rails application is to simply call "app.get" and pass parameters similar to a functional test.  You then can get access to the response object with "app.response".&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&gt; app.get '/posts/1'&lt;br /&gt;&gt; r = app.response&lt;br /&gt;&gt; r.body&lt;br /&gt;&gt; r.cookies&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-6801041064956671921?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/6801041064956671921/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2009/09/call-controller-action-from-script.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/6801041064956671921'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/6801041064956671921'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2009/09/call-controller-action-from-script.html' title='Call controller action from script console in rails app'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-1345116274200586354</id><published>2009-08-27T07:00:00.000-07:00</published><updated>2009-08-27T07:00:02.094-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tech'/><title type='text'>Insert new line in Excel formula - Mac and Windows</title><content type='html'>I ran across the need to insert a line break into a formula in Excel 2008 (I am pretty sure this works with most older versions too).  My problem was simple:&lt;br /&gt;&lt;br /&gt;What I had:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  Column A  Column B&lt;br /&gt;1  John       12345&lt;br /&gt;2  Fred       67890&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What I wanted was a newline within a cell that combined other cells:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  Column C&lt;br /&gt;1   John&lt;br /&gt;    12345&lt;br /&gt;2   Fred&lt;br /&gt;    67890&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;On Windows use the following:&lt;br /&gt;&lt;code&gt;=A1 &amp; CHAR(10) &amp; B1&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;On Mac use the following:&lt;br /&gt;&lt;code&gt;=A1 &amp; CHAR(13) &amp; B1&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The line feed / carriage return character is different, so at least for viewing and printing, the above char codes should be used depending on your operating system.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-1345116274200586354?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/1345116274200586354/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2009/08/insert-new-line-in-excel-formula-mac.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/1345116274200586354'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/1345116274200586354'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2009/08/insert-new-line-in-excel-formula-mac.html' title='Insert new line in Excel formula - Mac and Windows'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-4340489166509495847</id><published>2009-07-09T07:00:00.000-07:00</published><updated>2009-07-09T07:00:04.086-07:00</updated><title type='text'>jQuery select of a name field that has square brackets</title><content type='html'>Suppose you have the following input field:&lt;br /&gt;&lt;code&gt;&amp;lt;input type="text" name="users[][name]" value="John" /&amp;gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;You will recognize this as rails notation for being able to send a collection of user objects to the server in a post. (Other web frameworks use it as well).&lt;br /&gt;&lt;br /&gt;If you want to find that input field in jQuery, do:&lt;br /&gt;&lt;code&gt;jQuery( '[name="users[][name]"]' );&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The trick is to put the string you are looking for in double quotes, which means you then have to wrap the entire jQuery parameter in single quotes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-4340489166509495847?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/4340489166509495847/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2009/07/jquery-select-of-name-field-that-has.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/4340489166509495847'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/4340489166509495847'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2009/07/jquery-select-of-name-field-that-has.html' title='jQuery select of a name field that has square brackets'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-6074099953890611263</id><published>2009-05-30T07:00:00.000-07:00</published><updated>2009-05-30T07:00:00.577-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><title type='text'>Check if cookies are enabled on client side</title><content type='html'>Using just Javascript (with the help of jQuery and the jQuery cookie plugin), this bit of code will do the trick on checking whether the user's browser accepts cookies or not. This is helpful for posting a warning message on a login screen or when adding things to a shopping cart, etc.&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;script&amp;gt;&lt;br /&gt;  jQuery(document).ready(function()&lt;br /&gt;  {&lt;br /&gt;    var TEST_COOKIE = 'test_cookie';&lt;br /&gt;    jQuery.cookie( TEST_COOKIE, true );&lt;br /&gt;    if ( jQuery.cookie ( TEST_COOKIE ) )&lt;br /&gt;    {&lt;br /&gt;      jQuery.cookie( TEST_COOKIE, null );&lt;br /&gt;      alert( 'Good news, cookies are enabled.' );&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;      alert( 'Cookies are not enabled. Please enable and try again.' );&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-6074099953890611263?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/6074099953890611263/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2009/05/check-if-cookies-are-enabled-on-client.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/6074099953890611263'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/6074099953890611263'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2009/05/check-if-cookies-are-enabled-on-client.html' title='Check if cookies are enabled on client side'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-5418442462651422482</id><published>2009-05-08T14:40:00.000-07:00</published><updated>2009-05-08T14:47:34.863-07:00</updated><title type='text'>More fires in Santa Barbara</title><content type='html'>Another fire rages in Santa Barbara, CA - Jesusita Fire - the 3rd major one in 10 months. The last fire (Tea Fire, November 2008) destroyed over 200 homes.  This one has stretched further than the last fire, and so far taken about 75 homes with that number expected to rise.&lt;br /&gt;&lt;br /&gt;As a resident of Santa Barbara, it is hard to see family, friends and associates evacuated, some losing their homes. My thoughts and prayers go out to all the families that are affected, and to the fire personnel that are working around the clock battling the blaze.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-5418442462651422482?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/5418442462651422482/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2009/05/more-fires-in-santa-barbara.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/5418442462651422482'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/5418442462651422482'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2009/05/more-fires-in-santa-barbara.html' title='More fires in Santa Barbara'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-2491905608101704191</id><published>2009-04-07T12:48:00.000-07:00</published><updated>2009-04-07T13:29:10.815-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><title type='text'>Add javascript tabs to browser history (for "back" navigation)</title><content type='html'>As fancy AJAX websites become more popular, the "back" button is getting less useful and less functional. Often times you perform an action that perhaps repaints most of the browser window (think, viewing an email in Gmail), and you want to go back to your preview view (list of email in your inbox). In the old days, you would hit back and go to the previous page. But in Gmail and other AJAX-ey sites, you didn't go to a "new page" but instead had javascript repaint the divs. So hitting back would take you to the login screen or some other site. Fortunately Gmail has solved this by inserting various actions into your browser history, so that you can actually use the back and forward buttons to navigate through Gmail. &lt;br /&gt;&lt;br /&gt;jQuery has a &lt;a href="http://www.mikage.to/jquery/jquery_history.html"&gt;good history plugin&lt;/a&gt; that lets you add actions to the browser history, and on every page load you can register for a callback that gives you a value based on where you are in the history. It is up to you to write your JavaScript in a generic way that can save and respond to history save points. But jQuery does the cross-browser, behind the scenes heavy-lifting for you.&lt;br /&gt;&lt;br /&gt;My use of the history plugin was for a tabbed navigation where the tabs were all done using JavaScript to show/hide divs. It became a problem when a user would load the page, click a different tab, and while viewing that 2nd tab, click a link to another page. Then the user would click back and expect to be on that 2nd tab again, but instead would be shown the first tab.&lt;br /&gt;&lt;br /&gt;Here is some sample code that I used to easily solve this issue and add back/forward support for my AJAX tabs:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;var default_tab = 'home'; // this can be set by query string, url, etc&lt;br /&gt;&lt;br /&gt;function on_page_loaded( history_key )&lt;br /&gt;{&lt;br /&gt;  if( history_key )&lt;br /&gt;  {&lt;br /&gt;   // this gets run for every back/forward, if something was stored in&lt;br /&gt;   //  the browser history's location.hash&lt;br /&gt;   toggle_tab( history_key );&lt;br /&gt;  }&lt;br /&gt;  else&lt;br /&gt;  {&lt;br /&gt;    // this gets run for every page load where back/forward is not pressed&lt;br /&gt;    toggle_tab( default_tab );&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;jq(document).ready( function() {&lt;br /&gt;  // Initialize history plugin, and give it the function name &lt;br /&gt;  //  of your callback above&lt;br /&gt;  jq.historyInit( on_page_loaded );&lt;br /&gt;  &lt;br /&gt;  jq('a.tab_with_history').click( function()&lt;br /&gt;     {&lt;br /&gt;        // actually toggle the tab in UI&lt;br /&gt;        var tab_name = toggle_to_selected_tab( this );&lt;br /&gt;        // save to the history, the tab name -- important step!&lt;br /&gt;        jq.historyLoad( tab_name );&lt;br /&gt;        return false;&lt;br /&gt;     });&lt;br /&gt;});&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I will leave "toggle_tab" and "toggle_to_selected_tab" implementation to you as an exercise. I created a custom tab class with initialization methods that are generated from Ruby hashes and then toggling tabs is just a matter of finding the tab by name and flipping some css display values of the corresponding divs that each tab owns&lt;br /&gt;&lt;br /&gt;HTML:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;ul&amp;gt;&lt;br /&gt; &amp;lt;li&amp;gt;&amp;lt;a id="tab_1" class="tab_with_history" href="#1"&amp;gt;Tab 1&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt; &amp;lt;li&amp;gt;&amp;lt;a id="tab_2" class="tab_with_history" href="#2"&amp;gt;Tab 2&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;&amp;lt;/ul&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;div id="content_1" style="display: none"&amp;gt;contents of tab 1&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;div id="content_2" style="display: none"&amp;gt;contents of tab 2&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-2491905608101704191?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/2491905608101704191/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2009/04/add-javascript-tabs-to-browser-history.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/2491905608101704191'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/2491905608101704191'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2009/04/add-javascript-tabs-to-browser-history.html' title='Add javascript tabs to browser history (for &quot;back&quot; navigation)'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-4162991598616769429</id><published>2009-04-06T07:00:00.000-07:00</published><updated>2009-04-06T07:00:00.723-07:00</updated><title type='text'>Fedex isn't perfect...</title><content type='html'>I recently ordered some important documents for our upcoming trip to Japan. The order was shipped via 2-day Fedex. Well, 3 business days later it didn't arrive. And that was after I had checked the tracking status online and was told it was arriving around 4:30pm that day.&lt;br /&gt;&lt;br /&gt;Turns out my package, which was in LA (just 130 miles south of Santa Barbara), got to spend a night in Oakland before getting shipped back down south to Goleta (10 miles north of SB), and eventually on a truck from there to Santa Barbara.  Oh well.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://i30.photobucket.com/albums/c337/japanick/blog/fedex_is_not_perfect.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 766px; height: 744px;" src="http://i30.photobucket.com/albums/c337/japanick/blog/fedex_is_not_perfect.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-4162991598616769429?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/4162991598616769429/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2009/04/fedex-isnt-perfect.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/4162991598616769429'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/4162991598616769429'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2009/04/fedex-isnt-perfect.html' title='Fedex isn&apos;t perfect...'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-3800117575098782505</id><published>2009-03-31T07:00:00.000-07:00</published><updated>2009-03-31T07:00:00.548-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tech'/><category scheme='http://www.blogger.com/atom/ns#' term='ruby on rails'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><title type='text'>Ruby YAML config files - hash key confusion</title><content type='html'>If you have played around with YAML files in Rails at all, you may have run across a confusing issue:  often times in Rails, hashes are accessed via either a string or symbol but if you load up a YAML file, the hash can only be accessed by string!&lt;br /&gt;The reason is Rails has a "HashWithIndifferentAccess" object type, that is built on top of the standard ruby Hash, and YAML files by default use the standard ruby hash.&lt;br /&gt;E.g. &lt;br /&gt; &lt;code&gt;h = { :msg =&gt; 'Hello World', :date =&gt; Time.now }&lt;br /&gt; puts h[:msg]  # Hello World&lt;br /&gt; puts h['msg'] # nil&lt;br /&gt;&lt;br /&gt; h = HashWithIndifferentAccess.new( { :msg =&gt; 'Hello World', :date =&gt; Time.now } )&lt;br /&gt; puts h[:msg]  # Hello World&lt;br /&gt; puts h['msg'] # Hello World&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;You can get the indifferenct access behavior in YAML files by putting this at the top of your YAML file:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;--- !map:HashWithIndifferentAccess&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;That is the most flexible way to create your YAML files. If you strictly want symbol access only, you can also prefix each key in your YAML file with a colon:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;config.yml&lt;/i&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;development:&lt;br /&gt;  :key_that_is_a_symbol: value 1&lt;br /&gt;  key_that_is_NOT_a_symbol: value 2&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Once loaded, you will get this behavior:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;  config = YAML::load_file( 'config.yml' )['development']&lt;br /&gt;  puts config[:key_that_is_a_symbol]      # value 1&lt;br /&gt;  puts config[:key_that_is_NOT_a_symbol]  # nil&lt;br /&gt;  puts config['key_that_is_a_symbol']     # nil&lt;br /&gt;  puts config['key_that_is_NOT_a_symbol'] # value 2&lt;br /&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-3800117575098782505?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/3800117575098782505/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2009/03/ruby-yaml-config-files-hash-key.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/3800117575098782505'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/3800117575098782505'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2009/03/ruby-yaml-config-files-hash-key.html' title='Ruby YAML config files - hash key confusion'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-8957033599503569640</id><published>2009-03-30T11:20:00.001-07:00</published><updated>2009-03-30T11:22:12.184-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='random'/><title type='text'>KFC offers to fix nation's potholes for free</title><content type='html'>Interesting advertising method by fast-food chain KFC:&lt;br /&gt;&lt;a href="http://www.bostonherald.com/business/general/view/2009_03_30_KFC_s_road-repair_offer_has_special_patch_on_top/"&gt;http://www.bostonherald.com/business/general/view/2009_03_30_KFC_s_road-repair_offer_has_special_patch_on_top/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Perhaps it will start a new wave of sponsored public service projects during a time where the national and local governments are steeped in debt.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-8957033599503569640?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/8957033599503569640/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2009/03/kfc-offers-to-fix-nations-potholes-for.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/8957033599503569640'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/8957033599503569640'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2009/03/kfc-offers-to-fix-nations-potholes-for.html' title='KFC offers to fix nation&apos;s potholes for free'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-3645389391127844217</id><published>2009-03-30T07:00:00.000-07:00</published><updated>2009-03-30T07:00:00.580-07:00</updated><title type='text'>The British Isles: explained</title><content type='html'>Have you ever wondered what the difference between Great Britain, England, United Kingdom, and the British Isles were? How about Ireland versus Republic of Ireland? Well here is the answer to all your questions:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://leisureguy.files.wordpress.com/2008/02/uk.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 250px; height: 250px;" src="http://leisureguy.files.wordpress.com/2008/02/uk.gif" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;Source: &lt;a href="http://leisureguy.wordpress.com/2008/02/05/the-great-british-diagram/"&gt;http://leisureguy.wordpress.com/2008/02/05/the-great-british-diagram/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-3645389391127844217?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/3645389391127844217/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2009/03/british-isles-explained.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/3645389391127844217'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/3645389391127844217'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2009/03/british-isles-explained.html' title='The British Isles: explained'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-6449461653160742152</id><published>2009-03-27T07:00:00.000-07:00</published><updated>2009-03-27T07:00:01.268-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='user interfaces'/><title type='text'>Bad UI: Would you want this team designing your websites?</title><content type='html'>I just ran across the following site, and wasn't sure whether I was more appalled at the site itself and the layout, or by the fact that their business is in doing contract web design work. &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://i30.photobucket.com/albums/c337/japanick/blog/website4hire.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 199px;" src="http://i30.photobucket.com/albums/c337/japanick/blog/website4hire.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;Click the picture to view the large version of screenshot, or &lt;a href="http://www.website4hire.com"&gt;go to the website&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-6449461653160742152?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/6449461653160742152/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2009/03/bad-ui-would-you-want-this-team.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/6449461653160742152'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/6449461653160742152'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2009/03/bad-ui-would-you-want-this-team.html' title='Bad UI: Would you want this team designing your websites?'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-4977649648442075781</id><published>2009-03-23T07:00:00.000-07:00</published><updated>2009-03-23T07:00:00.977-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='links'/><title type='text'>Cool Website: ColorSchemer Online</title><content type='html'>ColorSchemer is a software company that produces tools for finding color schemes, complimentary colors, importing and exporting CSS color styles, quick preview of colors together in a mock website page, and more.  The desktop app is a great resource for web designers that are coming up with their own color schemes. It would also be useful for graphic designers in the print world too I imagine.&lt;br /&gt;&lt;br /&gt;While the entire studio is available at a steep price of $49.99, they do have one portion of their product available online for free. Check it out here:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.colorschemer.com/online.html"&gt;&lt;img style="display:block; margin:0px 10px 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 175px;" src="http://www.colorschemer.com/images/online_screen.jpg" border="0" alt="" /&gt;&lt;br /&gt;http://www.colorschemer.com/online.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-4977649648442075781?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/4977649648442075781/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2009/03/cool-website-colorschemer-online.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/4977649648442075781'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/4977649648442075781'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2009/03/cool-website-colorschemer-online.html' title='Cool Website: ColorSchemer Online'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-8422260116412880376</id><published>2009-03-17T07:00:00.000-07:00</published><updated>2009-03-30T11:38:04.523-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='user interfaces'/><category scheme='http://www.blogger.com/atom/ns#' term='mac tips'/><title type='text'>Shut down a Virtual Machine instance - VMWare Fusion</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://i30.photobucket.com/albums/c337/japanick/blog/shutdown_vm_instance.gif"&gt;&lt;img style="display:block; margin:0px 10px 10px; float:left;cursor:pointer; cursor:hand;width: 221px; height: 401px;" src="http://i30.photobucket.com/albums/c337/japanick/blog/shutdown_vm_instance.gif" border="0" alt="" /&gt;&lt;/a&gt;The other day I had a Windows XP virtual machine instance running on my Mac. When I came back later the OS had decided to restart automatically for windows updates but had frozen at the shutdown screen.  I tried closing the window, sending CTRL-ALT-DEL, and "Shut Down guest". Everything. Yet each time VMWare Fusion would ask if I really wanted to power off, and despite me saying yes..it would do nothing and the instance was still frozen.&lt;br /&gt;&lt;br /&gt;The trick is to go to the "Virtual Machine" menu option, and then press and hold the "alt" key, and you can then select "Power off" which is equivalent to unplugging the computer, rather than just hitting the power button a few times to no avail.  It shouldn't be that hard, and how do they expect users to discover those hidden options? I am also nominating this for a bad UI!&lt;br /&gt;&lt;div style="clear: left"&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-8422260116412880376?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/8422260116412880376/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2009/03/shut-down-virtual-machine-instance.html#comment-form' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/8422260116412880376'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/8422260116412880376'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2009/03/shut-down-virtual-machine-instance.html' title='Shut down a Virtual Machine instance - VMWare Fusion'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-6610389296369300024</id><published>2009-03-16T07:00:00.001-07:00</published><updated>2009-03-16T07:00:00.869-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tech'/><title type='text'>Amusing post by Google urging the public to use the verb 'Google' correctly</title><content type='html'>Just when you thought Google wanted everyone to say "I googled that the other day.." and basically have "search" be universally replaced by "google", think again!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://googleblog.blogspot.com/2006/10/do-you-google.html"&gt;http://googleblog.blogspot.com/2006/10/do-you-google.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-6610389296369300024?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/6610389296369300024/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2009/03/amusing-post-by-google-urging-public-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/6610389296369300024'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/6610389296369300024'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2009/03/amusing-post-by-google-urging-public-to.html' title='Amusing post by Google urging the public to use the verb &apos;Google&apos; correctly'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-6709694991888013146</id><published>2009-03-10T07:00:00.000-07:00</published><updated>2009-03-10T07:00:01.033-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='tech'/><category scheme='http://www.blogger.com/atom/ns#' term='ruby on rails'/><title type='text'>Use Rails url_for in Ext grids</title><content type='html'>In rails apps, it is best practice to always use &lt;code&gt;link_to&lt;/code&gt; and &lt;code&gt;url_for&lt;/code&gt; when generating URLs. This prevents your application from having hard-coded links that may break if you refactor controllers later. It also allows an easy way of creating links that send a put/post/delete command to your server.&lt;br /&gt;&lt;br /&gt;I found that I wanted that abstraction and power in an Ext grid that was in a view. If you have used Ext grids at all, you know that you set up a store and populate it with data (json object, async request, etc) and then give it some column information and Ext does the rest. In other words, it iterates across your records and displays the rows, so there's no way to use &lt;code&gt;&lt;%= link_to ... %&gt;&lt;/code&gt; for a cell in each row because the rendering is done client-side in JavaScript.&lt;br /&gt;&lt;br /&gt;My quick solution, that perhaps some will find helpful:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;var delete_link_template = '&lt;%= link_to( 'Delete', { :controller =&gt; 'my_controller', :action =&gt; 'destroy', :id =&gt; '__id__' },&lt;br /&gt;                                                   { :method =&gt; :delete, :confirm =&gt; 'Are you sure you want to leave this item?' } ).gsub( "\'", "\\\\'" ) %&gt;';&lt;br /&gt;&lt;br /&gt;    function actions_renderer( val, metadata, record ) {&lt;br /&gt;      var object_id = record.get("id");&lt;br /&gt;      return val + ': ' + delete_link_template.replace( "__id__", object_id );&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    &lt;br /&gt;// this is a portion of an example Ext grid being declared. Notice it uses 'actions_renderer', which is the function defined above&lt;br /&gt;var my_grid = new Ext.grid.GridPanel(&lt;br /&gt;  {&lt;br /&gt;    columns:&lt;br /&gt;    [&lt;br /&gt;      ...,&lt;br /&gt;      { header: "Manage", width: 140, dataIndex: 'name', renderer: actions_renderer }&lt;br /&gt;    ],&lt;br /&gt;    ...&lt;br /&gt;  } );&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-6709694991888013146?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/6709694991888013146/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2009/03/use-rails-urlfor-in-ext-grids.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/6709694991888013146'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/6709694991888013146'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2009/03/use-rails-urlfor-in-ext-grids.html' title='Use Rails url_for in Ext grids'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-4679534513490729743</id><published>2009-03-09T07:00:00.000-07:00</published><updated>2009-03-09T07:00:00.940-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='user interfaces'/><title type='text'>Not Google's best auto-populated list...</title><content type='html'>The other day I was &lt;a href="http://en.wikipedia.org/wiki/Google_(verb)"&gt;googling&lt;/a&gt; for something, and got the following list after simply typing "best way to"&lt;br /&gt;&lt;br /&gt; &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://i30.photobucket.com/albums/c337/japanick/blog/bestwaytoongoogle.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 459px; height: 288px;" src="http://i30.photobucket.com/albums/c337/japanick/blog/bestwaytoongoogle.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt; The sad thing is I'm sure these results are ordered by popularity and most use. But that Google would offer such phrases so high in the list is unfortunate.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-4679534513490729743?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/4679534513490729743/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2009/03/not-googles-best-auto-populated-list.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/4679534513490729743'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/4679534513490729743'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2009/03/not-googles-best-auto-populated-list.html' title='Not Google&apos;s best auto-populated list...'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-3007675069589147221</id><published>2009-03-03T07:00:00.000-08:00</published><updated>2009-03-03T07:00:01.313-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby on rails'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><title type='text'>How to override validation of has_many active record objects</title><content type='html'>I found myself needing to override the validation of "has_many" active record objects after using build to create them. The reason being that I was doing custom validation on each of the built objects anyway and wanted to display each of the child object's validation error message, not the generic "&amp;lt;object&amp;gt; is not valid".&lt;br /&gt;&lt;br /&gt;For example:&lt;pre&gt;&lt;br /&gt;class List &lt; ActiveRecord::Base&lt;br /&gt;  &lt;br /&gt;  has_many :phone_numbers, :dependent =&gt; :destroy&lt;br /&gt;&lt;br /&gt;  validate :validate_numbers&lt;br /&gt;&lt;br /&gt;  def build_items_from_file_stream( stream )&lt;br /&gt;    stream.split( "\n" ).each_with_index do |line, index|&lt;br /&gt;      next if line.blank?&lt;br /&gt;      phone = self.phone_numbers.build( :phone_number =&gt; line )&lt;br /&gt;      phone.file_line_number = index + 1&lt;br /&gt;      phone.unformatted_number = line&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  # this method overrides the automatically generated method&lt;br /&gt;  def validate_associated_records_for_phone_numbers&lt;br /&gt;    true&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def validate_numbers&lt;br /&gt;    self.phone_numbers.each do |phone|&lt;br /&gt;      if !phone.valid?&lt;br /&gt;        error_prefix = "File line #{phone.file_line_number}, '#{phone.unformatted_number}': "&lt;br /&gt;        errors.add error_prefix, target.errors.full_messages.join( ", " )&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Basically ActiveRecord will automatically create a validate method of the name:&lt;br /&gt;validate_associated_records_for_&lt;has_many_table_name&gt;&lt;br /&gt;That method steps across all of the associated objects, and if !valid? does:&lt;br /&gt;errors.add &lt;table_name&gt;, "is not valid"&lt;br /&gt;&lt;br /&gt;Without overriding that method, if you were to create a list (in my example above) that had an invalid phone number (assuming the phone_numbers class has validation too), you would get an error string something like:&lt;br /&gt; - Phone number is not valid&lt;br /&gt; - File line 1 '805-555-123': national number must contain 10 digits&lt;br /&gt; - Phone number is not valid&lt;br /&gt; - File line 2 '+11 805-555-1234': country code not found&lt;br /&gt;&lt;br /&gt;Clearly having "phone number is invalid" multiple times is not adding any value, and in fact making the list validation message more confusing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-3007675069589147221?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/3007675069589147221/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2009/03/how-to-override-validation-of-hasmany.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/3007675069589147221'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/3007675069589147221'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2009/03/how-to-override-validation-of-hasmany.html' title='How to override validation of has_many active record objects'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-5929692741442083189</id><published>2009-03-02T07:00:00.000-08:00</published><updated>2009-03-02T07:00:01.684-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='user interfaces'/><title type='text'>Bad UI: Vons card mileage points renewal form</title><content type='html'>I got an email from &lt;a href="http://www.vons.com"&gt;Vons&lt;/a&gt; (aka Safeway) a few days ago, saying that I needed to go to a webpage in order to renew my mileage points option with them (did you know you can &lt;a href="http://www.united.com/page/article/0,6722,1725,00.html"&gt;get United miles just by using your Vons card&lt;/a&gt;?).&lt;br /&gt;&lt;br /&gt; First, I was disappointed that I had to re-register. I had signed up on my United mileage account page for this service a year or two ago, and it was working. Why did I now have to go to Vons.com and fill out a form? But I didn't want to lose earning miles, so I dutifully filled it out.&lt;br /&gt;&lt;br /&gt;The form stated that all fields were required except club card # and email. Usually I avoid entering my email whenever possible on a form, but they gave the whole "providing your email will allow us to easily contact you in the event we need more information to process your renewal" speech. So I gave my email address. I was happy to see they had a check box where you could decide whether to get weekly specials and other junk email from them. I of course unchecked it and hit submit.  I was greeted with this error:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://i30.photobucket.com/albums/c337/japanick/blog/vons_invalid_email2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 531px; height: 448px;" src="http://i30.photobucket.com/albums/c337/japanick/blog/vons_invalid_email2.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;Clearly they had some server side validation of the checkbox (and didn't even bother to transform the error into a friendly message), and I'm guessing it was incorrectly wired up such that if the optout setting was not provided at all, it would cause a validation error. Well, when you have a checkbox on a form that does NOT get checked, that field does not even get sent across to the server (I know, it would make more sense to send that field, with a value of 'false', but it wasn't my decision. Also, Rails encapsulates that nicely with a hidden input field, but I digress). At any rate, all web developers should know that by now and have tested it. &lt;br /&gt;&lt;br /&gt; To outsmart the form, I tried removing my email address and resubmitting, hoping the site was at least smart enough to only validate the "opt out" setting if an email address was provided (since it was optional). But no:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://i30.photobucket.com/albums/c337/japanick/blog/vons_invalid_email.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 531px; height: 448px;" src="http://i30.photobucket.com/albums/c337/japanick/blog/vons_invalid_email.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;So now my only choice was to give an email address and check the box. I was trapped because I wanted to give my valid email address in case they had problems w/ my renewal (because I did not remember the phone number on my account...), and yet didn't want to get the weekly emails. Against my best judgment I gave them my email and my "consent" to blast me with whatever emails they wanted.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-5929692741442083189?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/5929692741442083189/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2009/03/bad-ui-vons-card-mileage-points-renewal.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/5929692741442083189'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/5929692741442083189'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2009/03/bad-ui-vons-card-mileage-points-renewal.html' title='Bad UI: Vons card mileage points renewal form'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-3203817345350560351</id><published>2009-02-28T11:32:00.000-08:00</published><updated>2009-02-28T14:48:19.865-08:00</updated><title type='text'>Not the response I was looking for...</title><content type='html'>When you make a nice comment about your wife (who's not in the room), social etiquette says you should expect the response from others to be something like:&lt;br /&gt; - "Awwww, that's so sweet!"&lt;br /&gt; - "I totally agree!", or maybe even&lt;br /&gt; - "That's nice. Now back to the topic at hand..."&lt;br /&gt;&lt;br /&gt;Apparently Facebook is immune to the standard social etiquette "guidelines" that we may have come to expect out in the real world. A few weeks ago I wrote the following about my wife:  "I have the greatest wife ever!"  She had just surprised me with a really kind act that I knew took sacrifice, but was done out of love for me. I was truly grateful and wanted to express my feelings to the world, so what better place than to broadcast it on my Facebook status!&lt;br /&gt;&lt;br /&gt;Apparently some took my statement not as a compliment to my wife, but as a challenge or perhaps an accusation against other males out there who have great wives. The only response I got that day about my status was this:&lt;br /&gt;&lt;br /&gt;  &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://i30.photobucket.com/albums/c337/japanick/blog/blog_facebook_status.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 554px; height: 203px;" src="http://i30.photobucket.com/albums/c337/japanick/blog/blog_facebook_status.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-3203817345350560351?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/3203817345350560351/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2009/02/not-response-i-was-looking-for.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/3203817345350560351'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/3203817345350560351'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2009/02/not-response-i-was-looking-for.html' title='Not the response I was looking for...'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-3251431631174375007</id><published>2009-02-03T11:50:00.000-08:00</published><updated>2009-02-04T00:27:05.654-08:00</updated><title type='text'>Free Grand Slam != Free Breakfast</title><content type='html'>Today Denny's ran a promotion offering free Grand Slam breakfasts to all customers from 6am to 2pm. A couple friends and I took part in the festive activities and enjoyed a great deal (and with only a 30 minute wait or so).&lt;br /&gt; I was surprised at some of the customers' questions and actions. Many assumed that the whole breakfast was free, and were shocked when they were given a bill for their coffee or orange juice. I overheard another man clarify with the waiter whether the 3 glasses of milk his table just ordered were free or not.  And another patron was actually walking out the front door until a manager yelled at him to stop and pay his bill, to which he reluctantly agreed to do.&lt;br /&gt;&lt;br /&gt; When I heard "free grand slams at Denny's" I immediately wondered what the catch was and what I would have to buy in order to get the deal. Apparently others heard the same phrase and immediately assumed that not only was there no catch, but everything at Denny's that morning was on the house.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-3251431631174375007?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/3251431631174375007/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2009/02/free-grand-slam-free-breakfast.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/3251431631174375007'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/3251431631174375007'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2009/02/free-grand-slam-free-breakfast.html' title='Free Grand Slam != Free Breakfast'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-4189245038897754337</id><published>2008-12-30T09:34:00.000-08:00</published><updated>2008-12-30T09:52:00.703-08:00</updated><title type='text'>Mac OS X does not allow "tabbing" to drop downs</title><content type='html'>When I got my first Mac (well, actually even before that when I was using my wife's Christmas present last year, which was our family's first Apple computer) I was astounded to realize that when using web forms (such as filling out a registration, or searching for plane tickets), hitting "tab" to advance to the next field worked great until you got to a checkbox or a dropdown. It would skip right over those! So no more signing into gmail and easily toggling the "remember me" checkbox with the keyboard. No more tab and "down", "down" when selecting my expiration date when purchasing something.&lt;br /&gt; I did some searches a year ago (apparently not very good ones), and came up empty. Of course I didn't try that hard.. I just continued on with whatever I was doing. But every time I would hit a form where I wanted to tab to a drop down, I got more and more irritated.  Given that the problem was both in Safari and Firefox should have tipped me off to the fact that it was a system setting somewhere, but I was beginning to think it was a hidden, hard-coded setting that I could not change.&lt;br /&gt;&lt;br /&gt;Fortunately, there are some &lt;a href="http://www.howtogeek.com/howto/apple/why-doesnt-tab-work-for-drop-down-controls-in-firefox-on-os-x/"&gt;prominent blog posts&lt;/a&gt; these days (and &lt;a href="http://www.joelonsoftware.com"&gt;Joel's&lt;/a&gt; wonderful &lt;a href="http://www.stackoverflow.com"&gt;stack overflow&lt;/a&gt; site with &lt;a href="http://stackoverflow.com/questions/2349/how-to-tab-focus-onto-a-dropdown-field-in-mac-osx"&gt;an answer&lt;/a&gt;). The answer is easy:&lt;br /&gt; a) System Preferences &gt; Keyboard and Mouse.&lt;br /&gt; b) "Keyboard Shortcuts" tab.&lt;br /&gt; c) Select "All Controls" in the bottom section about full keyboard access.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-4189245038897754337?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/4189245038897754337/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2008/12/mac-os-x-does-not-allow-tabbing-to-drop.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/4189245038897754337'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/4189245038897754337'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2008/12/mac-os-x-does-not-allow-tabbing-to-drop.html' title='Mac OS X does not allow &quot;tabbing&quot; to drop downs'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-3857083346954312050</id><published>2008-12-09T19:06:00.000-08:00</published><updated>2008-12-09T19:36:22.435-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='user interfaces'/><title type='text'>Bad UI: evite website</title><content type='html'>While recently creating an e-vite (&lt;a href="http://www.evite.com"&gt;www.evite.com&lt;/a&gt;), I was wanting to import my contact list from my gmail contacts. I won't get into how hard it was to export the right set of contacts and then manually transform the CSV columns into the right format that e-vite would accept. That part was understandable.&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://i30.photobucket.com/albums/c337/japanick/ui_evite.png"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 400px; height: 396px;" src="http://i30.photobucket.com/albums/c337/japanick/ui_evite.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;What I was disappointed in, was when I clicked "Import Contacts" on the "Send Invites" page [see diagram].  First, I was then taken away from this page and onto a dedicated "Import" wizard. The wizard itself had problems and it was not obvious what to do for simply uploading your own CSV file. A few clicks later, I uploaded the file, and then realized that I had to select every contact presented to me in a list in order to actually import them (just in case after you painstakingly created the CSV file, perhaps you then wanted to filter which contacts you really were importing...but how many users expect that to happen when they upload a big CSV file? Chances are they either: a) want to import them all, or b) already filtered out those they didn't want during the export or by messing with the file in Excel--this is what I did).  So then what's the value of giving them that option when its probably already too late or they don't want it?   Furthermore, I had uploaded 164 contacts, but the next page was showing me 20 in a list. I either had to "select all", then navigate to each page and "select all" on each page, or click a different link to "show all", then "select all", then finally "import." The first time around I simply hit "select all" and then "import" because it was not obvious at first that that wouldn't select ALL contacts (like the "select all" gmail provides in Spam and Trash, etc).&lt;br /&gt;&lt;br /&gt;So at that point, two surprises occurred.  First, I was taken back to the screen shown in the diagram, with all the imported contacts shoved into the text area. It seemed like a disconnect from the previous screen, and I wasn't aware that all the imported contacts would automatically be recipients, but okay no big deal.  Secondly though, I noticed it was only the first 20 contacts that were in the text area. So that was when I realized evite.com had chopped off my other 144 contacts. Then when I went to the Evite Address Book, hoping maybe they were in there, I didn't have ANY contacts!&lt;br /&gt;&lt;br /&gt; Turns out, the "import contacts" link in the diagram above is only for THIS ONE invitation! It is not importing contacts into your address book at all. So, I had to redo the process, but I knew that any people I didn't invite in this invitation wouldn't ever be added to my address book, in which case next time I was doing an evite I would yet again have to upload (assuming I wanted to change the recipient list at all).&lt;br /&gt;&lt;br /&gt;  Frustrated, I went out of the e-vite creation process, into My Account, then to the Evite Address Book management, then clicked "Import Contacts" there, and did the process over. The same confusing wizard. This time I first clicked "show all", waited for the page to reload, then successfully imported all my contacts. But so many steps of the process could have been smoother.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Lessons to learn:&lt;/span&gt;&lt;br /&gt;  * I often find that the user interaction for importing and exporting data (whether its contacts, emails, or other data) is not refined. It is usually either a feature thrown on at the end when a customer requests it, or just not given a lot of time because it's either seen as a "power user" feature and thus why spend time refining it, or simply because the number of people that user import/export is far fewer than say create an e-vite and type in some email addresses.&lt;br /&gt;  * When a user does want to import or export data, and they are presented with a hard-to-use interface, they will get frustrated. They will be unhappy with your software, and perhaps abort the import and thus be much less likely to further use your software.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-3857083346954312050?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/3857083346954312050/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2008/12/bad-ui-evite-website.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/3857083346954312050'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/3857083346954312050'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2008/12/bad-ui-evite-website.html' title='Bad UI: evite website'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-4316668366780799479</id><published>2008-11-29T12:12:00.000-08:00</published><updated>2008-11-29T12:39:17.742-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mac tips'/><category scheme='http://www.blogger.com/atom/ns#' term='tech'/><title type='text'>Mac OS X Terminal - case insensitive auto-complete</title><content type='html'>An annoying thing with the Mac terminal is that, out of the box, the tab completion* is case sensitive. Perhaps in linux land this is ok because most things are kept lower case. But, many default folders in Mac Os X start with upper-case letters (Desktop, Pictures, Public, etc).  So, to turn off the case-sensitive completion, simply type this on the command line:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&gt; echo "set completion-ignore-case On" &gt;&gt; ~/.inputrc&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Be sure to start a new terminal instance for the changes to take effect.&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;* (Tab completion is when you start typing a folder or file in the terminal/console and hit tab, it auto completes to any matches it finds. Very handy and if you don't already use it, you should!)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-4316668366780799479?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/4316668366780799479/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2008/11/mac-os-x-terminal-case-insensitive-auto.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/4316668366780799479'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/4316668366780799479'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2008/11/mac-os-x-terminal-case-insensitive-auto.html' title='Mac OS X Terminal - case insensitive auto-complete'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18636729.post-3453584502884931315</id><published>2008-11-23T21:39:00.000-08:00</published><updated>2008-11-23T21:52:28.646-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tech'/><title type='text'>Create a copy of a hard disk in VirtualBox</title><content type='html'>&lt;a href="http://www.virtualbox.org/"&gt;VirtualBox&lt;/a&gt; is a cool virtualization product, similar to Microsoft VirtualPC or VMWare.  It is free and available on Mac, Windows and Linux. It is capable of running Windows, DOS, Linux distributions and more.  It is worth checking out.&lt;br /&gt;&lt;br /&gt;It has an easy to use interface, and so far I have been pleased with the hardware support. Today though, I ran into a problem where I wanted to clone an existing virtual machine, so as to avoid going through the painful reinstallation process.  Simply copying the .vdi file and trying to create a new virtual machine did not work.  Instead you are greeted with this great message: "A hard disk with UUID {73e6fde6-9406-7e49-f29e-f0e927454f1a} or with the same properties ('/Users/Nick/VM/HardDisk1.vdi') is already registered."&lt;br /&gt;&lt;br /&gt;Here are the steps to correctly copy a virtual hard drive to use in another VM. This enables you to keep a "clean" installation drive around to base other instances off of.&lt;br /&gt;&lt;ol type="a"&gt;&lt;br /&gt;&lt;li&gt;Make sure the machine that contains the hard drive you want to copy, is turned off&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Go to "File" &gt; "Virtual Disk Manager..."&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Select the virtual disk you want to copy, and press "Release"&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Open terminal, and navigate to the folder containing your hard drive files (*.vdi)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Type: &lt;code&gt;vboxmanage clonevdi image_original.vdi image_copy.vdi&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Go back to the Virtual Disk Manager, and select "Add". Then find the image_copy.vdi file you just created&lt;/li&gt;&lt;br /&gt;&lt;li&gt;You can now use that new file in any new virtual machines you create through VirtualBox!&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Note: using xVM VirtualBox by Sun, version 2.0.4&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18636729-3453584502884931315?l=www.nickburwell.com%2Fblog' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/3453584502884931315/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.nickburwell.com/blog/2008/11/create-copy-of-hard-disk-in-virtualbox.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/3453584502884931315'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18636729/posts/default/3453584502884931315'/><link rel='alternate' type='text/html' href='http://www.nickburwell.com/blog/2008/11/create-copy-of-hard-disk-in-virtualbox.html' title='Create a copy of a hard disk in VirtualBox'/><author><name>Nick</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='16624996053548785495'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry></feed>