<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-1136000476179272289</atom:id><lastBuildDate>Wed, 21 Oct 2009 02:41:29 +0000</lastBuildDate><title>The Big Dumb Developer</title><description /><link>http://www.bigdumbdev.com/</link><managingEditor>noreply@blogger.com (Steve)</managingEditor><generator>Blogger</generator><openSearch:totalResults>32</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/TheBigDumbDeveloper" type="application/rss+xml" /><feedburner:emailServiceId>TheBigDumbDeveloper</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-5019977885010780544</guid><pubDate>Tue, 06 Oct 2009 00:16:00 +0000</pubDate><atom:updated>2009-10-05T19:54:05.920-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">development</category><title>Software and Football</title><description>Football has metrics - yards per rush, completion percentage, time of possession.  Do you think Mike Tomlin talked about their yards after the catch after they won the super bowl?  Do you think Arizona fans cared that their team won the time of possession battle?  In football, metrics are useful tools for the teams and only important in fantasy football.  Every football player and coach in the NFL understands that the only metric that matters is W's.&lt;br /&gt;&lt;br /&gt;We have metrics in software - burn downs, lines of code, reopen rates.  We spend years delivering metrics and no products.   We have SMART goals to justify our bonuses.  We WORSHIP our metrics.  In our fantasy world, we are world class developers and have the metrics to prove it.  When our products don't fly in the market, our business owners are idiots, we got bad requirements, our sales people suck; but our metrics are awesome.&lt;br /&gt;&lt;br /&gt;Are you smarter than the average linebacker?  Has your software career been concusion-free?  Then stop trying to be a rock star in fantasy development and start focusing on your product's success.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-5019977885010780544?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=36KOUQKFmlw:kEEE9gJxwEM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=36KOUQKFmlw:kEEE9gJxwEM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=36KOUQKFmlw:kEEE9gJxwEM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=36KOUQKFmlw:kEEE9gJxwEM:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=36KOUQKFmlw:kEEE9gJxwEM:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=36KOUQKFmlw:kEEE9gJxwEM:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=36KOUQKFmlw:kEEE9gJxwEM:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/36KOUQKFmlw" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/36KOUQKFmlw/software-and-football.html</link><author>noreply@blogger.com (Steve)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2009/10/software-and-football.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-5135974935224166457</guid><pubDate>Sat, 07 Feb 2009 07:31:00 +0000</pubDate><atom:updated>2009-02-07T01:55:10.678-06:00</atom:updated><title>A startup isn't a business</title><description>At a startup you are not really "In Business", you are trying to build a business.&lt;br /&gt;&lt;br /&gt;When you work at a startup, all you see is the vision.  The customers, the business model, the cash-o-la, your expanding team of minions.  WE CANNOT FAIL.  When you look at your competition, you see their current business - and it looks like crap.&lt;br /&gt;&lt;br /&gt;Trust me, their vision is just as grand as yours.  &lt;br /&gt;&lt;br /&gt;And your reality is just as crappy as theirs.&lt;br /&gt;&lt;br /&gt;Have a vision, but don't lose site of the current state.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-5135974935224166457?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=1pyHJTqvUPI:_eouWxbjj6Y:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=1pyHJTqvUPI:_eouWxbjj6Y:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=1pyHJTqvUPI:_eouWxbjj6Y:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=1pyHJTqvUPI:_eouWxbjj6Y:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=1pyHJTqvUPI:_eouWxbjj6Y:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=1pyHJTqvUPI:_eouWxbjj6Y:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=1pyHJTqvUPI:_eouWxbjj6Y:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/1pyHJTqvUPI" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/1pyHJTqvUPI/startup-isnt-business.html</link><author>noreply@blogger.com (Steve)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2009/02/startup-isnt-business.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-2290708469212384307</guid><pubDate>Mon, 30 Jun 2008 14:24:00 +0000</pubDate><atom:updated>2008-06-30T09:26:20.303-05:00</atom:updated><title>Cisco VPN on Vista</title><description>&lt;p&gt;If you use the Cisco VPN client on Vista this, bookmark this: &lt;a href="http://www.verier.co.uk/subtext/archive/2008/01/09/reason-442-failed-to-enable-virtual-adapter-with-cisco-vpn.aspx"&gt;http://www.verier.co.uk/subtext/archive/2008/01/09/reason-442-failed-to-enable-virtual-adapter-with-cisco-vpn.aspx&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;And, to avoid such problems, disconnect the VPN before you let you computer go to sleep.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-2290708469212384307?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=HbJMc4eJP74:RZREv1OhMLw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=HbJMc4eJP74:RZREv1OhMLw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=HbJMc4eJP74:RZREv1OhMLw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=HbJMc4eJP74:RZREv1OhMLw:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=HbJMc4eJP74:RZREv1OhMLw:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=HbJMc4eJP74:RZREv1OhMLw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=HbJMc4eJP74:RZREv1OhMLw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/HbJMc4eJP74" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/HbJMc4eJP74/cisco-vpn-on-vista.html</link><author>noreply@blogger.com (Steve)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2008/06/cisco-vpn-on-vista.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-6360877202170838638</guid><pubDate>Thu, 10 Apr 2008 04:40:00 +0000</pubDate><atom:updated>2008-04-09T23:47:24.072-05:00</atom:updated><title>Installing DB2 on Vista</title><description>In case anyone else runs into this, you have to log in as an administrator to install DB2 on Vista.  Logging in as administrator is different than logging in with an account that has administrator access.  And, because they said so, the administrator account is disabled by default.  Follow life hacker's instructions &lt;a href="http://lifehacker.com/341521/enable-vistas-administrator-account"&gt;to enable vista's administrator account&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-6360877202170838638?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=N3iDm-dv1TY:0pwz7Tz_990:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=N3iDm-dv1TY:0pwz7Tz_990:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=N3iDm-dv1TY:0pwz7Tz_990:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=N3iDm-dv1TY:0pwz7Tz_990:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=N3iDm-dv1TY:0pwz7Tz_990:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=N3iDm-dv1TY:0pwz7Tz_990:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=N3iDm-dv1TY:0pwz7Tz_990:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/N3iDm-dv1TY" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/N3iDm-dv1TY/installing-db2-on-vista.html</link><author>noreply@blogger.com (Steve)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">5</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2008/04/installing-db2-on-vista.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-3707278834230532883</guid><pubDate>Wed, 16 Jan 2008 16:50:00 +0000</pubDate><atom:updated>2008-01-16T11:16:29.037-06:00</atom:updated><title>My actions GET POSTs</title><description>Quick note on a pattern I've picked up from tinkering with Rails and have happily used in other web platforms - using the same controller action for both GETs and POSTs.  Basic pattern looks like this (pseudo code):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;someAction()&lt;br /&gt;{&lt;br /&gt;    if( request.isPost() ){&lt;br /&gt;       handle the posted data...&lt;br /&gt;    }&lt;br /&gt;    else{&lt;br /&gt;       handle setting up the form...&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In your HTML, you don't have to specify an action, it will just POST to whatever GET was used to fetch the form in the first place.  I'm implementing some file-import functionality today, and this came in handy as I can reuse the file form view for all of my various import actions.&lt;br /&gt;&lt;br /&gt;In Rails, you can accomplish this with routing - same rout pattern sent to different actions based on the request method.  There isn't an equivalent in my Struts 1.x app, so far that hasn't bothered me, though. &lt;br /&gt;&lt;br /&gt;I would love to hear what other people think about this pattern.  My initial thought was that coupling generating the form and handling the response was a negative, but in my day to day work I've yet to run into an example where coupling them together was a bad thing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-3707278834230532883?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=M-frgGeQOrA:hLvnpGJF45A:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=M-frgGeQOrA:hLvnpGJF45A:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=M-frgGeQOrA:hLvnpGJF45A:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=M-frgGeQOrA:hLvnpGJF45A:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=M-frgGeQOrA:hLvnpGJF45A:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=M-frgGeQOrA:hLvnpGJF45A:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=M-frgGeQOrA:hLvnpGJF45A:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/M-frgGeQOrA" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/M-frgGeQOrA/my-actions-get-posts.html</link><author>noreply@blogger.com (Steve)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2008/01/my-actions-get-posts.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-1580647081389659106</guid><pubDate>Wed, 14 Nov 2007 16:34:00 +0000</pubDate><atom:updated>2007-11-14T10:37:07.259-06:00</atom:updated><title>Safari won't set cookies from javascript on localhost</title><description>Ran into this today - if you're testing your work with Safari, it won't set cookies from javascript on localhost.  Hit you local box using 127.0.0.1 and it will work.  Grrrrr :(&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-1580647081389659106?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=G1iRgLGgz10:KX7iOHw1r_c:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=G1iRgLGgz10:KX7iOHw1r_c:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=G1iRgLGgz10:KX7iOHw1r_c:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=G1iRgLGgz10:KX7iOHw1r_c:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=G1iRgLGgz10:KX7iOHw1r_c:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=G1iRgLGgz10:KX7iOHw1r_c:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=G1iRgLGgz10:KX7iOHw1r_c:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/G1iRgLGgz10" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/G1iRgLGgz10/safari-wont-set-cookies-from-javascript.html</link><author>noreply@blogger.com (Steve)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2007/11/safari-wont-set-cookies-from-javascript.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-6675738495693359183</guid><pubDate>Mon, 08 Oct 2007 19:04:00 +0000</pubDate><atom:updated>2007-10-08T14:19:13.387-05:00</atom:updated><title>Metaprogramming in the wild - script.aculo.us effect's afterUpdate only the first time</title><description>So, I want to fade in some content and I need to adjust a scroll on the content.  &lt;br /&gt;&lt;br /&gt;I can't adjust the scroll while it's hidden because none of the scroll info will be set.  &lt;br /&gt;&lt;br /&gt;I can't update it after the animation, because there will be a nasty jump.  &lt;br /&gt;&lt;br /&gt;What I really want is to adjust the scroll after the first frame of animation - after the content has been shown but while it's still mostly transparent.&lt;br /&gt;&lt;br /&gt;The only script.aculo.us hook that will fire at this point is afterUpdate, but it's also going to fire on every animation.&lt;br /&gt;&lt;br /&gt;Enter some metaprogramming.  Define a afterUpdate that cleans up after itself:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;new Effect.Appear( this.details_div, {duration:.5, &lt;br /&gt;    afterUpdate : function(){&lt;br /&gt;        FooManager.adjustScroll();&lt;br /&gt;        this.afterUpdate = undefined;&lt;br /&gt;    }&lt;br /&gt;});&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This works like a champ.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-6675738495693359183?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=fgcD0lT5TMo:qWVq6MgrO3M:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=fgcD0lT5TMo:qWVq6MgrO3M:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=fgcD0lT5TMo:qWVq6MgrO3M:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=fgcD0lT5TMo:qWVq6MgrO3M:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=fgcD0lT5TMo:qWVq6MgrO3M:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=fgcD0lT5TMo:qWVq6MgrO3M:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=fgcD0lT5TMo:qWVq6MgrO3M:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/fgcD0lT5TMo" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/fgcD0lT5TMo/metaprogramming-in-wild-scriptaculous.html</link><author>noreply@blogger.com (Steve)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2007/10/metaprogramming-in-wild-scriptaculous.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-8146501511980384509</guid><pubDate>Tue, 25 Sep 2007 18:35:00 +0000</pubDate><atom:updated>2007-09-25T14:01:16.005-05:00</atom:updated><title>All Code is Business Logic</title><description>Worse than Failure really hit it out of the park with &lt;a href="http://worsethanfailure.com/Articles/The-Mythical-Business-Layer.aspx"&gt;The Mythical Business Layer&lt;/a&gt;.  It's a great article that makes the point that developers don't like solving the boring old business problems, so they transform them into big "enterprise" problems that are fun and challenging to solve ... with disastrous results.&lt;br /&gt;&lt;br /&gt;If you want to be successful, stop thinking about yourself and start thinking about your customers.  This is not a new concept - Dale Carnegie &lt;a href="http://www.amazon.com/How-Win-Friends-Influence-People/dp/0671027034/ref=pd_bbs_sr_1/104-0421833-1819163?ie=UTF8&amp;s=books&amp;qid=1190746438&amp;sr=8-1"&gt;figured this is out 1937&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-8146501511980384509?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=dYcsQXqqA94:UuBn0x2cNAo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=dYcsQXqqA94:UuBn0x2cNAo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=dYcsQXqqA94:UuBn0x2cNAo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=dYcsQXqqA94:UuBn0x2cNAo:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=dYcsQXqqA94:UuBn0x2cNAo:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=dYcsQXqqA94:UuBn0x2cNAo:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=dYcsQXqqA94:UuBn0x2cNAo:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/dYcsQXqqA94" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/dYcsQXqqA94/all-code-is-business-logic.html</link><author>noreply@blogger.com (Steve)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2007/09/all-code-is-business-logic.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-4537762201081157506</guid><pubDate>Tue, 18 Sep 2007 15:14:00 +0000</pubDate><atom:updated>2007-09-18T12:52:24.265-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">javascript</category><title>Undo isn't easy</title><description>Aza Raskin says &lt;a href="http://humanized.com/weblog/2007/09/14/undo-made-easy-with-ajax-part-1/"&gt;undo for web apps is easy&lt;/a&gt;.  *cough bullshit cough* I completely agree with Aza's overriding premise: undo is a lot better than a warning.  This makes his current article that much more frustrating - he's using an incorrect argument to champion a correct idea.  Kind of like saying &lt;a href="http://www.bigdumbdev.com/2007/07/programmer-are-expensive-cpus-are-cheap.html"&gt;performance doesn't matter because CPUs are cheep&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So, to the point.  Aza argues that you should use undo instead of warning because undo is, despite the prevailing opinions on the subject, easy to do in web apps.  This is just plain wrong - a general solution to undo in AJAX web apps is a hard problem.  He's off the tracks quickly:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;In this series of blog posts, my goal is to explain just how easy it is to provide Undo functionality&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;So, you need a series of posts to show how easy something is.  Ok, if it's so easy, why does it take a series of posts?&lt;br /&gt;&lt;br /&gt;Next, Aza deploys a commonly used (and completely incorrect) approach to prove his point: he offers up one specific example where his conjecture holds.  This is about as clever as saying "Everyone drives a Honda.  See, I drive a Honda".  To prove that undo is easy, you can't just show that in one specific example it is easy, you have to show that it is easy in all situations.  &lt;a href="http://humanized.com/weblog/2007/09/14/undo-made-easy-with-ajax-part-1/#comments"&gt;The comments&lt;/a&gt; are ample proof that there are scenarios where a solution is tricky.&lt;br /&gt;&lt;br /&gt;Aza continues, either out of ignorance or religious devotion, to defend his position by pointing out that his example is only valid in a specific, simple scenario.  This amounts to defending your position by agreeing you are wrong.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-4537762201081157506?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=jXu3pNaNBcQ:vQ3OoytwEyU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=jXu3pNaNBcQ:vQ3OoytwEyU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=jXu3pNaNBcQ:vQ3OoytwEyU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=jXu3pNaNBcQ:vQ3OoytwEyU:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=jXu3pNaNBcQ:vQ3OoytwEyU:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=jXu3pNaNBcQ:vQ3OoytwEyU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=jXu3pNaNBcQ:vQ3OoytwEyU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/jXu3pNaNBcQ" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/jXu3pNaNBcQ/undo-isnt-easy.html</link><author>noreply@blogger.com (Steve)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2007/09/undo-isnt-easy.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-4357283692556995229</guid><pubDate>Tue, 18 Sep 2007 11:30:00 +0000</pubDate><atom:updated>2007-09-18T06:57:50.845-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">javascript</category><title>Using a default params hash :: Avoiding defaulting with ||</title><description>I saw &lt;a href="http://feeds.feedburner.com/~r/ajaxian/~3/157585808/douglas-crockfords-elements-of-javascript-style"&gt;mention of Crockford's javascript style recommendations&lt;/a&gt; yesterday.  I'm a big fan.  One pattern, though, that I have begun generally avoid is using the || operator to specify default values.  Consider this code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;function doStuff(params){&lt;br /&gt;  params = params || {};&lt;br /&gt;  var foo = params.foo || 'fooValue';&lt;br /&gt;  var bar = params.bar || 'barValue';&lt;br /&gt;  ...&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I love how clean this pattern is.  The API is flexible and it reads very easily.  Unfortunately, there is a very subtle bug - you can't pass in values that are falsy because || uses type coercion.  So this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;function doStuff(foo){&lt;br /&gt;  foo = foo || 'foo not specified';&lt;br /&gt;  alert( foo );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;foo( '' );&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;will give you 'foo not specified' when the intent was to use an empty string.  You can only rely on the default operator when falsy values cannot be valid values.&lt;br /&gt;&lt;br /&gt;I have begun to use a default hash pattern I first saw in Ruby on Rails code (and is also used extensively in script.aculo.us):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;function doStuff(params){&lt;br /&gt;  params = params || {};&lt;br /&gt;  var default = { foo : 'fooDefault', bar : 'barDefault'};&lt;br /&gt;  params = merge( defaults, params );&lt;br /&gt;&lt;br /&gt;  alert( params.foo );&lt;br /&gt;};&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This will give you what you want.&lt;br /&gt;&lt;br /&gt;Here here an example merge function:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;function merge(ontoObj, fromObj){&lt;br /&gt;    for( var i in fromObj ){&lt;br /&gt;        if(!fromObj.hasOwnProperty(i))&lt;br /&gt;            continue;&lt;br /&gt;        ontoObj[i] = fromObj[i];&lt;br /&gt;    }&lt;br /&gt;    return ontoObj;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-4357283692556995229?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=yiAN4mMP61c:nyrSVDI1KUI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=yiAN4mMP61c:nyrSVDI1KUI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=yiAN4mMP61c:nyrSVDI1KUI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=yiAN4mMP61c:nyrSVDI1KUI:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=yiAN4mMP61c:nyrSVDI1KUI:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=yiAN4mMP61c:nyrSVDI1KUI:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=yiAN4mMP61c:nyrSVDI1KUI:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/yiAN4mMP61c" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/yiAN4mMP61c/using-default-params-hash-avoiding.html</link><author>noreply@blogger.com (Steve)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2007/09/using-default-params-hash-avoiding.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-1662524635214664563</guid><pubDate>Thu, 13 Sep 2007 16:00:00 +0000</pubDate><atom:updated>2007-09-13T15:52:43.332-05:00</atom:updated><title>replaceHTML - remove, insert, put back is better</title><description>** Updated **&lt;br /&gt;Steven put up &lt;a href="http://stevenlevithan.com/demo/replaceHtml2.html"&gt;another speed demo&lt;/a&gt; that demonstrates that replaceHtml is in fact faster than the remove-update-replace method, though not by nearly the same gap as innerHTML.&lt;br /&gt;*************&lt;br /&gt;&lt;br /&gt;Read an &lt;a href="http://ajaxian.com/archives/replacehtml-for-when-innerhtml-dogs-you-down"&gt;piece on Ajaxian&lt;/a&gt; this morning covering &lt;a href="http://blog.stevenlevithan.com/archives/faster-than-innerhtml"&gt;Steven Levithan's replaceHTML&lt;/a&gt; post on innerHTML being too slow and offering a replaceHtml alternative that is much faster.  It works by creating a new element, using innerHTML on it, then replacing the existing node with the new node.  Here is the code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;/* This is much faster than using (el.innerHTML = value) when there are many&lt;br /&gt;existing descendants, because in some browsers, innerHTML spends much longer&lt;br /&gt;removing existing elements than it does creating new ones. */&lt;br /&gt;function replaceHtml(el, html) {&lt;br /&gt; var oldEl = (typeof el === "string" ? document.getElementById(el) : el);&lt;br /&gt; /*@cc_on // Pure innerHTML is slightly faster in IE&lt;br /&gt; oldEl.innerHTML = html;&lt;br /&gt; return oldEl;&lt;br /&gt; @*/&lt;br /&gt; var newEl = oldEl.cloneNode(false);&lt;br /&gt; newEl.innerHTML = html;&lt;br /&gt; oldEl.parentNode.replaceChild(newEl, oldEl);&lt;br /&gt; /* Since we just removed the old element from the DOM, return a reference&lt;br /&gt; to the new element, which can be used to restore variable references. */&lt;br /&gt; return newEl;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This is a lot faster, but there really isn't any need to create a new node.  The reason the method is so much faster is due to using innerHTML on an element that is not in the DOM vs. one that is in the DOM.  Instead of creating a new node and deleting the old one, you can just take the node out of the DOM, use innerHTML, and then put it back.  This has the added benefit of not invalidating any existing references to your element.  &lt;br /&gt;&lt;br /&gt;I whipped up an example to compare the differences.  I generated an HTML string with 15,000 elements and used three different methods for updating a a div to this content - innerHTML, removing the node before innerHTML, and then the replaceHtml function.  I did each four times and profiled with Firebug.  Here is the script:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;var html = [];&lt;br /&gt;for( var i = 0; i &lt; 15000;i++ )&lt;br /&gt;{&lt;br /&gt; html.push("&amp;lt;span&amp;gt;CONTENT&amp;lt;/span&amp;gt;");&lt;br /&gt;}&lt;br /&gt;html = html.join("");&lt;br /&gt;var el = document.getElementById("div");&lt;br /&gt;el.innerHTML = html;&lt;br /&gt;function doit(){&lt;br /&gt; withoutRemove(el, html);&lt;br /&gt; withRemove(el,html);&lt;br /&gt; el = replaceHtml(el, html);&lt;br /&gt; withoutRemove(el, html);&lt;br /&gt; withRemove(el,html);&lt;br /&gt; el = replaceHtml(el, html);&lt;br /&gt; withoutRemove(el, html);&lt;br /&gt; withRemove(el,html);&lt;br /&gt; el = replaceHtml(el, html);&lt;br /&gt; withoutRemove(el, html);&lt;br /&gt; withRemove(el,html);&lt;br /&gt; el = replaceHtml(el, html); &lt;br /&gt;}&lt;br /&gt;function withoutRemove(el,html){&lt;br /&gt; el.innerHTML = html;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function withRemove(el,html){&lt;br /&gt; var nextSibling = el.nextSibling;&lt;br /&gt; var parent = el.parentNode;&lt;br /&gt; parent.removeChild(el);&lt;br /&gt; el.innerHTML = html;&lt;br /&gt; if(nextSibling)&lt;br /&gt;  parent.insertBefore(el,nextSibling)&lt;br /&gt; else&lt;br /&gt;  parent.appendChild(el);&lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;function replaceHtml(el, html) {&lt;br /&gt; var oldEl = el;&lt;br /&gt; /*@cc_on // Pure innerHTML is slightly faster in IE&lt;br /&gt; oldEl.innerHTML = html;&lt;br /&gt; return oldEl;&lt;br /&gt; @*/&lt;br /&gt; var newEl = oldEl.cloneNode(false);&lt;br /&gt; newEl.innerHTML = html;&lt;br /&gt; oldEl.parentNode.replaceChild(newEl, oldEl);&lt;br /&gt; /* Since we just removed the old element from the DOM, return a reference&lt;br /&gt; to the new element, which can be used to restore variable references. */&lt;br /&gt; return newEl;&lt;br /&gt;}; &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And here are the results:&lt;br /&gt;&lt;br /&gt;Method          Average Time&lt;br /&gt;-------------   ------------&lt;br /&gt;withoutRemove   4914.063ms&lt;br /&gt;replaceHtml     656.25ms&lt;br /&gt;withRemove      601.563ms&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-1662524635214664563?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=v6FLNoAv4dI:27lXFhW-8sc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=v6FLNoAv4dI:27lXFhW-8sc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=v6FLNoAv4dI:27lXFhW-8sc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=v6FLNoAv4dI:27lXFhW-8sc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=v6FLNoAv4dI:27lXFhW-8sc:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=v6FLNoAv4dI:27lXFhW-8sc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=v6FLNoAv4dI:27lXFhW-8sc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/v6FLNoAv4dI" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/v6FLNoAv4dI/replacehtml-remove-insert-put-back-is.html</link><author>noreply@blogger.com (Steve)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2007/09/replacehtml-remove-insert-put-back-is.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-2215840961446859772</guid><pubDate>Wed, 12 Sep 2007 20:34:00 +0000</pubDate><atom:updated>2007-09-12T16:15:02.265-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">javascript</category><title>using innerHTML with DOM methods</title><description>I tend to prefer to generate content following this pattern:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;var html = [];&lt;br /&gt;html.push('&amp;lt;h1&amp;gt;CONTENT!&amp;lt;/h1&amp;gt;more content...');&lt;br /&gt;...&lt;br /&gt;el.innerHTML = html.join('');&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;In most cases in most browsers this is the fastest way to create markup it's a lot easier to grock the markup this way verses using DOM methods.&lt;br /&gt;&lt;br /&gt;One issue I have with the approach is that you need a 'hook' element to dump the html into.  This leads to a lot of empty nodes sitting around waiting for script to innerHTML them.  Eventually, I stumbled on a way to avoid the hook elements and still have my innerHTML.&lt;br /&gt;&lt;br /&gt;The key is to create a temp element&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;var temp = document.createElement('p');&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;us it to parse an html string&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;temp.innerHTML = '&amp;lt;h1&amp;gt;content!...&amp;lt;/h1&amp;gt;';&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;then using DOM methods to insert the content&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;while( temp.childNodes.length &gt; 0 )&lt;br /&gt;  el.parentNode.insertBefore(temp.childNodes[0], el);&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Example:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;var html = "&amp;lt;div&amp;gt;A lot of content...&amp;lt;/div&amp;gt;";&lt;br /&gt;var temp = document.createElement('p');&lt;br /&gt;temp.innerHTML = html;&lt;br /&gt;var el = document.getElementById('idOfElementToInsertBefore');&lt;br /&gt;while( temp.childNodes.length &gt; 0 )&lt;br /&gt;  el.parentNode.insertBefore(temp.childNodes[0], el);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-2215840961446859772?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=qqD41u1rtxI:v2MBeaBEj2c:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=qqD41u1rtxI:v2MBeaBEj2c:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=qqD41u1rtxI:v2MBeaBEj2c:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=qqD41u1rtxI:v2MBeaBEj2c:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=qqD41u1rtxI:v2MBeaBEj2c:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=qqD41u1rtxI:v2MBeaBEj2c:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=qqD41u1rtxI:v2MBeaBEj2c:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/qqD41u1rtxI" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/qqD41u1rtxI/using-innerhtml-with-dom-methods.html</link><author>noreply@blogger.com (Steve)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2007/09/using-innerhtml-with-dom-methods.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-5332396760379246432</guid><pubDate>Wed, 05 Sep 2007 20:58:00 +0000</pubDate><atom:updated>2008-12-13T02:10:09.674-06:00</atom:updated><title>5 truths about web users</title><description>&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;1. Users don't care if you have an awesome build script.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Does the gmail development team have a continuous integration process?  Does Expedia.com's development team have full unit-test coverage for all their code?  Can Linked In deploy the website by pushing one button?&lt;br /&gt;&lt;br /&gt;I don't know and am still one of millions of happy customers.&lt;br /&gt;&lt;br /&gt;A kick ass environment can really help you build a great product - but it won't build it for you.  People tend to focus on problems they are comfortable with to avoid the really hard problem.  Like setting up a great environment instead of creating a great product that people love to use.&lt;br /&gt;&lt;br /&gt;Worry about having a great product before you worry about your development environment.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;2. Users have more than a LAN between their browser and your servers.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I am in the middle of building the latest and greatest.  The main page has 15 uncompressed javascript files, 10 background gifs, a couple of extra css files, and sends almost half a meg of data to render the page.  It takes about a second for all of this to show up in my browser.&lt;br /&gt;&lt;br /&gt;Of course, my browser is sitting on the server, and I've got endless RAM and multiple processors.&lt;br /&gt;&lt;br /&gt;When I put this on a test server and hit it from home through DSL, the cloud, and our shared pipe at work - a second becomes over 10 seconds.  Long enough that I check ESPN for any new football news.&lt;br /&gt;&lt;br /&gt;Having a slow app is like building a car with doors that don't open.  People won't buy a car if they have to crawl through the window to get in.&lt;br /&gt;&lt;br /&gt;Put your app on an external server and hit it with consumer-grade net access.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;3. Masturbatory animation only satisfies the developer.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I need tabs.  I know how to use multiple animation frameworks. Hell, I can roll my own animation!   So my tabs animate, rotate, morph, slide, and fade.  YEAH.&lt;br /&gt;&lt;br /&gt;Here is what I think:&lt;br /&gt;&lt;blockquote&gt;Ooh, my tabs rotate, change color, animate, and play a sound when you hover over them.  That's SOOO HOT!&lt;br /&gt;&lt;/blockquote&gt;Here is what my users think:&lt;br /&gt;&lt;blockquote&gt;What the shit!&lt;br /&gt;&lt;/blockquote&gt;Don't do anything just because you can - it will just get in the way.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;4. Users don't know flash or html.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Check out &lt;a href="http://www.aricalanphotography.com/"&gt;this photographer's site&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_9Z9ptEnpp-A/Rt-CExUXl4I/AAAAAAAAABU/QOa8PU4r2tY/s1600-h/Picture+1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_9Z9ptEnpp-A/Rt-CExUXl4I/AAAAAAAAABU/QOa8PU4r2tY/s400/Picture+1.png" alt="" id="BLOGGER_PHOTO_ID_5106943520931288962" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Here is what the developer thinks:&lt;br /&gt;&lt;blockquote&gt;HTML and Flash - I'm giving my users the best of both worlds!&lt;/blockquote&gt;Here is what the average user thinks:&lt;br /&gt;&lt;blockquote&gt;What the shit!&lt;/blockquote&gt;When your application asks users a question, first ask yourself "do I really need to ask?"  If you do, ask yourself "would my mom know how to answer that question?"  If they answer is no, rethink your solution.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;5. You users will not print out you home page, frame it, and hang it on their wall.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Your application is not art.  Users do not care if it "pops" or "looks hot".  Users care that it does what they expect when they click a link.  Users care that they can use the app without having to constantly think "how do I do that?".  Users &lt;span style="font-weight: bold;"&gt;really&lt;/span&gt; care when you app makes their lives easier.&lt;br /&gt;&lt;br /&gt;Don't worry how your app looks hanging on your wall, worry about how happy your users are.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-5332396760379246432?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=4ACmup9uQR8:f6D7zKf9pCg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=4ACmup9uQR8:f6D7zKf9pCg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=4ACmup9uQR8:f6D7zKf9pCg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=4ACmup9uQR8:f6D7zKf9pCg:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=4ACmup9uQR8:f6D7zKf9pCg:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=4ACmup9uQR8:f6D7zKf9pCg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=4ACmup9uQR8:f6D7zKf9pCg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/4ACmup9uQR8" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/4ACmup9uQR8/5-truths-about-web-users.html</link><author>noreply@blogger.com (Steve)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_9Z9ptEnpp-A/Rt-CExUXl4I/AAAAAAAAABU/QOa8PU4r2tY/s72-c/Picture+1.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2007/09/5-truths-about-web-users.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-497756590711962669</guid><pubDate>Mon, 27 Aug 2007 22:46:00 +0000</pubDate><atom:updated>2007-08-28T07:41:57.920-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">javascript</category><category domain="http://www.blogger.com/atom/ns#">adobe air</category><title>Simple, synchronous AIR configuration</title><description>I've spent some time the last couple of weeks poking around with AIR.  The Adobe Integrated Runtime promises to let you build desktop applications using Javascript.  Basically, it gives you Webkit and a series of APIs you can access through the window.runtime object that provide all sorts of things like access to the file system, drag and drop, and a SQL Lite database.  You can also use Flash and Flex, but I'm not smart enough for that.  I ended up trying to build a persistent key/value configuration system and quickly ran into a frustrating reality of AIR's SQL API - everything is asynchronous.  This makes using the DB for storing configuration frustratingly convoluted.&lt;br /&gt;&lt;br /&gt;You have a simple config table - key:string, value:string.  Say you want to read the value for the key "foo".  You end up with code that looks something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;var stmt = new air.SQLStatement();&lt;br /&gt;stmt.sqlConnection = conn;&lt;br /&gt;stmt.text = "select value from config where key = :key";&lt;br /&gt;stmt.parameters[":key"] = "foo";&lt;br /&gt;stmt.addEventListener(air.SQLEvent.RESULT, function(){&lt;br /&gt;  var fooValue = stmt.getResults().data[0];&lt;br /&gt;  doStuffWithFoo...&lt;br /&gt;});&lt;br /&gt;stmt.execute();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Which makes me throw up in my mouth a little bit.  I want to do something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;var fooValue = getConfig("foo");&lt;br /&gt;doStuffWithFoo...&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;But that damned async call just keeps getting in the way.&lt;br /&gt;&lt;br /&gt;Adobe &lt;a href="http://www.adobe.com/cfusion/webforums/forum/messageview.cfm?forumid=72&amp;catid=641&amp;threadid=1276219&amp;highlight_key=y&amp;keyword1=synchronous%20SQL#4613396" &gt;hasn't committed&lt;/a&gt; to building this yet "because of the development effort it would require".  My thoughts on that can be summed up in my previous post: &lt;a href="http://www.bigdumbdev.com/2007/07/programmer-are-expensive-cpus-are-cheap.html"&gt; "Programmers are expensive, CPUs are cheap" does not justify rapid development of slow code&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So, I wrote some convoluted code, scream "fuck this shit!" a couple of time, and wrote a little utility to provide a synchronous API - the Big Dumb Javascript AIR Configuration.  To install, include Configuration.js:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;script src="Configuration.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You then have to initialized the configuration system.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;BigDumbDev.Configuration.init( function(){ air.trace('configuration ready'); } );&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Reading and writing configs goes like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;BigDumbDev.Configuration.getConfig('key');&lt;br /&gt;&lt;br /&gt;BigDumbDev.Configuration.setConfig('key', 'value');&lt;br /&gt;&lt;br /&gt;BigDumbDev.Configuration.removeConfig('key');&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Sets and removes are immediately available, so you can do this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;BigDumbDev.Configuration.setConfig('foo','bar');&lt;br /&gt;var foo = BigDumbDev.Configuration.getConfig('foo');&lt;br /&gt;// foo is bar&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;You can see all the details in &lt;a href="http://designvigilante.com/files/AirConfig/Configuration.js"&gt;the source code&lt;/a&gt;.  There is no magic - it still does the DB calls asynchronously.  I cache the config values and read from the cache.  Update change the cache and then kick of the async call to update the database.&lt;br /&gt;&lt;br /&gt;You can download a &lt;a href="http://designvigilante.com/files/AirConfig/AirConfig.zip"&gt;sample AIR app&lt;/a&gt; that utilizes the system.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-497756590711962669?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=fzJjvd2xOyM:F5YCUK1MePc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=fzJjvd2xOyM:F5YCUK1MePc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=fzJjvd2xOyM:F5YCUK1MePc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=fzJjvd2xOyM:F5YCUK1MePc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=fzJjvd2xOyM:F5YCUK1MePc:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=fzJjvd2xOyM:F5YCUK1MePc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=fzJjvd2xOyM:F5YCUK1MePc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/fzJjvd2xOyM" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/fzJjvd2xOyM/simple-synchronous-air-configuration.html</link><author>noreply@blogger.com (Steve)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2007/08/simple-synchronous-air-configuration.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-1738622829865956707</guid><pubDate>Wed, 22 Aug 2007 13:18:00 +0000</pubDate><atom:updated>2007-08-22T08:26:04.848-05:00</atom:updated><title>Dynamic image resizing</title><description>I found this &lt;a href="http://www.youtube.com/watch?v=vIFCV2spKtg"&gt;image resizing software&lt;/a&gt; on &lt;a href="http://wonko.com/article/542"&gt;wonko&lt;/a&gt; this morning.  That's pretty awesome.  I wonder how long before I can use that with image magick...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-1738622829865956707?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=REZ-3Dm4J1Q:FI_4-bQRF5g:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=REZ-3Dm4J1Q:FI_4-bQRF5g:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=REZ-3Dm4J1Q:FI_4-bQRF5g:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=REZ-3Dm4J1Q:FI_4-bQRF5g:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=REZ-3Dm4J1Q:FI_4-bQRF5g:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=REZ-3Dm4J1Q:FI_4-bQRF5g:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=REZ-3Dm4J1Q:FI_4-bQRF5g:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/REZ-3Dm4J1Q" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/REZ-3Dm4J1Q/dynamic-image-resizing.html</link><author>noreply@blogger.com (Steve)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2007/08/dynamic-image-resizing.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-9147407445699028471</guid><pubDate>Tue, 14 Aug 2007 15:29:00 +0000</pubDate><atom:updated>2007-08-14T11:59:04.527-05:00</atom:updated><title>Web development and the iPhone revisited</title><description>I read a great post over at &lt;a href="http://www.ajaxperformance.com"&gt;Ajax Performance&lt;/a&gt; &lt;a href="http://www.ajaxperformance.com/2007/06/24/in-defense-of-ajax-for-the-iphone/"&gt;defending AJAX as the iPhone development environment&lt;/a&gt;.  This reminded me of &lt;a href="http://www.bigdumbdev.com/2007/07/steve-jobs-gives-iphinger-to-mac.html"&gt;my own take&lt;/a&gt; during the iPhone brouhaha, and I decided I had a little more to say.&lt;br /&gt;&lt;br /&gt;Web development is has come a long way, but building a local app still has a lot of advantages.  But, hey, when the first cars came out, horses were still a lot better.  Apple didn't decide on AJAX because you can build cooler apps - they decided on it because it is the future, it is where the talent goes, and because &lt;a href="http://finance.yahoo.com/q/bc?s=MSFT&amp;t=my&amp;l=on&amp;z=m&amp;q=l&amp;c="&gt;the horse business hasn't done much for Microsoft the last decade&lt;/a&gt;.  Google has managed to become the &lt;a href="http://www.gizmag.com/go/7385/"&gt;most valuable brand in the world&lt;/a&gt; without an OS and a native API.  &lt;br /&gt;&lt;br /&gt;Apple is obviously committed to this - they were willing to &lt;a href="http://www.downloadsquad.com/2007/08/13/mobile-minute-iphone-apis-are-like-life-theyre-full-of-compr/"&gt;pay the price of&lt;/a&gt; not bothering with an native API.  Time spent with a Cocoa iPhone is time not spent making the web better.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-9147407445699028471?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=kFlR6TXtz74:nLRIvkz8P8I:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=kFlR6TXtz74:nLRIvkz8P8I:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=kFlR6TXtz74:nLRIvkz8P8I:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=kFlR6TXtz74:nLRIvkz8P8I:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=kFlR6TXtz74:nLRIvkz8P8I:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=kFlR6TXtz74:nLRIvkz8P8I:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=kFlR6TXtz74:nLRIvkz8P8I:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/kFlR6TXtz74" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/kFlR6TXtz74/web-development-and-iphone-revisited.html</link><author>noreply@blogger.com (Steve)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2007/08/web-development-and-iphone-revisited.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-4408082956739854612</guid><pubDate>Mon, 13 Aug 2007 03:42:00 +0000</pubDate><atom:updated>2007-08-12T22:52:08.640-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ruby</category><title>Build a better skimmer - part 2</title><description>We saw in &lt;a href="http://www.bigdumbdev.com/2007/08/build-better-gallery-skimmer-part-1.html"&gt;part 1&lt;/a&gt; that we can build a more efficient skimming implementation by using a "film strip" image instead of a bunch of single images.  For my example, I built the filmstrip by hand - it sucked.  So, I whipped up a quick ruby script for creating a filmstrip of all the jpg's in a directory.  If you don't already have RMagick installed, you can find instructions for installing it on the &lt;a href="http://rmagick.rubyforge.org/"&gt;RMagick Homepage&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The script first crops the images to 160x160, then creates a vertical strip using RMagick's montage functionality.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;br /&gt;require 'rubygems'&lt;br /&gt;require 'RMagick'&lt;br /&gt;&lt;br /&gt;files = Dir['*.jpg']&lt;br /&gt;imageList = Magick::ImageList.new&lt;br /&gt;numImages = 0&lt;br /&gt;files.each do |file|&lt;br /&gt;  unless file == 'filmStrip.jpg'&lt;br /&gt;    puts "adding #{file}"&lt;br /&gt;    img = Magick::Image.read(file)[0]&lt;br /&gt;    img.crop_resized!(160,160)&lt;br /&gt;    imageList &amp;lt;&amp;lt; img&lt;br /&gt;    numImages = numImages + 1&lt;br /&gt;  end&lt;br /&gt;end  &lt;br /&gt;&lt;br /&gt;filmStrip = imageList.montage do&lt;br /&gt;  self.geometry = "160x160+0+0"&lt;br /&gt;  self.tile = "1x#{numImages}"&lt;br /&gt;end&lt;br /&gt;  &lt;br /&gt;filmStrip.write('filmStrip.jpg')&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-4408082956739854612?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=pcZB4i3ELqY:i4uZE3qQRUs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=pcZB4i3ELqY:i4uZE3qQRUs:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=pcZB4i3ELqY:i4uZE3qQRUs:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=pcZB4i3ELqY:i4uZE3qQRUs:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=pcZB4i3ELqY:i4uZE3qQRUs:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=pcZB4i3ELqY:i4uZE3qQRUs:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=pcZB4i3ELqY:i4uZE3qQRUs:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/pcZB4i3ELqY" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/pcZB4i3ELqY/build-better-skimmer-part-2.html</link><author>noreply@blogger.com (Steve)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2007/08/build-better-skimmer-part-2.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-7219443438466412754</guid><pubDate>Sat, 11 Aug 2007 04:04:00 +0000</pubDate><atom:updated>2008-12-13T02:10:10.378-06:00</atom:updated><title>Build a better gallery skimmer - part 1</title><description>&lt;script type="text/javascript"&gt;digg_url='http://www.bigdumbdev.com/2007/08/build-better-gallery-skimmer-part-1.html';&lt;/script&gt;&lt;br /&gt;&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;Apple's web developers could do better.  This is the first entry in a big dumb effort to implement a faster and more efficient version of Apple's new skimming functionality than their current .mac gallery implementation.&lt;br /&gt;&lt;br /&gt;You have probably seen Apple's new &lt;a href="http://gallery.mac.com/emily_parker"&gt;gallery preview skimming functionality&lt;/a&gt;.  This is really cool.  Surprisingly, though, the implementation is rather pedestrian.  15 seconds with firebug and it's clear - Apple sure doesn't care about doing this efficiently.  Maybe they &lt;a href="http://www.bigdumbdev.com/2007/07/programmer-are-expensive-cpus-are-cheap.html"&gt;saved a few weeks developing this&lt;/a&gt;, but that demo site takes almost 1 minute to load - on my PowerBook G4 over DSL.  But, if they did care about speeding it up and just ran out of time, wouldn't they have at least stripped all the whitespace and comments out of their javascript?  Here are the last 128 lines from the main gallery.js:&lt;br /&gt;&lt;br /&gt;&lt;div style="height:200px; overflow:auto;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="javascript"&gt;&lt;br /&gt;/*&lt;br /&gt;&lt;br /&gt;require('core');&lt;br /&gt;&lt;br /&gt;Gallery.WebWidgetPanel = Mac.FormView.extend({&lt;br /&gt; isPanel: true,&lt;br /&gt; outlets: ["widgetCode", "photo", "reflection", "flash", "lTitle", 'lInstructionalText', 'lCopySnippetLink', 'lDoneButton'],&lt;br /&gt; widgetCode: ".widgetCode?",&lt;br /&gt; widgetTag: "",&lt;br /&gt;&lt;br /&gt; lTitle : Mac.LabelView.extend({localize:true}).outletFor(".lTitle?"),&lt;br /&gt; lInstructionalText : Mac.LabelView.extend({localize:true}).outletFor(".lInstructionalText?"),&lt;br /&gt; lCopySnippetLink : Mac.LabelView.extend({localize:true}).outletFor(".lCopySnippetLink?"),&lt;br /&gt; lDoneButton : Mac.LabelView.extend({&lt;br /&gt; localize:true,&lt;br /&gt; toolTip: "_VisitorExperience.AlbumOptions.WebWidget.Done.Button.Tooltip"&lt;br /&gt; }).outletFor(".lDoneButton?"),&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; flash: ".flash?",&lt;br /&gt;&lt;br /&gt; getSmallest: function() {&lt;br /&gt; if (Gallery.albumController.get("videoSmall"))&lt;br /&gt; {&lt;br /&gt; return Gallery.albumController.get("videoSmall");&lt;br /&gt; }&lt;br /&gt; else&lt;br /&gt; if (Gallery.albumController.get("videoMedium"))&lt;br /&gt; {&lt;br /&gt; return Gallery.albumController.get("videoMedium");&lt;br /&gt; }&lt;br /&gt; else&lt;br /&gt; {&lt;br /&gt; return Gallery.albumController.get("videoLarge");&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; },&lt;br /&gt;&lt;br /&gt; generateData: function ()&lt;br /&gt; {&lt;br /&gt;&lt;br /&gt; if(Gallery.detailView().isVideo &amp;&amp; Gallery.detailView().showOnIndex) {&lt;br /&gt; var height= Gallery.albumController.get("thumbImageHeight") + 16;&lt;br /&gt; var width = 320;&lt;br /&gt; var noScript = false;&lt;br /&gt; var widgetID = 'galleryWidget_' + Math.floor(Math.random() * 100000);&lt;br /&gt; var widgetAlbumTitle = Gallery.albumController.get("title");&lt;br /&gt; var widgetAlbumURL = Gallery.albumController.get("url");&lt;br /&gt; var widgetPosterImg = Gallery.albumController.get("medium");&lt;br /&gt; var widgetMovieURL = this.getSmallest();&lt;br /&gt; var styleTxt ="&amp;lt;style type=\"text/css\" media=\"screen\"&amp;gt;.widget_header a { color: white ! important; display: block; text-align: center; font-size: 11px ! important; font-family: \"Helvetica Neue\", helvetica; text-decoration:none ! important; background:transparent url('http://gallery.mac.com/g/flash/gall_link_arrow.png') no-repeat scroll top right; padding-top: 3px; padding-bottom: 0px; padding-right: 16px; margin-right: 0px; height: 12px; padding-left: 5px; text-overflow: ellipsis; overflow: hidden; } .widget_header:hover a { text-decoration: underline ! important; color: white; background-image: url('http://gallery.mac.com/g/flash/gall_link_arrow_on.png'); } .widget_header { overflow: hidden; text-overflow: ellipsis; background: black url('http://gallery.mac.com/g/flash/gallery_widget_bg.png') repeat-x scroll top center; height: 20px; width: 100%; display: block; top: 0px; z-index: 4; cursor: pointer; } .widget_header a{ } .movie_div { display:block; z-index: 1; position: absolute; top: 20px; left: 0px; cursor: pointer; background-color: #000; } .movie_play_badge { width: 40px; height: 30px; position: absolute; left: 50%; margin-left: -20px; display: block; top: 50%; margin-top: -23px; background: transparent url('http://gallery.mac.com/g/flash/movie_play_bg.png') no-repeat top center; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='http://gallery.mac.com/g/flash/movie_play_bg.png'); } .qt_ctrls { background: transparent url('http://gallery.mac.com/g/flash/qt_control_left.gif') no-repeat top left; height: 16px; text-align: right; display:block; margin: 0px; }&amp;lt;/style&amp;gt;";&lt;br /&gt;&lt;br /&gt; var htmlTxt = '&amp;lt;div id=\"'+ widgetID+ '\" class=\"shared_movie\" style=\"text-align: center; width: ' + width + 'px; display:block; height: '+ (height + 22) + 'px; position: relative;\"&amp;gt;&amp;lt;div class=\"widget_header\"&amp;gt;&amp;lt;img src=\"http://gallery.mac.com/g/flash/gallery_logo.png\" width=\"21\" height=\"19\" alt=\".Mac Gallery\" style=\"float: left\" /&amp;gt;&amp;lt;a title=\"' + widgetAlbumTitle + '\" href=\"'+ widgetAlbumURL + '\" target=\"_blank\"&amp;gt;' + widgetAlbumTitle + '&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div id=\"movieDiv\" class=\"movie_div\" &amp;gt;&amp;lt;a id=\"movieLink\" class=\"movie_link\" href=\"'+ widgetAlbumURL + '/' + widgetMovieURL + '\" target=\"_blank\"&amp;gt;&amp;lt;img id=\"playBadge\" class=\"movie_play_badge\" src=\"http://gallery.mac.com/g/flash/movie_play_badge.png\" border=\"0\" width=\"40\" height=\"30\" alt=\"Play Movie\" /&amp;gt;&amp;lt;img class=\"movie_poster\" id=\"moviePoster\" src=\"' + widgetPosterImg + '" width=\"320\" alt=\"\" border=\"0\" style=\"padding: 0px; margin: 0px\"/&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;div class=\"qt_ctrls\" id=\"qtCtrls\"&amp;gt;&amp;lt;img src=\"http://gallery.mac.com/g/flash/qt_ctrl_right.gif\" width=\"57\" height=\"16\" alt=\"\" &amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;';&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; var scriptTxt = "&amp;lt;script src=\"http://gallery.mac.com/g/flash/gallery_moviewidget.js\" type=\"text/javascript\" charset=\"utf-8\"&amp;gt;&amp;lt;/script&amp;gt;&amp;lt;script type=\"text/javascript\" charset=\"utf-8\"&amp;gt; initWidget('"+ widgetAlbumURL +"','" + widgetMovieURL + "', 320, "+ height +", '"+ widgetID +"', true);&amp;lt;/script&amp;gt;";&lt;br /&gt;&lt;br /&gt; var source = Gallery.albumController.get("path");&lt;br /&gt;&lt;br /&gt; this.flash.innerHTML = styleTxt + htmlTxt;&lt;br /&gt;&lt;br /&gt; this.widgetTag = styleTxt + htmlTxt + scriptTxt;&lt;br /&gt; this.widgetCode.value = this.widgetTag;&lt;br /&gt;&lt;br /&gt; var links = this.flash.getElementsByTagName('a');&lt;br /&gt; for (i=0; i&amp;lt;links.length; i++){&lt;br /&gt; links[i].removeAttribute('href');&lt;br /&gt; links[i].setStyle({cursor: 'default'});&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; } else {&lt;br /&gt; this.widgetTag = this.createSnippetCode();&lt;br /&gt; this.flash.innerHTML = this.createSnippetCode(true);&lt;br /&gt; this.widgetCode.value = this.createSnippetCode();&lt;br /&gt; }&lt;br /&gt; },&lt;br /&gt;&lt;br /&gt; createSnippetCode: function(previewBool) {&lt;br /&gt; var height = 260;&lt;br /&gt; var width = 320;&lt;br /&gt; var source = Gallery.albumController.get("path");&lt;br /&gt; if (previewBool) {&lt;br /&gt; previewTxt = 'preview=true&amp;';&lt;br /&gt; } else {&lt;br /&gt; previewTxt = '';&lt;br /&gt; }&lt;br /&gt; var flashvars = previewTxt + 'feed=' + source + '?webdav-method=truthget&amp;depth=infinity&amp;feedfmt=atom&amp;widgetWidth=' + width + '&amp;widgetHeight=' + height;&lt;br /&gt; var widgetTag;&lt;br /&gt; widgetTag = '&amp;lt;object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0" width="'+width+'" height="'+height+'" id="photowidget" align="middle"&amp;gt;';&lt;br /&gt; widgetTag += '&amp;lt;param name="allowScriptAccess" value="always" /&amp;gt;';&lt;br /&gt; widgetTag += '&amp;lt;param name="movie" value="http://' + HOST + '/g/flash/photowidget.swf?def" /&amp;gt;';&lt;br /&gt; widgetTag += '&amp;lt;param name="quality" value="high" /&amp;gt;';&lt;br /&gt; widgetTag += '&amp;lt;param name="bgcolor" value="#000000" /&amp;gt;';&lt;br /&gt; widgetTag += '&amp;lt;param name="wmode" value="opaque" /&amp;gt;';&lt;br /&gt; widgetTag += '&amp;lt;param name="flashVars" value="' + flashvars + '" /&amp;gt;';&lt;br /&gt; widgetTag += '&amp;lt;embed src="http://' + HOST + '/g/flash/photowidget.swf?abab" quality="high" bgcolor="#000000" width="' + width + '" height="' + height + '" wmode="opaque" name="photowidget" align="middle" allowScriptAccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashVars="' + flashvars + '" /&amp;gt;';&lt;br /&gt; widgetTag += '&amp;lt;/object&amp;gt;';&lt;br /&gt; return widgetTag;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; },&lt;br /&gt;&lt;br /&gt; copyToClipboard: function()&lt;br /&gt; {&lt;br /&gt; var flashcopier = 'flashcopier';&lt;br /&gt; if(!document.getElementById(flashcopier)) {&lt;br /&gt; var divholder = document.createElement('div');&lt;br /&gt; divholder.id = flashcopier;&lt;br /&gt; document.body.appendChild(divholder);&lt;br /&gt; }&lt;br /&gt; document.getElementById(flashcopier).innerHTML = '';&lt;br /&gt; var divinfo = '&amp;lt;embed src="/g/flash/_clipboard.swf" FlashVars="clipboard='+escape(this.widgetTag)+'" width="0" height="0" type="application/x-shockwave-flash"&amp;gt;&amp;lt;/embed&amp;gt;';&lt;br /&gt; document.getElementById(flashcopier).innerHTML = divinfo;&lt;br /&gt; new Effect.Highlight(this.widgetCode, {duration: .5, startcolor: "#70b0ff", endcolor: "#ffffff" });&lt;br /&gt; },&lt;br /&gt;&lt;br /&gt; commitForm: function() {&lt;br /&gt; this.set("isVisible", false);&lt;br /&gt; this.style.display = '';&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;*/&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;That's right, it's one big comment!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Next up, images.  It requests a lot of them.  A LOT of them.  Here is a screenshot from firebug:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_9Z9ptEnpp-A/Rr073tCyVyI/AAAAAAAAAA8/wdyoKAjiMGc/s1600-h/perf.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_9Z9ptEnpp-A/Rr073tCyVyI/AAAAAAAAAA8/wdyoKAjiMGc/s400/perf.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5097296181423396642" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;That's right, 137 images.  Most of these (let's say 100) are 160x160 images for making the skim gallery effect.  Looking into the gallery code, the image is swapped by changing the src on an image.  This approach has some drawbacks:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;You're eating your net latency once for each image (divided by ~4, as the browser will request more than one at a time).  Even if you're latency is only 100ms, you've got 100 images / 4 threads * 100ms = 2500ms.  So, two and a half seconds eaten up in overhead.  This gets worse the farther away you are from the server (light is only so fast, after all). &lt;/li&gt;&lt;br /&gt;&lt;li&gt;You can do better than changing the source&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;A common web developer tool is to use one bigger image as a background to a smaller element and shift the position of the background to achieve some effect.  Example: &lt;a href="http://www.modxcms.com/simple-rounded-corner-css-boxes.html"&gt;rounded box borders&lt;/a&gt;.  We can use this here.  Instead of 20 images for each gallery, create one image per gallery that's 160px x 3200px, then shift it to display whatever image we want.  So, for 5 galleries, you're downloading 5 images instead of 100.  This will cut out a lot of latency.&lt;br /&gt;&lt;br /&gt;But is it faster?  Well, how about an example.  I took 5 gallery images and constructed a &lt;a href="http://designvigilante.com/files/photoSkim/filmStrip.jpg"&gt;film strip image&lt;/a&gt;.  I built a test page/script - same 5 image - one method uses the filmstrip and background offset, the other uses an image src.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://designvigilante.com/files/photoSkim/photoSkim.html"&gt;Here is the example&lt;/a&gt;.  The top image uses the film strip approach.  The bottom uses Apple's mechinism.&lt;br /&gt;&lt;br /&gt;I used firebug's profiler to compare the performance:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://designvigilante.com/files/photoSkim/perf2.png" border="0"/&gt;&lt;br /&gt;&lt;br /&gt;big dumb dev - &lt;strike&gt;.23ms&lt;/strike&gt;.41ms average&lt;br /&gt;apple - 2.1ms average&lt;br /&gt;&lt;br /&gt;So, better than 4x improvement.&lt;br /&gt;&lt;br /&gt;And this is where part 1 ends.&lt;br /&gt;&lt;br /&gt;Next up - &lt;a href="http://www.bigdumbdev.com/2007/08/build-better-skimmer-part-2.html"&gt;part 2 : how to build a film strip image&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-7219443438466412754?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=SqjxStapywg:gTZDELtkSGc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=SqjxStapywg:gTZDELtkSGc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=SqjxStapywg:gTZDELtkSGc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=SqjxStapywg:gTZDELtkSGc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=SqjxStapywg:gTZDELtkSGc:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=SqjxStapywg:gTZDELtkSGc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=SqjxStapywg:gTZDELtkSGc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/SqjxStapywg" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/SqjxStapywg/build-better-gallery-skimmer-part-1.html</link><author>noreply@blogger.com (Steve)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_9Z9ptEnpp-A/Rr073tCyVyI/AAAAAAAAAA8/wdyoKAjiMGc/s72-c/perf.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">14</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2007/08/build-better-gallery-skimmer-part-1.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-8433690498047972649</guid><pubDate>Fri, 10 Aug 2007 19:49:00 +0000</pubDate><atom:updated>2007-08-10T14:52:26.762-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">javascript</category><title>Don't use "new Array()"</title><description>Check out these two lines of code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="javascript"&gt;&lt;br /&gt;var foo = new Array();&lt;br /&gt;var bar = [];&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;They do the same thing.  So, save yourself 9 characters, and use [].&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-8433690498047972649?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=C1KsUB1a4Hk:1mx-7vpWDx8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=C1KsUB1a4Hk:1mx-7vpWDx8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=C1KsUB1a4Hk:1mx-7vpWDx8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=C1KsUB1a4Hk:1mx-7vpWDx8:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=C1KsUB1a4Hk:1mx-7vpWDx8:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=C1KsUB1a4Hk:1mx-7vpWDx8:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=C1KsUB1a4Hk:1mx-7vpWDx8:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/C1KsUB1a4Hk" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/C1KsUB1a4Hk/dont-use-new-array.html</link><author>noreply@blogger.com (Steve)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2007/08/dont-use-new-array.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-438223525380641950</guid><pubDate>Fri, 10 Aug 2007 05:36:00 +0000</pubDate><atom:updated>2007-08-10T10:23:35.425-05:00</atom:updated><title>Dynamic table search/filter using a single input</title><description>I've seen a lot of tables with column filters - each column has a filter.  This is the &lt;strong&gt;Excel Model&lt;/strong&gt;.  My buddy Travis asked me if I had ever seen it done with one search box - the &lt;strong&gt;iTunes Model&lt;/strong&gt;.  Well, I haven't, and some time spent searching around didn't turn up anything.  Honestly, I didn't search that hard, because I wanted to build it myself.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://designvigilante.com/files/tableSearch/tableSearch.html"&gt;Here is the end product&lt;/a&gt;.  Note, I have only tested this in Firefox and Safari.  Update: tested in IE.&lt;br /&gt;&lt;br /&gt;So, how do you build it?&lt;br /&gt;&lt;br /&gt;First, the behavior:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;The table to be searched has an arbitrary number of columns.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;There is one text box for searching&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Searching is dynamic - start typing and it starts filtering&lt;/li&gt;&lt;br /&gt;&lt;li&gt;When you search, each word you search for has to appear in at least one column in a row, or that row is hidden&lt;/li&gt;&lt;br /&gt;&lt;li&gt;All the words you search for don't have to appear in each column.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;It's late, so I'll leave the rest of the details for now.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-438223525380641950?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=gcOLHNu4a7I:Fs46Ll32UEA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=gcOLHNu4a7I:Fs46Ll32UEA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=gcOLHNu4a7I:Fs46Ll32UEA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=gcOLHNu4a7I:Fs46Ll32UEA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=gcOLHNu4a7I:Fs46Ll32UEA:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=gcOLHNu4a7I:Fs46Ll32UEA:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=gcOLHNu4a7I:Fs46Ll32UEA:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/gcOLHNu4a7I" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/gcOLHNu4a7I/table-searchfilter-using-single-input.html</link><author>noreply@blogger.com (Steve)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">7</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2007/08/table-searchfilter-using-single-input.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-6289767171753519991</guid><pubDate>Thu, 02 Aug 2007 20:29:00 +0000</pubDate><atom:updated>2007-08-02T15:47:20.509-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Crapcasts</category><title>Crapcasts</title><description>I stumbled onto a "great" &lt;a href="http://www.showmedo.com/videos/video?name=920020&amp;fromSeriesID=92"&gt;screencast for preloading images in javascript&lt;/a&gt; today.  These "crapcasts" are like puzzles in the Sunday paper - how many problems can you find?  I'll leave that to the comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-6289767171753519991?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=SKaiOzNmKlk:Y0CTkFaf21o:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=SKaiOzNmKlk:Y0CTkFaf21o:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=SKaiOzNmKlk:Y0CTkFaf21o:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=SKaiOzNmKlk:Y0CTkFaf21o:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=SKaiOzNmKlk:Y0CTkFaf21o:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=SKaiOzNmKlk:Y0CTkFaf21o:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=SKaiOzNmKlk:Y0CTkFaf21o:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/SKaiOzNmKlk" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/SKaiOzNmKlk/crapcasts.html</link><author>noreply@blogger.com (Steve)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2007/08/crapcasts.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-3721418632101533416</guid><pubDate>Sat, 21 Jul 2007 19:41:00 +0000</pubDate><atom:updated>2007-07-22T08:04:28.217-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">coding</category><title>"Programmers are expensive, CPUs are cheap" does not justify rapid development of slow code</title><description>If you've seen at least one argument between a Ruby on Rails Fanboy and an Enterprise Java Fundamentalist - you've heard something like this:&lt;br /&gt;&lt;blockquote&gt;"RoR is 100 times slower than Java."&lt;br /&gt;"Developers are expensive and CPU cycles are cheap.  It's more important to save developer time than CPU time!"&lt;br /&gt;"You aren't a real developer!!"&lt;br /&gt;"At least I don't use tables!!!"&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;I am troubled by how pervasive this "I'm expensive, CPUs are cheap, I don't need to concern myself with performance" attitude has become.  Comparing the relative costs of processing cycles vs. a developer is just silly.&lt;br /&gt;  &lt;br /&gt;Everyone knows, &lt;a href="http://www.mindview.net/WebLog/log-0025"&gt;programmers are expensive&lt;/a&gt; and &lt;a href="http://www.digitalkingdom.org/~rlpowell/rants/prog_features.html"&gt;CPUs are cheap&lt;/a&gt;.  This is obviously true.  Developers like to point this out right before they tell you interpreted languages are better, or OR Mapping is better, or loose typing is better.  Like stating the obvious will somehow qualify their point of view.  Could anyone who likes to spout this please stop!  You might as well say "Puppies are cute, roaches are ugly.  Python is better than C++" or "Rocks are harder than pillows, pointers are evil".&lt;br /&gt;&lt;br /&gt;First of all, it's not the development cost vs. operational costs.  You have to consider how often the product is going to be operated.  Think of it this way - "Automobile engineers cost 100k a year.  Gas costs $3 a gallon.  Engineers are way more expensive than gas.  Who cares that it only gets 5MPG, or engineers were able to design the car twice as fast."  If your product is successful, there should be many more man-hours of operation than there were development.&lt;br /&gt;&lt;br /&gt;Secondly, CPU cycles are inconsequential when measuring the "cost" of slower code.  How about the value of our customers' time waiting on all those extra CPU cycles?  Think of it this way - "Engineers are expensive, electricity is cheap.  It doesn't matter that our microwaves take twice as long to pop popcorn, we saved a lot of money developing them."  People don't care about CPU cycles, but they do care deeply about their time.  Imaging trying to use the argument on the other end: you are demoing your latest project to the big-wigs for the first time:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;"And there you have it, what do you think."&lt;br /&gt;"It feels slow."&lt;br /&gt;"Don't worry, CPU cycles are cheap."&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Please note: I am a big fan of interpreted languages and loose typing.  These technologies are great and there are many situations where they are the most appropriate tools.&lt;br /&gt;&lt;br /&gt;But, please, stop with the "Developers are expensive, cycles are cheap" bullshit.  That's about as insightful as pointing out bananas are yellow and lettuce is green.  The trade-off for slower code isn't just so-cheap-they're-free CPU cycles, it's your customers' TIME, and that is very expensive.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-3721418632101533416?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=qZv66I6ZjhU:82pXF5xIjKs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=qZv66I6ZjhU:82pXF5xIjKs:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=qZv66I6ZjhU:82pXF5xIjKs:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=qZv66I6ZjhU:82pXF5xIjKs:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=qZv66I6ZjhU:82pXF5xIjKs:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=qZv66I6ZjhU:82pXF5xIjKs:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=qZv66I6ZjhU:82pXF5xIjKs:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/qZv66I6ZjhU" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/qZv66I6ZjhU/programmer-are-expensive-cpus-are-cheap.html</link><author>noreply@blogger.com (Steve)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2007/07/programmer-are-expensive-cpus-are-cheap.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-2065253626747394448</guid><pubDate>Sun, 15 Jul 2007 14:06:00 +0000</pubDate><atom:updated>2007-07-17T18:41:31.293-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">javascript</category><title>Javascript image anchor highlighting</title><description>When using an image as an anchor, you very often want to make the image "highlight" when you hover over it.  We've all seen this before - create a highlighted version of the image, add some javascript, and you get the effect.  Here is an example:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://brewer.designvigilante.com/files/imageHover/moveDown.png" onmouseover="this.setAttribute('src','http://brewer.designvigilante.com/files/imageHover/moveDown_over.png');" onmouseout="this.setAttribute('src','http://brewer.designvigilante.com/files/imageHover/moveDown.png');"/&gt;&lt;br /&gt;&lt;br /&gt;Here is the markup:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;img src="http://brewer.designvigilante.com/files/imageHover/moveDown.png"&lt;br /&gt;onmouseover="this.setAttribute('src','.../moveDown_over.png');"&lt;br /&gt;onmouseout="this.setAttribute('src','.../moveDown.png');"&lt;br /&gt;/&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This works for one image, but quickly become bothersome as you use more images.  So, how to pull this out into a script that does it automatically for us?                                                                                                                                        First thought - walk the DOM and get all the images, then add the event handlers to each one.  This will work, but it is not optimal:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Walking the DOM can be expensive.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;If you have a lot of images, you're adding a lot of event handlers.  Each one takes up memory, and is also a potential memory leak if you delete the element later on without deleting the handlers.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;If you add new images after the page loads, you'll have to remember to add the handlers to each.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;We can avoid all of these problems by using &lt;a href="http://developer.yahoo.com/yui/examples/event/event-delegation.html" target="_blank"&gt;event delegation&lt;/a&gt;. Event delegation allows us to attach one event handler to the document body.  When an event is fired on a node, the event will bubble up DOM tree unless is is canceled.  The event object contains the original target element, so we are able to write one function to handle image highlighting for the entire page.  Here is what the event handler code should look like:&lt;br /&gt;&lt;pre&gt;&lt;code class="javascript"&gt;&lt;br /&gt;var handleMouseOver = function(e)&lt;br /&gt;{&lt;br /&gt;  e = e || window.event; // handle IE&lt;br /&gt;  var el = e.target || e.srcElement; // e.target points to the element that was moused over.  srcElement is for IE&lt;br /&gt;  // If the element is an image, and it's parent is an anchor&lt;br /&gt;  if( el.tagName.toLowerCase() == "img" &amp;&amp; el.parentNode.tagName.toLowerCase() == "a" )&lt;br /&gt;  {&lt;br /&gt;    // add _over to the name of the image.&lt;br /&gt;    var src = el.getAttribute( "src" );&lt;br /&gt;    var dot = src.indexOf('.');&lt;br /&gt;    el.setAttribute( "src", src.substring( 0, dot ) + "_over" + src.substring( dot ) );&lt;br /&gt;  }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;// Mouse out is the same, except removing '_over' from the image&lt;br /&gt;var handleMouseOut = function( e ){&lt;br /&gt;  e = e || window.event;&lt;br /&gt;  var el = e.target || e.srcElement;&lt;br /&gt;  if( el.tagName.toLowerCase() == "img" &amp;&amp; el.parentNode.tagName.toLowerCase() == "a" )&lt;br /&gt;  {&lt;br /&gt;    var src = el.getAttribute( "src" );&lt;br /&gt;    el.setAttribute( "src", src.replace( "_over", "" ) );&lt;br /&gt;  }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Note that you need to upload a highlighted version of the image for this to work.&lt;br /&gt;&lt;br /&gt;So, how to bind these to the document body?  We need o be concerned with handler collision - that is multiple handlers binding to the same event and overwriting each other.  We will explore this more in a upcoming post, for now we'll just ignore this case. &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code class="javascript"&gt;&lt;br /&gt;var ImageAnchorHoverHighlighter=function(){&lt;br /&gt;    var handleMouseOver = function(e)&lt;br /&gt;    {&lt;br /&gt;        e = e || window.event;&lt;br /&gt;        var el = e.target || e.srcElement;&lt;br /&gt;        if( el.tagName.toLowerCase() == "img" &amp;&amp; el.parentNode.tagName.toLowerCase() == "a" )&lt;br /&gt;        {&lt;br /&gt;            var src = el.getAttribute( "src" );&lt;br /&gt;            var dot = src.indexOf('.');&lt;br /&gt;            el.setAttribute( "src", src.substring( 0, dot ) + "_over" + src.substring( dot ) );&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;    var handleMouseOut = function( e ){&lt;br /&gt;        e = e || window.event;&lt;br /&gt;        var el = e.target || e.srcElement;&lt;br /&gt;        if( el.tagName.toLowerCase() == "img" &amp;&amp; el.parentNode.tagName.toLowerCase() == "a" )&lt;br /&gt;        {&lt;br /&gt;            var src = el.getAttribute( "src" );&lt;br /&gt;            el.setAttribute( "src", src.replace( "_over", "" ) );&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;    &lt;br /&gt;    return {        &lt;br /&gt;        init : function(){&lt;br /&gt;            var b = document.body;&lt;br /&gt;            document.onmouseover = handleMouseOver;&lt;br /&gt;            document.onmouseout = handleMouseOut;&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;}();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://brewer.designvigilante.com/files/imageHover/example.html" target=_"blank"&gt;Working example&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Later on, I'll look at solving event collision, handling missing highlight image, labels, and background images.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-2065253626747394448?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=SuF3sMfG96Y:GX-YKmggHeM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=SuF3sMfG96Y:GX-YKmggHeM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=SuF3sMfG96Y:GX-YKmggHeM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=SuF3sMfG96Y:GX-YKmggHeM:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=SuF3sMfG96Y:GX-YKmggHeM:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=SuF3sMfG96Y:GX-YKmggHeM:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=SuF3sMfG96Y:GX-YKmggHeM:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/SuF3sMfG96Y" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/SuF3sMfG96Y/javascript-image-anchor-highlighting.html</link><author>noreply@blogger.com (Steve)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2007/07/javascript-image-anchor-highlighting.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-3282977732636570771</guid><pubDate>Thu, 12 Jul 2007 21:05:00 +0000</pubDate><atom:updated>2007-07-12T16:16:40.804-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">coding humor</category><title>When comments suck</title><description>Here are some big dumb comments I stumbled upon today:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;    con = getConnection(DB_POOL);           //get the database connection&lt;br /&gt;    stmt = con.prepareStatement( query );   //prepare the statement&lt;br /&gt;    rs = stmt.executeQuery();               //execute query&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This code is Department of Redundancy Department Approved /*approved by the department of redundancy department*/  &lt;br /&gt;&lt;br /&gt;I love that the variable names are so short and unclear.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-3282977732636570771?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=3JAIs4hJjYo:Aw2lwRS7JyE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=3JAIs4hJjYo:Aw2lwRS7JyE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=3JAIs4hJjYo:Aw2lwRS7JyE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=3JAIs4hJjYo:Aw2lwRS7JyE:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=3JAIs4hJjYo:Aw2lwRS7JyE:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=3JAIs4hJjYo:Aw2lwRS7JyE:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=3JAIs4hJjYo:Aw2lwRS7JyE:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/3JAIs4hJjYo" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/3JAIs4hJjYo/when-comments-suck.html</link><author>noreply@blogger.com (Steve)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2007/07/when-comments-suck.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-1136000476179272289.post-3346683155824616701</guid><pubDate>Tue, 10 Jul 2007 13:51:00 +0000</pubDate><atom:updated>2007-07-12T06:58:06.352-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">iPhone development</category><category domain="http://www.blogger.com/atom/ns#">Apple</category><title>Steve Jobs gives the iPhinger to Mac developers</title><description>Apple is waving a white flag.  They are in the same &lt;a href="http://joelonsoftware.com/articles/APIWar.html"&gt;API wars&lt;/a&gt; as Microsoft - it's the OS vs. the web, and Apple is changing sides.  You see, Apple has "&lt;a href="http://developer.apple.com/iphone/"&gt;very sweet solution&lt;/a&gt;" for development on the iPhone - and it doesn't include core animations.&lt;br /&gt;&lt;br /&gt;If you go cuckoo for Cocoa, faithfully attend the WWDC, and live by the covenants of the HIG, you would probably expect to have a leg up when it comes to "the next big thing" from Apple.  Well, sorry, you lose - web apps will be the only 3rd party apps allowed on the iPhone.  While you were standing in line outside an Apple store, web developers were able to build and launch the first 3rd party iPhone apps.  Steve Jobs has repaid you for years of loyalty with a big, revolutionary, game-changing &lt;span style="font-weight: bold;"&gt;iPhinger&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;It's a web app world.&lt;span style="font-style: italic;font-size:180%;" &gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1136000476179272289-3346683155824616701?l=www.bigdumbdev.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=zygY_Inn-a4:sXR2yP1WKIk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=zygY_Inn-a4:sXR2yP1WKIk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=zygY_Inn-a4:sXR2yP1WKIk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=zygY_Inn-a4:sXR2yP1WKIk:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=zygY_Inn-a4:sXR2yP1WKIk:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?a=zygY_Inn-a4:sXR2yP1WKIk:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/TheBigDumbDeveloper?i=zygY_Inn-a4:sXR2yP1WKIk:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/TheBigDumbDeveloper/~4/zygY_Inn-a4" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/TheBigDumbDeveloper/~3/zygY_Inn-a4/steve-jobs-gives-iphinger-to-mac.html</link><author>noreply@blogger.com (Steve)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.bigdumbdev.com/2007/07/steve-jobs-gives-iphinger-to-mac.html</feedburner:origLink></item></channel></rss>
