<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2534873540987199356</id><updated>2011-11-27T18:15:56.987-05:00</updated><category term='shoes'/><category term='ruby'/><category term='mythtv help wtf'/><category term='tools'/><category term='javascript'/><category term='google maps'/><category term='java'/><category term='customerDisasters'/><category term='toolchain'/><category term='apple'/><category term='tmoble'/><category term='programming'/><category term='firebug'/><category term='projects'/><category term='struts2'/><category term='maemo mapper'/><category term='troubleshooting'/><category term='iphone'/><category term='android'/><category term='transactions'/><category term='nokia'/><category term='python'/><category term='spring'/><category term='g1'/><category term='rails'/><category term='builds'/><category term='market'/><category term='macbook'/><category term='GPS'/><category term='cryingontheinside'/><category term='N800'/><category term='HUD'/><category term='pygame'/><category term='prototypes'/><category term='web programming'/><category term='jruby'/><category term='fanboyism'/><category term='faster development'/><category term='ubuntu'/><category term='rant'/><category term='prototype'/><category term='code generation'/><category term='google'/><title type='text'>Programming as art</title><subtitle type='html'>Why do we think if it's not difficult and complex then it's not worth using?</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://programmingasart.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://programmingasart.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>prodrive555</name><uri>http://www.blogger.com/profile/01056033371628831177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>22</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2534873540987199356.post-1152550937646545306</id><published>2010-07-12T21:30:00.000-05:00</published><updated>2010-07-12T21:30:00.389-05:00</updated><title type='text'>Android SharedPreference Read-Once Gotcha</title><content type='html'>I use &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;SharedPreferences&lt;/span&gt;&lt;/span&gt; in a horrible way. &amp;nbsp;I use it to store application data. It's much easier to use a key/value store than a SQLite DB or writing to a file. &amp;nbsp;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Because SharedPreferences are stored in the &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;/data/data&lt;/span&gt;&lt;/span&gt; directory they can't be reached without root for saving. &amp;nbsp;To fix this I store a copy of the file on the &lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;/sdcard&lt;/span&gt;&lt;/span&gt;. &amp;nbsp;On start up I copy the "public" version over the &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;/data/data&lt;/span&gt;&lt;/span&gt; private file. &amp;nbsp;(This has the side effect of allowing modification of the data and reloading by editing the file when attached to a computer)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The problem is that when you call &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;getSharedPreferences&lt;/span&gt;&lt;/span&gt;&amp;nbsp;you always get the same instance back. It doesn't reload the file. &amp;nbsp;This was an issue for me because I was using that to create the &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;/data/data&lt;/span&gt;&lt;/span&gt; file if it didn't exist, copy the &lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;/sdcard&lt;/span&gt;&lt;/span&gt; file over and then tried to reload by calling it again. &amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To fix the problem I had to check if the &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;/data/data&lt;/span&gt;&lt;/span&gt; file existed during the copy operation and create through java.io.File methods first, then copy, then call &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;getSharedPreferences&lt;/span&gt;&lt;/span&gt;.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2534873540987199356-1152550937646545306?l=programmingasart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programmingasart.blogspot.com/feeds/1152550937646545306/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2534873540987199356&amp;postID=1152550937646545306' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/1152550937646545306'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/1152550937646545306'/><link rel='alternate' type='text/html' href='http://programmingasart.blogspot.com/2010/07/android-sharedpreference-read-once.html' title='Android SharedPreference Read-Once Gotcha'/><author><name>prodrive555</name><uri>http://www.blogger.com/profile/01056033371628831177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2534873540987199356.post-8403739263009966136</id><published>2010-07-11T23:44:00.000-05:00</published><updated>2010-07-11T23:44:27.756-05:00</updated><title type='text'>Drop And Give Me Twenty! v2.0</title><content type='html'>Just pushed version 2.0 to the market! &amp;nbsp;Added a lot of user requested features:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Reset&lt;/li&gt;&lt;li&gt;Manually change your level and day/week&lt;/li&gt;&lt;li&gt;Manual entry (It's more of a stopwatch mode)&lt;/li&gt;&lt;li&gt;Sound on/off&lt;/li&gt;&lt;li&gt;Minor updates to the Progress chart to make it more flexable&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;I don't know which is more nerve wracking, the update because I can destroy data now or the initial release due to the unknown.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2534873540987199356-8403739263009966136?l=programmingasart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programmingasart.blogspot.com/feeds/8403739263009966136/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2534873540987199356&amp;postID=8403739263009966136' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/8403739263009966136'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/8403739263009966136'/><link rel='alternate' type='text/html' href='http://programmingasart.blogspot.com/2010/07/drop-and-give-me-twenty-v20.html' title='Drop And Give Me Twenty! v2.0'/><author><name>prodrive555</name><uri>http://www.blogger.com/profile/01056033371628831177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2534873540987199356.post-6051703669257409134</id><published>2010-06-15T20:08:00.000-05:00</published><updated>2010-06-15T20:08:55.419-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='market'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>First Android app published!</title><content type='html'>Last night I finished up version 1.0 of my 100 pushup app for Android and published it to the market. You can search for DGMT to install. &lt;br /&gt;I hope to add a few more things to finish up. I want to add a proximity counter for those who don't want to touch the screen with their nose. &amp;nbsp;An editor for the&amp;nbsp;exercises. Better graphing through custom coding instead of using a library. And in the far future uploading data to a web app for generating custom workouts for your skill level based on others like you.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://lh6.ggpht.com/_m9aqeI3RDq0/TBb6kP23zbI/AAAAAAAABJQ/Wkt-d-OSJbU/s1600/market___search_q_pname_.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="200" src="http://lh6.ggpht.com/_m9aqeI3RDq0/TBb6kP23zbI/AAAAAAAABJQ/Wkt-d-OSJbU/s200/market___search_q_pname_.png" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;(Use Barcode Scanner on this QR code for a direct link to my app in the market.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2534873540987199356-6051703669257409134?l=programmingasart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programmingasart.blogspot.com/feeds/6051703669257409134/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2534873540987199356&amp;postID=6051703669257409134' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/6051703669257409134'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/6051703669257409134'/><link rel='alternate' type='text/html' href='http://programmingasart.blogspot.com/2010/06/first-android-app-published.html' title='First Android app published!'/><author><name>prodrive555</name><uri>http://www.blogger.com/profile/01056033371628831177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_m9aqeI3RDq0/TBb6kP23zbI/AAAAAAAABJQ/Wkt-d-OSJbU/s72-c/market___search_q_pname_.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2534873540987199356.post-5853188947774609958</id><published>2009-11-24T21:30:00.002-05:00</published><updated>2009-11-24T21:34:17.644-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='prototype'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Android Prototyping Templates</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_m9aqeI3RDq0/SwyW__TShKI/AAAAAAAABEU/o8WygasnfI8/s1600/Android-frame_2.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 320px; height: 247px;" src="http://4.bp.blogspot.com/_m9aqeI3RDq0/SwyW__TShKI/AAAAAAAABEU/o8WygasnfI8/s320/Android-frame_2.jpg" alt="" id="BLOGGER_PHOTO_ID_5407863278633387170" border="0" /&gt;&lt;/a&gt;I couldn't find much in the way of Android prototyping tools on the internet so I decided to create one of my own.&lt;br /&gt;&lt;br /&gt;This is for hand sketching ideas out.  When printed on 8.5x11 it comes out almost the exact size of the G1 screen.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2534873540987199356-5853188947774609958?l=programmingasart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programmingasart.blogspot.com/feeds/5853188947774609958/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2534873540987199356&amp;postID=5853188947774609958' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/5853188947774609958'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/5853188947774609958'/><link rel='alternate' type='text/html' href='http://programmingasart.blogspot.com/2009/11/android-prototyping-templates.html' title='Android Prototyping Templates'/><author><name>prodrive555</name><uri>http://www.blogger.com/profile/01056033371628831177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_m9aqeI3RDq0/SwyW__TShKI/AAAAAAAABEU/o8WygasnfI8/s72-c/Android-frame_2.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2534873540987199356.post-7393405215457866578</id><published>2009-03-04T22:14:00.003-05:00</published><updated>2009-03-04T22:20:57.810-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fanboyism'/><category scheme='http://www.blogger.com/atom/ns#' term='macbook'/><category scheme='http://www.blogger.com/atom/ns#' term='apple'/><title type='text'>Why I love my MacBook</title><content type='html'>One of the most under publicized features of the Intel (maybe older?) MacBooks and MacBook Pros is the multi-touch trackpad.  First off it has a much larger area than any PC laptop I've had which makes for less drag-lift-move-drag motions.  Second the acceleration and resolution are perfect out of the box.  Third double tap right click and double finger scrolling ANYWHERE on the pad makes things so much better.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;How much better? &lt;b&gt; I like the trackpad so much that reaching over to use the attached mouse is a hassle&lt;/b&gt;.  I thought I'd never say anything like that.  As far as other trackpads are concerned, I'd rather spend a half hour getting a mouse even for 5 minutes of use.  They're just that bad.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Its just another example of Apple's attention to details that makes them a much better experience.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2534873540987199356-7393405215457866578?l=programmingasart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programmingasart.blogspot.com/feeds/7393405215457866578/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2534873540987199356&amp;postID=7393405215457866578' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/7393405215457866578'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/7393405215457866578'/><link rel='alternate' type='text/html' href='http://programmingasart.blogspot.com/2009/03/why-i-love-my-macbook.html' title='Why I love my MacBook'/><author><name>prodrive555</name><uri>http://www.blogger.com/profile/01056033371628831177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2534873540987199356.post-6788447239899916870</id><published>2008-12-29T15:28:00.005-05:00</published><updated>2008-12-29T16:11:04.393-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='customerDisasters'/><category scheme='http://www.blogger.com/atom/ns#' term='tmoble'/><category scheme='http://www.blogger.com/atom/ns#' term='google'/><category scheme='http://www.blogger.com/atom/ns#' term='g1'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>T-Mobile's Android root runs shallow</title><content type='html'>&lt;p&gt;T-Mobile's only Android device, the G1, isn't as open as you would think.  The device lacks root access and the bootloader requires a signed image.  Older versions of the OS have had a successful jailbreak but the most recent (R30) over the air firmware upload "fixed" that.&lt;/p&gt;&lt;p&gt;I jumped on the G1 bandwagon the day after it was announced hoping that it would live up to the openness Android was claiming.  To be fair, the SDK does allow access to quite a bit more than the iPhone's SDK does which makes for some interesting   applications not do able on the iPhone (for now). But the Google/T-Mobile team has stopped a bit short when it comes to moving from one Android device to another.  There's no desktop client nor is there a backup/restore client!  Think about that for a moment.  When the time comes that you have the option to move to another Android device or, as in my case, have to replace your current one you're out of luck.&lt;/p&gt;&lt;p&gt;I searched the internet and even posted in a few google read forums (groups.google.com/groups/android-developers, forums.t-mobile.com) about how to move from one to the other.  I read about the jailbreaking &amp;lt; R30 and the R30 hacked image if you already were jailbroken. I was told that it's T-Mobile's fault and to stop complaining. I was even told by one person that they clear their phone all the time for app testing and it only takes about 10-15 minutes and isn't a big deal.  That person obviously isn't &lt;i&gt;really&lt;/i&gt; using their phone.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;T-Mobile customer support isn't much better either.  They say you just have to download the applications again from the market and accept the data loss or they'll tell you about the jailbreak and how R30 shut it down and it's "impossible" to hack this new version.  When you try to tell them that you want T-Mobile to provide root access or unlock the boot loader they tell you that Google writes the code and HTC makes the phone. They have nothing to do with it.  This is a lack of understanding on the support staff's part.  Google writes the base code, but it's modified for T-Mobile and only runs as a signed image.&lt;/p&gt;&lt;p&gt;Basically it seems that what's happening is that Google released some software prematurely as usual with their code but this is a very different case than the web were only the Google devoted will pick up the software before it's ready for prime time.  T-Mobile pushed out the G1 as a iPhone replacement when it is not because of the build quality, the hardware itself and the premature OS.  Now that they actually have real users with real problems that should have been caught long before in acceptance testing, they just want to ignore them.  And they'll be able to because most people using the G1 won't know any better. There's always the Google apologists (and in some cases the Android devs themselves) that will say it's not their problem. There's no way to actually get in contact with someone who actually knows something about this level of detail about the G1 at T-Mobile. And finally, we already paid and signed a contract and are well past the 14 day return period. So the only way out is to pay more money to T-Mobile.&lt;/p&gt;&lt;p&gt;For anyone out there looking to develop on Android and the G1, PLEASE, PLEASE just spend the extra money on the Google Dev Phone 1 (http://code.google.com/android/dev-devices.html).&lt;/p&gt;&lt;ul&gt;&lt;li&gt;No Contract&lt;/li&gt;&lt;br /&gt;&lt;li&gt;No $18/$36 upgrade/activation fee (which is a whole different kind of BS)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;u&gt;Full&lt;/u&gt; Control of your phone. Add new images. Root access. &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;To me this is what the G1 should have been. This is what Android was to represent.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2534873540987199356-6788447239899916870?l=programmingasart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programmingasart.blogspot.com/feeds/6788447239899916870/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2534873540987199356&amp;postID=6788447239899916870' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/6788447239899916870'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/6788447239899916870'/><link rel='alternate' type='text/html' href='http://programmingasart.blogspot.com/2008/12/t-mobiles-android-root-runs-shallow.html' title='T-Mobile&apos;s Android root runs shallow'/><author><name>prodrive555</name><uri>http://www.blogger.com/profile/01056033371628831177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2534873540987199356.post-4014028843731074249</id><published>2008-10-12T22:16:00.008-05:00</published><updated>2008-10-12T22:52:39.921-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='faster development'/><category scheme='http://www.blogger.com/atom/ns#' term='firebug'/><title type='text'>Firebug Console for power users == REPL</title><content type='html'>&lt;p&gt;There have been many, many posts through out the internet explaining why Firebug is the greatest thing ever for the web developer from the CSS editor to the AJAX transmission viewer to the javascript debugger. I'm going to throw one more thing in; javascript REPL.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;REPL stands for Read, Evaluate, Print, Loop for those that don't know and basically means it's an interactive shell into your program.  Most of us know about the console in Firebug but how many know about the power it gives? When you open Firebug the console tab is selected by default.  You may know this as the place those &lt;tt&gt;console.log()&lt;/tt&gt; messages go.  At the bottom is a blank line denoted by "&amp;gt;&amp;gt;&amp;gt;", this is the interactive part. You can execute a line of javascript here.  If you click the circle with the up arrow on the right you open the multiline console.  I recommend this as the way to go.  You can write multiple lines, such as functions, and execute with ctrl-enter or command-enter.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;Anyway, back to that REPL.  The console lets you interact with any loaded javascript on the page.  You can change global variables, call functions, pretty much anything javascripty.  This is where the power comes in. You can define functions meaning you can &lt;i&gt;redefine&lt;/i&gt; functions! And it'll work when some element or function on the page calls it.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;Imagine for a moment that your trying to create a new function or debug a function on your production server where you have to interact with the real data.  You can't just change the code, check it in, build and deploy each time due to various issues like time and the client noticing the site going up and down.  What you can do, and what I had to do recently, is open the console, paste in the fixes to the definition of the function, evaluate it, and then go about interacting with the page. It becomes a much faster solution that has a couple of benefits.&lt;br /&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;No redeploy until you know it works&lt;/li&gt;&lt;li&gt;Don't have to worry about anyone else getting in there and using your code while you're testing it out&lt;/li&gt;&lt;li&gt;Interaction with the real problem, with the real data causing it.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;If you go about writing your javascript code with the console in mind there are some great uses for it. &lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Have your logging statements controlled by a global variable.  On the page it's false and not printing. When you need to see what's going on in Production or some other uncontrolled by you environment, just change that variable to true and you get your logging.&lt;/li&gt;&lt;li&gt;Fire functions and events while developing so you don't have to keep reloading the page and waiting for template recompiles. I like to use this when writing something with AJAX calls while working on the backend.  I create a &lt;tt&gt;refresh()&lt;/tt&gt; method ,that is the initial loader on the page anyway, and call it from the console.&lt;/li&gt;&lt;li&gt;Last, but not least, a personal favorite, testing out javascript expressions.  We all have been there where you can't remember exactly how &lt;tt&gt;substring()&lt;/tt&gt; works and you'd just like to try on the page instead of googling it and then interpreting what you find to fit your scenario.  I use this all the time for things like figuring out a complex Prototype.js expression on the page to see how it works and tweet it before putting it on the page for real and going through the refresh cycle.  In fact I'd go as far to say it'd be very, very hard to do without and I'm starting to wish for one in Java (aside from things like groovysh and jirb)&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;I hope this opens up some options and makes life easier for you developers out there. At least when working in Firefox. Firebug does have the downside of making you feel that much more helpless when you have some stupid IE bug.&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2534873540987199356-4014028843731074249?l=programmingasart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programmingasart.blogspot.com/feeds/4014028843731074249/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2534873540987199356&amp;postID=4014028843731074249' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/4014028843731074249'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/4014028843731074249'/><link rel='alternate' type='text/html' href='http://programmingasart.blogspot.com/2008/10/firebug-console-for-power-users.html' title='Firebug Console for power users == REPL'/><author><name>prodrive555</name><uri>http://www.blogger.com/profile/01056033371628831177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2534873540987199356.post-6297880185719629083</id><published>2008-09-24T07:05:00.005-05:00</published><updated>2008-09-24T22:18:28.570-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rant'/><category scheme='http://www.blogger.com/atom/ns#' term='cryingontheinside'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Google, T-Mobile and HTC invent English</title><content type='html'>Imagine for a moment that the year is 2008 BC and Google, T-Mobile and HTC get to get together and create a new language called English.  "Its wonderful", they say. "It can be used for communication during business. Its open, any country can adopt it and change it as they see fit!" yada, yada, yada.&lt;br /&gt;And its true. England, the US and Australia all want in.  So they turn to HTC and T-Mobile to give us a platform to introduce English to the world.&lt;br /&gt;They call together members of the press to announce their darling creation and what do they bring to the stage?&lt;br /&gt;&lt;br /&gt;A half retarded, southerner with one leg named Andy.  Sure he meets all the requirements; human, vocal cords, at least one eye, some type of self awareness. But something's off, he's not quite there.  He talks with a drawl. He takes a bit too long to form sentences and has a slight stutter. He really can't remember all that much. He can sing but is off key unless you provide him with some other piece of equipment. He can't dance but is open to learning.  Actually, he can't do much but is always open to learning as long as someone else teaches him. He "shur' as heck ain't gonna'" learn on his own. Oh, and to top it all off T-Mobile won't let him go any further than 1Km from his house without taking his other leg off. (But they'll reattach it at the beginning of the next billing cycle)&lt;br /&gt;&lt;br /&gt;Andy, ambassador of English to the World! (I think the World might want to stick to the romantic languages)&lt;br /&gt;&lt;br /&gt;This is what "The big G and the pink T" gave us yesterday.  Some phone from 2005 with a flashy new interface.  What is it about the G1/Dream that HTC needed so much time to develop? Sure the digital compass is new, but other than that it's a smart phone from before there was an iPhone. It seems that they didn't take any ideas from the iPhone at all.  Why isn't the Touch HD the android phone?  When you preemptively answer the "Why HTC" question in your press conference, you know things aren't going to go over well.&lt;br /&gt;&lt;br /&gt;I'm sure the spin machines at those camps will try to say that "Oh, no this is better than the iPhone because it's open and unrestricted.." at first. Then when they get tired of saying that, they'll get angry and start with the "Well, this was never intended to be an iPhone killer." &lt;br /&gt;&lt;br /&gt;Another underlying cause of concern for me is that Google didn't stop this train wreck. Either they seem to really be confident and are just treating this like another Google Beta or they don't care.  Someone there had to know that this was not a good phone.  No one voiced any concern?  And to stand on stage, even with all the phone's shortcomings, and tout it as something so great in a post iPhone world is disheartening.&lt;br /&gt;&lt;br /&gt;And T-Mobile, unless you have another android phone coming, I really think you've got yourself a Zune to At&amp;amp;t's iPod.  Congratulations!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;EDIT 9-24-08&lt;/span&gt;&lt;br /&gt;T-Mobile has started taking steps in the right direction.  They are reducing the 1Gb cap from a hard, fast rule to a reserved right for those that abuse the system.  Also, phones after the first shipment will contain a 3.5mm headphone adapter.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2534873540987199356-6297880185719629083?l=programmingasart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programmingasart.blogspot.com/feeds/6297880185719629083/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2534873540987199356&amp;postID=6297880185719629083' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/6297880185719629083'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/6297880185719629083'/><link rel='alternate' type='text/html' href='http://programmingasart.blogspot.com/2008/09/google-t-mobile-and-htc-invent-english.html' title='Google, T-Mobile and HTC invent English'/><author><name>prodrive555</name><uri>http://www.blogger.com/profile/01056033371628831177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2534873540987199356.post-35199471495492043</id><published>2008-07-19T18:51:00.005-05:00</published><updated>2008-10-21T12:44:27.952-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='web programming'/><category scheme='http://www.blogger.com/atom/ns#' term='prototype'/><title type='text'>T-Mobile Address Manager export "Hack"</title><content type='html'>&lt;p&gt;&lt;b&gt;Edit&lt;/b&gt;: Thanks to yincrash for pointing out that they changed their namespace on this object to &lt;tt&gt;TMO.ABPORTAL.&lt;/tt&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;My friend Candice got a 1st Gen iPhone on the cheap and needed to get her numbers from T-Mobile's new online Address Manager (TAB).  It does syncing to and from a regular T-Mobile phone but the iPhone isn't a regular T-Mobile Phone.  The app is new and they have a note about it not syncing changes made on the website to the phone yet and either by design or evil plotting there was no way to export the contacts.  &lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;My vocation to the rescue! They were using the prototype.js library to run the app and after some digging around I found the data store.&lt;br /&gt;&lt;code&gt;TMO.ABPORTAL.ABIHM.ContactManager&lt;/code&gt; is the object that manages the contacts' actions and the &lt;code&gt;_datas&lt;/code&gt; property is an array of contact javascript objects.  So in the firebug console I wrote some code to get the contacts and wrote a csv file to an empty div.  I then took that div into Wordpad to get the lines to break correctly on Windows and did an import into Windows Address Book.  The rest is history!&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;Here's the code I used:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;var data = ["firstname,lastname,name,homeMobile,homePhone1,homePhone2,workMobile,workPhone1,workPhone2"];&lt;br /&gt;TMO.ABPORTAL.ABIHM.contactManager._datas.each(function(person) {&lt;br /&gt;    var a = [];&lt;br /&gt;    a.push(person.firstname);&lt;br /&gt;    a.push(person.lastname);&lt;br /&gt;    a.push(person.name);&lt;br /&gt;    a.push(person.homeMobile);&lt;br /&gt;    a.push(person.homePhone1);&lt;br /&gt;    a.push(person.homePhone2);&lt;br /&gt;    a.push(person.workMobile);&lt;br /&gt;    a.push(person.workPhone1);&lt;br /&gt;    a.push(person.workPhone2);&lt;br /&gt;    data.push(a.join(","));&lt;br /&gt;});&lt;br /&gt;$('L_footer_pane').update(data.join('\r\n'));&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2534873540987199356-35199471495492043?l=programmingasart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programmingasart.blogspot.com/feeds/35199471495492043/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2534873540987199356&amp;postID=35199471495492043' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/35199471495492043'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/35199471495492043'/><link rel='alternate' type='text/html' href='http://programmingasart.blogspot.com/2008/07/t-mobile-address-manager-hack.html' title='T-Mobile Address Manager export &quot;Hack&quot;'/><author><name>prodrive555</name><uri>http://www.blogger.com/profile/01056033371628831177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2534873540987199356.post-4748762734922434803</id><published>2008-05-13T00:05:00.000-05:00</published><updated>2008-05-13T00:05:00.977-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='web programming'/><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='jruby'/><category scheme='http://www.blogger.com/atom/ns#' term='struts2'/><title type='text'>Playing with the Struts 2 Dispatcher</title><content type='html'>&lt;div&gt;&lt;br /&gt;Due to the nature of our permission handling on a project at work I am in need of a way to pass URLs in to the Struts dispatcher and get back the class name and method of the action to invoke (possibly the results as well...).  See we have our classes implement a "SecurityAware" interface that returns an array of [OR'd] permission names required to view a page.  We also have a permission based menu system that sometimes requires different permissions than the page the menu item points to.  I had run into a problem in trying to find all those needed permissions between the database and the source code which was a lot of manual work.  So you can see why I'd want to just pass in the URLs from the menu and get the action, call the security method and display the needed permissions for the resulting page.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;What I did was start taking a trip through the Struts 2 source and the test classes for an idea of what was going on.  I started at the FilterDispatcher since that's the one class that I define and is the starting point of my (any?) Struts2 applications. &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;The filterDispatcher creates a Dispatcher object.  This seems to be the core configuration beast of the system.  This has an ActionMapper injected into it.  This is where my problems begin.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;How are things injected into the FilterDispatcher since I'm "creating" it in the web.xml?  There's a ConfigurationManager that is created inside that loads the struts config files and I've had luck printing out parameters that I've set in my struts.xml so I think it's loading correctly. What I'm now having trouble with is the ActionMapper.  I'm playing with this in jRuby and I have no idea how to deal with Java5 Generics (I guess I could Google it...) so I took the route of just injecting my created actionMapper.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;actionMapper =  DefaultActionMapper.new&lt;br /&gt;dispatcher.configurationManager.configuration.container.inject(actionMapper)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This does have an effect in that I can set &lt;tt&gt;struts.enable.SlashesInActionNames&lt;/tt&gt; to true and then call &lt;tt&gt;actionMapper.slashesInActionNames?&lt;/tt&gt; and have the result be true (it defaults to false, so there is a change).&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;I should mention that I'm running this code in the struts blank example app's WEB-INF/classes directory.  I can create a &lt;tt&gt;MockServletRequest&lt;/tt&gt; and pass in URLs that should and shouldn't work.  It errors out appropriately when the URL doesn't end with ".action" and I can get it to parse the namespace portion correctly, but I'm having no luck with the Method.  For example &lt;tt&gt;/example/Login_input.action&lt;/tt&gt; should result in an &lt;tt&gt;ActionMapping&lt;/tt&gt; with:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Name: Login_input&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Namespace: /example&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Method: input&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Or at least that's what I'm expecting, but I never get anything for the method. &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;Here's my code so far. &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;require 'java'&lt;br /&gt;&lt;br /&gt;import 'org.apache.struts2.dispatcher.Dispatcher'&lt;br /&gt;import 'org.apache.struts2.dispatcher.FilterDispatcher'&lt;br /&gt;import 'org.apache.struts2.dispatcher.mapper.DefaultActionMapper'&lt;br /&gt;&lt;br /&gt;import 'org.springframework.mock.web.MockServletContext'&lt;br /&gt;import 'org.springframework.mock.web.MockFilterConfig'&lt;br /&gt;import 'org.springframework.mock.web.MockHttpServletRequest'&lt;br /&gt;import 'org.springframework.mock.web.MockHttpServletResponse'&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;filterConfig = MockFilterConfig.new&lt;br /&gt;servletContext = MockServletContext.new&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;dispatcher = Dispatcher.new(servletContext, {})&lt;br /&gt;dispatcher.init&lt;br /&gt;Dispatcher.instance = dispatcher&lt;br /&gt;&lt;br /&gt;actionMapper =  DefaultActionMapper.new&lt;br /&gt;dispatcher.configurationManager.configuration.container.inject(actionMapper)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;request = MockHttpServletRequest.new(servletContext, 'GET', '/example/other.action');  &lt;br /&gt;response = MockHttpServletResponse.new;&lt;br /&gt;&lt;br /&gt;actionMapping = actionMapper.getMapping(request,dispatcher.configurationManager)&lt;br /&gt;puts "Name: #{actionMapping.name}"&lt;br /&gt;puts "Namespace: #{actionMapping.namespace}"&lt;br /&gt;puts "Method: #{actionMapping.method}"&lt;br /&gt;puts "Result: #{actionMapping.result}"&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2534873540987199356-4748762734922434803?l=programmingasart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programmingasart.blogspot.com/feeds/4748762734922434803/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2534873540987199356&amp;postID=4748762734922434803' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/4748762734922434803'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/4748762734922434803'/><link rel='alternate' type='text/html' href='http://programmingasart.blogspot.com/2008/05/playing-with-struts-2-dispatcher.html' title='Playing with the Struts 2 Dispatcher'/><author><name>prodrive555</name><uri>http://www.blogger.com/profile/01056033371628831177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2534873540987199356.post-4239854518244472624</id><published>2008-04-16T22:51:00.003-05:00</published><updated>2008-04-16T22:56:39.308-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mythtv help wtf'/><title type='text'>MythTV allowing schedules but showing none</title><content type='html'>&lt;div&gt;My MythTV is on the fritz. Maybe because I keep screwing with it... It would let me "schedule" things through mythweb or by Manage Recordings -&gt; Schedule Recording and would save the recording schedule I picked but would not show anything in the upcoming recordings section.  This had happened to me once before and luckily I vaguely remembered how to fix it.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;If this happens to you, or to me again, check that your recording device is hooked up to your listings.  I think it's under Input Devices in setupmythtv, aka the backend setup.  In my case I had my card and I had Schedules Direct but my card's television input was not pointing to anything. I pointed it to Schedules Direct and exited out, went back into the frontend and all my upcoming shows were there.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2534873540987199356-4239854518244472624?l=programmingasart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programmingasart.blogspot.com/feeds/4239854518244472624/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2534873540987199356&amp;postID=4239854518244472624' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/4239854518244472624'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/4239854518244472624'/><link rel='alternate' type='text/html' href='http://programmingasart.blogspot.com/2008/04/mythtv-allowing-schedules-but-showing.html' title='MythTV allowing schedules but showing none'/><author><name>prodrive555</name><uri>http://www.blogger.com/profile/01056033371628831177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2534873540987199356.post-9016649904412571866</id><published>2008-04-06T22:35:00.003-05:00</published><updated>2008-04-08T18:34:08.349-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='maemo mapper'/><category scheme='http://www.blogger.com/atom/ns#' term='GPS'/><title type='text'>Maemo Mapper paths.db break down</title><content type='html'>&lt;div&gt;&lt;br /&gt;When connected to GPS mapper has a track log in the paths.db file in &lt;tt&gt;/home/user/.maemo-mapper/&lt;/tt&gt;.  If you take a look at the file with the sqlite3 client you'll see a table named &lt;tt&gt;track_path&lt;/tt&gt;. This is where the data points are stored but they're not in degrees. A &lt;tt&gt;.schema&lt;/tt&gt; reveals that the columns are called &lt;tt&gt;unitx&lt;/tt&gt; and &lt;tt&gt;unity&lt;/tt&gt;.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;A dig through the internet found me source that was using a function called &lt;tt&gt;unit2latlon&lt;/tt&gt;.  So I downloaded the source from the &lt;a href="https://garage.maemo.org/projects/maemo-mapper/"&gt;garage&lt;/a&gt; and grep'd for the definition of this function.  It turns out to be a macro in &lt;tt&gt;defines.h&lt;/tt&gt;.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;Here's the macro converted to ruby for easy use.  It only does long and lat. I still have to find what the altitude is in...&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;TILE_SIZE_P2 = 8&lt;br /&gt;MAX_ZOOM = 20&lt;br /&gt;&lt;br /&gt;WORLD_SIZE_UNITS = 2 &lt;&lt; MAX_ZOOM + TILE_SIZE_P2&lt;br /&gt;&lt;br /&gt;MERCATOR_SPAN = -6.28318377773622 &lt;br /&gt;MERCATOR_TOP = 3.14159188886811 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def unit_2_lat_lon(unitx, unity)&lt;br /&gt;    lon = ((unitx) * (360.0 / WORLD_SIZE_UNITS)) - 180.0&lt;br /&gt;    lat = (360.0 * (Math.atan(  Math.exp ((unity * (MERCATOR_SPAN / WORLD_SIZE_UNITS)) + MERCATOR_TOP)))) * (1.0 / Math::PI) - 90.0;&lt;br /&gt;    return lat,lon&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;It's line for line the same as the Maemo-Mapper team's code.  There was a lot more in the defines.h file, but this is all that's needed to run the function. I ran the last point in the database and checked the output in Google maps (straight copy and paste!) and it &lt;em&gt;is&lt;/em&gt; where it stopped logging!&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;irb(main):001:0&gt; lat,lon = unit_2_lat_lon(157094175,199470581)&lt;br /&gt;=&gt; [41.9127500226541, -74.6601469069719]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2534873540987199356-9016649904412571866?l=programmingasart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programmingasart.blogspot.com/feeds/9016649904412571866/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2534873540987199356&amp;postID=9016649904412571866' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/9016649904412571866'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/9016649904412571866'/><link rel='alternate' type='text/html' href='http://programmingasart.blogspot.com/2008/04/maemo-mapper-pathsdb-break-down.html' title='Maemo Mapper paths.db break down'/><author><name>prodrive555</name><uri>http://www.blogger.com/profile/01056033371628831177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2534873540987199356.post-1680688519856146591</id><published>2008-04-04T20:45:00.006-05:00</published><updated>2008-04-04T21:05:17.432-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='maemo mapper'/><category scheme='http://www.blogger.com/atom/ns#' term='N800'/><category scheme='http://www.blogger.com/atom/ns#' term='GPS'/><category scheme='http://www.blogger.com/atom/ns#' term='google maps'/><title type='text'>Google Maps, Maemo Mapper, GPX, KML all get me to the rally!</title><content type='html'>&lt;div&gt;I'm a bit of a rally fan. Not the political kind, but the motorsports kind (you may have see it in the x-games...).  This weekend is the 2008 &lt;a href="http://www.rallynewyork.com"&gt;Rally New York&lt;/a&gt;.  If you've ever been to a rally before you know what a pain it is finding and getting to spectator points.  If you haven't, I suggest you do, and believe me, it's a pain. There's usually a spectator guide and if you dig around the site some scanned maps that have been marked but these always leave me a little in the dark.  So each time I go to one of these I usually take a few hours checking out google maps and figuring out where the spectator points are and how to get there.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;It started out with just printing out the pdf's and the maps, but then I got a psp and I started downloading Google maps and drawing on them and loading them as pictures. Then I got the Nokia N800, suddenly there was no need for print outs (yay! I'm going green while driving &gt; 300 miles to a fuel burning frenzy).  The N800 can handle PDFs and with the help of Maemo Mapper can handle maps for me.  That coupled with a bluetooth GPS receiver gives me a really great tool for navigating to the different points.  Now I have an iPhone as well which has maps and PDF abilities (if it only had GPS!) &lt;br /&gt;So what I did this year was plot everything on Google Maps:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;iframe width="425" height="350" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="http://maps.google.com/maps/ms?ie=UTF8&amp;amp;hl=en&amp;amp;msa=0&amp;amp;msid=100851554567307611363.00044a0e895f18fcf099b&amp;amp;ll=41.805605,-74.562836&amp;amp;spn=0.264618,0.391045&amp;amp;output=embed&amp;amp;s=AARTsJr7qEXKVNgvtO84oYLnmPq8pV1PWA"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;small&gt;&lt;a href="http://maps.google.com/maps/ms?ie=UTF8&amp;amp;hl=en&amp;amp;msa=0&amp;amp;msid=100851554567307611363.00044a0e895f18fcf099b&amp;amp;ll=41.805605,-74.562836&amp;amp;spn=0.264618,0.391045&amp;amp;source=embed" style="color:#0000FF;text-align:left"&gt;View Larger Map&lt;/a&gt;&lt;/small&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;The cameras are spectator points. The orange lines are the closed road courses and the blue lines are the recommended approaches to the spectator areas.  While editing a map you can download the kml file to view in Google Earth. This file just contains a link to the actual .kml file that has the lines and points in it.  I tried putting this file on a server and hitting it in my iPhone's maps.app. But after getting a polite error about not being able to find anything matching the search I looked on the web and found that the only kml elements Google Maps for Mobile (which maps.app is based on I hear) is the point.  So lines were out and my iPhone was out.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;Next I looked up what format Maemo Mapper supported, which is GPX.  I fired up gpsbabel and converted my real kml file to gpx only to have Maemo Mapper choke on it.  It turns out that Mapper wants only one type of dataset at a time.  The kml had lines and points which were converted to "trk"'s and waypoints.  But I really only needed to store my spectator areas as Points of Interest (POI). Mapper stores it's POI in a sqlite3 database in /home/user/MyDocs/.documents/Maps/poi.db by default.  By getting that file I was able to write a ruby script that took out the "Point" elements from the kml file and create sql insert statements.  Putting that db back and fixing permissions (I was ssh'd in as root so the file became pwn'd) gave me the spectator points. Since they're the only things in there it makes for very easy viewing!&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;Then came the "approaches", I have them as line fragments on the google maps but Mapper only supports Routes and tracks.  I don't know if tracks would have helped me as I think they're in a db called paths.db but the routes are stored in an xml file in gpx format.  Gpsbable dropped the names and descriptions when it converted the lines so I created a new ruby script that took the LineStrings from kml and created trkpt's from them.  Reloading the route file in Mapper gave me my route to the place plus the route fragments to the spectator areas.  Since they were all in the same route file I could then download tiles around the routes and have everything internet free. I also added a description to some of the points in the line for turn directions/hints.  You can count the bends in your google map to know which one to add it to and remember it goes at the beginning of a line not the end. So if you have a right turn between segment 2 and 3 add the turn description to segment 3.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;Hopefully that'll be everything I need. I'm bringing my old phone just in case I need to tether (damn you iPhone and your lame bluetooth support) to the N800 for data.  Now about that battery life...&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2534873540987199356-1680688519856146591?l=programmingasart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programmingasart.blogspot.com/feeds/1680688519856146591/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2534873540987199356&amp;postID=1680688519856146591' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/1680688519856146591'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/1680688519856146591'/><link rel='alternate' type='text/html' href='http://programmingasart.blogspot.com/2008/04/im-bit-of-rally-fan.html' title='Google Maps, Maemo Mapper, GPX, KML all get me to the rally!'/><author><name>prodrive555</name><uri>http://www.blogger.com/profile/01056033371628831177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2534873540987199356.post-3767834466051772344</id><published>2008-03-30T12:26:00.004-05:00</published><updated>2011-03-13T22:49:42.617-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='builds'/><category scheme='http://www.blogger.com/atom/ns#' term='toolchain'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>Building source on Ubuntu</title><content type='html'>If you're trying to build anything from source on Ubuntu don't forget to &lt;code&gt; sudo apt-get install build-essential &lt;/code&gt; before you start!&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I was trying to build the iphone toolchain on Ubuntu 7.10 and was getting this error when trying to &lt;code&gt;./configure --enable-optimized&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre&gt;checking for C compiler default output file name... configure: error: C compiler cannot create executables&lt;br /&gt;See 'config.log' for more details.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;I knew there was some basic install stuff you needed before hand but I had to search for it. Once installed your configure step will work.&lt;br /&gt;&lt;br /&gt;[update]&lt;br /&gt;If you have to build ruby gems with native extensions then also add&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: arial, verdana, helvetica, arial, sans; font-size: 13px; line-height: 21px;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre style="background-color: #333333; color: white; font-size: 1em; overflow-x: auto; overflow-y: auto; padding-bottom: 1em; padding-left: 1em; padding-right: 1em; padding-top: 1em;"&gt;&lt;code style="font-family: 'Bitstream Vera Sans Mono', 'courier new', courier, monospace; font-size: 1.1em;"&gt;sudo apt-get install ruby1.8-dev&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2534873540987199356-3767834466051772344?l=programmingasart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programmingasart.blogspot.com/feeds/3767834466051772344/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2534873540987199356&amp;postID=3767834466051772344' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/3767834466051772344'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/3767834466051772344'/><link rel='alternate' type='text/html' href='http://programmingasart.blogspot.com/2008/03/building-source-on-ubuntu.html' title='Building source on Ubuntu'/><author><name>prodrive555</name><uri>http://www.blogger.com/profile/01056033371628831177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2534873540987199356.post-7755791317605385266</id><published>2008-01-21T23:34:00.001-05:00</published><updated>2008-02-15T01:31:22.868-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='code generation'/><title type='text'>HTML as a programming language</title><content type='html'>I read an article a couple days ago about robots that were programmed by genetic algorithms where one of the patterns that evolved was that of a liar.  I've been looking for something to try out with genetic algorithms and thought it would be interesting to see if I could create a liar bot as well.&lt;br /&gt;Since I've been reading Programming Collective Intellegence (along with everyone else!) and Dave always telling me this stuff needs to be done as a tree ("LISP, NICK! LISP!") I started thinking down that path.&lt;br /&gt;Then I realized that HTML is a tree, and quickly coded up this useless calculating proof of concept: HTML programming!&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;body&gt;&lt;br /&gt;  &amp;lt;div class="add"&gt;&lt;br /&gt;      &amp;lt;div class="power"&gt;&lt;br /&gt;          &amp;lt;div&gt;x&amp;lt;/div&gt;&lt;br /&gt;          &amp;lt;div&gt;2&amp;lt;/div&gt;&lt;br /&gt;      &amp;lt;/div&gt;&lt;br /&gt;      &amp;lt;div class="multiply"&gt;&lt;br /&gt;          &amp;lt;div&gt;5&amp;lt;/div&gt;&lt;br /&gt;          &lt;&amp;lt;div&gt;x&amp;lt;/div&gt;&lt;br /&gt;      &amp;lt;/div&gt;&lt;br /&gt;      &amp;lt;div&gt;4&amp;lt;/div&gt;&lt;br /&gt;  &amp;lt;/div&gt;&lt;br /&gt;&amp;lt;/body&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;This is the "Code". It's a polynomial, x^2+5x+4. And then the "interpreter":&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;function writeExpression(action, actors) {&lt;br /&gt;    //console.debug(action,actors);&lt;br /&gt;    if (action == 'add') action = '+';&lt;br /&gt;    if (action == 'subtract') action = '-';&lt;br /&gt;    if (action == 'multiply') action = '*';&lt;br /&gt;    if (action == 'power') action = 'Math.pow(';&lt;br /&gt;&lt;br /&gt;    var openParen = action.indexOf("(");&lt;br /&gt;    if (openParen &gt; -1) {&lt;br /&gt;         action += actors.join(",")+")";&lt;br /&gt;         return action;&lt;br /&gt;    } else {&lt;br /&gt;         return actors.join(action);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function depthFirst(el) {&lt;br /&gt;    if (el.childElements().length == 0) return el.innerHTML;&lt;br /&gt;    var children = [];&lt;br /&gt;    for(var i = 0; i &lt; el.childElements().length; i++) {&lt;br /&gt;        children.push(depthFirst(el.childElements()[i]));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    var expression = writeExpression(el.className, children);&lt;br /&gt;    //console.log(expression);&lt;br /&gt;    return expression;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function parse() {&lt;br /&gt;    var code = depthFirst($(document.body));&lt;br /&gt;    $(document.body).insert("&amp;lt;br/&gt;"+code);&lt;br /&gt;    x = prompt('X = ?');&lt;br /&gt;    eval("fun = function(x) {return "+code+";}; alert('f(x) = "+code+"\\nf("+x+") = '+fun(x));");&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;It's just a depth first search that then decodes the class name into an operator and returns the equation for that branch.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2534873540987199356-7755791317605385266?l=programmingasart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programmingasart.blogspot.com/feeds/7755791317605385266/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2534873540987199356&amp;postID=7755791317605385266' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/7755791317605385266'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/7755791317605385266'/><link rel='alternate' type='text/html' href='http://programmingasart.blogspot.com/2008/01/html-as-programming-language.html' title='HTML as a programming language'/><author><name>prodrive555</name><uri>http://www.blogger.com/profile/01056033371628831177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2534873540987199356.post-2688278516691811957</id><published>2008-01-06T04:27:00.001-05:00</published><updated>2008-01-06T04:29:31.465-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='projects'/><category scheme='http://www.blogger.com/atom/ns#' term='pygame'/><category scheme='http://www.blogger.com/atom/ns#' term='nokia'/><category scheme='http://www.blogger.com/atom/ns#' term='N800'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='GPS'/><category scheme='http://www.blogger.com/atom/ns#' term='HUD'/><title type='text'>Reflecting off a cd case 2</title><content type='html'>&lt;a href="http://www.flickr.com/photos/37579119@N00/2170739699/" title="photo sharing"&gt;&lt;img src="http://farm3.static.flickr.com/2220/2170739699_1a8b4537b6_m.jpg" alt="" style="border: solid 2px #000000;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-size: 0.9em; margin-top: 0px;"&gt;&lt;a href="http://www.flickr.com/photos/37579119@N00/2170739699/"&gt;Reflecting off a cd case 2&lt;/a&gt; &lt;br /&gt;Originally uploaded by &lt;a href="http://www.flickr.com/people/37579119@N00/"&gt;joecagit&lt;/a&gt;&lt;/span&gt;&lt;br clear="all" /&gt;&lt;p&gt;Progress has been made!&lt;br /&gt;Using GPSD's python wrapper I'm connecting to GPSD running on my desktop machine. I also fixed the spacing of the lines on the speed chart and the number of numbered lines on the compass. I also dropped in the current speed value.&lt;br /&gt;&lt;br /&gt;The first test revealed how tiny the font at 25 (pixels? points?) is. So I bumped it up to 50 and doubled the draw size of the two gauges.  Either by luck or some math that I some how got right, the fonts fix perfectly.  &lt;br /&gt;&lt;br /&gt;When trying to take this picture I noticed that the display goes away completely when the any part of the light from the GPS is behind it.  That means that the HUD will disappear in other car's lights or street lights, etc.  I hope that won't be too much of an issue.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2534873540987199356-2688278516691811957?l=programmingasart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programmingasart.blogspot.com/feeds/2688278516691811957/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2534873540987199356&amp;postID=2688278516691811957' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/2688278516691811957'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/2688278516691811957'/><link rel='alternate' type='text/html' href='http://programmingasart.blogspot.com/2008/01/reflecting-off-cd-case-2.html' title='Reflecting off a cd case 2'/><author><name>prodrive555</name><uri>http://www.blogger.com/profile/01056033371628831177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm3.static.flickr.com/2220/2170739699_1a8b4537b6_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2534873540987199356.post-1257468921610924080</id><published>2008-01-04T00:55:00.001-05:00</published><updated>2008-01-06T04:35:10.928-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='projects'/><category scheme='http://www.blogger.com/atom/ns#' term='pygame'/><category scheme='http://www.blogger.com/atom/ns#' term='nokia'/><category scheme='http://www.blogger.com/atom/ns#' term='N800'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='HUD'/><title type='text'>Running on N800!</title><content type='html'>&lt;style type="text/css"&gt;.flickr-photo { border: solid 2px #000000; }.flickr-yourcomment { }.flickr-frame { text-align: left; padding: 3px; }.flickr-caption { font-size: 0.8em; margin-top: 0px; }&lt;/style&gt;&lt;div class="flickr-frame"&gt; &lt;a href="http://www.flickr.com/photos/37579119@N00/2165385600/" title="photo sharing"&gt;&lt;img src="http://farm3.static.flickr.com/2229/2165385600_b5fbce1661_m.jpg" width="240" height="160" alt="IMG_2250.JPG" /&gt;&lt;/a&gt;&lt;br /&gt; &lt;span class="flickr-caption"&gt;&lt;a href="http://www.flickr.com/photos/37579119@N00/2165385600/"&gt;IMG_2250.JPG&lt;/a&gt;, originally uploaded by &lt;a href="http://www.flickr.com/people/37579119@N00/"&gt;joecagit&lt;/a&gt;.&lt;/span&gt;&lt;/div&gt;    &lt;p class="flickr-yourcomment"&gt; Thanks to pygame and anyone who worked on porting it and python to Maemo I have the first steps running on the N800!  &lt;br /&gt;Fullscreen - check&lt;br /&gt;Flip Horizontal - check&lt;br /&gt;&lt;br /&gt;I also found wiimote.py on the internet and will be trying to integrate a wiimote as an "angle of attack" and G-meter. &lt;br /&gt;&lt;br /&gt;It's taking a little bit of time since I have to now learn python to get this all to work. But, hey, one more language to add to my collection.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2534873540987199356-1257468921610924080?l=programmingasart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programmingasart.blogspot.com/feeds/1257468921610924080/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2534873540987199356&amp;postID=1257468921610924080' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/1257468921610924080'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/1257468921610924080'/><link rel='alternate' type='text/html' href='http://programmingasart.blogspot.com/2008/01/running-on-n800.html' title='Running on N800!'/><author><name>prodrive555</name><uri>http://www.blogger.com/profile/01056033371628831177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm3.static.flickr.com/2229/2165385600_b5fbce1661_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2534873540987199356.post-4904322624695359508</id><published>2008-01-01T22:09:00.001-05:00</published><updated>2008-01-06T04:34:14.437-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='projects'/><category scheme='http://www.blogger.com/atom/ns#' term='prototypes'/><category scheme='http://www.blogger.com/atom/ns#' term='nokia'/><category scheme='http://www.blogger.com/atom/ns#' term='N800'/><category scheme='http://www.blogger.com/atom/ns#' term='shoes'/><category scheme='http://www.blogger.com/atom/ns#' term='GPS'/><category scheme='http://www.blogger.com/atom/ns#' term='HUD'/><title type='text'>First Prototype HUD GPS Hookup</title><content type='html'>&lt;style type="text/css"&gt;.flickr-photo { border: solid 2px #000000; }.flickr-yourcomment { }.flickr-frame { text-align: left; padding: 3px; }.flickr-caption { font-size: 0.8em; margin-top: 0px; }&lt;/style&gt;&lt;div class="flickr-frame"&gt; &lt;a href="http://www.flickr.com/photos/37579119@N00/2156295515/" title="photo sharing"&gt;&lt;img src="http://farm3.static.flickr.com/2305/2156295515_24fea3d154_m.jpg" width="240" height="160" alt="IMG_2246.JPG" /&gt;&lt;/a&gt;&lt;br /&gt; &lt;span class="flickr-caption"&gt;&lt;a href="http://www.flickr.com/photos/37579119@N00/2156295515/"&gt;IMG_2246.JPG&lt;/a&gt;, originally uploaded by &lt;a href="http://www.flickr.com/people/37579119@N00/"&gt;joecagit&lt;/a&gt;.&lt;/span&gt;&lt;/div&gt;    &lt;p class="flickr-yourcomment"&gt; This is the first test of my prototype for a car HUD.  What I'm going for is a fighter jet feel in my car.  I'm prototyping using Shoes for now to just work out the details quickly. I'm using gpsd with Net::Telnet in Ruby to access the heading (across the top) and speed (down the side). &lt;br /&gt;The image doesn't really make sense since the heading coming over the wire isn't what's showing on the compass.  I think I took the picture as one of the bad sentences came across.  (Every once in a while it would change to 358ish degrees when it was supposed to be about 2 degrees) &lt;br /&gt;Also the speed coming across is either in knots or meters/second so that's what's showing on the HUD not the 25 mph on the GPS. &lt;br /&gt;I have to still figure out how to get the waypoint information from the GPS to update the hud. That's what the little circle is.  Hardcoded to 285 in the picture.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2534873540987199356-4904322624695359508?l=programmingasart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programmingasart.blogspot.com/feeds/4904322624695359508/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2534873540987199356&amp;postID=4904322624695359508' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/4904322624695359508'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/4904322624695359508'/><link rel='alternate' type='text/html' href='http://programmingasart.blogspot.com/2008/01/img2246jpg.html' title='First Prototype HUD GPS Hookup'/><author><name>prodrive555</name><uri>http://www.blogger.com/profile/01056033371628831177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm3.static.flickr.com/2305/2156295515_24fea3d154_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2534873540987199356.post-6286818493514162814</id><published>2007-11-29T22:21:00.001-05:00</published><updated>2008-04-06T22:50:44.710-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='prototype'/><title type='text'>Prototype/Javascript rules</title><content type='html'>I was doing some work with the new prototype this week to display some tables that represent a part of the file system.  Since each one of them was a folder and could have numerous files I needed each one to collapse, but I wanted to keep all the info in  the same table so divs where out. &lt;br /&gt;This isn't ground breaking, but it shows the power of the prototype.js 1.6.  This code closed each row after the header row and I didn't need to provide unique id's for each row on each table!  All I did as you'll see below is pass the link that was toggling the collapse and expansion.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;function _toggle(a) { &lt;br /&gt;            a = $(a); &lt;br /&gt;            var trs = a.up('tbody').childElements(); &lt;br /&gt;            trs.without(trs.first()).invoke('toggle'); &lt;br /&gt;            a.update(a.innerHTML == "-"?"+":"-"); &lt;br /&gt;            return false; &lt;br /&gt;        } &lt;br /&gt;        Event.observe(window, 'load', function() { &lt;br /&gt;            $$('a[rel="toggle"]').each(function(a) { _toggle(a);}); &lt;br /&gt;        });&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The table would be rendered something like this.  You can see the toggling link.  I added a "rel" attribute to be able to identify and collapse all the tables when the page loaded. &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;table&gt; &lt;br /&gt;        &amp;lt;tbody&gt; &lt;br /&gt;                &amp;lt;tr&gt;&lt;br /&gt;                     &amp;lt;td class="name" colspan="2"&gt;&lt;br /&gt;                        &amp;lt;div&gt;&amp;lt;a href="#" onclick="_toggle(this); return false;" rel="toggle"&gt;-&amp;lt;/a&gt;&amp;lt;/div&gt;Template Something&lt;br /&gt;                     &amp;lt;/td&gt;&lt;br /&gt;                 &amp;lt;/tr&gt;&lt;br /&gt;     &amp;lt;/tbody&gt;&lt;br /&gt;&amp;lt;/table&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;So little code that does so much.  But it really isn't that much.  It's just that doing this the old way required you to put in so much code with id parsing to get it done.  So really it's just the right about of code for the perceived work.  I like it!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2534873540987199356-6286818493514162814?l=programmingasart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programmingasart.blogspot.com/feeds/6286818493514162814/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2534873540987199356&amp;postID=6286818493514162814' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/6286818493514162814'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/6286818493514162814'/><link rel='alternate' type='text/html' href='http://programmingasart.blogspot.com/2007/11/prototypejavascript-rules.html' title='Prototype/Javascript rules'/><author><name>prodrive555</name><uri>http://www.blogger.com/profile/01056033371628831177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2534873540987199356.post-7121527714209130631</id><published>2007-11-13T21:33:00.000-05:00</published><updated>2007-11-13T22:35:37.123-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='transactions'/><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><title type='text'>Spring Transactions</title><content type='html'>Spring offers the capability to manage DB transactions outside of the application container.  We recently came across this need with Hibernate.  Since we are using Java 5 we went with annotations.  After some fumbling around trying to understand what was happening, we got something working.  Then we tried to push it further.&lt;br /&gt;&lt;br /&gt;We were trying to solve the situation where you have two transactions in a wrapper method.  The two transactions should be independent.  An exception in the second should not cause a roll back in the first. (This was a hypothetical situation I think. It was brought up by another programmer).  So here's what we had:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class Service {&lt;br /&gt;   public wrapperMethod() {&lt;br /&gt;       txMethodA();&lt;br /&gt;       txMethodB();&lt;br /&gt;   }&lt;br /&gt;   @Transactional&lt;br /&gt;   public txMethodA(){ ... do some db inserts. commit. }&lt;br /&gt;   @Transactional&lt;br /&gt;   public txMethodB(){ ... do some db inserts. throw exception. commit. }&lt;br /&gt;}&lt;br /&gt;class Action {&lt;br /&gt;   public execute() {&lt;br /&gt;      service.wrapperMethod();&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As a test we would sometimes throw an exception between the two methods inside the wrapper.  We were also using Spring's OpenSessionInView filter.&lt;br /&gt;&lt;br /&gt;What we immediately found it this situation was that because of the OSV filter setting readOnly to true that we couldn't use txMethodA to insert with out a transaction on the wrapperMethod.  So we put a transaction on the wrapperMethod.  This led to the exception rolling &lt;em&gt;all&lt;/em&gt; inserts back.  So it seemed that the transactional annotation was being ignored.  &lt;br /&gt;We then tried changing the propagation on txMethodA and txMethodB to REQUIRES_NEW to try to create a new transaction for each method.  This too was ignored. Anything we tried would not result in the commit of one and and the rollback of the other.&lt;br /&gt;&lt;br /&gt;Well, after some reading (duh) from the Spring docs, namely &lt;a href="http://static.springframework.org/spring/docs/2.0.x/reference/transaction.html"&gt;chapter 9&lt;/a&gt; it dawned on me. &lt;br /&gt;&lt;br /&gt;This maybe obvious to some people, but I run up against this once in a while and it doesn't seem intuitive to me so I forget how it works all the time.  Take this example:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class A{&lt;br /&gt;  public doSomething() {&lt;br /&gt;    doSomethingElse();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public doSomethingElse() {&lt;br /&gt;    println "Class A";&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class B extends A {&lt;br /&gt;  public doSomethingElse() {&lt;br /&gt;    println "Class B";&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;B b = new B();&lt;br /&gt;b.doSomethingElse(); //-&gt; Class B&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Turns out it actually works like I expect, i.e. prints "Class B". I was thinking that this would print "Class A".  This was disheartening because I thought I figured out what was happening.  &lt;br /&gt;&lt;br /&gt;Turns out I was close but not quite there. I read the section on &lt;a href="http://static.springframework.org/spring/docs/2.0.x/reference/aop.html#aop-understanding-aop-proxies"&gt;proxies&lt;/a&gt; which is what Spring creates for each transactional class, even if the transaction is only on one method.  It is the proxy class/object that gets wired in to the action, not the actual session.  This is important be cause, as the page says, self references in the session object will &lt;em&gt;not&lt;/em&gt; go through the proxy. &lt;br /&gt;&lt;br /&gt;I guess the proxy can be though of as using the decorator pattern, but doesn't add anything to it.  So what was happening?  &lt;br /&gt;&lt;br /&gt;Our original call to the wrapper was through the proxy.  This would set up transactions if we had them on the wrapper, but we didn't. That is why we got the readOnly error.  We were still using the OSIV transaction.  Once we added a transaction to the wrapper class and called through the proxy the transaction was started for the wrapper but then the self referenced calls to txMethodA and txMethodB where only in the service object.  Not throught the proxy. The pojo service object knows nothing about transactions so that's why nothing happened and it seemed like it was being ignored.&lt;br /&gt;&lt;br /&gt;This is just something to keep in mind not only when using spring transactions but when using any Spring AOP advised code.  It's also a sign I need to read more...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2534873540987199356-7121527714209130631?l=programmingasart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programmingasart.blogspot.com/feeds/7121527714209130631/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2534873540987199356&amp;postID=7121527714209130631' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/7121527714209130631'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/7121527714209130631'/><link rel='alternate' type='text/html' href='http://programmingasart.blogspot.com/2007/11/spring-transactions.html' title='Spring Transactions'/><author><name>prodrive555</name><uri>http://www.blogger.com/profile/01056033371628831177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2534873540987199356.post-301707898199753385</id><published>2007-11-04T17:12:00.000-05:00</published><updated>2007-11-04T17:30:09.097-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='troubleshooting'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>Rails "What the...?'"s</title><content type='html'>I recently stumbled across 2 rails behaviors that have left me scratching my head.  They both involve respond_to.&lt;br /&gt;The first is how respond_to handles requests from Javascript changing the browsers location.&lt;br /&gt;&lt;pre&gt;window.location='http://some/new/page';&lt;/pre&gt;&lt;br /&gt;Coming from Safari (and IE 6, I think) the request will be treated as a XHR. So this will cause your respond_to to return the .js action. I don't know if this is rails fault or the browser's but luckily you can fall back to request.xhr?&lt;br /&gt;I had to replace my respond_to section with this:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;render :template =&gt; 'items/new.rjs' if request.xhr?&lt;br /&gt;render :template =&gt; 'items/new' unless request.xhr?&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;to get it to behave like I would expect across all browsers.&lt;br /&gt;&lt;br /&gt;The other issue I had was during testing.  I had a simple edit action:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;def edit&lt;br /&gt; @item = Item.find(params[:id])&lt;br /&gt; respond_to do |wants|&lt;br /&gt;   wants.js&lt;br /&gt;   wants.html&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Notice the order of the wants. The XHR is before the regular request. From my test I was calling&lt;br /&gt;&lt;pre&gt;get :edit, :id =&gt; 1&lt;/pre&gt;&lt;br /&gt;and asserting&lt;br /&gt;&lt;pre&gt; assert_template 'edit'&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This was failing because it was "&lt;span style="font-style: italic;font-family:courier new;" &gt;expecting &lt;"edit"&gt; but rendering &lt;"edit.rjs"&gt;&lt;/span&gt;". Hitting the action in a browser rendered the right result but the test failed.  I had to reverse those two, so that the regular request was before the XHR request and then it worked. There seems to be first-come-first-serve functionality if the mime-type isn't specified.&lt;br /&gt;I'll have to look into why the functional test "get" method doesn't set a mime-type.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2534873540987199356-301707898199753385?l=programmingasart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programmingasart.blogspot.com/feeds/301707898199753385/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2534873540987199356&amp;postID=301707898199753385' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/301707898199753385'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/301707898199753385'/><link rel='alternate' type='text/html' href='http://programmingasart.blogspot.com/2007/11/rails-what-thes.html' title='Rails &quot;What the...?&apos;&quot;s'/><author><name>prodrive555</name><uri>http://www.blogger.com/profile/01056033371628831177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2534873540987199356.post-4587096058041880861</id><published>2007-10-28T17:30:00.000-05:00</published><updated>2007-11-04T17:47:25.601-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='struts2'/><title type='text'>Struts 2 Dynamic Validators</title><content type='html'>We had a need for a dynamic, DB driven form with simple validation at work.  The site was to be used by multiple clients and they would all have the same basic functionality except that each client would have a form they could customize and specify validation on any of the fields if necessary.  Spec wise the validation was to be required or not.  I figured that as time would move on they'd want other validations as well so I figured we could use the existing Struts2/XWork validators as to not recreate the wheel.&lt;br /&gt;&lt;br /&gt;The plan was simple.  Have a table that represented the form's fields with a client foreign key and a validator foreign key.  The validator key linked to the validator table that would provide all the information needed by a Struts2/XWork field validator. This would actually be two tables, the first would be the "parent" storing the validator class name and the the second would be a mapping of parameter names and values.  Basically everything that's in the validation xml but in the database.&lt;br /&gt;&lt;br /&gt;When the action was gotten we would loop over the fields and render each one based on the type. When the form was posted we would then loop over the list of validators, instantiate each one, populate  it's parameters and call .validate() on them.&lt;br /&gt;&lt;br /&gt;Creating the form and validators with correctly populated parameters was easy. The problem came when it tried to validate.  See the validation framework validates the action class, as it should. So when it came time to validate a field, a getFieldName() method would be called on the action class. Since the form is dynamic that method won't exist and validation will fail.&lt;br /&gt;&lt;br /&gt;I tried implementing the class as a commons DynaBean. That didn't work (didn't expect it to really, but just trying anything).&lt;br /&gt;I tried implementing the class in Groovy and using MetaExpandoClass to handle the calls to the missing methods, but that type of magic only works within Groovy and the XWork classes don't know about that.&lt;br /&gt;I tried the java.lang.reflection.Proxy class and a ImplementationHandler but those aren't for handling dynamic methods.&lt;br /&gt;The only think I didn't try is doing it like the old struts 1 map backed forms. Where the field name would be something like myfields[name] and the validating on the map. But I don't think that will work either. I don't really like that solution either because it forces you to be aware of the implementation and when entering validators in the db you'd have to be aware of that. Or if you used an ExpressionValidator with OGNL.&lt;br /&gt;I'd hate to have to create an implementation of the XWork OGNL parser that looks for DynaBeans and treat them appropriately.  But I think that might be the only solution.&lt;br /&gt;Something I'd look into if work really need this functionality but for now I've spent way too much time on it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2534873540987199356-4587096058041880861?l=programmingasart.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://programmingasart.blogspot.com/feeds/4587096058041880861/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2534873540987199356&amp;postID=4587096058041880861' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/4587096058041880861'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2534873540987199356/posts/default/4587096058041880861'/><link rel='alternate' type='text/html' href='http://programmingasart.blogspot.com/2007/10/struts-2-dynamic-validators.html' title='Struts 2 Dynamic Validators'/><author><name>prodrive555</name><uri>http://www.blogger.com/profile/01056033371628831177</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry></feed>
