<?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-29718960</id><updated>2012-01-28T21:51:52.378-08:00</updated><category term='solr'/><category term='external disk'/><category term='ant'/><category term='java'/><category term='books'/><category term='apple'/><category term='vmware'/><category term='collaboration'/><category term='programming'/><category term='scm'/><category term='moodle'/><category term='os x'/><category term='rural'/><category term='django'/><category term='flex'/><category term='netbeans'/><category term='hadoop'/><category term='misc'/><category term='android'/><category term='python'/><category term='groovy'/><category term='rails'/><category term='family'/><category term='mac'/><category term='5tech'/><category term='evdo'/><category term='testing'/><category term='mercurial'/><category term='management'/><category term='talks'/><category term='webtest'/><category term='subversion'/><category term='google'/><category term='svn'/><title type='text'>Western Skies</title><subtitle type='html'>Information and expertise from beneath the Western Skies of rural Oregon.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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>76</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-29718960.post-6394685596687079888</id><published>2011-10-14T21:44:00.000-07:00</published><updated>2011-10-14T21:44:37.640-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='solr'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>Why is my Rails app calling Solr so often?</title><content type='html'>I work on the back-end of a Rails &lt;a href="http://www.xydo.com/"&gt;app&lt;/a&gt; that uses Solr via Sunspot.  Looking at the solr logs, I could see the same item being added/indexed repeatedly sometimes right before it was deleted from solr.  I didn't write the code, but I was tasked with figuring it out.&lt;br /&gt;&lt;br /&gt;Glancing at the main path of the code didn't show anything obvious.  I figured the superfluous solr calls were&amp;nbsp; happening via callbacks somewhere in the graph of objects related to my object in solr, but which one(s).&amp;nbsp; Again, I didn't write the code, I just had to make it perform.&lt;br /&gt;&lt;br /&gt;I hit on the idea of monkey-patching (for good, not evil) the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Sunspot&lt;/span&gt; module.&amp;nbsp; Fortunately, most/all of the methods on the Sunspot module just forward the call onto the session object.&amp;nbsp; So, it's really easy to replace the original call with anything you want and still call the real Sunspot code, if that's what you want to do.&lt;br /&gt;&lt;br /&gt;This is so easy to do that I even did it the first time in the rails console.&amp;nbsp; In that case, I was happy to abort the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;index&lt;/span&gt; operation when it first happened.&amp;nbsp; So, I whipped this up in a text file and pasted it into the console:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;module Sunspot&lt;br /&gt;&amp;nbsp; class &amp;lt;&amp;lt;self&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; def index(*objects)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; raise "not gonna do it!"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; end&lt;br /&gt;&amp;nbsp; end&lt;br /&gt;end&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Then, I invoked the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;destroy&lt;/span&gt; operation that was triggering the solr adds, got the stack trace, and could clearly see which dependent object was causing the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;index&lt;/span&gt; operation.&lt;br /&gt;&lt;br /&gt;For another case, I needed to run a complex workflow in a script to trigger the offending solr operations.  In that case, I wanted something automatically installed when the script started up, and I wanted something that didn't abort - all I wanted was a stack trace.  So, I installed the monkey-patch in &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;config/initializers/sunspot.rb&lt;/span&gt; and had a more involved &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;index&lt;/span&gt; function:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; def index(*objects)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; puts "Indexing the following objects:"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; objects.each { |o| puts "#{o.class} - #{o.id}" }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; puts "From: =============="&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; raise rescue puts $!.backtrace&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; puts ===========\n"&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; session.index(*objects)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;That last line is the body of the real version of the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;index&lt;/span&gt; method - like I said, trivial to re-implement; no alias chaining required.&lt;br /&gt;&lt;br /&gt;Maybe there's some cooler way to figure this out, but this worked for me.&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-6394685596687079888?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/6394685596687079888/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=6394685596687079888' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/6394685596687079888'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/6394685596687079888'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2011/10/why-is-my-rails-app-calling-solr-so.html' title='Why is my Rails app calling Solr so often?'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-6104339953023393762</id><published>2011-08-18T09:50:00.000-07:00</published><updated>2011-08-18T09:50:38.572-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>Rails/Rspec does not clean up model instances on MySQL</title><content type='html'>I recently solved a thorn in my side relating to some &lt;a href="http://rspec.info/"&gt;Rspec&lt;/a&gt; tests in our code base when running on my development machine using MySQL.&amp;nbsp; For some reason, some instances that were created using &lt;a href="https://github.com/thoughtbot/factory_girl"&gt;Factory Girl&lt;/a&gt; weren't getting cleaned up, which in turn would cause subsequent test runs to fail because of duplicate data.&amp;nbsp; So, I'd DELETE the whole tables from the MySQL prompt.&amp;nbsp; I looked in the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;test.log&lt;/span&gt; file, and I could see the save points being issued before the objects were created, but they weren't getting removed at the end of the test.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;I didn't have a lot of time to look into it, and I didn't know where to look - Rspec, Factory Girl, Rails?&amp;nbsp; So, in the short-term, I just added &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;after_each&lt;/span&gt; calls to destroy the objects.&amp;nbsp; And, I moved on.&lt;br /&gt;&lt;br /&gt;Then, I was dumping schemas in MySQL using SHOW CREATE TABLE in order to analyze some tables and indexes, and I noticed the storage ENGINE flag on the tables.&amp;nbsp; I went back and looked at the tables in my test database that were giving me trouble, and, of course(?), they were MyISAM rather than InnoDB.&amp;nbsp; So, transaction rollback (used to clean up after tests) didn't work.&lt;br /&gt;&lt;br /&gt;I changed the storage engine on those tables (ALTER TABLE t1 ENGINE = InnoDB), commented out the manual clean-up code, and voila!&amp;nbsp; It works right now.&amp;nbsp; Pretty obvious in retrospect, but I didn't even know where to start looking in our stack.&lt;br /&gt;&lt;br /&gt;I hope this helps some other poor souls, too.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Charles.&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-6104339953023393762?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/6104339953023393762/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=6104339953023393762' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/6104339953023393762'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/6104339953023393762'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2011/08/railsrspec-does-not-clean-up-model.html' title='Rails/Rspec does not clean up model instances on MySQL'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-3937248721515178944</id><published>2011-04-26T10:02:00.000-07:00</published><updated>2011-05-11T16:54:27.211-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Freeing up phone space on Android</title><content type='html'>For the last couple of months my Motorola Droid running Android 2.2.2 has been complaining about being "low on space" for the phone, not the SD card.&amp;nbsp; I pruned some apps, but that didn't help much. Things really came to a head this morning when my phone was so low on memory that it was no longer downloading email.&lt;br /&gt;&lt;br /&gt;I found this article to be quite helpful - &lt;br /&gt;&lt;a href="http://www.androidcentral.com/monthly-maintenance-keeping-things-speedy"&gt;http://www.androidcentral.com/monthly-maintenance-keeping-things-speedy&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;For me, the two big ones were Messaging and the Browser cache.&amp;nbsp; I had a couple of threads in Messaging containing a number of pictures.&amp;nbsp; Once I saved the pictures off to the SD card, I purged the threads, that freed up ~20MB.&amp;nbsp; Clearing the browser cache freed another ~20MB, but that will probably evaporate again as the browser caches things.&lt;br /&gt;&lt;br /&gt;Here's a minor whine about Android:&amp;nbsp; the SD card and phone storage settings page tells you how big your SD card is and how much space is remaining, but the phone storage just says how much is left.&amp;nbsp; Without knowing how much I had to start with, it's hard to know if, say, 20MB is a lot or not.&amp;nbsp; As near as I can tell, Android seems to complain when the space is less than 25MB.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update:&lt;/b&gt; I ran out of space again, and clearing the browser cache didn't help.&amp;nbsp; After bumping around some more, first I discovered that in "Manage Applications" the one and only menu option is to sort by size.&amp;nbsp; Doing that revealed that the new pig was the (post pay-wall version) New York Times application.&amp;nbsp; It was using over 60MB of data space in the Phone Storage area.&amp;nbsp; The app doesn't have a "clear cache" function, so I used the "Clear Data" button from within Manage Applications, and I was back in action.&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-3937248721515178944?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/3937248721515178944/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=3937248721515178944' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/3937248721515178944'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/3937248721515178944'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2011/04/freeing-up-phone-space-on-android.html' title='Freeing up phone space on Android'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-415731153965427787</id><published>2010-11-05T17:19:00.000-07:00</published><updated>2010-11-05T17:19:41.592-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hadoop'/><title type='text'>A Fix for "Exceeded MAX_FAILED_UNIQUE_FETCHES" in Hadoop</title><content type='html'>In a project I'm currently working on, we're moving a bunch of our back-end processing to &lt;a href="http://http//hadoop.apache.org/"&gt;Hadoop&lt;/a&gt;.&amp;nbsp; We started a two-node cluster: one master, one slave. &amp;nbsp;That seemed to work fine. &amp;nbsp;Then, we went to four nodes, and about the same time I was testing out a new Hadoop job. &amp;nbsp;The (single) reducer was hanging with this somewhat cryptic message:&lt;br /&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: 14px; white-space: pre;"&gt;Shuffle Error: Exceeded MAX_FAILED_UNIQUE_FETCHES; bailing-out&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;I went out to the slave node and looked through the job logs, and I could see that it was timing out trying to transfer data from one of the other slave nodes - an upstream mapper node.  Upon closer scrutiny of the the log file I realized that Hadoop was trying to transfer from the other slave's public IP address, which is behind a firewall that blocks public access.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Key take-away number one&lt;/b&gt;: when you're just starting out with Hadoop, if you only have one slave, you've only demonstrated one real communication path: master-to-slave.  Your cluster isn't doing any slave-to-slave transfers because everything was on the one slave.  Also, our initial job had no reducer, so it ran fine on the new, 4-node cluster because it was still only master-slave communication.&lt;br /&gt;&lt;br /&gt;For some reason, the mapper slave was advertising the location of the map output data via its public IP address. My first attempt at fixing this problem involved the &lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;dfs.datanode.dns.interface&lt;/span&gt; configuration parameter (and it's &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;mapred&lt;/span&gt; equivalent).  This tells Hadoop that when a process (mapred or dfs) wants to figure out it's host name, use the IP address associated with the given interface.  (You could even have dfs and mapred using separate interfaces for additional throughput.)&lt;br /&gt;&lt;br /&gt;This failed for me because I had one interface with two addresses, not two interfaces.  I dug through the Hadoop DNS code (&lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;org.apache.hadoop.net.DNS&lt;/span&gt; - God, I love open-source: you can just look for yourself) and saw that if there is one interface, the code loops through the IP addresses and performs reverse DNS lookups and takes the first successful result. I was fortunate in that the private IP address was coming up first in that enumeration of the IPs on the interface, but it still wasn't working.  I talked to our system admin/configuration guru.  It turns out that our hosting provider doesn't provide reverse DNS for those private IP addresses.  We could have set up our own DNS server for just these reverse lookups, but there was a brute-force option available to us.&lt;br /&gt;&lt;br /&gt;You can bypass all of Hadoop's efforts to automatically figure out the slave's host name by specifying the &lt;span class="Apple-style-span" style="font-family: 'Courier New',Courier,monospace;"&gt;slave.host.name&lt;/span&gt; parameter in the configuration files.  If that is set, Hadoop will just take your word for it and use the name you provide.  Now, in theory, this might be onerous - it means you have a different configuration file per-slave.  However, our cluster is configured and maintained via &lt;a href="http://http//www.puppetlabs.com/"&gt;Puppet&lt;/a&gt;.  So, our puppet master just tweaked his Puppet script, and we never looked back.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Take-away number two&lt;/b&gt;: Exceeded MAX_FAILED_UNIQUE_FETCHES could mean a simple connectivity problem.  I'm sure there are other possible causes, but an inability to connect between slaves is comparatively simple to troubleshoot.&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-415731153965427787?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/415731153965427787/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=415731153965427787' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/415731153965427787'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/415731153965427787'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2010/11/fix-for-exceeded-maxfaileduniquefetches.html' title='A Fix for &quot;Exceeded MAX_FAILED_UNIQUE_FETCHES&quot; in Hadoop'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-6800605227859514637</id><published>2010-04-06T14:56:00.000-07:00</published><updated>2010-04-07T14:26:57.445-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='django'/><category scheme='http://www.blogger.com/atom/ns#' term='5tech'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Django vs. Grails</title><content type='html'>When I came up with the &lt;a href="http://western-skies.blogspot.com/2010/03/five-technologies-in-five-weeks.html"&gt;Five Technologies in Five Weeks&lt;/a&gt; project, I hadn't intended to compare any of the technologies to each other directly.&amp;nbsp; My original ordering for the technologies didn't have any head-to-head match-ups, but I just finished my &lt;a href="http://western-skies.blogspot.com/2010/04/5tech-week-2-grails.html"&gt;Grails project&lt;/a&gt;, which was "right after" (modulo interruptions) my &lt;a href="http://western-skies.blogspot.com/2010/03/5tech-week-1-google-app-engine.html"&gt;Django/GAE project&lt;/a&gt;.&amp;nbsp; And, while I was working on Grails, I kept comparing it to Django, and I felt compelled to write up my observations.&lt;br /&gt;&lt;br /&gt;"All things being equal, which they never are" (&lt;a href="http://manager-tools.com/"&gt;Manager Tools&lt;/a&gt;), I'd choose Django over Grails for a new, green-field project.&amp;nbsp; However, given the constraint to run in a Java environment, I'd gladly choose Grails over the other Java/J2EE frameworks I'm familiar with.&amp;nbsp; (Django on Jython would be a contender as would &lt;a href="http://wicket.apache.org/"&gt;Wicket&lt;/a&gt;, but I don't have hands-on experience with either.)&amp;nbsp; This is not a slam on Grails.&lt;br /&gt;&lt;br /&gt;Here are some of the reasons I prefer Django over Grails:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Development Speed&lt;/b&gt; (not runtime performance): running (a trivial number of) unit tests for Grails on my machine took about 15 seconds (with Folding@Home in the background).&amp;nbsp; Django unit tests typically only take me a couple of seconds (for a trivial number of tests).&amp;nbsp; Integration tests in Grails were 30-40 seconds; Django might be 5 seconds.&amp;nbsp; Although Grails will reload the running webapp when you make a change, sometimes things are really buggered, which requires a full restart.&amp;nbsp; That seemed to happen more often in Grails than Django, and restarts take ~20 seconds vs. 2 seconds.&lt;br /&gt;Compared to the 5-7 minutes I've seen WebSphere to restart an application, Grails is blazingly fast.&amp;nbsp; But the 15-30 seconds that many operations take in Grails is long enough for the mind to wander, which is not good.&lt;br /&gt;&lt;i&gt;Update&lt;/i&gt;: a commenter pointed out the (under-documented) interactive mode of Grails.&amp;nbsp; That speeds the edit-test-edit loop considerably.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Voodoo&lt;/b&gt;: both Grails and Django do some voodoo behind the scenes to reduce the amount of chimp programming (e.g., non-DRY boilerplate) the programmer has to do.&amp;nbsp; This voodoo involves topics of the high priests like meta object programming that mere mortals typically don't have to worry about.&amp;nbsp; Maybe it's just that I don't have as much "time behind the wheel" with Grails, but I feel like its voodoo leaks out a bit and is too voodoo-rific.&amp;nbsp; A Grails programmer has to be aware of which methods are dynamically added to a class in order to separate unit tests (no voodoo) from integration tests (full voodoo). And, although I like the power of dynamic finder methods like &lt;i&gt;User.findByName()&lt;/i&gt;, it kinda bugs me that the code for that doesn't exist somewhere that I can see (you know, on punch cards!)&amp;nbsp; You don't see the dynamic methods on a Django class, but there are a lot fewer of them, so it seems less voodoo-rific.&amp;nbsp; Again, maybe more time behind the wheel of Grails would make me feel more comfortable.&lt;br /&gt;(As an aside, when I taught Python and Django in Spring 2009, the students didn't even notice the voodoo of fields on models in Django until I pointed it out to them.&amp;nbsp; Then, I exploded their heads with MOP.)&lt;/li&gt;&lt;li&gt;&lt;b&gt;View Technology&lt;/b&gt;: I have a long-standing personal preference for templates instead of ASP/JSP-like mark-up languages, and I'd lump Grails GSP pages in the latter category.&amp;nbsp; Back in the day, Jason Hunter wrote an essay called &lt;a href="http://www.servlets.com/soapbox/problems-jsp.html"&gt;The Problems with JSP&lt;/a&gt; that really stuck with me.&amp;nbsp; GSPs are much, much better than the Model 1 JSP pages that Hunter talks about, but they still feel similar enough to make me think about using something like Velocity with Grails.&amp;nbsp; Django kicks templates up a notch by having inheritance with templates, which I really love. (Even if Django didn't invent template inheritance.) &lt;/li&gt;&lt;li&gt;&lt;b&gt;Dynamic Language Issues&lt;/b&gt;: This is a real unfair comparison because I've been using Python for 15 years, but I felt that errors in Grails/Groovy were more cryptic and hard to find compared to Python.&amp;nbsp; If I typo the named parameter to a method in Python, it lets me know immediately.&amp;nbsp; More than once in Grails I misspelled a named parameter to a constructor, which failed silently and then lead to a validation failure later when I went to save the object.&amp;nbsp; Some of that is from lack of experience with Groovy/Grails - i.e., learning what error messages really mean.&amp;nbsp; But still, Python seems to fail in a more helpful way.&amp;nbsp; (I'd say Python fails gracefully, but if anything it's the opposite: very loud - "you dumb-ass, there is no parameter called recipent" when I misspelled recipient.) &lt;/li&gt;&lt;/ul&gt;I don't mean for this to be a hit-piece against Grails; I really like Grails.&amp;nbsp; I look forward to using it some more.&amp;nbsp; It's just that, for what it's worth, I like Django more.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-6800605227859514637?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/6800605227859514637/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=6800605227859514637' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/6800605227859514637'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/6800605227859514637'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2010/04/django-vs-grails.html' title='Django vs. Grails'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-5118603555041889962</id><published>2010-04-06T13:54:00.000-07:00</published><updated>2010-04-06T14:06:02.660-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='5tech'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>5Tech - Week 2: Grails</title><content type='html'>For the second project and technology in five weeks I chose &lt;a href="http://grails.org/"&gt;Grails&lt;/a&gt;.&amp;nbsp; I was very curious to try Grails on on a "real"/non-tutorial project to confirm its usability and productivity.&amp;nbsp; On my last contract gig, I was in a non-development role (configuration management) on a project that was using JSF 1.1/Spring/Hibernate and WebSphere, and their development looked really painful by my standards.&amp;nbsp; For example, they'd spend 5-7 minutes to redeploy the app just to inspect some HTML change in the JSF page.&amp;nbsp; I was looking to Grails to provide a much more productive environment.&lt;br /&gt;&lt;br /&gt;The project involved creating a system to process events and route them to users.&amp;nbsp; It was inspired by a code base that I worked on for a previous client.&amp;nbsp; (This was done with their permission.)&amp;nbsp; They have a large code base that includes "application functionality" like this event routing, as well as a lot of "technical functionality" that they rolled themselves years ago before modern tools like Spring and Hibernate were created and became mainstream.&amp;nbsp; In a way, this was a small prototype to research the feasibility of reimplementing the application functionality on a more modern platform - Grails.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Analysis&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;All in all the project went very smoothly. Because Grails is comparatively mature, there exists a fair amount of documentation, including numerous books.&amp;nbsp; I leaned heavily on &lt;a href="http://www.amazon.com/Grails-Action-Glen-Smith/dp/1933988932?ie=UTF8&amp;amp;tag=westernskies-20&amp;amp;link_code=btl&amp;amp;camp=213689&amp;amp;creative=392969" target="_blank"&gt;Grails in Action&lt;/a&gt;&lt;img alt="" border="0" height="1" src="http://www.assoc-amazon.com/e/ir?t=westernskies-20&amp;amp;l=btl&amp;amp;camp=213689&amp;amp;creative=392969&amp;amp;o=1&amp;amp;a=1933988932" style="border: medium none ! important; margin: 0px ! important; padding: 0px ! important;" width="1" /&gt; by Smith and Ledbrook.&amp;nbsp; I was able to follow their examples and adapt them to my application easily.&amp;nbsp; There just weren't any serious gaps or surprises.&lt;br /&gt;&lt;br /&gt;Using Grails to create domain classes (database entities) was a breeze.&amp;nbsp; It's so nice to just declare the fields and their constraints and have Grails "do the right thing."&amp;nbsp; You don't have to bother with annotations, let alone XML configuration files.&amp;nbsp; Creating controllers to process web requests is trivial, and being able to scaffold them to get the basic CRUD functionality in place immediately was very conducive to high productivity.&lt;br /&gt;&lt;br /&gt;I also liked the idea that services are a first-class concept in Grails (along with controllers and domain classes), which makes it very easy to program with them.&amp;nbsp;&amp;nbsp; Grails wires them into the classes that use the services via Spring, but again, you don't have to monkey with Spring's &lt;i&gt;applicationContext&lt;/i&gt;.xml file.&amp;nbsp; Finally, adding the REST interface for incoming events was almost trivial, especially since I already had the service in place.&lt;br /&gt;&lt;br /&gt;Grails (like Rails) treats testing as a core concept, not something you wave your hands at after the fact.&amp;nbsp; It has the concept of unit and integration tests, and there are a number of functional test plug-ins, too.&amp;nbsp; I did a fair amount of unit and integration testing, which was a real live-saver.&amp;nbsp; Due to the very dynamic nature of Groovy, many of my typos were not caught in the compile phase, but exercising the code in tests did catch those.&amp;nbsp; I had very few issues when I ran the actual web application.&lt;br /&gt;&lt;br /&gt;A lot of developers are unclear on the difference between unit testing and integration testing.&amp;nbsp; For better or worse, Gails makes some clear distinctions.&amp;nbsp; A lot of the Grails voodoo (e.g., dependency injection and adding dynamic methods to classes) is not available in unit tests, or you have to add it yourself via mocking or manual injection.&amp;nbsp; Thus, there is a simple distinction: if it runs under "&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;test-app -unit&lt;/span&gt;", it's a unit test, otherwise it's an integration test.&amp;nbsp; This bit me once early on when I wrote a test that needed that higher-order functionality, but I put it in a unit test.&amp;nbsp; First I got a null pointer exception because the service hadn't been injected, then I got a missing method exception because the &lt;i&gt;save&lt;/i&gt; method on the domain object hadn't been added dynamically. However, the fix was simple enough - move the test to the integration folder, and it ran fine with &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;-integration&lt;/span&gt;.&amp;nbsp; Then, I copied it back, added a few mocks (very easy in Grails), and I had a unit test, too.&lt;br /&gt;&lt;br /&gt;In terms of "project management," this step of the Five Technologies suffered from some "life happens" distractions.&amp;nbsp; Rather than running Monday through Friday, it ended up being Tuesday through Monday, and some of those days were a bit short-changed.&amp;nbsp; When I was on task, the &lt;a href="http://www.pomodorotechnique.com/"&gt;Pomodoro Technique&lt;/a&gt; continued to be effective, and I replaced my dead watch/timer with a dedicated Android application called Pomodoro Tasks - it's even &lt;a href="http://code.google.com/p/pomodorotasks/"&gt;open-source&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;In conclusion, Grails was another success for the &lt;a href="http://western-skies.blogspot.com/2010/03/five-technologies-in-five-weeks.html"&gt;Five Technologies in Five Weeks&lt;/a&gt; project.&amp;nbsp; I got the application functionality done that I expected.&amp;nbsp; Grails was very usable and productive - no nasty surprises.&amp;nbsp;&amp;nbsp; What's next?&amp;nbsp; Probably, &lt;a href="http://platform.netbeans.org/"&gt;NetBeans Platform&lt;/a&gt; because I have documentation for it already whereas I'm waiting on some Android books.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-5118603555041889962?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/5118603555041889962/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=5118603555041889962' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/5118603555041889962'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/5118603555041889962'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2010/04/5tech-week-2-grails.html' title='5Tech - Week 2: Grails'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-4386396621661408040</id><published>2010-03-24T11:15:00.000-07:00</published><updated>2010-04-06T14:06:24.059-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='django'/><category scheme='http://www.blogger.com/atom/ns#' term='5tech'/><title type='text'>5Tech - Week 1: Google App Engine</title><content type='html'>For the first of the five technologies in five weeks, I picked something easy - &lt;a href="http://code.google.com/appengine/docs/python/gettingstarted/"&gt;Google App Engine using Python&lt;/a&gt; and &lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt;.  As someone who's been using Python for 15 years, there was no language learning curve.  And using the &lt;a href="http://code.google.com/appengine/articles/appengine_helper_for_django.html"&gt;Django helper for app engine&lt;/a&gt; package allowed me to leverage my Django experience.  So with a minimal learning curve, the results were basically all good.&lt;br /&gt;&lt;br /&gt;The project involved creating a simple application to monitor web sites to check if they are up or down and notify the user about status changes.  As such, the core of the application isn't even a web app.  In fact, I've implemented the same thing a couple of different times as a standalone program in Python or Java.  However, to run a standalone application like that requires a server where it can run, and that's not something I've always had access to.  GAE's cron service provides the ability to run checks periodically - just like the main loop in my standalone applications, and GAE provides a large number of notification options, although I only used email initially.  The application does have a web interface for configuring checks and viewing the status&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold;"&gt;Project Analysis&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;My biggest problem developing the application was the fact that I was working with three separate but overlapping tools/frameworks: GAE, Django, and the Django helper.  These all worked fine, but  when I wanted to do some task, I didn't know where to look for the "right" way to do it.  After wasting a bunch of time searching for things only to find that the Django way was the right way, I just quit asking and adopted the "try Django first" strategy.  And then, the first time I went to apply that I got burned - there are some slight differences in how the &lt;span style="font-style: italic;"&gt;filter&lt;/span&gt; method is handled in Django helper versus "native" Django.  But for the most part, Django first is the way to go. In addition to the online documentation for these three tools/frameworks , I used &lt;a href="http://www.amazon.com/gp/product/059652272X?ie=UTF8&amp;amp;tag=westernskies-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=059652272X"&gt;Programming Google App Engine&lt;/a&gt; by Sanderson, which covers all of them - I highly recommend it.&lt;br /&gt;&lt;br /&gt;Although my plan with Five Technologies is to use best practices,  I am embarrassed to admit that I didn't practice much test driven development on this project despite having "home field advantage" with the technology - Django.  Some of that is due to the exploratory nature of the programming - just figuring out which end is up, and some of it was the confusion over how to do tests - as noted above, the answer is "the Django way".   Also, I found a bug in the app engine helper when loading a fixture, which hung me up - I'll be submitting a patch shortly.&lt;br /&gt;&lt;br /&gt;One (non-technical) practice that I adopted was the &lt;a href="http://www.pomodorotechnique.com/"&gt;Pomodoro Technique&lt;/a&gt;, and that worked pretty well.  The 25 minute mini-sprints were really nice to contain technology-induced ADD.  However, the watch I was using as my timer died during a pomodoro which lead to a very long and productive pomodoro.&lt;br /&gt;&lt;br /&gt;In terms of the bigger goals of Five Technologies, I have another confession: I did not restrict myself to one week.  I created version 0.1 and deployed it to the cloud within one week, but  the week following this project I went to the &lt;a href="http://www.mindviewinc.com/Conferences/JavaPosseRoundup/"&gt;Java Posse Roundup&lt;/a&gt;, and I kept working on the Django app, even though I should have been focusing on Java.  It's just that after a week of working on GAE, I had built up some good momentum and didn't want to quit.  I fear that this will be a real problem for the next projects because I won't have the luxury of continuing to work on whatever technology when I begin the next project.&lt;br /&gt;&lt;br /&gt;In conclusion, the first technology experiment was a success, even if I wasn't dogmatic.  What's next?  Most likely &lt;a href="http://grails.org/"&gt;Grails&lt;/a&gt;.  Stay tuned.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update:&lt;/b&gt;&amp;nbsp; I forgot to mention something cool I learned about - schema migration, or the lack thereof.&amp;nbsp; Before I began the project I was fretting about schema migration on GAE because I've been too lazy to learn something like &lt;a href="http://south.aeracode.org/"&gt;South&lt;/a&gt;, and therefore I do schema migrations at a SQL command prompt.&amp;nbsp; Obviously, there is no SQL problem for a NoSQL database like Google's BigTable.&amp;nbsp; Then I forgot about the issue, but half way through I looked up and said, "hey, I haven't been doing any migrations, but this all works."&amp;nbsp; Duh! -&amp;nbsp; like many NoSQL databases, BigTable is schema-less, so there is no schema to migrate.&amp;nbsp; Problem solved.&amp;nbsp; OK, the application has to be prepared to do with an attribute on a record/row that isn't present, but that code is basically the same as dealing with a NULL value that you might specify as the default value when you issue an ALTER TABLE to add a column.&amp;nbsp; Also, you can still imagine scenarios where you might still have to do some sort of schema/data conversion, but without even consciously thinking about it, I managed to avoid those.&amp;nbsp; That was cool.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-4386396621661408040?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/4386396621661408040/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=4386396621661408040' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/4386396621661408040'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/4386396621661408040'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2010/03/5tech-week-1-google-app-engine.html' title='5Tech - Week 1: Google App Engine'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-5453088216822009244</id><published>2010-03-08T16:35:00.000-08:00</published><updated>2010-03-08T22:03:00.468-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='5tech'/><title type='text'>Five Technologies in Five Weeks</title><content type='html'>I am currently between consulting jobs, and during the down time, I have embarked on a project to learn five new (to me) technologies in five weeks.  The reasons for doing this include:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Learn new things - this project is a variant on the "learn one new language a year" meme that's been going around.  I'm just taking on five things (not necessarily languages) in much less than a year.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Bust some code - it's been a while since I've been able to do any hard-core coding.  This will be a sprint which can blow out some cobwebs.&lt;/li&gt;&lt;li&gt;Improve my development practices by trying some new techniques and focusing on refining existing ones.&lt;/li&gt;&lt;/ul&gt;The technologies I plan on tackling are (subject to change):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://code.google.com/appengine/docs/python/overview.html"&gt;Google App Engine&lt;/a&gt; (with Python, not Java)&lt;/li&gt;&lt;li&gt;&lt;a href="http://grails.org/"&gt;Grails&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://developer.android.com/index.html"&gt;Android&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://platform.netbeans.org/"&gt;NetBeans Platform&lt;/a&gt; (not just using the IDE)&lt;/li&gt;&lt;li&gt;&lt;a href="http://griffon.codehaus.org/"&gt;Griffon&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;I chose these technologies  because I know of them but haven't actually built anything with them.  Also, they are technologies that I'm interested in testing out to see how usable/effective they are and if I should pursue them further.&lt;br /&gt;&lt;br /&gt;In a way, each week's technology is a bit like a "spike" in an agile project, only I'm not looking to evaluate/sketch out solutions to application problems but rather evaluate technologies in a more abstract sense. Although, in some cases (e.g., NetBeans Platform and Griffon) I have some application ideas I'd like to implement, and I really am spiking possible solutions.&lt;br /&gt;&lt;br /&gt;For each technology, I've got a modest application in mind.  I have (or will have) a series of story cards describing various aspects of the application I'd like to create.  And then, I will sprint for a week to implement as many of the stories as possible.  I'll also post at least one blog entry as a retrospective for each sprint.&lt;br /&gt;&lt;br /&gt;I've been planning this for some time - ever since the end was in sight on my last contract.  The most significant threat to this undertaking is not failing at one or more technologies, but rather if I find another contract before I've completed the technologies.  (There are worse things than finding a paying job when you're currently between jobs.)  Another known disruption to the "five weeks" is that I'm taking one week off to go to the &lt;a href="http://www.mindviewinc.com/Conferences/JavaPosseRoundup/"&gt;Java Posse Roundup&lt;/a&gt;, which will technically make this five technologies in six weeks, but that isn't as snappy as five in five.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-5453088216822009244?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/5453088216822009244/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=5453088216822009244' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/5453088216822009244'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/5453088216822009244'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2010/03/five-technologies-in-five-weeks.html' title='Five Technologies in Five Weeks'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-3694936483334398059</id><published>2010-03-04T10:12:00.000-08:00</published><updated>2010-03-04T16:14:35.778-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='management'/><title type='text'>Hiring is Only for Managers?</title><content type='html'>A friend of mine told me that he just met the new guy on their team. I thought it was odd that he was just meeting a new team member, so I asked if he wasn't around during the interviews, and he told me that the developers on the team never interview candidates - only managers do that.  As near as I can tell, they do this to minimize the time required during interviewing.  This is just wrong.&lt;br /&gt;&lt;br /&gt;In the words of &lt;a href="http://www.manager-tools.com/"&gt;Manager Tools&lt;/a&gt;, "hiring is the most important job that a manager does" because, in part, failures pull down the whole team for months or years.  And, team-fit is a crucial part of that interviewing process.  All things being equal (which they never are), it's better to hire a technical 8 who has a 10 personality than it is to hire a technical 10 who was only an 8 (or less) personality.  If nothing else, you can teach technical stuff, but you can't teach personality.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.daveramsey.com/entreleadership"&gt;Dave Ramsey&lt;/a&gt; describes his lengthy, multi-round interview process that even includes dinner with spouses to ensure team (in the largest sense) fit.  As lengthy as the process is, he points out that fixing a hiring mistake costs much more than the added time of proper interviews.&lt;br /&gt;&lt;br /&gt;I'd even argue that this manager-only interviewing process produces shortcoming in the technical area, too, because the manager works off of a superficial checklist that s/he has to get through quickly in the interview.  Thus, if a candidate is asked "do you know web framework X," and the answer is "no, but I know frameworks A through F, and I wrote a framework I call G," that candidate is treated the same as someone straight out of school who doesn't know any frameworks.  This narrow-mindedness leads to hires that know framework X, but they store passwords as plain-text because no one told them not to, and none of them knows how to use MD5 to store a password (another story from my friend).   These are what &lt;a href="http://www.ericsink.com/bos/Hazards_of_Hiring.html"&gt;Erik Sink&lt;/a&gt; calls programmers not developers - you want (well-rounded) developers.&lt;br /&gt;&lt;br /&gt;So, with apologies to Georges Clemenceau, interviewing is too important to be left exclusively to the managers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-3694936483334398059?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/3694936483334398059/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=3694936483334398059' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/3694936483334398059'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/3694936483334398059'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2010/03/hiring-is-only-for-managers.html' title='Hiring is Only for Managers?'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-7056774238072267462</id><published>2010-02-11T10:11:00.000-08:00</published><updated>2010-02-11T10:30:15.508-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='misc'/><title type='text'>JIRA Workflow Transition Displaying Wrong Text</title><content type='html'>I've been doing some JIRA administration and customization for a client, and I ran into a problem that was driving me crazy.  I created a new workflow to deal with an Issue Type called Change Request by copying an exsiting workflow.  I renamed one of the transitions from "Close Issue" to "Decline CR," and I associated a screen with the transition (the reason for creating a new workflow). &lt;br /&gt;&lt;br /&gt;The name of the transition ("Decline CR") displayed correctly in the administration page, but in the regular display page of a Change Request issue, the name of the workflow action was still the old value ("Close Issue") from the original workflow.  I tried a few things to fix it, but nothing seemed to help.  I even tried changing the workflow scheme and changing it back.  Still nothing.&lt;br /&gt;&lt;br /&gt;This morning while fishing around in the administration pages, I found the problem.  The transition included an internationalization property, &lt;span style="font-family: courier new;"&gt;jira.i18n.title&lt;/span&gt;, that specifies what appears to be the title of the workflow action, &lt;span style="font-family: courier new;"&gt;closeissue.title&lt;/span&gt;.  I picked up that property when I cloned the workflow - the ultimate origin of the workflow was the JIRA's default workflow, which was internationalized.  Removing the property got the workflow action name ("Decline CR") to display correctly.  (I'm not working in a multi-language environment, so I don't need any localization.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-7056774238072267462?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/7056774238072267462/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=7056774238072267462' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/7056774238072267462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/7056774238072267462'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2010/02/jira-workflow-transition-displaying.html' title='JIRA Workflow Transition Displaying Wrong Text'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-524357348810299044</id><published>2009-10-01T20:58:00.000-07:00</published><updated>2009-10-01T21:25:49.686-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='django'/><category scheme='http://www.blogger.com/atom/ns#' term='rural'/><title type='text'>World's Ugliest URLs</title><content type='html'>I live outside the city of &lt;a href="http://www.ci.monmouth.or.us/"&gt;Monmouth, Oregon&lt;/a&gt; (beneath the &lt;a href="http://www.westernskiesweb.com"&gt;Western Skies&lt;/a&gt;, of course).  Our city's official website has URLs like:&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;http://www.ci.monmouth.or.us/index.asp?Type=B_BASIC&amp;amp;SEC={F6D36CB4-8AB1-4E2F-9F16-EEB14A3A83DD}&lt;/span&gt; - &lt;a href="http://www.ci.monmouth.or.us/index.asp?Type=B_BASIC&amp;amp;SEC=%7BF6D36CB4-8AB1-4E2F-9F16-EEB14A3A83DD%7D"&gt;Things to See &amp;amp; Do&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;http://www.ci.monmouth.or.us/index.asp?Type=B_BASIC&amp;amp;SEC={6010A930-F666-42AF-A359-971AC53933A1}&lt;/span&gt; - &lt;a href="http://www.ci.monmouth.or.us/index.asp?Type=B_BASIC&amp;amp;SEC=%7B6010A930-F666-42AF-A359-971AC53933A1%7D"&gt;City Government&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;OK, maybe they're not the ugliest in the world, but those bad boys have gotta rank way up there.  Anyway, when I first heard &lt;a href="http://jacobian.org/"&gt;Jacob Kaplan-Moss&lt;/a&gt; talk about pretty URLs in &lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt;, I thought some of  criticisms were a little nit-picky.  Initially, I didn't see anything wrong with &lt;span style="font-family: courier new;"&gt;index.php&lt;/span&gt;, but I could see the basic point even before seeing Monmouth's URLs.  When I converted the &lt;a href="http://www.etfarms.com"&gt;Evergreen Terrace Farms&lt;/a&gt; site from PHP to Django, cleaning up the URLs was something I was pleased with.  For example, &lt;a href="www.etfarms.com/animals/bart"&gt;www.et-farms.com/animals/detail.php?name=bart&lt;/a&gt; became &lt;a href="www.etfarms.com/animals/bart"&gt;www.etfarms.com/animals/bart&lt;/a&gt;.  So, I guess I have drunk the Kool-Aide, and I have become a bit of a URL snob.&lt;br /&gt;&lt;br /&gt;Regardless of how picky you are about URLs, I think any sane person would agree that those URLs for the Monmouth site are just crazy.  Just imagine trying to read one of those to your mom over the phone - "no, it's 42AF, and the A and the F are capitalized."&lt;br /&gt;&lt;br /&gt;In my opinion, the saddest thing is that the site is a commercial product created by a company that boasts about how many governments they've sold it to.  It would be one thing if some students created something like that for a senior project, but when you're charging people money for something like that you should at least not expose the ugliest of the ugly Microsoft crap from the depths of the implementation (I assume those are UUIDs generated by .Net).  I guess I'm also disappointed that no one in the city even noticed those URLs before putting out taxpayer money.&lt;br /&gt;&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-524357348810299044?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/524357348810299044/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=524357348810299044' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/524357348810299044'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/524357348810299044'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2009/10/worlds-ugliest-urls.html' title='World&apos;s Ugliest URLs'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-4671859348716471261</id><published>2009-09-16T20:49:00.001-07:00</published><updated>2009-09-16T20:51:56.123-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='talks'/><title type='text'>Presenting an Updated Version of OSS Jobs Talk</title><content type='html'>I'm giving an updated version of "How to Get a Software Job w/o Experience" at Willamette University tomorrow, 9/24/09.  It's a fun talk that I enjoy doing.  I updated the SlideShare version, rather than uploading a new version, so the old version is publicly unavailable.&lt;br /&gt;&lt;div style="width: 425px; text-align: left;" id="__ss_1257783"&gt;&lt;a style="margin: 12px 0pt 3px; font-family: Helvetica,Arial,Sans-serif; font-style: normal; font-variant: normal; font-weight: normal; font-size: 14px; line-height: normal; font-size-adjust: none; font-stretch: normal; display: block; text-decoration: underline;" href="http://www.slideshare.net/ws.cander/how-to-get-a-software-job-wo-experience" title="How to Get a Software Job w/o Experience"&gt;How to Get a Software Job w/o Experience&lt;/a&gt;&lt;object style="margin: 0px;" height="355" width="425"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=fossforstudents-090407010826-phpapp02&amp;amp;stripped_title=how-to-get-a-software-job-wo-experience"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=fossforstudents-090407010826-phpapp02&amp;amp;stripped_title=how-to-get-a-software-job-wo-experience" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" height="355" width="425"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size: 11px; font-family: tahoma,arial; height: 26px; padding-top: 2px;"&gt;View more &lt;a style="text-decoration: underline;" href="http://www.slideshare.net/"&gt;documents&lt;/a&gt; from &lt;a style="text-decoration: underline;" href="http://www.slideshare.net/ws.cander"&gt;Charles Anderson&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-4671859348716471261?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/4671859348716471261/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=4671859348716471261' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/4671859348716471261'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/4671859348716471261'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2009/09/presenting-updated-version-of-oss-jobs.html' title='Presenting an Updated Version of OSS Jobs Talk'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-1019368656983761487</id><published>2009-08-23T21:33:00.001-07:00</published><updated>2009-09-09T16:27:43.324-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mercurial'/><title type='text'>Mercurial for the Homeless</title><content type='html'>Generally, I'm not one to talk about crazy dreams.  You know those ones right before you wake up that seem like a Salvador Dali painting?  Anyway, I had one the other day where either I was homeless living out of a car, or I was observing someone like that.  Anyway, it dawned on me in the dream that Mercurial (or any DVCS) would be perfect for that situation because I figured that the homeless person would only have intermittent network connectivity, but he still needed to get work done.&lt;br /&gt;OK, maybe the part about someone living out of their car "needing" to get coding done is a bit crazy, but I already admitted that it was a weird dream.  I suppose jet-setting open-source gurus might feel kinda homeless from time to time, and they do need to make use of their time on planes, so maybe it wasn't so crazy after all.  And, when you get right down to it, the two use cases are more similar than different, and Mercurial and other DVCSs excel at it.&lt;br /&gt;For the record, the rest of the dream was related to work I'm doing for a client converting from CVS to SVN without necessarily having shell access to the server machines.  I thought of a zillion ways where I could do something trivially in Mercurial but SVN (without shell access) just kept kicking my butt.  I just hope shell access comes through, so the dreams can cease.&lt;br /&gt;&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-1019368656983761487?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/1019368656983761487/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=1019368656983761487' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/1019368656983761487'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/1019368656983761487'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2009/08/mercurial-for-homless.html' title='Mercurial for the Homeless'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-1418609849054885013</id><published>2009-08-06T14:10:00.000-07:00</published><updated>2009-08-06T14:29:44.151-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scm'/><title type='text'>Problem with Hudson as a Windows Service</title><content type='html'>Setting up &lt;a href="http://wiki.hudson-ci.org/display/HUDSON/Installing+Hudson+as+a+Windows+service"&gt;Hudson to run as a windows &lt;/a&gt;service is wicked easy.  However, at a client we ran into a problem with the user that the service runs as.  By default, the service runs as the Local Service (or maybe Local System) user.  Also, by default Hudson runs out of the &lt;span style="font-family:courier new;"&gt;.hudson&lt;/span&gt; directory under the user's home directory (in Documents and Settings).&lt;br /&gt;&lt;br /&gt;This ran fine until someone  logged into the console.  Hint number one that there was a problem was that Windows took forever to log the user in while there was a huge amount of disk activity.  Then, suddenly Hudson reverted to its state from several weeks before - recently added users and builds were missing.  Looking around I could see that many users had a &lt;span style="font-family:courier new;"&gt;.hudson&lt;/span&gt; directory (as well as Maven &lt;span style="font-family:courier new;"&gt;.m2&lt;/span&gt; directories), which made no sense - only the Local Service user was running Hudson.&lt;br /&gt;&lt;br /&gt;As near as I could tell, logging in on the console was somehow changing the value of the Local Service user's home directory. And for some reason, Windows thought everyone should have a &lt;span style="font-family: courier new;"&gt;.hudson&lt;/span&gt; directory.    (Thus the long time to login - Windows was copying the Hudson directory to the new user.)&lt;br /&gt;&lt;br /&gt;Anyway, the solution was to create a real directory for Hudson - &lt;span style="font-family:courier new;"&gt;C:\Hudson&lt;/span&gt;, and to point Hudson at that by setting the &lt;a href="https://hudson.dev.java.net/admin.html"&gt;HUDSON_HOME &lt;/a&gt;environment variable.  To make this as easy as possible, I just set it via the Control Panel as a system-wide environment variable. I filled the directory with the contents of the&lt;span style="font-family:courier new;"&gt; .hudson&lt;/span&gt; directory in my home, as it seemed to have most/all of the recent users and jobs.&lt;br /&gt;&lt;br /&gt;Also, while fixing all of this up, I created a limited (non-administrator) user to run the service.  This is just good security that was skipped when Hudson was initially set-up (by someone else) as a quick proof-of-concept prototype.&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-1418609849054885013?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/1418609849054885013/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=1418609849054885013' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/1418609849054885013'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/1418609849054885013'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2009/08/problem-with-hudson-as-windows-service.html' title='Problem with Hudson as a Windows Service'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-2606737014842602103</id><published>2009-07-14T20:21:00.000-07:00</published><updated>2009-07-14T22:02:10.719-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='books'/><title type='text'>Book: The Principles of Successful Freelancing</title><content type='html'>The &lt;a href="http://www.amazon.com/gp/product/0980455243?ie=UTF8&amp;amp;tag=westernskies-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=0980455243"&gt;Principles of Successful Freelancing&lt;/a&gt; by Miles Burke&lt;br /&gt;ISBN 978-0-98004552-4-6&lt;br /&gt;&lt;br /&gt;The Principles of Successful Freelancing is a comprehensive introduction (if that's not a contradiction of terms) to striking out on your own as a freelancer.  This book is perfect for someone who is considering moving to freelancing or possibly for someone just starting out.&lt;br /&gt;&lt;br /&gt;Mr. Burke covers all of the basic areas of starting and running a freelance business.  He discusses how to set up your business and your office, how to sell your services, how to manage your money, and how to give good customer service, which is ultimately the most important aspect of a personal freelancing business.  He also addresses how to balance work and life beyond work, which is hard in general and specifically hard in a one-man shop.  He concludes with something I haven't seen in a "start you own business" book - where to go next.  Do you want to remain as a one-man shop, do you want to grow into a "real" business, or do you just want to "retreat" to the old 9-to-5 job?  I don't recall a book like this consider the option of going back to the grind.&lt;br /&gt;&lt;br /&gt;Each chapter concludes with two "case studies" - Emily and Jacob.  These two characters represent two very different people who might want to go into freelancing.  The studies at the end of each chapter explain how these personality types might react to the issues and challenges discussed in the chapter.  This device helps the reader envision how he or she might deal with the issues discussed.&lt;br /&gt;&lt;br /&gt;Early on, I got the mistaken impression that this book was a bit fluffy.  The typography has a fair amount of white space, and it looks kinda arty rather than serious and dense.  (OK, I grew up with punched cards and line printers.  When's Matlock on?) But, by the time I finished the book, as I looked back across it, I really couldn't think of anything that wasn't covered.  Sure, there are whole MBAs built around marketing, and this book only has one chapter on it, but the Mr. Burke provides a perfectly reasonable introduction to the subject.  I think I got this "fluffy" mis-impression because immediately prior to reading Successful Freelancing I read Eric Sink's &lt;a href="http://www.amazon.com/gp/product/1590596234?ie=UTF8&amp;amp;tag=westernskies-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=1590596234"&gt;The Business of Software&lt;/a&gt;, which is very detailed about a few aspects specifically related to running a small software business.  Successful Freelancing covers a wider range of topics, and it is not aimed specifically at software freelancers.  If anything, it's aimed more at web designers who probably like nicer typography.&lt;br /&gt;&lt;br /&gt;To conclude, The Principles of Successful Freelancing is a great first introduction to the idea of freelancing.  It covers all the bases to help someone evaluate whether or not to go into business for himself.&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;br /&gt;&lt;br /&gt;&lt;iframe src="http://rcm.amazon.com/e/cm?t=westernskies-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=as1&amp;amp;asins=0980455243&amp;amp;md=10FE9736YVPPT7A0FBG2&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="width: 120px; height: 240px;" marginwidth="0" marginheight="0" frameborder="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-2606737014842602103?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/2606737014842602103/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=2606737014842602103' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/2606737014842602103'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/2606737014842602103'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2009/07/book-principles-of-successful.html' title='Book: The Principles of Successful Freelancing'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-7667729186998254019</id><published>2009-07-13T15:31:00.000-07:00</published><updated>2009-07-13T15:41:57.829-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='os x'/><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><title type='text'>Choosing Java Versions on Mac OS X</title><content type='html'>While debugging another manifestation of the &lt;a href="http://western-skies.blogspot.com/2008/10/webtest-groovy-example-thows.html"&gt;"wrong library for groovy webtest" bug&lt;/a&gt; recently, I found an &lt;a href="http://lists.apple.com/archives/Java-dev/2009/May/msg00212.html"&gt;email thread&lt;/a&gt; that makes reference the &lt;span style="font-family: courier new;"&gt;java_home&lt;/span&gt; command (sadly, I can't find an online manual page to link to) to cleanly select a specific version of the JVM under OS X.  Here I thought manually pawing through /System/Library/Frameworks to look for versions to set JAVA_HOME to was the "right" way to do it.  Learn something new every day.&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-7667729186998254019?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/7667729186998254019/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=7667729186998254019' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/7667729186998254019'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/7667729186998254019'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2009/07/choosing-java-versions-on-mac-os-x.html' title='Choosing Java Versions on Mac OS X'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-1159264983477428057</id><published>2009-07-03T13:59:00.000-07:00</published><updated>2009-07-03T15:58:00.294-07:00</updated><title type='text'>Dealing with DreamHost Server Migration</title><content type='html'>DreamHost sent me an email telling me that my account had been moved to another server.  OK, fine - "what's that mean to me, Al Franken?"  They said that it shouldn't affect most sites, but that you'd have to look out for paths in your applications that look like "&lt;span style="font-family: courier new;"&gt;/home/.something/username&lt;/span&gt;". &lt;br /&gt;So, when when on my clients emailed me to say that his WordPress site was giving him an error message that read:&lt;br /&gt;&lt;br /&gt;Unable to create directory /home/.spuds/user/&lt;span style="text-decoration: underline;"&gt;domain&lt;/span&gt;&lt;a href="http://leftofthedialmag.com/wp-content/uploads/2009/07" target="_blank"&gt;.com/wp-content/&lt;wbr&gt;uploads/2009/07&lt;/a&gt;. Is its parent directory writable by the server?&lt;br /&gt;&lt;br /&gt;I knew that I had been bitten by this error.  OK, how to fix it?  I &lt;span style="font-family: courier new;"&gt;grep&lt;/span&gt;'ed the WP PHP files, but couldn't find a path like that.  So where was it coming from?&lt;br /&gt;&lt;br /&gt;On a hunch, I decided to look at the &lt;span style="font-family: courier new;"&gt;wp_options&lt;/span&gt; table in the WP database and found a row called &lt;span style="font-family: courier new;"&gt;upload_path&lt;/span&gt;, and sure enough, it contained the offending directory.  I just removed the "&lt;span style="font-family: courier new;"&gt;.spuds&lt;/span&gt;" portion of the path, as per DH's directions, and it all worked.&lt;br /&gt;&lt;br /&gt;So, if you're on DreamHost, and they moved your WordPress blog, and it suddenly stopped working with that error message, try looking through &lt;span style="font-family: courier new;"&gt;wp_options&lt;/span&gt; in your databse.  (FYI, DH puts a random string between the &lt;span style="font-family: courier new;"&gt;wp&lt;/span&gt; and the &lt;span style="font-family: courier new;"&gt;options&lt;/span&gt; to prevent collisions with other users in the same database.)&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-1159264983477428057?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/1159264983477428057/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=1159264983477428057' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/1159264983477428057'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/1159264983477428057'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2009/07/dealing-with-dreamhost-server-migration.html' title='Dealing with DreamHost Server Migration'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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><entry><id>tag:blogger.com,1999:blog-29718960.post-2270238050062788611</id><published>2009-06-30T14:50:00.000-07:00</published><updated>2009-06-30T14:54:02.266-07:00</updated><title type='text'>Aliens have taken control of my PowerPoint!</title><content type='html'>I just cut-and-pasted some text from a PDF into PowerPoint, and this is how it rendered:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_VaSVUz85HT8/SkqI838zpLI/AAAAAAAAABo/RrYksz2aVi4/s1600-h/aliens.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 212px;" src="http://3.bp.blogspot.com/_VaSVUz85HT8/SkqI838zpLI/AAAAAAAAABo/RrYksz2aVi4/s400/aliens.png" alt="" id="BLOGGER_PHOTO_ID_5353241686475777202" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The aliens are the bullet points from the source PDF.  WTF?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-2270238050062788611?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/2270238050062788611/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=2270238050062788611' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/2270238050062788611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/2270238050062788611'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2009/06/aliens-have-taken-control-of-my.html' title='Aliens have taken control of my PowerPoint!'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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://3.bp.blogspot.com/_VaSVUz85HT8/SkqI838zpLI/AAAAAAAAABo/RrYksz2aVi4/s72-c/aliens.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29718960.post-9027760617592326764</id><published>2009-06-26T15:33:00.000-07:00</published><updated>2009-06-26T16:04:56.871-07:00</updated><title type='text'>Little Summary of the Open Source Bridge Conference</title><content type='html'>It's been about a week since the &lt;a href="http://opensourcebridge.org/"&gt;Open Source Bridge Conference&lt;/a&gt;, and here are some brief thoughts about it.  I'd summarize it by saying that it's approximately 80% as good as &lt;a href="http://en.oreilly.com/oscon2008"&gt;OSCON&lt;/a&gt; for nearly one tenth the cost, and it was here in Portland.&lt;br /&gt;&lt;br /&gt;Of course, it was smaller than OSCON - a lot smaller.  But it had a lot of what I go to OSCON for - talks about cool open-source software.  There weren't as many talks, not as many projects, not as many "rock stars", but it's the same basic idea.  The exhibitors area made a Soviet-era consumer electronics show look like NES.  I felt sorry for them.&lt;br /&gt;&lt;br /&gt;As I hinted at, the price (something like $250 for non-early bird) was beyond reasonable - it's cheap, in a good way.  At the moment, I'm between clients, so there's no way I could afford over $1000 for OSCON.  If I had that kind of money this year, I probably would have blown it on the &lt;a href="http://www.mindviewinc.com/Conferences/JavaPosseRoundup/"&gt;Java Posse Roundup&lt;/a&gt; - maybe next year.&lt;br /&gt;&lt;br /&gt;Finally, having it in Portland was crucial for me, especially this year.  However, I realized a down side to that: since I'm basically local, at the end of the day, I didn't hang around for social events or the hackers lounge,  but I rather went out with friends whom I was staying with in the area.  So the fact that it's local sort of limited my participation.&lt;br /&gt;&lt;br /&gt;Anyway, it was a great version 1.0, and I look forward to going to OSB again next year.  Oh yeah, props out to O'Reilly for being a sponsor of a "competing" conference.  That was cool.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-9027760617592326764?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/9027760617592326764/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=9027760617592326764' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/9027760617592326764'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/9027760617592326764'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2009/06/little-summary-of-open-source-bridge.html' title='Little Summary of the Open Source Bridge Conference'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-4109869728729959936</id><published>2009-06-26T10:39:00.000-07:00</published><updated>2009-06-26T15:33:28.508-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scm'/><category scheme='http://www.blogger.com/atom/ns#' term='mercurial'/><title type='text'>Version control: Autopia vs. off-roading</title><content type='html'>When I was a kid, it was cool to go to Disneyland and ride the &lt;a href="http://en.wikipedia.org/wiki/Autopia"&gt;Autopia&lt;/a&gt; ride.  For those of you unfamiliar with it, you get to "drive" a car along a track.  As I recall, you get a gas pedal, and the steering worked for about plus-or-minus a foot off the center-line of the track.  It is a far cry from driving a real go-cart let alone a real car on the highway or going off-roading (not that I've ever intentionally been off-roading.)  Comparing traditional centralized version control systems to distributed version control systems is a bit like autopia vs. off-roading.&lt;br /&gt;&lt;br /&gt;With a centralized version control system (VCS), your options are limited, and to a certain extent that can be a good thing.  A critical difference between Autopia and a centralized VCS, is that the VCS actually goes somewhere - your code line continues to move forward and doesn't loop back to the starting point.&lt;br /&gt;&lt;br /&gt;A distributed VCS (DVCS) can follow the exact same path that a cetralized VCS provides/requires - just like you could drive a 4x4 along the Autopia track.  With a DVCS tool like &lt;a href="http://mercurial.selenic.com/wiki/"&gt;Mercurial&lt;/a&gt;, you can implement policies that end up following the same trajectory as you would with &lt;a href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt;.  You have one "master" repository; everyone checks out from it; everyone commits directly to the central repo; the only branching is officially sanctioned, and it occurs in master repo.  And that's fine for a lot of applications.  Also, some organizations want to operate on the straight and narrow, which is fine if it works for them. &lt;br /&gt;&lt;br /&gt;As I mentioned before, I think &lt;a href="http://western-skies.blogspot.com/2008/02/simply-mercurial.html"&gt;Mercurial is very simple&lt;/a&gt; to use on that path.  But, the blessing or curse or fun or power of a DVCS is that you need not follow that track.  You can go off the track.  Doing so might be the fastest way to get where you're going.  Or, you might end up in the weeds. And, you can drive back onto the main road.  Developers can head off in some strange direction in their private repo, share their changes with other repos, bring in changes from other repos, abandon their work, or merge it all back into the designated "main" repo.  All the while, they have a real VCS tracking their work and saving it - not just random hacking in a random directory.&lt;br /&gt;&lt;br /&gt;If Autopia is where you want to be, more power to you.  I wouldn't recommend using a DVCS in that environment.  Although I don't go seriously "off-road" in my development, I like to have the option to get a little mud on the tires.  And even if I'm "driving on the track" and using Mercurial like a centralized VCS, I like  to clone a tree onto my laptop to operate disconnected for an extended period, which is something that's not generally possible with traditional VCSs. &lt;br /&gt;&lt;br /&gt;My most "extreme" use of Mercurial to-date has been to mirror a P4 repository that I only have intermittent access to.  Hg lets me do all my work without having to get the admin to let me onto the P4 repo from by dyanamic IP address. Before that, I would work for weeks without checking in, which makes me nervous.  Due to some ignorance and poor planning, I created a bit of a mess in my hg development repo, but I was able straighten it all out, build a series of mq patches, stage them on another repo, and push them back to the P4 tree.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-4109869728729959936?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/4109869728729959936/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=4109869728729959936' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/4109869728729959936'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/4109869728729959936'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2009/06/version-control-autopia-vs-off-roading.html' title='Version control: Autopia vs. off-roading'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-6682440153904568774</id><published>2009-06-01T16:07:00.001-07:00</published><updated>2009-06-01T16:21:10.726-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='django'/><title type='text'>404 Errors with Django flatpages</title><content type='html'>In a Python class I'm teaching, I had the students do the Django tutorial with some added bits.  One of the added bits was to add an About page using &lt;a href="http://docs.djangoproject.com/en/dev/ref/contrib/flatpages/"&gt;Django flatpages&lt;/a&gt;.  A couple of students had problems where they were getting 404 errors even though there was a flat page defined at the &lt;span style="font-family:courier new;"&gt;/about/&lt;/span&gt; URL.&lt;br /&gt;&lt;br /&gt;I had one student zip up his project (including his sqlite database) and send it to me.  (One of the other "added bits" was that they had to create portable projects - no hardcoded paths in &lt;span style="font-family:courier new;"&gt;settings.py&lt;/span&gt;.)   When I first ran his project, sure enough - 404.  I poked around, and everything looked good.  Then, I used &lt;span style="font-family:courier new;"&gt;manage.py loaddata&lt;/span&gt; to load my data (including a flat page) into his DB, and it all worked fine.  So, it was a data issue, not a project-level mis-configuration.&lt;br /&gt;&lt;br /&gt;After reading a comment from another student about this problem, I looked into the database using &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/5817"&gt;SQLite Manager&lt;/a&gt;, where I could see that the flat page was assigned with site_id #3, not the default #1, and somewhere along the line he had created multiple sites in his DB.  I looked in &lt;span style="font-family:courier new;"&gt;settings.py&lt;/span&gt;, and sure enough, &lt;span style="font-family:courier new;"&gt;SITE_ID&lt;/span&gt; referred to site #1, not #3  As noted in the flat pages docs, this needs to match (under some circumstance).  Changing that, fixed it all up with the students original data.&lt;br /&gt;&lt;br /&gt;If you have been having this problem, I am hopeful that the Google sent you here, and you can see how to fix it.&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-6682440153904568774?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/6682440153904568774/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=6682440153904568774' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/6682440153904568774'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/6682440153904568774'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2009/06/404-errors-with-django-flatpages.html' title='404 Errors with Django flatpages'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-8931954961241922549</id><published>2009-04-10T14:51:00.000-07:00</published><updated>2009-04-10T14:57:16.007-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='talks'/><title type='text'>How to Get a Software Job w/o Experience.</title><content type='html'>This is a talk I gave at WOU last week.  I also presented it later the same week at &lt;a href="http://beaverbarcamp.org"&gt;Beaver Bar Camp&lt;/a&gt;.  In an ideal world, I would have delivered the talk at least a few weeks before the deadline for Google Summer of Code applications.  :-(  OTOH, maybe some students will join some F/OSS projects this summer, and they can nail the application next year.&lt;br /&gt;&lt;br /&gt;&lt;div style="width: 425px; text-align: left;" id="__ss_1257783"&gt;&lt;a style="margin: 12px 0pt 3px; font-family: Helvetica,Arial,Sans-serif; font-style: normal; font-variant: normal; font-weight: normal; font-size: 14px; line-height: normal; font-size-adjust: none; font-stretch: normal; display: block; text-decoration: underline;" href="http://www.slideshare.net/ws.cander/how-to-get-a-software-job-wo-experience?type=presentation" title="How to Get a Software Job w/o Experience"&gt;How to Get a Software Job w/o Experience&lt;/a&gt;&lt;object style="margin: 0px;" height="355" width="425"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=fossforstudents-090407010826-phpapp02&amp;amp;stripped_title=how-to-get-a-software-job-wo-experience"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=fossforstudents-090407010826-phpapp02&amp;amp;stripped_title=how-to-get-a-software-job-wo-experience" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" height="355" width="425"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size: 11px; font-family: tahoma,arial; height: 26px; padding-top: 2px;"&gt;View more &lt;a style="text-decoration: underline;" href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a style="text-decoration: underline;" href="http://www.slideshare.net/ws.cander"&gt;Charles Anderson&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Slideshare liked it (but I'm not sure what their criteria are): "Your presentation How to Get a Software Job w/o Experience is currently being showcased on the 'Career' page by our editorial team."&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-8931954961241922549?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/8931954961241922549/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=8931954961241922549' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/8931954961241922549'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/8931954961241922549'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2009/04/how-to-get-software-job-wo-experience.html' title='How to Get a Software Job w/o Experience.'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-9179473221846828461</id><published>2009-03-24T20:37:00.000-07:00</published><updated>2009-03-24T21:12:23.188-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='books'/><title type='text'>Book: Writing for Scholars</title><content type='html'>&lt;a href="http://www.amazon.com/gp/product/8763002213?ie=UTF8&amp;amp;tag=westernskies-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=8763002213"&gt;Writing for Scholars: A Practical Guide to Making Sense and Being Heard&lt;/a&gt; by Lynn P. &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;Nygaard&lt;/span&gt;&lt;br /&gt;ISBN: 9788215013916&lt;br /&gt;&lt;br /&gt;Writing for Scholars is a great guide for (aspiring) academic writers.  The simplest thing I could say is that it ought to be required reading for anyone in graduate school who will be doing academic writing - e.g., journal articles or a dissertation.  In my experience, academic writing was something that a graduate student was expected to either know already or absorb quickly without little or no coaching.&lt;br /&gt;&lt;br /&gt;I've read a couple of books on the subject of academic writing, especially in the area of the sciences.  Those books focused on a lot of the minutia of presenting and formatting one's work in a journal or similar medium.  Ms. &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;Nygaard&lt;/span&gt; takes a much larger view of the writing process, and she &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;de&lt;/span&gt;-emphasizes (without completely dismissing) the technical minutia, putting it in the later chapters.  She begins by talking about how to develop good writing habits, which is applicable to non-academic writers, too.  She also explains the academic dialogue and how an academic paper has to fit into and extend that dialogue.&lt;br /&gt;&lt;br /&gt;She continues by explaining how to identify your audience, which is also applicable to non-academic writing.  Then she gets down to what I would term the core of the writing process: forming your argument and expressing it in standard academic form (abstract, introduction, method, results, discussion).  She also explains how and when to use figures and tables.&lt;br /&gt;&lt;br /&gt;A couple of topics that I don't recall reading in other books are: feedback (giving and receiving) and presenting a paper at a conference.  Again, both of these are subjects which were never taught in my graduate schooling.  These are both crucial topics that complete the academic dialogue.&lt;br /&gt;&lt;br /&gt;Throughout the book, Ms. &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;Nygaard&lt;/span&gt; includes numerous (sometimes humorous) examples drawn from a wide range of academic disciplines.  Perhaps I'm just reading it through my own science-tinted glasses, but I'd say the book does lean more towards the "hard" sciences rather than social sciences or liberal arts.  However, I would assume that non-science writers would find this book just as useful as the geeks in the world.&lt;br /&gt;&lt;br /&gt;If I had to make a minor criticism of this book, I'd say that Ms. &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;Nygaard&lt;/span&gt; should include some references to other sources relating to the various topics she addresses.  This is a short book (less than 200 pages), and that's a good thing.  But, as a short book, it cannot possibly be the end-all and be-all encyclopedia for academic writing.  For example, her chapter on figures and tables is a great introduction, but references to authors like &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;Tufte&lt;/span&gt; would serve the (novice) reader well.&lt;br /&gt;&lt;br /&gt;In conclusion, Writing for Scholars is a great guide to academic writing.  It is a must-read for anyone beginning a career that will involve such writing, and even seasoned writers can learn a few things by filling in some gaps that were left over from learning by osmosis.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;br /&gt;&lt;br /&gt;&lt;iframe src="http://rcm.amazon.com/e/cm?t=westernskies-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=as1&amp;amp;asins=8763002213&amp;amp;md=10FE9736YVPPT7A0FBG2&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="width: 120px; height: 240px;" marginwidth="0" marginheight="0" frameborder="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-9179473221846828461?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/9179473221846828461/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=9179473221846828461' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/9179473221846828461'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/9179473221846828461'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2009/03/book-writing-for-scholars.html' title='Book: Writing for Scholars'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-926408652563446323</id><published>2009-03-04T15:47:00.000-08:00</published><updated>2009-03-04T16:57:10.089-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='django'/><category scheme='http://www.blogger.com/atom/ns#' term='books'/><title type='text'>Book: Pro Django</title><content type='html'>&lt;a href="http://www.blogger.com/href=%22http://www.amazon.com/gp/product/1430210478?ie=UTF8&amp;amp;tag=westernskies-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=1430210478"&gt;Pro Django&lt;/a&gt; by Marty Alchin&lt;br /&gt;ISBN: 978-1-4302-1047-4&lt;br /&gt;&lt;br /&gt;Pro Django is an excellent book on Django, but it's not for beginners.  The term "Pro" gets thrown around a lot, and it gets applied to things that might better be described with "Dummies."    This is the Real Mc Coy - it's serious advanced stuff.&lt;br /&gt;&lt;br /&gt;The chapters are centered around nice little chunks of the Django system: Models, Views, Forms, Templates, etc.  Each chapter is a nice, self-contained bit of Django knowledge, except for Chapter 2, which is a great survey of advanced Python like meta classes.  Most chapters also include an Applied Techniques section which gives some examples of how to apply the material in the chapter.&lt;br /&gt;&lt;br /&gt;While reading this book, what struck me was how the chapters seem to pack in a level of detail that you'd typically find only in a comprehensive reference, but yet this book is not a bunch of dry reference material, or worse yet, copies of online manuals.  The reader gets serious detailed information, but it almost reads like a fluffy tutorial.  It's pretty remarkable.&lt;br /&gt;&lt;br /&gt;Something that's unique about this book at this time (Q1 2009) is that it covers the 1.0 version of Django.  A bunch of the first books on Django were written against 0.96 or earlier.  You'd think there wouldn't be much difference (0.04 versions if you only look at the numbers), but the jump to 1.0 was significant for Django.  It's nice to have a book that reflects the 1.0 world.&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;br /&gt;&lt;br /&gt;&lt;iframe src="http://rcm.amazon.com/e/cm?t=westernskies-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=as1&amp;amp;asins=1430210478&amp;amp;md=10FE9736YVPPT7A0FBG2&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="width: 120px; height: 240px;" marginwidth="0" marginheight="0" frameborder="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-926408652563446323?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/926408652563446323/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=926408652563446323' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/926408652563446323'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/926408652563446323'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2009/03/book-pro-django.html' title='Book: Pro Django'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-5303532406705382059</id><published>2009-03-02T15:07:00.000-08:00</published><updated>2009-09-17T21:37:56.079-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><title type='text'>Does OpenOffice Base suck?</title><content type='html'>Is it just me, or does &lt;a href="http://dba.openoffice.org/"&gt;OpenOffice Base&lt;/a&gt; (the database tool in their suite) suck?  Or maybe it just sucks on the Mac?  Honestly, I'm not throwing bombs just to be a tool.  If I'm doing something wrong, please tell me.&lt;br /&gt;&lt;br /&gt;For some time I've been looking for a database tool along the lines of Access, but which runs on the Mac and possibly other platforms.  It's not that I'm a big Access fan - I've only used it a time or two, but every now and then, I have a task that cries out to be implemented with a database.  Creating a desktop application from scratch using something like Swing and JavaDB/Derby seems like overkill (not too mention, way too much work), but I've always thought that there should be a database tool that's based on Java (cross-platform) and some open-source database (e.g., Derby or SQLite).&lt;br /&gt;&lt;br /&gt;On paper, Base is just that tool.  I heard somewhere that it's written in Java, and I know that it uses HSQLDB, but can use any JDBC database.  Looking through the interface it's got tables, forms, and reports.  And OpenOffice runs on Macs, Windows, and Linux.  Sounds perfect.&lt;br /&gt;&lt;br /&gt;Here's just a short list of the issues I've had:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The first time I ran it, it crashed before I'd even defined any tables.  D'oh!&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Once, the UI locked up (no visible updates but the mouse still worked) while I was trying to add a List Box.  I kept trying until it crashed.  When it came back, I had a zillion List Boxes in the spot where I was adding them.&lt;/li&gt;&lt;li&gt;After removing the List Boxes, it crashed again.  After restarting, the recovery process restored all those list boxes.  I removed them all again, it crashed again, and they were all restored again.&lt;/li&gt;&lt;li&gt;Eventually, I removed the List Boxes, saved and quit.  After restarting, the boxes were finally gone.  This marked a new work pattern - save and quit every ~5 minutes.  Sometimes, saving alone wasn't enough to prevent work from being lost.&lt;/li&gt;&lt;li&gt;The replace form control function crashed consistently enough for me to realize it doesn't work.  This is a shame because the form wizard creates text boxes by default, which need to be converted.  I had to add new controls, wire them up, remove the original text box, and move the new control into place - all while saving frequently.&lt;/li&gt;&lt;li&gt;It took me forever to get a List Box that wasn't tied to a database table or query - e.g., Gender can only be Male or Female (or Gelded on &lt;a href="http://www.etfarms.com/"&gt;our farm&lt;/a&gt;).  To do that, you have to turn off wizard mode.&lt;/li&gt;&lt;li&gt;There are various UI boogers on the Mac - e.g., list boxes are sometimes not quite tall enough so the text in the box is chopped when the list is not dropped down.&lt;/li&gt;&lt;li&gt;The documentation that I could find was minimal, at best.  I realize that's a common complaint about open-source projects, but for something as big as OpenOffice, I expected more.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Anyway, it's so unusable, I don't think I can use it for my own personal purposes, let alone recommend it to clients.  Quite a shame.  I'm thinking to checking out FileMaker.  It runs on both PCs and Macs, and it has a free 30 day trial.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-5303532406705382059?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/5303532406705382059/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=5303532406705382059' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/5303532406705382059'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/5303532406705382059'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2009/03/does-openoffice-base-suck.html' title='Does OpenOffice Base suck?'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-5294742489489995776</id><published>2009-02-25T14:48:00.001-08:00</published><updated>2009-02-25T14:50:35.789-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='talks'/><title type='text'>Talk:  How To Protect Yourself and Your Computer Online</title><content type='html'>This is a talk I recently gave at the Monmouth Senior Center.  Nothing earth-shattering for techies, but useful information for the non-techies in town.&lt;div style="width: 425px; text-align: left;" id="__ss_1070349"&gt;&lt;a style="margin: 12px 0pt 3px; font-family: Helvetica,Arial,Sans-serif; font-style: normal; font-variant: normal; font-weight: normal; font-size: 14px; line-height: normal; font-size-adjust: none; font-stretch: normal; display: block; text-decoration: underline;" href="http://www.slideshare.net/ws.cander/how-to-protect-yourself-and-your-computer-online?type=powerpoint" title="How To Protect Yourself and Your Computer Online"&gt;How To Protect Yourself and Your Computer Online&lt;/a&gt;&lt;object style="margin: 0px;" height="355" width="425"&gt;&lt;param name="movie" value="http://static.slideshare.net/swf/ssplayer2.swf?doc=online-protection-090225164251-phpapp02&amp;amp;stripped_title=how-to-protect-yourself-and-your-computer-online"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;embed src="http://static.slideshare.net/swf/ssplayer2.swf?doc=online-protection-090225164251-phpapp02&amp;amp;stripped_title=how-to-protect-yourself-and-your-computer-online" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" height="355" width="425"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size: 11px; font-family: tahoma,arial; height: 26px; padding-top: 2px;"&gt;View more &lt;a style="text-decoration: underline;" href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a style="text-decoration: underline;" href="http://www.slideshare.net/ws.cander"&gt;Charles Anderson&lt;/a&gt;. (tags: &lt;a style="text-decoration: underline;" href="http://slideshare.net/tag/securityonline"&gt;securityonline&lt;/a&gt; &lt;a style="text-decoration: underline;" href="http://slideshare.net/tag/fraud"&gt;fraud&lt;/a&gt;)&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-5294742489489995776?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/5294742489489995776/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=5294742489489995776' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/5294742489489995776'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/5294742489489995776'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2009/02/talk-how-to-protect-yourself-and-your.html' title='Talk:  How To Protect Yourself and Your Computer Online'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-7298489098726272000</id><published>2009-02-20T21:51:00.000-08:00</published><updated>2009-02-23T21:43:25.699-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='evdo'/><category scheme='http://www.blogger.com/atom/ns#' term='rural'/><title type='text'>Cell Phone (EVDO) for Rural Internet Access</title><content type='html'>The name &lt;a href="http://westernskiesweb.com/"&gt;Western Skies&lt;/a&gt; (name of &lt;a href="http://western-skies.blogspot.com/"&gt;this blog&lt;/a&gt; and my &lt;a href="http://westernskiesweb.com"&gt;consulting company&lt;/a&gt;) comes from song "&lt;a href="http://www.cowboylyrics.com/lyrics/ledoux-chris/western-skies-15471.html"&gt;Western Skies&lt;/a&gt;" by the late &lt;a href="http://www.chrisledoux.com/"&gt;Chris LeDoux&lt;/a&gt; where he talks about living out west (Wyoming) rather than in Nashville.  Similarly, I choose to live out in the country in Oregon instead of Silicon Valley.  On the plus side, I have "watch(ed) an eagle fly" (in town, no less) and listened to "the coyotes call at night."  On the minus side, there is no broadband Internet access out here.  I've recently switched to Verizon EVDO service, and it's mostly working.  This is the first of a series of posts on the subject of using EVDO for our sole Internet service.&lt;br /&gt;&lt;br /&gt;Previously, I was using 128Kbit (16 Kbyte) per second ISDN.  It cost $85/month, which means it was slow and expensive, but the data amount was unlimited.  Also, it was a business service from Qwest, which meant when it went out, they were Johnny on the spot to fix it - they even asked at 9pm if it was OK if they didn't roll a truck until morning or if I needed it fixed that night.&lt;br /&gt;&lt;br /&gt;I had been thinking of switching for some time, but Qwest forced my hand when they notified me that they would no longer serve as an ISP for the ISDN line.  They still provide ISDN service, but their ISP (Qwest.net) no longer accepts ISDN calls.  To add insult to injury, they suggested that I see if DSL was available - if it were, there's no way I'd suffer the indignity of ISDN!  I could have changed ISPs, but the ones I found all charged more and/or had usage limits expressed in hours per month (not MB/GB, just hours of connect time).&lt;br /&gt;&lt;br /&gt;Since there's no DSL or Cable, the only other contender would be satellite.  However, at times, I do a lot of work at the command line via &lt;span style="font-family: courier new;"&gt;ssh&lt;/span&gt;, and the latency of satellite would have been completely impractical.  A neighbor of ours has it, and she says she can't even run IM over it very well.&lt;br /&gt;&lt;br /&gt;When we first moved out here, there wasn't hardly any cell phone coverage.  Mostly our phones just spent their batteries looking for signal.  Then, Verizon put up a tower that we can see from our driveway - a pretty clear line-of-sight.  Our Sprint cell phones get 4 bars of (roaming) signal, except when they catch wind of 1 bar of Sprint, which they'll chase blindly.&lt;br /&gt;&lt;br /&gt;After checking out Verizon's offerings online and talking to a sales rep, I signed up for service and "bought" a UM 175 EVDO modem (free with 2 year contract) at Costco (to save on the activation fee).  Verizon offers a 30 day trial, which I figured I'd use to test things out before cancelling the ISDN line.    Even though our phones got a strong signal, I wasn't certain that the data signal would work.  Of course, you'd think that if a telco bothered to put up a tower (or an antenna on someone's leased tower), they'd provision it with all the latest features (e.g., EVDO), but then again telcos don't always behave rationally.&lt;br /&gt;&lt;br /&gt;To make a long story short, it really does seem to work.  The bandwidth is much better - I see anywhere from 100KB/sec to 800KBps with 100-300 KBps being common.  Not great compared to the &lt;a href="http://www.minetfiber.com/"&gt;fiber in town&lt;/a&gt;, but much better than 16KBps.   &lt;span style="font-family: courier new;"&gt;Ping&lt;/span&gt; shows the latency being pretty large (150-250ms), but it seemed alright when I tried it over &lt;span style="font-family: courier new;"&gt;ssh&lt;/span&gt;.  (I'm no longer working for the client where I was using &lt;span style="font-family: courier new;"&gt;ssh&lt;/span&gt; full-time, so I haven't really put it to a real test.)&lt;br /&gt;&lt;br /&gt;However, and this could be huge, the 5GB/month cap is problematic.  In theory, our regular email and web surfing fits well within that limit, however that doesn't leave much room for podcasts or video (which I never got into on ISDN, anyway.)  The cap works out to ~170MB per day, and many podcast episodes are ~50MB.  So, I'm still trying to figure out how to live with the cap - giving up podcasts is not an option.&lt;br /&gt;&lt;br /&gt;At some point, I'll post about my experiences setting up the Verizon UM 175 USB modem on a couple of Macs, as well as my new found hobby: Podcast Mule - downloading podcasts (and OS updates) from WiFi access points in town and bringing them home on my laptop.&lt;br /&gt;&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-7298489098726272000?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/7298489098726272000/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=7298489098726272000' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/7298489098726272000'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/7298489098726272000'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2009/02/cell-phone-evdo-for-rural-internet.html' title='Cell Phone (EVDO) for Rural Internet Access'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29718960.post-7336119949744263350</id><published>2009-01-30T19:02:00.000-08:00</published><updated>2009-01-30T19:06:56.875-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='talks'/><title type='text'>Speaking on Groovy again</title><content type='html'>I'll be repeating my talk on Groovy at noon on February 3rd at noon in Salem, Oregon.  From the email notice:&lt;br /&gt;&lt;br /&gt;This presentation will be in Information Systems Division conference room on the first floor, suite 103, of the State Public Service Building.  Here is a &lt;a href="http://maps.google.com/maps?f=q&amp;amp;hl=en&amp;amp;geocode=&amp;amp;time=&amp;amp;date=&amp;amp;ttype=&amp;amp;q=255+Capitol+Street+NE,+Salem,+Oregon&amp;amp;sll=37.0625,-95.677068&amp;amp;sspn=37.956457,71.015625&amp;amp;ie=UTF8&amp;amp;z=16&amp;amp;iwloc=addr&amp;amp;om=1"&gt;Google Map link&lt;/a&gt; for the location.&lt;br /&gt;&lt;br /&gt;Parking on Court and Capitol streets is the closest to the Public Service Building.  The spots are metered.&lt;br /&gt;&lt;br /&gt;Maybe I'll see you there,&lt;br /&gt;Charles.&lt;br /&gt;&lt;br /&gt;P.S.  My slide deck will be almost identical to the &lt;a href="http://western-skies.blogspot.com/2009/01/groovy-at-sjug.html"&gt;last Groovy talk&lt;/a&gt;, so I won't be posting a new one.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-7336119949744263350?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/7336119949744263350/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=7336119949744263350' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/7336119949744263350'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/7336119949744263350'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2009/01/speaking-on-groovy-again.html' title='Speaking on Groovy again'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-6327523864555255423</id><published>2009-01-30T18:38:00.000-08:00</published><updated>2009-01-30T19:01:53.831-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='misc'/><title type='text'>Converting a WordPress blog to a 'One-Click Install' on DreamHost</title><content type='html'>We set up a WordPress blog on DreamHost a while ago for a client.  It was a custom install due to a bunch of craziness related to him getting booted from his old hosting setup.  It all worked fine, and then DreamHost sent me a "nag email" (their term) asking me to upgrade because the old version had security issues.  Fair enough.&lt;br /&gt;&lt;br /&gt;I had another site to upgrade, but it had been installed as a one-click install.  The upgrade for that was one click (plus some backing up).  I could have manually upgraded this custom install, but if I did that, I knew I'd have to continue doing manual upgrades.  Therefore, I wanted to convert this custom WP install to a one-click install.&lt;br /&gt;&lt;br /&gt;DreamHost didn't seem to have any instructions, but how hard could it be?  Basically, the procedure was pretty similar to what you'd go through to move a WP from one server to another.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Backup the database and the old site:  I backed up the old DB using &lt;span style="font-family: courier new;"&gt;mysqldump&lt;/span&gt;, and I tarred up the old site.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Export the old site: from the WP admin page, select Export and dump all authors.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Create a new database in the DreamHost control panel.  In theory, you could drop all the tables in the old DB and re-use it, but I was being paranoid, which paided off later.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Move old site out of the way:  just move the old site directory to a new name - e.g., &lt;span style="font-family: courier new;"&gt;mv site.com  save.site.com&lt;/span&gt;.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Create a new 'One-Click Install' WordPress site using Advanced Mode, since we had a custom theme and a bunch of other content (pictures).  This was put in the new database.  After DreamHost emailed me to tell me that was done, I logged in and changed the admin password.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Import the old content from the Admin Import function.  Actually, DreamHost's email included the URL for that page.  One issue I ran into was the "user name" for the old posts:  WP thought the old posts by admin were from some other user because in the old blog, the admin user had a different display name.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Copy in the custom theme and other content from the old saved directory into the new blog site.  Enable the theme.  Set up Akismet - this is where having the old DB around was useful; I just looked in the wp_options table to find the API key instead of having to dig around for it.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-6327523864555255423?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/6327523864555255423/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=6327523864555255423' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/6327523864555255423'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/6327523864555255423'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2009/01/converting-wordpress-blog-to-one-click.html' title='Converting a WordPress blog to a &apos;One-Click Install&apos; on DreamHost'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-6477041599610289497</id><published>2009-01-22T15:45:00.001-08:00</published><updated>2009-01-22T15:53:21.474-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='talks'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Jython talk at SJUG</title><content type='html'>Here are the slides of a talk I gave last February at the Salem Java Users Group - SJUG.  Although it looks like it's primarily about Python and Jython, my bigger emphasis was on extension programming - scripting existing Java code.  In other words, a form of &lt;a href="http://memeagora.blogspot.com/2006/12/polyglot-programming.html"&gt;polyglot programming&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div style="width: 425px; text-align: left;" id="__ss_902443"&gt;&lt;a style="margin: 12px 0pt 3px; font-family: Helvetica,Arial,Sans-serif; font-style: normal; font-variant: normal; font-weight: normal; font-size: 14px; line-height: normal; font-size-adjust: none; font-stretch: normal; display: block; text-decoration: underline;" href="http://www.slideshare.net/ws.cander/jython-integrating-python-and-java-presentation?type=powerpoint" title="Jython: Integrating Python and Java"&gt;Jython: Integrating Python and Java&lt;/a&gt;&lt;object style="margin: 0px;" height="355" width="425"&gt;&lt;param name="movie" value="http://static.slideshare.net/swf/ssplayer2.swf?doc=jythonsjug-1231456687734950-1&amp;amp;stripped_title=jython-integrating-python-and-java-presentation"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;embed src="http://static.slideshare.net/swf/ssplayer2.swf?doc=jythonsjug-1231456687734950-1&amp;amp;stripped_title=jython-integrating-python-and-java-presentation" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" height="355" width="425"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size: 11px; font-family: tahoma,arial; height: 26px; padding-top: 2px;"&gt;View more &lt;a style="text-decoration: underline;" href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; or &lt;a style="text-decoration: underline;" href="http://www.slideshare.net/upload?type=powerpoint"&gt;upload&lt;/a&gt; your own. (tags: &lt;a style="text-decoration: underline;" href="http://slideshare.net/tag/jython"&gt;jython&lt;/a&gt; &lt;a style="text-decoration: underline;" href="http://slideshare.net/tag/python"&gt;python&lt;/a&gt;)&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-6477041599610289497?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/6477041599610289497/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=6477041599610289497' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/6477041599610289497'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/6477041599610289497'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2009/01/jython-talk-at-sjug.html' title='Jython talk at SJUG'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-3448484028340943513</id><published>2009-01-21T21:09:00.000-08:00</published><updated>2009-01-21T21:45:06.837-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='books'/><title type='text'>Book: Java Power Tools</title><content type='html'>&lt;a href="http://www.amazon.com/gp/product/0596527934?ie=UTF8&amp;amp;tag=westernskies-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=0596527934"&gt;Java Power Tools&lt;/a&gt; by John Ferguson Smart&lt;br /&gt;ISBN: 978-0-596-52793-8&lt;br /&gt;&lt;br /&gt;Java Power Tools provides a fairly detailed introduction to a number of tools for Java programmers.  It fits nicely between the &lt;a href="http://oreilly.com/hacks/"&gt;O'Reilly Hacks&lt;/a&gt; series and having a dozen books like &lt;a href="http://www.amazon.com/gp/product/0596006098?ie=UTF8&amp;amp;tag=westernskies-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=0596006098"&gt;Ant: The Definitive Guide, 2nd Edition&lt;/a&gt;.  Like the Hacks books, Java Power Tools provides an introduction to a bunch of tools.  The Hacks books are great for answering the question "I've heard of that tool, but where does it fit?"  But whereas the Hacks books provide just an appetizer, this book provides a main course, enough to get seriously started with the tool being discussed.  And then, if you want all the gory details, a Definitive Guide could provide the full five-course meal.&lt;br /&gt;&lt;br /&gt;The selection of tools presented was really good, at least for me.  For example, I know about continuous integrations servers, but I haven't set one up.  At one client site, they were using &lt;a href="https://hudson.dev.java.net/"&gt;Hudson&lt;/a&gt;, which I had some exposure to, but didn't know much about the others like &lt;a href="http://cruisecontrol.sourceforge.net/"&gt;Cruise Control&lt;/a&gt;, &lt;a href="http://continuum.apache.org/"&gt;Continuum&lt;/a&gt;, and &lt;a href="http://luntbuild.javaforge.com/"&gt;LuntBuild&lt;/a&gt;.  Similarly, I've been using &lt;a href="http://www.junit.org/"&gt;JUnit&lt;/a&gt; 3.x for years, but I didn't really know what was different in JUnit 4 or how that compares to &lt;a href="http://testng.org"&gt;TestNG&lt;/a&gt;.  This book provided me with a great overview of these and other tools.  Java Power Tools provides a great way to get up to speed with a general area of tooling (e.g., continuous integration servers) or a good cross-section of the majority of the Java tools in use today.&lt;br /&gt;&lt;br /&gt;If I had to pick something to complain about, it would be Part II - Version Control Tools.  These aren't really Java tools, although every programmer (Java or otherwise) should be using them.  Or given the decision to include version control tools, I'd suggest excluding CVS because it's old and including at least one distributed version control tool like &lt;a href="http://www.selenic.com/mercurial"&gt;Mercurial&lt;/a&gt; (used by the Open JDK project and NetBeans) or &lt;a href="http://git-scm.com/"&gt;git&lt;/a&gt; (used by the Linux kernel).&lt;br /&gt;&lt;br /&gt;So, in conclusion, unless you have no free will about tool selection or you already know all of these tools backwards and forwards, I highly recommend this book to almost any Java programmer.&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;br /&gt;&lt;br /&gt;&lt;iframe src="http://rcm.amazon.com/e/cm?t=westernskies-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=as1&amp;amp;asins=0596527934&amp;amp;md=10FE9736YVPPT7A0FBG2&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="width: 120px; height: 240px;" marginwidth="0" marginheight="0" frameborder="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-3448484028340943513?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/3448484028340943513/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=3448484028340943513' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/3448484028340943513'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/3448484028340943513'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2009/01/book-java-power-tools.html' title='Book: Java Power Tools'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-7492624809423046002</id><published>2009-01-07T15:33:00.000-08:00</published><updated>2009-01-22T15:38:47.272-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='talks'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Groovy at SJUG</title><content type='html'>On January 6th, I spoke at the Salem Java Users Group on Groovy.  The premise was not to replace Java, but rather to show how it can be used in addition to Java.  Here are the slides.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="width: 425px; text-align: left;" id="__ss_902434"&gt;&lt;a style="margin: 12px 0pt 3px; font-family: Helvetica,Arial,Sans-serif; font-style: normal; font-variant: normal; font-weight: normal; font-size: 14px; line-height: normal; font-size-adjust: none; font-stretch: normal; display: block; text-decoration: underline;" href="http://www.slideshare.net/ws.cander/groovy-a-scripting-language-for-java-presentation?type=powerpoint" title="Groovy a Scripting Language for Java"&gt;Groovy a Scripting Language for Java&lt;/a&gt;&lt;object style="margin: 0px;" height="355" width="425"&gt;&lt;param name="movie" value="http://static.slideshare.net/swf/ssplayer2.swf?doc=groovysjug-1231456422916223-1&amp;amp;stripped_title=groovy-a-scripting-language-for-java-presentation"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;embed src="http://static.slideshare.net/swf/ssplayer2.swf?doc=groovysjug-1231456422916223-1&amp;amp;stripped_title=groovy-a-scripting-language-for-java-presentation" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" height="355" width="425"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size: 11px; font-family: tahoma,arial; height: 26px; padding-top: 2px;"&gt;View more &lt;a style="text-decoration: underline;" href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; or &lt;a style="text-decoration: underline;" href="http://www.slideshare.net/upload?type=powerpoint"&gt;upload&lt;/a&gt; your own. (tags: &lt;a style="text-decoration: underline;" href="http://slideshare.net/tag/java"&gt;java.&lt;/a&gt; &lt;a style="text-decoration: underline;" href="http://slideshare.net/tag/groovy"&gt;groovy&lt;/a&gt;)&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-7492624809423046002?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/7492624809423046002/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=7492624809423046002' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/7492624809423046002'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/7492624809423046002'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2009/01/groovy-at-sjug.html' title='Groovy at SJUG'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-5248729317434926374</id><published>2008-11-26T14:59:00.000-08:00</published><updated>2008-11-26T21:20:42.128-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='books'/><title type='text'>Book: The Productive Programmer</title><content type='html'>&lt;a href="http://www.amazon.com/gp/product/0596519788?ie=UTF8&amp;amp;tag=westernskies-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=0596519788"&gt;The Productive Programmer&lt;/a&gt; by Neil Ford&lt;br /&gt;ISBN: 978-0-596-51978-0&lt;br /&gt;&lt;br /&gt;I've always had a more-than-passing interest in &lt;a href="http://wiki.43folders.com/index.php/Productivity_pr0n"&gt;productivity porn&lt;/a&gt;, as &lt;a href="http://www.merlinmann.com/"&gt;Merlin Mann&lt;/a&gt; calls it.  I'm not obsessive about seeking out productivity books (I can quit any time), but I've read more than a few such books in my day, and I do keep my tasks organized with &lt;a href="http://www.omnigroup.com/applications/omnifocus/"&gt;OmniFocus&lt;/a&gt;.  When I saw The Productive Programmer at the &lt;a href="http://www.powells.com/"&gt;Powell's&lt;/a&gt; table at &lt;a href="http://en.oreilly.com/oscon2008/"&gt;OSCON 2008&lt;/a&gt;, I confess I got pretty tingly, kinda like "when we used to climb the rope in gym class."  Here was a book talking about productivity aimed specifically at what I do every day - programming, not management, not sales, not coaching a football team, but programming.  In the words of Cartman, "sweet."&lt;br /&gt;&lt;br /&gt;That said, I wouldn't classify this book as hard-core productivity porn.  It doesn't lay out a dogmatic formula, nor does it suggest or require specific tools or techniques.  And that's probably a good thing;  in my experience, programmers can be some of the most opinionated people I've known, especially when it comes to their craft (e.g., &lt;a href="http://en.wikipedia.org/wiki/Editor_wars"&gt;editor wars&lt;/a&gt;).  If the author had attempted to prescribe a specific set of practices, I think almost every programmer would have found something to hate about the book, and what's the point of that - we could just as easily go back to ragging on emacs, Windows, or Steve Jobs.&lt;br /&gt;&lt;br /&gt;Instead, Mr. Ford offers a number of possible suggestions that one can take or leave.  These are organized into two parts: mechanics (the productivity principles) and practice (philosphy), or what I would call tactical (little picture) and strategic (big picture) techniques.  Mechanics includes things like controlling interruptions from things like email and using tools like &lt;a href="http://blacktree.com/?quicksilver"&gt;Quicksilver&lt;/a&gt; (which I finally started using after reading this book).  Philosophy includes things like test-driven development/design (TDD) and using things like static analysis tools.&lt;br /&gt;&lt;br /&gt;The various suggestions were all very well and good, but what I liked most about this book is that it made me thing about mom-and-apple-pie topics like TDD (of course, we all write unit tests, right?) from a totally different angle - productivity.  Of course, that what the agile folks have been saying all along, but somehow this book shed a whole new light on it and helps drive it even deeper.  And the whole book got me thinking about the bigger question - "how can I be more productive and effective in my programming?"&lt;br /&gt;&lt;br /&gt;Like I said, this isn't hard-core productivity porn, but it's a very useful and approachable guide to productivity by a programmer for programmers.  Maybe that makes it productivity literary erotica?&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;br /&gt;&lt;br /&gt;&lt;iframe src="http://rcm.amazon.com/e/cm?t=westernskies-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=as1&amp;amp;asins=0596519788&amp;amp;md=10FE9736YVPPT7A0FBG2&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="width: 120px; height: 240px;" marginwidth="0" marginheight="0" frameborder="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-5248729317434926374?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/5248729317434926374/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=5248729317434926374' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/5248729317434926374'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/5248729317434926374'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/11/book-productive-programmer.html' title='Book: The Productive Programmer'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-2697332268435493058</id><published>2008-11-26T14:33:00.000-08:00</published><updated>2008-12-03T11:09:52.472-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vmware'/><title type='text'>In Praise of TDD and Mocking</title><content type='html'>As noted elsewhere in the blog, I've been doing a bunch of work to script ESXi using Vmware's (&lt;a href="http://western-skies.blogspot.com/2008/11/vmware-rcli-and-exit-status.html"&gt;sometimes troublesome&lt;/a&gt;) RCLI tools.  I'm developing a higher-level set of code written in Python.  (In theory, using Vmware's Perl toolkit would be cleaner, and I wouldn't have to bitch about the RCLI tools, but I've &lt;a href="http://media.arstechnica.com/news.media/540/chinese-python-poster.jpg"&gt;done enough Perl&lt;/a&gt; for one lifetime.)  In addition to the mom-and-apple-pie goodness of TDD, I'm also getting a huge &lt;a href="http://western-skies.blogspot.com/2008/11/book-productive-programmer.html"&gt;productivity boost&lt;/a&gt; by employing TDD via mocking.&lt;br /&gt;&lt;br /&gt;In the code I'm writing, each method typically makes one or more RCLI calls.  Each RCLI call takes 3-5 seconds.  I structured the code so that the RCLI invocations all funnel through one point in the code which can easily be monkey-patched to go through a mock function.  (More details on that in a later post.)  After mocking, the result is that I can execute 20 tests with dozens of mocked RCLI calls in less than a tenth of second.  After the unit tests pass, I can push the code out to a real host and run real RCLI comannds, and for the most part, "it just works."&lt;br /&gt;&lt;br /&gt;When I started, I figured mocking was the only way to unit test this code, and it was more convenient to develop the code on a machine where I don't have the RCLI installed.  The performance boost was unexpected but by far the most significant benefit of the unit tests.  And when I needed to perform a couple of refactorings during the development, I got to enjoy wicked fast speed plus safety - two great tastes that taste great together.&lt;br /&gt;&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-2697332268435493058?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/2697332268435493058/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=2697332268435493058' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/2697332268435493058'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/2697332268435493058'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/11/in-praise-of-tdd-and-mocking.html' title='In Praise of TDD and Mocking'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-3231448785821192226</id><published>2008-11-20T12:20:00.000-08:00</published><updated>2008-11-20T16:01:51.146-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vmware'/><title type='text'>Vmware RCLI and exit status</title><content type='html'>Yet another gripe about Vmware's RCLI commands: they almost always return an exit status of zero, even if the command failed.  For example,   '&lt;span style="font-family:courier new;"&gt;vmware-cmd -s unregister&lt;/span&gt;' for a non-existent virtual machine, return a status of zero (which is the same as if the command succeeded).  One has to look at the standard output of the command to see "&lt;span style="font-family:courier new;"&gt;No virtual machine found&lt;/span&gt;."  This is OK for an interactive user, but it's a pain-in-the-ass if you're trying to write scripts, as I happen to be.  For every command, I have to parse the output to see if it succeed or not.&lt;br /&gt;&lt;br /&gt;But then some commands (e.g., &lt;span style="font-family: courier new;"&gt;vifs&lt;/span&gt;) do return useful exit codes, at least some of the time.  This whole process has to be handled on a case-by-case basis.&lt;br /&gt;&lt;br /&gt;Speaking of parsing output, the outputs are not consistent.  For example, when that unregister command is successful, it returns "&lt;span style="font-family:courier new;"&gt;unregister() = 1&lt;/span&gt;".  Note there is a space on both sides of the equals sign.  When the corresponding register command succeeds, it returns "&lt;span style="font-family:courier new;"&gt;register() =1&lt;/span&gt;".  Note that there is no space on the left side of the equal sign.  As I write code to parse these outputs (because I can't count on the exit status), I can't help but wonder how brittle this code will be...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-3231448785821192226?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/3231448785821192226/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=3231448785821192226' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/3231448785821192226'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/3231448785821192226'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/11/vmware-rcli-and-exit-status.html' title='Vmware RCLI and exit status'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-643694520957898836</id><published>2008-11-07T21:02:00.000-08:00</published><updated>2008-11-08T10:35:00.362-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='books'/><title type='text'>Book: Working Effectively with Legacy Code</title><content type='html'>&lt;a href="http://www.amazon.com/gp/product/0131177052?ie=UTF8&amp;amp;tag=westernskies-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=0131177052"&gt;Working Effectively with Legacy Code&lt;/a&gt; by Michael Feathers&lt;br /&gt;ISBN: 0-13-11705-2&lt;br /&gt;&lt;br /&gt;"...legacy code is simply code without tests... Code without tests is bad code."&lt;br /&gt;From those statements, it doesn't take much to figure out what this book is about - how to write unit tests for code without tests.  Of course, if you've ever tried to do that, you know that it's easier said than done.  Many/most programmers who inherit a &lt;a href="http://en.wikipedia.org/wiki/Big_ball_of_mud"&gt;big ball of mud&lt;/a&gt; of code without tests (legacy code) just punt; the existing code has no tests, I can't see how to get any of it under test, so I'll just hack and pray - just like the original author(s) did.&lt;br /&gt;&lt;br /&gt;That's where this book comes in.  It's a primarily large collection of recipes about how to write unit tests for legacy code.  That said, the focus is not really on how to write the tests but rather how to get chunks of the legacy code into a test harness so that you can write unit tests to characterize the existing functionality before adding or modifying functionality.  It also contains techniques to add new functionality in such a way that you can test it immediately and possibly execute the "clean up" that the original author(s) promised would happen as soon as that next deadline was reached - all those years and deadlines ago.&lt;br /&gt;&lt;br /&gt;The bulk of the book (Part 2) is organized as a series of complaints or excuses and how to deal with them.  These include such topics as "My application has no structure," "Dependencies on libraries are killing me," and "This class is too big, and I don't want it to get any bigger."  In each chapter, the author provides examples (in multiple languages - Java, C++, C, etc.) of these problems and specific techniques that can be used to address them.  The last chapter (Part 3) is an encyclopedia of the techniques for easy reference.&lt;br /&gt;&lt;br /&gt;If you're lucky enough to do only green-field development, you might think this book would be useless.  However, one interpretation of this books is that it is a list of sins to avoid while your playing in the green field.  And, many of the techniques can be interpreted as best practices for how to write you code to ensure it's testable.  (Of course, you're following test driven development and achieving near 100% coverage, so that would never be a problem with your new code, would it? :-)&lt;br /&gt;&lt;br /&gt;My one disappointment with this book was that I was hoping it would provide ideas about how to create higher-level (e.g., functional) tests.  Of course, high-level tests are no substitute for unit tests.  It's just that I was tasked with creating "some tests" quickly for an entire application, and unit tests are not practical in this particular case, which is my problem, not the author's.&lt;br /&gt;&lt;br /&gt;This book is an excellent resource and cookbook for how to add unit tests to an existing code base that lacks tests, and it also provides design and implementation templates to ensure that new code is testable as it's created.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;br /&gt;&lt;br /&gt;&lt;iframe src="http://rcm.amazon.com/e/cm?t=westernskies-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=as1&amp;amp;asins=0131177052&amp;amp;md=10FE9736YVPPT7A0FBG2&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="width: 120px; height: 240px;" marginwidth="0" marginheight="0" frameborder="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-643694520957898836?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/643694520957898836/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=643694520957898836' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/643694520957898836'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/643694520957898836'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/11/book-working-effectively-with-legacy.html' title='Book: Working Effectively with Legacy Code'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-347315783795496936</id><published>2008-11-05T15:46:00.000-08:00</published><updated>2008-11-05T16:12:22.537-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vmware'/><title type='text'>vmware-cmd: SystemError=HASH(0x95d8d70)</title><content type='html'>More tales from the dark side.  Trying to start a VM out on an ESXi host:&lt;br /&gt;&lt;pre&gt;vmware-cmd  [conn options]  '[datastore] path-to-vm/conf.vmx' start hard&lt;br /&gt;&lt;/pre&gt;Returns this output:&lt;br /&gt;&lt;pre&gt;Fault string: A general system error occurred: Internal error&lt;br /&gt;&lt;span class="anchor" id="line-225"&gt;&lt;/span&gt;Fault detail: SystemError=HASH(0x95d8d70)&lt;br /&gt;&lt;/pre&gt;I spent hours permuting the parameters.  And &lt;span style="font-family: courier new;"&gt;vmware-cmd&lt;/span&gt;'s &lt;span style="font-family: courier new;"&gt;-v&lt;/span&gt; option doesn't dump out all of the SOAP guts, so I had no view on what was going on.   Finally I ran a &lt;span style="font-family: courier new;"&gt;vifs --dir&lt;/span&gt; out on the VM dir and found a bunch of vmware.log files.  I fetched one that showed a normal startup and then this:&lt;br /&gt;&lt;pre&gt;Nov 05 05:51:51.883: vmx| [msg.License.product.expired] This product has expired.&lt;br /&gt;&lt;span class="anchor" id="line-230"&gt;&lt;/span&gt;Nov 05 05:51:51.883: vmx| Be sure that your host machine's date and time are set correctly.&lt;br /&gt;&lt;/pre&gt;There was a &lt;a href="http://itknowledgeexchange.techtarget.com/virtualization-pro/vmware-releases-emergency-patch-for-esx-35-update-2-bug/"&gt;botched version of ESXi&lt;/a&gt; that we installed that contained a time bomb, and it had come home to roost.  Fair enough - our bad, but certainly there could be a better error message than &lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;SystemError=HASH(0x95d8d70).&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-347315783795496936?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/347315783795496936/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=347315783795496936' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/347315783795496936'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/347315783795496936'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/11/vmware-cmd-systemerrorhash0x95d8d70.html' title='vmware-cmd: SystemError=HASH(0x95d8d70)'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-1525494846161038057</id><published>2008-11-05T11:56:00.000-08:00</published><updated>2008-11-05T12:07:45.434-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vmware'/><title type='text'>Vmware ESXi - Unable to clone virtual disk</title><content type='html'>To import a VM from VMware Server to ESXi one must convert the disk by cloning the old one using &lt;span style="font-family: courier new;"&gt;vmkfstools&lt;/span&gt;.  Fair enough.  Doing this using the ESXi RCLI tools should look something like (based on what I've seen for non-RCLI for ESX):&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;vmkfstools [conn-options] -i old-disk new-disk -d thin&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;However, when you do this with RCLI, you get the following useless error message:&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;Unable to clone virtual disk : A general system error occurred: Internal error&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Using the &lt;span style="font-family: courier new;"&gt;--verbose&lt;/span&gt; flag to look at the gory SOAP details I could see that the thin option wasn't getting sent.  Looking through the Perl code it looks like one needs to specify both the &lt;span style="font-family: courier new;"&gt;-d&lt;/span&gt; and &lt;span style="font-family: courier new;"&gt;-a&lt;/span&gt; (adapter type) options.  Once I added &lt;span style="font-family: courier new;"&gt;-a lsilogic&lt;/span&gt; it worked like a charm.&lt;br /&gt;&lt;br /&gt;My big complaint (and I have other examples of this up my sleeve) is if the user makes a simple, bonehead parameter error, the command should point it out rather than saying "general system error...internal error."  I hope this post will help someone else out if s/he is unlucky enough to encounter this error message.&lt;br /&gt;&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-1525494846161038057?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/1525494846161038057/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=1525494846161038057' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/1525494846161038057'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/1525494846161038057'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/11/vmware-esxi-unable-to-clone-virtual.html' title='Vmware ESXi - Unable to clone virtual disk'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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><entry><id>tag:blogger.com,1999:blog-29718960.post-4023411746941531049</id><published>2008-10-30T14:09:00.000-07:00</published><updated>2008-10-30T15:06:53.494-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='os x'/><category scheme='http://www.blogger.com/atom/ns#' term='webtest'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>WebTest Groovy example thows NoSuchMethodError</title><content type='html'>I've been working on a project to do functional testing on a web application using &lt;a href="http://webtest.canoo.com/"&gt;WebTest&lt;/a&gt;.  I've coded up some prototypes using the standard XML/Ant format/language/DSL, but I wanted to try doing it in Groovy, since I'm not a big fan of XML.  I copied the &lt;a href="http://webtest.canoo.com/webtest/manual/groovyTesting.html"&gt;sample application from the manual&lt;/a&gt;, but when I ran it I was getting and exception:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Caught: : java.lang.NoSuchMethodError: org.apache.xpath.compiler.FunctionTable.installFunction(Ljava/lang/String;Ljava/lang/Class;)I&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    at test.run(test.groovy:33)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    at test.main(test.groovy)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(If you're following along at home, you'll note that that line number is too large for the example - I've already hacked some stuff into it.)&lt;br /&gt;&lt;br /&gt;I couldn't find any examples online of people having exactly the same problem, but I'd seen other errors blaming an old version of &lt;span style="font-family:courier new;"&gt;xalan.jar&lt;/span&gt; for this problem, especially under Mac OS 10.5 - my platform.  (BTW, this happened under both Java5 and Java6.) Although I didn't have CLASSPATH set to anything, I figured I'd try setting it to have the version of &lt;span style="font-family:courier new;"&gt;xalan.jar&lt;/span&gt; that ships with WebTest, and it worked.  So, my complete invocation line is:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;groovy -cp /usr/local/java/webtest_1720/lib/xalan-2.7.0.jar  -Dwebtest.home=/usr/local/java/webtest_1720 test.groovy &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-4023411746941531049?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/4023411746941531049/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=4023411746941531049' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/4023411746941531049'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/4023411746941531049'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/10/webtest-groovy-example-thows.html' title='WebTest Groovy example thows NoSuchMethodError'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29718960.post-5877659474811336055</id><published>2008-10-29T16:05:00.001-07:00</published><updated>2008-10-29T16:17:30.512-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vmware'/><title type='text'>VMware ESXi default resource pool name</title><content type='html'>I've been playing around with ESXi trying to figure out how to use their Remote Command Line Interface (RCLI) to import and run a VM.  This has been a major PITA, which I suppose I could have been documenting as I go but I didn't.  (Full disclosure - I'm doing this without any formal training, without their snazzy Virtual Infrastructure tools, or anything else.)&lt;br /&gt;&lt;br /&gt;According to VMware's RCLI Installation and Reference Guide, the data center and resource pool parameters to &lt;span style="font-family:courier new;"&gt;vmware-cmd -s register&lt;/span&gt; are optional, but nonetheless, it kept telling me "Must specify resource pool".&lt;br /&gt;&lt;br /&gt;Eventually, I found a &lt;a href="http://communities.vmware.com/thread/169709"&gt;forum thread&lt;/a&gt; that contained the answer: &lt;span style="font-weight: bold;"&gt;Resources&lt;/span&gt;.  (Kinda like "&lt;a href="http://www.youtube.com/watch?v=PSxihhBzCjk"&gt;plastics&lt;/a&gt;" only different.)  I don't have a data center set up, but I found that using almost any word for the data center name seemed to work.&lt;br /&gt;&lt;br /&gt;So, in the end, this is what worked for me (your milage may vary):&lt;br /&gt;&lt;pre&gt;vmware-cmd  [conn options] -s register '[datastore-name] vm-dir/conf.vmx' root Resources&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-5877659474811336055?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/5877659474811336055/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=5877659474811336055' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/5877659474811336055'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/5877659474811336055'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/10/vmware-esxi-default-resource-pool-name.html' title='VMware ESXi default resource pool name'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-3346579527079477949</id><published>2008-09-04T16:19:00.000-07:00</published><updated>2010-01-21T15:33:18.726-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ant'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><title type='text'>Increasing Memory for Ant</title><content type='html'>I had an issue today with the &lt;span style="font-family:courier new;"&gt;javac&lt;/span&gt; Ant task running out of memory when compiling a project (~800 files) under Java 6 on the Mac.  It was fine under the default Java 5 compiler on the Mac, and it was fine under Java 6 on the PC.  Initially, I set &lt;span style="font-family:courier new;"&gt;memoryMaximumSize&lt;/span&gt; on the &lt;span style="font-family:courier new;"&gt;javac&lt;/span&gt; task, which also required that &lt;span style="font-family:courier new;"&gt;fork&lt;/span&gt; be set.&lt;br /&gt;This was OK, but since this was specific to compiling on the Mac, I figured the solution should be specific to my environment on the Mac.  After looking at the source of the &lt;span style="font-family:courier new;"&gt;ant&lt;/span&gt; script, I realized that the &lt;span style="font-family:courier new;"&gt;ANT_OPTS&lt;/span&gt; variable could be set to contain an option (&lt;span style="font-family:courier new;"&gt;-Xmx512m&lt;/span&gt;) for the JRE running Ant, and that &lt;span style="font-family:courier new;"&gt;ANT_OPTS&lt;/span&gt; could be set from either &lt;span style="font-family:courier new;"&gt;~/.antrc&lt;/span&gt; or &lt;span style="font-family:courier new;"&gt;~/.ant/ant.conf&lt;/span&gt;.  So, I created &lt;span style="font-family:courier new;"&gt;~/.antrc&lt;/span&gt; with one line: &lt;span style="font-family:courier new;"&gt;ANT_OPTS=-DXmx512m&lt;/span&gt;.&lt;br /&gt;(&lt;span style="font-weight: bold;"&gt;Update&lt;/span&gt;: oops, that should be &lt;span style="font-family:courier new;"&gt;ANT_OPTS=-Xmx512m)&lt;/span&gt;&lt;br /&gt;And it worked perfectly, of course - so simple it had to work.&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-3346579527079477949?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/3346579527079477949/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=3346579527079477949' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/3346579527079477949'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/3346579527079477949'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/09/increasing-memory-for-ant.html' title='Increasing Memory for Ant'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-8651746716100753295</id><published>2008-08-28T15:12:00.000-07:00</published><updated>2008-09-11T10:17:21.671-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='ant'/><title type='text'>Ant, JavaDoc, and CreateProcess error=87</title><content type='html'>I've been developing an Ant build file for a large-ish base of existing code.  I've been using my Mac as the primary devleopment platform, but the ultimate target (for the other developers) is Windows.  My task to build the javadocs runs fine on OS X, but the first time I rant it on Windows, I got the following:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;c:\demo\build.xml:180: Javadoc failed: java.io.IOException: Cannot run program "c:\Program Files\Java\jdk1.6.0\bin\javadoc.exe": CreateProcess error=87, The parameter is incorrect&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;After about 10 minutes of Googling, I found a/the simple solution: add the &lt;span style="font-family:courier new;"&gt;useexternalfile &lt;/span&gt;attribute to the &lt;span style="font-family:courier new;"&gt;javadoc &lt;/span&gt;task in Ant. Voila , back in business, on the PC at least, and it didn't seem to break the build on the Mac.&lt;br /&gt;&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-8651746716100753295?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/8651746716100753295/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=8651746716100753295' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/8651746716100753295'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/8651746716100753295'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/08/ant-javadoc-and-createprocess-error87.html' title='Ant, JavaDoc, and CreateProcess error=87'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-3191238961646473554</id><published>2008-08-12T21:02:00.000-07:00</published><updated>2008-09-03T19:40:15.850-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='books'/><title type='text'>Book: Essential SQLAlchemy</title><content type='html'>&lt;a href="http://www.blogger.com/%3Ca%20href=%22http://www.amazon.com/gp/product/0596516142?ie=UTF8&amp;amp;tag=westernskies-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0596516142%22%3EEssential%20SQLAlchemy%3C/a%3E"&gt;Essential SQLAlchemy &lt;/a&gt;by Rick Copeland&lt;br /&gt;&lt;a href="http://oreilly.com/catalog/9780596516147/"&gt;O'Reilly Media&lt;/a&gt;&lt;br /&gt;ISBN 10: 0-596-51614-2 / ISBN 13: 9780596516147&lt;br /&gt;&lt;br /&gt;This is a great book describing how to use SQLAlchemy to connect Python programs to databases.  In fact, at the moment (mid-summer 2008), it is &lt;span style="font-style: italic;"&gt;the&lt;/span&gt; book, since there are no other books on the subject, yet.  Athough I am not (yet) a SQLAlchemy user, this book seems to cover all of the core topics in SQLAlchemy.  The text includes many straightforward examples of how to use various facilities in SQLAlchemy and how to map various database programming problems into Python code via SQLAlchemy.  Copeland also provides a whirlwind tour of some extensions to SQLAlchemy.&lt;br /&gt;&lt;br /&gt;I heard about SQLAlchemy project on the &lt;a href="http://thisweekindjango.com/"&gt;This Week in Django&lt;/a&gt; podcast.  Django doesn’t use SQLAlchmey, but it does use a similar object-relational mapper (ORM). As I mentioned, I haven’t used SQLAlchemy so I came into this book with a somewhat blank slate.  I have, however, been programming in Python since before 1.0, and I’ve worked with database APIs and ORMs since the early 90s in C++, Java, and Python.  So, I was familiar with the basic landscape of database programming, even if I hadn’t used SQLAlchemy.  And, I’m currently working on a large Python project that is coded using the Python database API directly, which is very tedious.  So, the whole time I was reading this book, I was looking at how to fit SQLAlchemy into this existing code base.&lt;br /&gt;&lt;br /&gt;To be honest, the first chapter (the proverbial introduction) almost turned me off.  The author starts out slowly enough, but then he starts touching on a huge number details, which were glazing my eyes over.  However, the second chapter (getting started) started back at ground zero and stepped through everything in a nice clear fashion, and the rest of the book continued in that vein.  He covers all the topics you would expect in a database programming book: queries, updates, joins, the built-in types, and how to hook in to provide support for your own types.&lt;br /&gt;&lt;br /&gt;Something I didn’t realize about SQLAlchemy coming into this is that SQLAlchemy is both an ORM (what I expected) as well as a high-level, database-independent API.  Which is to say, you can just access the database as tables, columns and rows rather than as classes, attributes, and object instances.  Although I’d personally prefer to use the ORM, I can imagine cases where it might not be the right tool for the job, and it’s good to have a choice.&lt;br /&gt;&lt;br /&gt;I was also surprised to see the ORM supports two styles of object-relational access: the data mapper pattern (which I had seen in Django and Hibernate) and the active record (used in Ruby).  The author does a good job of explaining both of these and how to use them.  He even devotes a whole chapter to Exlir, which is an extension that implements the active record pattern.&lt;br /&gt;&lt;br /&gt;One thing that many people might consider odd is the fact that although SQLAlchemy is an ORM, the author waits until chapter eight to discuss how to map object inheritance hierarchies onto relational databases.  Most books I’ve read on ORMs discuss this topic early, but I applaud Copeland’s decisions to hold off on discussing it.  When books bring this up early (e.g., in chapter three), the discussion often gets bogged down in details, which glaze the reader’s eyes.  I’ve dealt with the issue of inheritance mapping enough in ORMs I’ve used and those I’ve written enough that I’m not that interested in the topic (assuming the tool provides the typical, reasonable solutions), and was grateful that he held off on it.&lt;br /&gt;&lt;br /&gt;One issue I had with the overall structure of the book is that I’m hard pressed to pigeon-hole the book.  Books about a single technology such as SQLAlchemy usually occupy one end or the other of a spectrum.  Either they’re hard-core references, often times copying-and-pasting API documentation from a web site (I really hate that), or they’re largish tutorials that may or may not contain enough technical meat.  This is a short (roughly 200 page) book that contains plenty of technical meat, but it also includes some simple tutorial motivations for using various capabilities of the tool.  Although this mix felt odd to me, I’m sure it will be perfect when I go to apply SQLAlchemy to my existing database projects since I don’t really want a hand-holding tutorial, but a pure reference wouldn’t quite work for me either when I’m just starting out.&lt;br /&gt;&lt;br /&gt;In conclusion, Essential SQLAlchemy provides a thorough presentation of the SQLAlchemy tool for interfacing Python code to SQL databases.  The author covers a number of different methods in which SQLAlchemy can be used to access databases from Python, and he provides plenty of details of the various APIs available to the programmer.&lt;br /&gt;&lt;br /&gt;Enjoy,&lt;br /&gt;Charles.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;iframe src="http://rcm.amazon.com/e/cm?t=westernskies-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=as1&amp;amp;asins=0596516142&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="width: 120px; height: 240px;" marginwidth="0" marginheight="0" frameborder="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-3191238961646473554?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/3191238961646473554/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=3191238961646473554' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/3191238961646473554'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/3191238961646473554'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/08/book-essential-sqlalchemy.html' title='Book: Essential SQLAlchemy'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-1953655121167460340</id><published>2008-07-06T16:16:00.000-07:00</published><updated>2009-09-17T21:39:43.851-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='django'/><title type='text'>Converting a Django Site to newforms-admin</title><content type='html'>Right after I learned about &lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt; at OSCON 2006, I created a prototype to replace an &lt;a href="http://www.etfarms.com/"&gt;existing PHP site&lt;/a&gt;.  Due to various distractions, I haven't done much with that Django site since then and it never went live, but I've come back to it recently.&lt;br /&gt;&lt;br /&gt;My first order of business was to upgrade from 0.95 to something modern.  The first stop was to upgrade to trunk.  Following the &lt;a href="http://www.djangoproject.com/documentation/install/"&gt;instructions&lt;/a&gt; on the Django site, I got it running on trunk and only had to change &lt;span style="font-family:courier new;"&gt;maxlength&lt;/span&gt; to &lt;span style="font-family:courier new;"&gt;max_length&lt;/span&gt; in my models.&lt;br /&gt;&lt;br /&gt;Since, &lt;a href="http://code.djangoproject.com/wiki/NewformsAdminBranch"&gt;newforms-admin&lt;/a&gt; will be merging with trunk soon, porting to newforms-admin was my next step.  I pointed my django install at my newforms admin svn tree and let it rip - i.e., I didn't bother reading any documentation or anything.&lt;br /&gt;It blew up with a nasty-looking traceback that ended with this:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    func(self, *args, **kwargs) &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; TypeError: __init__() got an unexpected keyword argument 'prepopulate_from' &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A quick Google search turned up &lt;a href="http://groups.google.com/group/django-users/browse_thread/thread/21dfd618a038610f/12f64e3f7e4e969f?#12f64e3f7e4e969f"&gt;this thread&lt;/a&gt; on the Django Users mailing list.  Five minutes of reading the newforms-admin wiki page and refactoring my code, and I was up and running.  So, despite the ugly-looking traceback, it just wan't that bad.&lt;br /&gt;&lt;br /&gt;Granted,  my project is pretty small because I never had much time to work on it.  However, all in all, the conversion process from 0.95 to the bleeding edge of newforms-admin was pretty painless.&lt;br /&gt;&lt;br /&gt;Another happy Django user,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-1953655121167460340?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/1953655121167460340/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=1953655121167460340' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/1953655121167460340'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/1953655121167460340'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/07/converting-django-site-to-newforms.html' title='Converting a Django Site to newforms-admin'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-489387628152121486</id><published>2008-07-06T13:06:00.000-07:00</published><updated>2008-07-06T13:41:46.192-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='books'/><title type='text'>Book: Effective Java</title><content type='html'>&lt;a href="http://www.amazon.com/gp/product/0321356683?ie=UTF8&amp;amp;tag=westernskies-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0321356683"&gt;Effective Java, 2nd Edition&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=westernskies-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0321356683" alt="" style="border: medium none  ! important; margin: 0px ! important;" border="0" height="1" width="1" /&gt; by Joshua Bloch.  ISBN 0321356683&lt;br /&gt;&lt;br /&gt;This is the best book that I've read that I didn't know I needed to read.  If you are a pretty good Java programmer, and you want to be better, this is a book you should definitely read.&lt;br /&gt;&lt;br /&gt;Back in the day (BITD), we had Scott Meyer's book &lt;a href="http://www.amazon.com/gp/product/0321334876?ie=UTF8&amp;amp;tag=westernskies-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0321334876"&gt;Effective C++&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=westernskies-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0321334876" alt="" style="border: medium none  ! important; margin: 0px ! important;" border="0" height="1" width="1" /&gt;, and we needed it.  Even without templates and all the "new" things in C++, C++ was a large and complex language.  I loved &lt;span style="font-style: italic;"&gt;Effective C++&lt;/span&gt; not only because it had lots of tips to keep you out of trouble when coding C++, but also because the organization was brilliant: each tip was about the right length to be read while sitting on the can.&lt;br /&gt;&lt;br /&gt;I ignored the first edition of &lt;span style="font-style: italic;"&gt;Effective Java&lt;/span&gt; book when it came out because I smugly assumed that Java was so superior to C++ (Java is C++ with the pointy bits filed down) that it wasn't really necessary.  And that may or may not have been true in the 1.0 or 1.1 days of Java, but with the release of Java 5, the language has certainly grown and is now sufficiently complex that a book like this is a necessity, especially if you've recently moved up to Java 5 or Java 6.  Lucky for me, this book landed on my desk against my will.&lt;br /&gt;&lt;br /&gt;The book uses that same sitting-on-the-can format from &lt;span style="font-style: italic;"&gt;Effective C++&lt;/span&gt;; the information is broken down into nice, small bits of information that you can read one or two at a time.  These are grouped into 10 sections.  There are specific sections for Java 5 features like Generics and Enumerations, which is great for people like me who were stuck on 1.4 for far too long.&lt;br /&gt;&lt;br /&gt;What is really amazing about this book is that I learned a lot about topics that I thought I already knew about.  For example, I've used serialization in a number of formats (built-in and do-it-yourself) for years, but I realized there's a lot more that I had no idea about.  I will certainly think twice before doing any serialization in the future.&lt;br /&gt;&lt;br /&gt;Unless you're the sort that knows the &lt;a href="http://www.amazon.com/gp/product/0321246780?ie=UTF8&amp;amp;tag=westernskies-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0321246780"&gt;Java Language Specification&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=westernskies-20&amp;amp;l=as2&amp;amp;o=1&amp;amp;a=0321246780" alt="" style="border: medium none  ! important; margin: 0px ! important;" border="0" height="1" width="1" /&gt; by heart, you need to read this book.&lt;br /&gt;&lt;br /&gt;Enjoy,&lt;br /&gt;Charles.&lt;br /&gt;&lt;br /&gt;&lt;iframe src="http://rcm.amazon.com/e/cm?t=westernskies-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=as1&amp;amp;asins=0321356683&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="width: 120px; height: 240px;" marginwidth="0" marginheight="0" frameborder="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-489387628152121486?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/489387628152121486/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=489387628152121486' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/489387628152121486'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/489387628152121486'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/07/book-effective-java.html' title='Book: Effective Java'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-7877415459119301547</id><published>2008-06-24T17:42:00.000-07:00</published><updated>2008-06-24T17:52:01.028-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scm'/><category scheme='http://www.blogger.com/atom/ns#' term='mercurial'/><title type='text'>Configuring TortiseMerge for use with Mercurial</title><content type='html'>I've been using &lt;a href="http://www.selenic.com/mercurial/"&gt;Mercurial &lt;/a&gt;primarily on a Mac, but also on a Windows box for a client.  Since the Windows box isn't my primary platform, it tends to be under-configured/under-tricked-out.  After my first conflicted &lt;span style="font-family: courier new;"&gt;hg merge&lt;/span&gt;, it was time to set up a merge program.&lt;br /&gt;I guess Mercurial looks through the registry where it was finding some wacked out description for P4 merge.  (The client currently uses P4.)  It was referring to some path that didn't exist.&lt;br /&gt;I have &lt;a href="http://tortoisesvn.tigris.org/"&gt;TortiseSVN &lt;/a&gt;on the machine from work for a different client, so I figured I'd use that merge program.  Googling around, I didn't find an example, so here you go (even though it's not real hard - see &lt;a href="http://www.selenic.com/mercurial/wiki/index.cgi/MergeToolConfiguration"&gt;MergeToolConfiguration &lt;/a&gt;for details):&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;[ui]&lt;br /&gt;merge=TortoiseMerge&lt;br /&gt;[merge-tools]&lt;br /&gt;TortoiseMerge.executable=C:\Programs\TortoiseSVN\bin\TortoiseMerge.exe&lt;br /&gt;TortoiseMerge.args=/mine:$local /theirs:$other /base:$base -o /merged:$output&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-7877415459119301547?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/7877415459119301547/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=7877415459119301547' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/7877415459119301547'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/7877415459119301547'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/06/configuring-tortisemerge-for-use-with.html' title='Configuring TortiseMerge for use with Mercurial'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-8658986483945972258</id><published>2008-05-27T17:10:00.000-07:00</published><updated>2008-07-06T13:50:41.914-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scm'/><category scheme='http://www.blogger.com/atom/ns#' term='mercurial'/><title type='text'>DVCS (Mercurial) for Students</title><content type='html'>I just had a bit of an epiphany for yet another reason why &lt;a href="http://en.wikipedia.org/wiki/Distributed_version_control"&gt;distributed version control systems&lt;/a&gt; (DVCS) like &lt;a href="http://www.selenic.com/mercurial/wiki/"&gt;Mercurial&lt;/a&gt; rock.  In an advanced software engineering class (e.g., a capstone project), it would be appropriate to have project teams using a SCM/VCS tool.  At my campus, we've never pushed that because it can be a pain to set up a server for students to access.  Gotta have a dedicated host for it.  Firewalls have to be open.  Permissions and users have to be set up.  Yada, yada, yada.&lt;br /&gt;&lt;br /&gt;However, with a DVCS tool like Mercurial, it would be trivial and wouldn't require any networking at all.  Students could use the modern equivalent of SneakerNet: ThumbNet.  Put the whole repo on a thumb drive, meet up with your project partners, push and pull, done.  Or, if the project is small enough - just email whole repos around.  In this context, "distributed" also means you don't need any support from &lt;a href="http://en.wikipedia.org/wiki/The_man"&gt;The Man&lt;/a&gt;, and that's a good thing.&lt;br /&gt;&lt;br /&gt;For better or worse, I don't teach those classes, but if I did....&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-8658986483945972258?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/8658986483945972258/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=8658986483945972258' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/8658986483945972258'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/8658986483945972258'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/05/dvcs-mercurial-for-students.html' title='DVCS (Mercurial) for Students'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-5432061849792388342</id><published>2008-05-16T12:40:00.000-07:00</published><updated>2008-07-06T13:53:04.759-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>@Override is your friend</title><content type='html'>When Java 5 came out, I had my head down teaching and wasn't really paying attention.  I've since started working with it and have been using annotations for "big" tasks like Hibernate/JPA metadata.  I was pretty underwhelmed by &lt;span style="font-family:courier new;"&gt;@Override&lt;/span&gt; - one of the only stock annotations.  When I implement &lt;span style="font-family:courier new;"&gt;toString&lt;/span&gt;, I know I'm overriding the method on &lt;span style="font-family:courier new;"&gt;Object&lt;/span&gt;.  Who cares?&lt;br /&gt;&lt;br /&gt;The other day I was beating my head into the desk trying to figure out why a Swing table wasn't editable.  I had overridden the &lt;span style="font-family:courier new;"&gt;isCellEditable&lt;/span&gt; method on &lt;span style="font-family:courier new;"&gt;JTable&lt;/span&gt;, but the cells weren't editable. Then, I remembered something from the &lt;a href="http://java.sun.com/docs/books/tutorial/java/javaOO/annotations.html"&gt;annoations tutorial&lt;/a&gt; I'd read at some point:  "While it's not required ... it helps to prevent errors."  So, I added &lt;span style="font-family:courier new;"&gt;@Override&lt;/span&gt;, and sure enough - I'd misspelled the method name, just the sort of error that &lt;span style="font-family:courier new;"&gt;@Override&lt;/span&gt; can prevent.&lt;br /&gt;&lt;br /&gt;I've got the religion.  And like any recent convert, I suggest you get it too.&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-5432061849792388342?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/5432061849792388342/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=5432061849792388342' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/5432061849792388342'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/5432061849792388342'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/05/override-is-your-friend.html' title='@Override is your friend'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-4910345361886705366</id><published>2008-05-12T22:06:00.000-07:00</published><updated>2008-05-14T22:18:45.752-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='webtest'/><category scheme='http://www.blogger.com/atom/ns#' term='ant'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Data Driven, my eye!</title><content type='html'>I've started using the &lt;a href="http://webtest.canoo.com/"&gt;WebTest&lt;/a&gt; web testing framework.  Mostly, it's pretty cool.  However, I have a bone to pick with &lt;a href="http://opensource.basehaus.com/webtest/screencasts/data-driven-webtest.htm"&gt;screencast&lt;/a&gt; demonstrating the &lt;a href="http://webtest.canoo.com/webtest/manual/dataDriven.html"&gt;dataDriven&lt;/a&gt; task.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;There's a "slide" that says "Do you know the dataDriven Ant task?"  I know of no such standard Ant task.  It turns out that it's specific to WebTest.  Not really clear.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;They show no configuration steps to use it, implying that it works out-of-the-box.  I don't know if my environment is wacked (I installed from the developer build, as they suggested), but I had to add an Ant &lt;span style="font-family:courier new;"&gt;taskdef &lt;/span&gt; referring to &lt;span style="font-family:courier new;"&gt;com.canoo.ant.task.PropertyTableTask&lt;/span&gt;, and I only found that by looking in the source.&lt;/li&gt;&lt;li&gt;The screencast shows running ant at the command line, which is how I've been running my tests, but I had to run their webtest script instead.  Again, maybe my installation is wacked.&lt;/li&gt;&lt;li&gt;I really wish it could handle data in a TSV/CSV/text file, since I don't have Excel installed on the machine where I'm running these tests, but it only seems to accept an xls file.&lt;/li&gt;&lt;li&gt;Just to add insult to injury, Google Spreadsheet (which I'm using to generate the data file) seems to append a bunch of  empty lines to my spreadsheet, which causes the dataDriven task to repeat the last line 90-odd times.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;Grrr,&lt;br /&gt;Charles - aka Cranky Pants.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update:&lt;/span&gt;&lt;br /&gt;OK, so it sucked to be me, but not any more.  I figured out my various issues with the &lt;span style="font-family:courier new;"&gt;dataDriven&lt;/span&gt; task.  It turns out that the screencast (clearly) shows them developing in the &lt;span style="font-style: italic;"&gt;tests&lt;/span&gt; directory of a WebTest project.  I missed that and tried to use &lt;span style="font-family:courier new;"&gt;dataDriven&lt;/span&gt; in the top-level &lt;span style="font-family:courier new;"&gt;build.xml&lt;/span&gt; in a target that didn't declare &lt;span style="font-family:courier new;"&gt;wt.defineTasks &lt;/span&gt;as a dependency.  Guess what &lt;span style="font-family:courier new;"&gt;wt.defineTask&lt;/span&gt; does - yup, it does the &lt;span style="font-family:courier new;"&gt;taskdef&lt;/span&gt;. &lt;br /&gt;I coupled that breakthrough with breaking down and using Excel to create the xls file (instead of exporting from Google) and viola - I'm livin' large and no longer cranky.&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;br /&gt;&lt;br /&gt;P.S. Apologies to &lt;a href="http://en.wikipedia.org/wiki/Earache_My_Eye"&gt;Cheech and Chong&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-4910345361886705366?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/4910345361886705366/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=4910345361886705366' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/4910345361886705366'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/4910345361886705366'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/05/ive-started-using-webtest-web-testing.html' title='Data Driven, my eye!'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-7642552034163614178</id><published>2008-05-07T11:50:00.000-07:00</published><updated>2008-12-11T00:46:54.355-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='os x'/><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><title type='text'>Universal???</title><content type='html'>Apple has released Java6 for the Mac, which I have been eagerly awaiting.  However, their download page is a bit contradictory:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_VaSVUz85HT8/SCH7KP_JVtI/AAAAAAAAAAU/gigef0zhIAM/s1600-h/Universal-huh.jpg"&gt;&lt;img style="cursor: pointer;" src="http://1.bp.blogspot.com/_VaSVUz85HT8/SCH7KP_JVtI/AAAAAAAAAAU/gigef0zhIAM/s320/Universal-huh.jpg" alt="" id="BLOGGER_PHOTO_ID_5197711598470911698" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;This is limited to 64-bit Intel macs (which is fine with me), but yet they still call it Universal.  What's Universal about that?  The only way I could imagine it being less universal is if it they specified a number of cores or CPU speed.&lt;br /&gt;&lt;br /&gt;Anyway, Java6 is good stuff for those of us on Universal Core2 Duo iMacs.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-7642552034163614178?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/7642552034163614178/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=7642552034163614178' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/7642552034163614178'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/7642552034163614178'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/05/universal.html' title='Universal???'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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://1.bp.blogspot.com/_VaSVUz85HT8/SCH7KP_JVtI/AAAAAAAAAAU/gigef0zhIAM/s72-c/Universal-huh.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29718960.post-352380392300553859</id><published>2008-03-29T14:07:00.000-07:00</published><updated>2008-12-11T00:46:54.554-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='netbeans'/><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><title type='text'>Netbeans is a memory hog?</title><content type='html'>I was looking at Activity Monitor on my iMac, and I couldn't read the size entry for the Netbeans process that was running.  So, I selected it and got a detail report:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_VaSVUz85HT8/R-6wZMB0TEI/AAAAAAAAAAM/MNLT1nJ5bLo/s1600-h/nb-hog.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_VaSVUz85HT8/R-6wZMB0TEI/AAAAAAAAAAM/MNLT1nJ5bLo/s320/nb-hog.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5183274167922084930" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I knew that Java and Netbeans could be memory hogs, but 16 million TB (16 exabytes) is a bit much.  Good thing I have virtual memory!  &lt;span style="font-style:italic;"&gt;(I didn't alter the image, but clearly it's a bug with Activity Monitor and/or OS X 10.5.2.)&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-352380392300553859?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/352380392300553859/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=352380392300553859' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/352380392300553859'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/352380392300553859'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/03/netbeans-is-memory-hog.html' title='Netbeans is a memory hog?'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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://1.bp.blogspot.com/_VaSVUz85HT8/R-6wZMB0TEI/AAAAAAAAAAM/MNLT1nJ5bLo/s72-c/nb-hog.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29718960.post-1200901290403325700</id><published>2008-02-28T23:03:00.000-08:00</published><updated>2008-02-29T00:31:08.054-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Simple, complete example of Python getstate and setstate</title><content type='html'>I've been doing serialization and/or object-relation mapping in languages like C++ and Java for at least 15 years.  I've known about Python's serialization facility (the &lt;a href="http://docs.python.org/lib/module-pickle.html"&gt;pickle&lt;/a&gt; and &lt;a href="http://docs.python.org/lib/module-cPickle.html"&gt;cPickle&lt;/a&gt; modules) for as long as they've existed, but I've never had a need to use them.  Recently, I needed to pickle an object to store in &lt;a href="http://www.danga.com/memcached/"&gt;memcached&lt;/a&gt; to reduce database traffic. &lt;br /&gt;&lt;br /&gt;Wouldn't you know it - the first class I try to pickle throws an exception because it contains some attributes that can't be serialized.  I couldn't figure out where the problem was because the Exception and trace back didn't include the name of the attribute that contained the threading lock that couldn't be serialized.  However, a quick look at the code revealed a couple of suspects.&lt;br /&gt;&lt;br /&gt;Even though I didn't know which attributes were causing the problem, I knew that the only solution would be to take control of the serialization process.  Once I could pick and choose which attributes were being pickled, I could search for the offender(s).  As it turned out, both of my initial suspects were guilty of evading pickling.&lt;br /&gt;&lt;br /&gt;From the &lt;a href="http://docs.python.org/lib/pickle-inst.html"&gt;documentation on pickling&lt;/a&gt;, I could see that implementing the &lt;span style="font-family: courier new;"&gt;__getstate__&lt;/span&gt; and &lt;span style="font-family: courier new;"&gt;__setstate__&lt;/span&gt; methods, but it wasn't clear what those methods need to look like.  I found an example online, but the guy was having problems (it was posted to a mailing list), and as I implemented my own methods, I realized what his problem was.  So, here's the code: &lt;br /&gt;&lt;span style="font-family: courier new;"&gt;&lt;pre&gt;&lt;br /&gt;    def __getstate__(self):&lt;br /&gt;        result = self.__dict__.copy()&lt;br /&gt;        del result['log']&lt;br /&gt;        del result['cfg']&lt;br /&gt;        return result&lt;br /&gt;&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;The problem I was having with pickling were the logging and configuration attributes.  These needed to be removed from the object before pickling.  Fortunately, they're not unique to the instance, so they're easy to recreate during unpickling.&lt;br /&gt;&lt;br /&gt;As you can tell,&lt;span style="font-family: courier new;"&gt; __getstate__&lt;/span&gt; returns a dictionary of the object's state.  By default (if you didn't implement the method), this is just the &lt;span style="font-family: courier new;"&gt;__dict__&lt;/span&gt; member.  To exclude some attributes, we just need to delete the keys from the dictionary.  However, the crucial step is that you have to make a (shallow) copy of &lt;span style="font-family: courier new;"&gt;__dict__&lt;/span&gt; first.  Otherwise, deleting the keys from the dictionary is the same as deleting the attributes from the instance, which would be bad.  (This is where the other example I found online failed - he didn't make a copy.)&lt;br /&gt;&lt;br /&gt;The &lt;span style="font-family: courier new;"&gt;__setstate__&lt;/span&gt; method is the reverse, only we don't have to mess with copies:&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; &lt;pre&gt;&lt;br /&gt;def __setstate__(self, dict):&lt;br /&gt;    self.__dict__ = dict&lt;/span&gt;&lt;br /&gt;    cfg = self.cfg = getConfig()&lt;/span&gt;&lt;br /&gt;    self.log = getLog()&lt;br /&gt;&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-1200901290403325700?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/1200901290403325700/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=1200901290403325700' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/1200901290403325700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/1200901290403325700'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/02/simple-complete-example-of-python.html' title='Simple, complete example of Python getstate and setstate'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-7941242721583628242</id><published>2008-02-23T23:11:00.000-08:00</published><updated>2008-03-18T20:25:01.169-07:00</updated><title type='text'>Mac OS X 10.5.2 did not completely fix stacks</title><content type='html'>Apple's newest update to Leopard, 10.5.2, has greatly improved the new Stack feature by adding a hierarchical list view, but it is still not as functional as the list view in Tiger.   As I &lt;a href="http://western-skies.blogspot.com/2006/07/tip-managing-applications-on-os-x.html"&gt;noted before&lt;/a&gt;, I created my own directory that has a collection of aliases (symbolic links) to the applications I use most frequently, as well as links to Applications, Utilities, and the LocalApps directory where I install third-party applications.  The problem is even with the 10.5.2 update, the list view does not follow the symbolic links, so my folder of links is basically useless.&lt;br /&gt;&lt;br /&gt;I'm still pleased with the list view - it is a huge improvement, but I won't be totally satisfied until it follows links.&lt;br /&gt;&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-7941242721583628242?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/7941242721583628242/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=7941242721583628242' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/7941242721583628242'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/7941242721583628242'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/02/mac-os-x-1052-did-not-completely-fix.html' title='Mac OS X 10.5.2 did not completely fix stacks'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-8144266504043664298</id><published>2008-02-17T01:32:00.000-08:00</published><updated>2008-02-18T21:54:59.151-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mercurial'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Simply Mercurial</title><content type='html'>&lt;a href="http://www.selenic.com/mercurial/wiki/"&gt;Mercurial&lt;/a&gt; is the easiest revision control system I've used, "and so can you"  to quote Stephen Colbert.  I became interested in the idea of a distributed SCM tool in order to keep my revision history with me while I'm on the road and not necessarily connected.  I would have assumed that to get that power, the tool would be more complex - you can't get something for free, right?  However, Mercurial is so easy to use, I'm using it for simple one-off revision needs.&lt;br /&gt;&lt;br /&gt;Consider the case of a lone developer with a modest number of files to keep track of.  To use Mercurial, all he needs to do change into the directory where the files are and run:&lt;span style="font-family: courier new;"&gt;hg init&lt;/span&gt;&lt;br /&gt;That creates a repository, hidden in the &lt;span style="font-family: courier new;"&gt;.hg&lt;/span&gt; subdirectory, and sets the directory up as a working directory.  The &lt;span style="font-family: courier new;"&gt;hg status&lt;/span&gt; command shows that none of the files is under control, yet.  Running &lt;span style="font-family: courier new;"&gt;hg add *&lt;/span&gt; (or whatever subset of the files is appropriate) marks all of the files to be added to the repository.  Finally, &lt;span style="font-family: courier new;"&gt;hg commit&lt;/span&gt; commits the files.&lt;br /&gt;&lt;br /&gt;The real beauty was in that first step - &lt;span style="font-family: courier new;"&gt;hg init&lt;/span&gt;.  That is so much easier than CVS or Subversion where you either have to create a new repository or figure out where in an existing repository you want to put these files.  And it's easier than the dinosaurs, RCS and SCCS, where you have to set up subdirectories to hold the version files in every subdirectory - not to mention the fact that those tools don't really deal with multiple users.&lt;br /&gt;&lt;br /&gt;Mercurial is about as simple as can be, and if you never work with multiple developers and passing changes around between developers and repositories, then it stays that simple.  Period.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-8144266504043664298?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/8144266504043664298/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=8144266504043664298' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/8144266504043664298'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/8144266504043664298'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/02/simply-mercurial.html' title='Simply Mercurial'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-2452008762397527706</id><published>2008-02-02T23:34:00.000-08:00</published><updated>2008-03-18T20:28:23.449-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Complete example of __getattr_ in Python</title><content type='html'>I've always known about the &lt;a href="http://docs.python.org/ref/attribute-access.html#l2h-207"&gt;&lt;span style="font-family:courier new;"&gt;_getattr_&lt;/span&gt;&lt;/a&gt; function on classes in Python and how it could theoretically be used.  However, I never had a real need to implement it, and so I had never actually implemented &lt;span style="font-family:courier new;"&gt;__getattr__&lt;/span&gt;.  For whatever reason, it was a tad more difficult that I thought, so I figured I'd share an example with you'all.&lt;br /&gt;&lt;br /&gt;In case you don't already know, the idea is that any time any code makes are reference to an attribute a class (e.g., &lt;span style="font-style: italic;"&gt;obj.x&lt;/span&gt; ), &lt;span style="font-family:courier new;"&gt;__getattr__&lt;/span&gt; gets called to fetch or compute the value of the attribute.  This function can do almost anything, but you must be careful when making  references to attributes, because that will trigger a recursive call to &lt;span style="font-family:courier new;"&gt;__getattr__&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;In my case, I was writing some code for unit testing.  I needed to create a mock object that's used to store configuration information for the system. In the real object, every configuration attribute is initialized from an ini file parsed by &lt;a href="http://docs.python.org/lib/module-ConfigParser.html"&gt;ConfigParser&lt;/a&gt; in the constructor.  For testing, didn't want to have a huge configuration file for every test.  So, I wanted to create a system that performed lazy initialization of the data attributes - i.e., only look in the ini file if we actually need a given item, and if the attribute is never referenced, we never need to fetch it from the ini file.    Therefore, the ini file only needs the attributes that are actually used by a given test.  Implementing &lt;span style="font-family:courier new;"&gt;__getattr__&lt;/span&gt; is the way to hook into the process to provide this lazy initialization.&lt;br /&gt;&lt;br /&gt;The basic outline/algorithm is:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;If the attribute already exists on &lt;span style="font-style: italic;"&gt;self&lt;/span&gt;, return that value&lt;/li&gt;&lt;li&gt;Fetch/compute the missing value&lt;/li&gt;&lt;li&gt;Store the value on &lt;span style="font-style: italic;"&gt;self&lt;/span&gt; for subsequent use&lt;/li&gt;&lt;li&gt;Return the value&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;The key to making this work and avoiding infinite recursion is the &lt;span style="font-family:courier new;"&gt;__dict__&lt;/span&gt; attribute, which is a (regular) dictionary, the keys of which are attributes that exist on the object and the values are the values of the attributes.  We can access these keys and values without going through &lt;span style="font-family:courier new;"&gt;__getattr__&lt;/span&gt;, thus avoiding recursion.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def __getattr__(self, attrName):&lt;br /&gt;  if not self.__dict__.has_key(attrName):&lt;br /&gt;     value = self.fetchAttr(attrName)    # computes the value&lt;br /&gt;     self.__dict__[attrName] = value&lt;br /&gt;  return self.__dict__[attrName]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It's pretty straightforward.  In retrospect, I'm not sure what tripped me up when I first went to implement it.  In the end, the &lt;span style="font-style: italic;"&gt;fetchAttr&lt;/span&gt; function ended up being pretty fancy, but I'll write more about that later.  You gotta love a dynamic language like Python that makes this as simple as it is, even if it does require a bunch of underscores.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-2452008762397527706?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/2452008762397527706/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=2452008762397527706' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/2452008762397527706'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/2452008762397527706'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/02/complete-example-of-getattr-in-python.html' title='Complete example of __getattr_ in Python'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-1266151693378205522</id><published>2008-01-24T00:30:00.000-08:00</published><updated>2008-01-24T00:40:33.027-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><title type='text'>Remove Office on Mac sux</title><content type='html'>The Remove Office program that comes with the trial version of Microsoft Office just sucks.  The two times I've used it, it's failed.   The first time,  I had my old iMac connected via Firewire (target disk mode) to my new iMac.  I ran Remove Office on the new iMac to remove the trial version, and it removed the non-trial version on my old iMac - without even asking me which version to remove.  Now, on my new MacBook, I tried running Remove Office (without any other computers connected), and it couldn't find the trial version to remove - never mind the fact that I was running Remove Office from the folder containing Office. &lt;br /&gt;&lt;br /&gt;My advice to anyone is to just use 'rm -r' from the Terminal window.  If you just drag it to the trash (without emptying the trash), the trail version will keep launching.&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-1266151693378205522?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/1266151693378205522/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=1266151693378205522' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/1266151693378205522'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/1266151693378205522'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/01/remove-office-on-mac-sux.html' title='Remove Office on Mac sux'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-7927044735574960202</id><published>2008-01-20T16:12:00.000-08:00</published><updated>2008-01-20T16:45:05.706-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='moodle'/><title type='text'>Exporting from ExamView to Moodle</title><content type='html'>I've just started using &lt;a href="http://moodle.org"&gt;Moodle&lt;/a&gt; for a course (more on that later), and I wanted to import some questions I wrote using ExamView into Moodle.  Although our version of Moodle (1.8?) suggests that it can import EvamView questions, it failed for me.  I came across this &lt;a href="http://forum.fscreations.com/index.php?s=58df390f7d0ab7df6d39732a4cb35cfd&amp;amp;showtopic=3779&amp;amp;st=0&amp;amp;#entry7042"&gt;post that&lt;/a&gt; suggests that it isn't even supported - at least not by the company that makes ExamView.  Based on that post, here's what I ended up doing:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;From ExamView Pro (version 4.0.8) export as Blackboard 5.x, which is a zip file.&lt;/li&gt;&lt;li&gt;Unzip the zip file.&lt;/li&gt;&lt;li&gt;Import the .dat file into Moodle as a Blackboard, not Blackboard V6+&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;(And, all of this is made more complicated by the fact that I've basically abandoned the PC for the Mac, and I only have a version of ExamView for the PC.  Praise be to VMware for &lt;a href="http://www.vmware.com/products/fusion/"&gt;Fusion&lt;/a&gt;.)&lt;br /&gt;&lt;br /&gt;There may be a simpler way to do this, but it works, which is all that matters right now.  It would be swell if I could automate the process...&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-7927044735574960202?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/7927044735574960202/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=7927044735574960202' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/7927044735574960202'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/7927044735574960202'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2008/01/exporting-from-examview-to-moodle.html' title='Exporting from ExamView to Moodle'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-5385308337174138185</id><published>2007-10-12T10:45:00.000-07:00</published><updated>2007-10-12T21:12:28.708-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><category scheme='http://www.blogger.com/atom/ns#' term='svn'/><title type='text'>Subersion on the Mac</title><content type='html'>If you've ever used &lt;a href="http://subversion.tigris.org/"&gt;Subversion &lt;/a&gt;(SVN) on Windows, chances are you've used &lt;a href="http://tortoisesvn.tigris.org/"&gt;TortiseSVN&lt;/a&gt;.  (If you haven't, definitely check it out.)  It works as an extension to Windows Explorer.  What this means, is that you don't have a separate UI for SVN - you do everything in Explorer.  I was really struck by how cool this was when I was working on an old project using an old version of Perforce; it seemed barbaric to have to keep switching between the SCM UI and Explorer.&lt;br /&gt;&lt;br /&gt;Until recently, there wasn't anything like that for the Mac, at least not anything that was free/open source and that I knew about.  Then, along comes &lt;a href="http://scplugin.tigris.org/"&gt;SCPlugin&lt;/a&gt;.  From the web page: "The goal of the SCPlugin project is to integrate Subversion into the Mac OS X Finder. The inspiration for this project came from the TortoiseSVN  project."&lt;br /&gt;&lt;br /&gt;As of this writing, it's at version 0.7, which means it has a few rough spots, but for the light use I've put it to so far, it's been mostly pretty good.  And since it's 0.7, it has nowhere to go but up.&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-5385308337174138185?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/5385308337174138185/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=5385308337174138185' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/5385308337174138185'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/5385308337174138185'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2007/10/subersion-on-mac.html' title='Subersion on the Mac'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-2972783024275691390</id><published>2007-10-04T21:16:00.000-07:00</published><updated>2007-10-04T21:28:57.758-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='misc'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Seven Habits of Effective Text Editing - with Vim</title><content type='html'>I'm a big fan of &lt;a href="http://vim.org/"&gt;vim&lt;/a&gt;.  It's the Unix vi editor with a large number of improvements.  The biggest thing I like about it is that it runs pretty much everywhere - Unix/Linux, Mac, and Windows.  Having a powerful, familiar editor on Windows was a huge technological leap forward for me when I spent a lot of time on Windows, and it's still very useful on those occasions when I'm "stuck" on Windows.&lt;br /&gt;&lt;br /&gt;I recently stumbled across an &lt;a href="http://www.moolenaar.net/habits.html"&gt;old article&lt;/a&gt; (Nov 2002) from the creator of vim, Bram Moolenaar, that describes how to use vim more effectively.  The big thing I learned from it is how to use ctrl-N to complete things like identifiers in programming languages - e.g., type "read&lt;ctrl-n&gt;" and it expands to "readlines" and offers you a list of other options in your program.  Granted, this is old hat for fancy-ass IDEs like Eclipse and Netbeans, but I had no idea that little old vim had it.  I guess that's what they mean by vim means "vi-improved."&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;br /&gt;&lt;/ctrl-n&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-2972783024275691390?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/2972783024275691390/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=2972783024275691390' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/2972783024275691390'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/2972783024275691390'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2007/10/seven-habits-of-effective-text-editing.html' title='Seven Habits of Effective Text Editing - with Vim'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-802453461174347695</id><published>2007-09-25T14:30:00.000-07:00</published><updated>2007-09-25T14:38:17.289-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scm'/><category scheme='http://www.blogger.com/atom/ns#' term='subversion'/><category scheme='http://www.blogger.com/atom/ns#' term='svn'/><title type='text'>Very non-intuitive error message from SVN</title><content type='html'>I just got the following error message out of Subversion (on the command line under Linux):&lt;br /&gt;&lt;br /&gt;&lt;span class="code"&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;sh: ./svn-commit.tmp: Permission denied&lt;br /&gt;svn: Commit failed (details follow):&lt;br /&gt;svn: system(' svn-commit.tmp') returned 32256&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It sounds like a file permission problem, but I couldn't find any problems - I was working in my own directory that I checked out of SVN.  I ran &lt;span style="font-family:courier new;"&gt;strace&lt;/span&gt; to see what was going on, and right about the time that the Shinola hit the fan, I could see that it was trying to fire up an editor for the check-in comment.  I looked, and I did not have the EDITOR environment variable set.  Once I set it, it worked fine.&lt;br /&gt;&lt;br /&gt;Let's see, "Permisssion denied" means that an environment variable was not set.  Sure, that makes sense - NOT.&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-802453461174347695?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/802453461174347695/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=802453461174347695' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/802453461174347695'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/802453461174347695'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2007/09/very-non-intuitive-error-message-from.html' title='Very non-intuitive error message from SVN'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-5006869481354813639</id><published>2007-09-04T19:52:00.000-07:00</published><updated>2007-09-05T21:14:53.342-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><category scheme='http://www.blogger.com/atom/ns#' term='external disk'/><category scheme='http://www.blogger.com/atom/ns#' term='apple'/><title type='text'>Getting Maxtor OneTouch III to work on MacTel</title><content type='html'>I recently bought a Maxtor (or is it Seagate?) &lt;a href="http://www.maxtorsolutions.com/en/catalog/OTIII_Triple/"&gt;OneTouch III &lt;/a&gt;external hard drive.  It's a pretty sweet drive, maybe a bit big and noisy, but perfect for my needs - backing up my systems.  One really nice thing is that it's totally Mac-centric: it ships preformatted with HFS+, it supports Firewire 400 and 800 (nice with the &lt;a href="http://western-skies.blogspot.com/2007/08/new-imac.html"&gt;new iMac&lt;/a&gt;), and it includes Retrospect Express backup software, which originated on the Mac, as I recall.&lt;br /&gt;&lt;br /&gt;It include a button on the front that you can program to do various things, the most obvious being to initiate a backup.  But it didn't work; I'd push the button and nothing would happen.  After poking around, I found  &lt;a href="http://www.seagate.com/ww/v/index.jsp?locale=en-US&amp;name=Maxtor_OneTouch_MacIntel_Update&amp;amp;vgnextoid=770f8b9c4a8ff010VgnVCM100000dd04090aRCRD"&gt;this update&lt;/a&gt; for Intel Macs.  After installing it (and rebooting), it works like a charm.&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-5006869481354813639?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/5006869481354813639/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=5006869481354813639' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/5006869481354813639'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/5006869481354813639'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2007/09/getting-maxtor-onetouch-iii-to-work-on.html' title='Getting Maxtor OneTouch III to work on MacTel'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-4925089761200540165</id><published>2007-08-29T19:58:00.000-07:00</published><updated>2007-09-03T20:53:38.463-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='os x'/><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><category scheme='http://www.blogger.com/atom/ns#' term='apple'/><title type='text'>What's in an OS X Package (.pkg) file?</title><content type='html'>I recently had occasion to figure out how packages work on OS X.  This isn't an extensive treatise on the subject, and I didn't bother to look for any docs.  This is just some poking around I did in the Finder and mostly in Terminal.&lt;br /&gt;&lt;br /&gt;The original motivation was that I wanted to uninstall a package that I'd installed.  The package file is &lt;span style="font-family:courier new;"&gt;Subversion-1.4.4.pkg&lt;/span&gt;.  The first thing I learned is that packages are another case where a directory (aka folder) shows up as a single file in the Finder.  You can see the contents in the Finder by control-clicking on the package file and selecting &lt;span style="font-family:courier new;"&gt;Show Package Contents&lt;/span&gt;.  The Finder opens up a new window (just like any other folder).&lt;br /&gt;&lt;br /&gt;All I see in my package is a folder called &lt;span style="font-family:courier new;"&gt;Contents&lt;/span&gt;.  Within that folder, is a file called &lt;span style="font-family:courier new;"&gt;Archive.pax.gz&lt;/span&gt;, which is a compressed &lt;span style="font-family:courier new;"&gt;pax&lt;/span&gt; archive.  &lt;span style="font-family:courier new;"&gt;Pax&lt;/span&gt; is an archive program like &lt;span style="font-family:courier new;"&gt;tar&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;cpio&lt;/span&gt;.  (Actually, it's an experiment on genetic engineering - in order to "solve" the &lt;span style="font-family:courier new;"&gt;tar&lt;/span&gt; vs. &lt;span style="font-family:courier new;"&gt;cpio&lt;/span&gt; wars, they merged the two and called it &lt;span style="font-family:courier new;"&gt;pax&lt;/span&gt;, Latin for peace.)  The &lt;span style="font-family:courier new;"&gt;pax&lt;/span&gt; archive was subsequently compressed with &lt;span style="font-family:courier new;"&gt;gzip&lt;/span&gt; - hence the &lt;span style="font-family:courier new;"&gt;gz&lt;/span&gt; extension.&lt;br /&gt;&lt;br /&gt;Too see what's in the archive, we need to decompress it and get pax to print a listing of the contents.  I did this as follows, although there are other ways to skin this cat:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-size:85%;"&gt;cd /tmp&lt;br /&gt;gzip -d &lt; Subversion-1.4.4.pkg/Contents/Archive.pax.gz | pax -v&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:georgia;font-size:100%;"&gt;(&lt;/span&gt;&lt;span style="font-family:courier new;font-size:100%;"&gt;Pax&lt;/span&gt;&lt;span style="font-size:100%;"&gt; &lt;/span&gt;&lt;span style="font-family:georgia;font-size:100%;"&gt;contains an option to do decompression, but I'm too old fashion.)  Note that I redirect the compressed archive into&lt;/span&gt;&lt;span style="font-size:100%;"&gt; &lt;/span&gt;&lt;span style="font-family:courier new;font-size:100%;"&gt;gzip&lt;/span&gt;&lt;span style="font-size:100%;"&gt;.  &lt;/span&gt;&lt;span style="font-family:georgia;font-size:100%;"&gt;I did this because I wanted to leave the archive compressed.  I could have decompressed the archive and then ran&lt;/span&gt;&lt;span style="font-size:100%;"&gt; &lt;/span&gt;&lt;span style="font-family:courier new;font-size:100%;"&gt;pax&lt;/span&gt;&lt;span style="font-size:100%;"&gt; &lt;/span&gt;&lt;span style="font-family:georgia;font-size:100%;"&gt;on&lt;/span&gt;&lt;span style="font-size:100%;"&gt; &lt;span style="font-family: georgia;"&gt;that, but I wanted to leave the entire package unharmed.   The first bit of the output&lt;/span&gt; &lt;span style="font-family: georgia;"&gt;looks like:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;-rwxr-xr-x  1 root     wheel    1664424 Jun 22 23:57 ./usr/local/bin/svnadmin&lt;br /&gt;-rwxr-xr-x  1 root     wheel    1571744 Jun 22 23:57 ./usr/local/bin/svndumpfilter&lt;br /&gt;-rwxr-xr-x  1 root     wheel    1664612 Jun 22 23:57 ./usr/local/bin/svnlook   &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: georgia;"&gt;So, we can see that these are the files that got installed (in&lt;/span&gt; &lt;span style="font-family:courier new;"&gt;/usr/local&lt;/span&gt;&lt;span style="font-family: georgia;"&gt;).  One nice thing to note is that the path names are all relative - they begin with "./" rather than just "/".  This means the files can be installed anywhere - change into a directory, extract the archive, and the files will show up in a directory called&lt;/span&gt; &lt;span style="font-family:courier new;"&gt;usr/local&lt;/span&gt; &lt;span style="font-family: georgia;"&gt;below your current directory.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: georgia;"&gt;How can I use all of this to uninstall these files?  Again, there are many ways to skin the cat, but here's what I did.  I extracted the archive to&lt;/span&gt; &lt;span style="font-family:courier new;"&gt;/tmp&lt;/span&gt;.  &lt;span style="font-family: georgia;"&gt;("I thought you wanted to remove the files.  Why are you extracting them again?"  Patience, my friend.)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;cd /tmp &lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-size:85%;"&gt;gzip -d &lt; Subversion-1.4.4.pkg/Contents/Archive.pax.gz | pax -r&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family: georgia;"&gt;This creates all of the files, but under &lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:100%;"&gt;/tmp&lt;/span&gt;&lt;span style="font-size:100%;"&gt; &lt;span style="font-family: georgia;"&gt;- e.g., &lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:100%;"&gt;/tmp/usr/local/bin/svnadmin&lt;/span&gt;&lt;span style="font-size:100%;"&gt;.  &lt;span style="font-family: georgia;"&gt;I can now use &lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: georgia;font-family:courier new;font-size:100%;"  &gt;find&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family: georgia;"&gt; to get me a list of just the files:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;find usr -type f -print &gt; /tmp/fff&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family: georgia;"&gt;I then looked through the file names in &lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;font-size:100%;"&gt;/tmp/fff&lt;/span&gt;&lt;span style="font-size:100%;"&gt;, &lt;span style="font-family: georgia;"&gt;and they made sense, so I removed them all.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;sudo rm -i `cat /tmp/fff`&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family: georgia;"&gt;The&lt;/span&gt; &lt;/span&gt;&lt;span style="font-family:courier new;font-size:100%;"&gt;sudo&lt;/span&gt;&lt;span style="font-size:100%;"&gt; &lt;span style="font-family: georgia;"&gt;command was needed because the files were not owned by my user ID.  The package installer asked for the administrator password and installed the files owned by&lt;/span&gt; root &lt;span style="font-family: georgia;"&gt;(as I recall).  Of course, I could have avoiding "installing" the files in&lt;/span&gt; &lt;/span&gt;&lt;span style="font-family:courier new;font-size:100%;"&gt;/tmp&lt;/span&gt;&lt;span style="font-size:100%;"&gt; &lt;span style="font-family: georgia;"&gt;by running the output of&lt;/span&gt; pax -v &lt;span style="font-family: georgia;"&gt;through some&lt;/span&gt; &lt;/span&gt;&lt;span style="font-family:courier new;font-size:100%;"&gt;awk&lt;/span&gt;&lt;span style="font-size:100%;"&gt; &lt;span style="font-family: georgia;"&gt;or&lt;/span&gt; &lt;/span&gt;&lt;span style="font-family:courier new;font-size:100%;"&gt;perl&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family: georgia;"&gt;, but the archive was small, and I knew the options to &lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: georgia;font-family:courier new;font-size:100%;"  &gt;find&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family: georgia;"&gt; off the top of my head - I would have had to look up some&lt;/span&gt; &lt;/span&gt;&lt;span style="font-family:courier new;font-size:100%;"&gt;awk&lt;/span&gt;&lt;span style="font-size:100%;"&gt; &lt;span style="font-family: georgia;"&gt;or&lt;/span&gt; &lt;/span&gt;&lt;span style="font-family:courier new;font-size:100%;"&gt;perl&lt;/span&gt;&lt;span style="font-size:100%;"&gt;, &lt;span style="font-family: georgia;"&gt;since I don't use them that often any more.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: georgia;"&gt;enjoy,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: georgia;"&gt;Charles.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family: georgia;"&gt;P.S.  This post almost never was: Blogger mangled the fonts repeatedly, and I almost gave up on it.  Stupid JavaScript HTML editors! &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-4925089761200540165?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/4925089761200540165/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=4925089761200540165' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/4925089761200540165'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/4925089761200540165'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2007/08/whats-in-os-x-package-pkg-file.html' title='What&apos;s in an OS X Package (.pkg) file?'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-473435052820915345</id><published>2007-08-22T19:47:00.000-07:00</published><updated>2007-08-22T21:39:26.160-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='books'/><title type='text'>Everything I Know About Business I Learned from My Mama</title><content type='html'>&lt;a href="http://www.amazon.com/gp/product/0470127562?ie=UTF8&amp;tag=westernskies-20&amp;amp;linkCode=as2&amp;camp=1789&amp;amp;creative=9325&amp;creativeASIN=0470127562"&gt;&lt;span style="font-style: italic;"&gt;Everything I Know About Business I Learned from My Mama&lt;/span&gt;&lt;/a&gt; by &lt;a href="http://www.timknox.com/"&gt;Tim Knox&lt;/a&gt; is nominally a business book.  However, it is certainly not your typical business book.  The author doesn't tell you what corporate structure (e.g., LLC vs. S-Corp) is best, how to keep the books, or how to manage a Fortune 500 company.  Rather, this is a bigger picture view of going into business for yourself.  Tim Knox is all about entrepreneurship.&lt;br /&gt;&lt;br /&gt;Although this book isn't really a how-to manual with lots of nuts-and-bolts details.  It would be a really good book for someone who is thinking of going into business for himself.  It even begins with a bunch of reasons why someone shouldn't go into business.  If after reading the book, someone still wanted to go into business, he should probably read a few more books before jumping in.  (The&lt;span style="font-style: italic;"&gt; &lt;a href="http://www.amazon.com/gp/product/0887307280?ie=UTF8&amp;tag=westernskies-20&amp;amp;linkCode=as2&amp;camp=1789&amp;amp;creative=9325&amp;creativeASIN=0887307280"&gt;E-Myth Revisited: Why Most Small Businesses Don't Work and What to Do About It&lt;/a&gt;&lt;/span&gt; is next on my list to read.)&lt;br /&gt;&lt;br /&gt;The book is pretty short and humorous, and the chapters are nice little bite-sized chunks.  Here's an attempt as his sense of humor: this would be a great book to keep next to the toilet - each chapter is about one visit long.  (I have a special place in my heart for books like that.)   I suspect the book was easy for Tim to write since he's been writing newspaper articles for some time.  I can easily imagine that many of the chapters are extensions of articles he wrote for the paper, bless his heart.&lt;br /&gt;&lt;br /&gt;One minor nit I could pick with the title is that there isn't all that much mention of stuff his mama told him.  Rather, there's a fair amount of common sense that one's mother might impart.&lt;br /&gt;&lt;br /&gt;I bought this book because I've been listening to Tim on Dan Miller's radio show - see &lt;a href="http://www.48days.com/"&gt;www.48days.com&lt;/a&gt;. Dan is a career coach and wrote the book &lt;a style="font-style: italic;" href="http://www.amazon.com/gp/product/0805444793?ie=UTF8&amp;tag=westernskies-20&amp;amp;linkCode=as2&amp;camp=1789&amp;amp;creative=9325&amp;creativeASIN=0805444793"&gt;48 Days to the Work You Love&lt;/a&gt;.  The two of them spend a lot of time telling people to quit jobs they hate and move towards work they love.  The radio show recently ended, and they've switched to an Internet format.  The radio shows and the new Internet shows are available as &lt;a href="http://www.48days.com/podcast.php"&gt;podcasts&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;br /&gt;&lt;br /&gt;&lt;iframe src="http://rcm.amazon.com/e/cm?t=westernskies-20&amp;o=1&amp;amp;p=8&amp;l=as1&amp;amp;asins=0470127562&amp;fc1=000000&amp;amp;IS2=1&amp;lt1=_blank&amp;amp;amp;amp;lc1=0000FF&amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;f=ifr" style="width: 120px; height: 240px;" marginwidth="0" marginheight="0" frameborder="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-473435052820915345?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/473435052820915345/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=473435052820915345' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/473435052820915345'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/473435052820915345'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2007/08/everything-i-know-about-business-i.html' title='Everything I Know About Business I Learned from My Mama'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-4414702279695376115</id><published>2007-08-22T16:27:00.000-07:00</published><updated>2007-08-22T20:44:37.357-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='misc'/><title type='text'>Roomba Rants</title><content type='html'>I recently started using my (comparatively old) &lt;a href="http://www.irobot.com/"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;Roomba&lt;/span&gt;&lt;/a&gt; again, and I've been reminded of my chief complaint about &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;Roomba&lt;/span&gt;: it gets dirty and needs to be cleaned.&lt;br /&gt;&lt;br /&gt;Our house is a regular petting zoo, so stuff accumulates pretty quickly. This fills up the bin, which isn't so bad because emptying the bin is quick and easy.  But the human hair and pet fur fowls the brush, and that takes some serious effort to clean.  I suppose the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;Roomba&lt;/span&gt; for pets (which appears to be discontinued) addresses this with a brush that is comparatively easy to clean.&lt;br /&gt;&lt;br /&gt;And then last night I discovered a new place to clean: the side sweeper brush.  That thing was totally fowled (not surprising considering I just discovered that I needed to clean it - "read all the words"), and it took me 10 to 15 minutes with my pocket knife and tweezers.&lt;br /&gt;&lt;br /&gt;I find it ironic that a cleaning tool requires a non-trivial amount of cleaning.  Perhaps if I kept up with regular vacuuming, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;Roomba&lt;/span&gt; wouldn't get so overwhelmed by crap.&lt;br /&gt;&lt;br /&gt;Finally, the reason I'm just getting back to using &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;Roomba&lt;/span&gt; is that I just got a new battery after killing the old one some time ago.  It turns out managing batteries with &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;Roomba&lt;/span&gt; is a bit different than other devices I've used.  Typically, I run devices down and recharge them.  If I don't have an immediate use, I'd leave the device uncharged.  Well, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;Roomba&lt;/span&gt; keeps discharging the battery even if it's not in use.  And if you do that to a battery that's already low, it deeply discharges the battery - definitely not A Good Thing.  I noticed the discharging thing: sometimes when I'd charge the battery and not use &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;Roomba&lt;/span&gt; immediately, the battery would be low when I went to use it.  So, Roomba prefers being left on the charger, even if you're not using it, which is something I tend to avoid with other devices.   Anyway, the result was that I only got ~50 cycles out of the original battery - not good.  The recording on &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;Roomba's&lt;/span&gt; tech support tells you if you're not using the unit anytime soon, you should take the battery out.  Fortunately, it's easy to install and remove the battery - e.g., no screws required.&lt;br /&gt;&lt;br /&gt;Don't get me wrong: &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;Roomba&lt;/span&gt; is still fun to use, and I did just put down more money for a new battery.  So, I will continue to use it.  It's just not as carefree and easy as I'd like to see it.&lt;br /&gt;&lt;br /&gt;Later,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-4414702279695376115?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/4414702279695376115/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=4414702279695376115' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/4414702279695376115'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/4414702279695376115'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2007/08/roomba-rants.html' title='Roomba Rants'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-8317698346961722949</id><published>2007-08-17T21:46:00.000-07:00</published><updated>2008-02-23T23:26:15.423-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><category scheme='http://www.blogger.com/atom/ns#' term='apple'/><title type='text'>New iMac</title><content type='html'>Even though I was &lt;a href="http://western-skies.blogspot.com/2006/11/core2-mac-mini.html"&gt;wishing for a Core2 Mini&lt;/a&gt;, when it was (finally) released (somewhat silently), I opted instead for one of the new iMacs, and I'm loving it.&lt;br /&gt;&lt;br /&gt;My original plan was to get a Mini and use a KVM along with the PC boat-anchor that I keep around for a client.  However, after using a KVM for a while with other PCs, I realized that KVMs can be kinda hokey.  For example, my KVM makes a keyboard look generic - i.e., it hides any special keys.  Also, although I have a cool 22" Viewsonic LCD, it's not as nice as an Apple display.&lt;br /&gt;&lt;br /&gt;I opted for the 20" 2.4Ghz model with the stock 1GB of memory.  I was very pleased to see how easy it will be to upgrade the memory when I get a few extra dollars.   The 24" was pretty tempting (the price is quite reasonable), but I figured if I ever need a larger display, I can use the external video connected to my (somewhat inferior) Viewsonic for a ~40" display experience.&lt;br /&gt;&lt;br /&gt;The CPU is hella fast, although I admit I'm comparing it to an 800 Mhz G4 iMac which was significantly taxes (~20% CPU) running Firefox and Gmail.  To date, the only time I'm maxed out the two cores was converting audio files into MP3 with  iTunes.  My Internet is still only 128K ISDN, which makes for slow Gmail, but Steve Jobs can't be expected to fix that.&lt;br /&gt;&lt;br /&gt;The new, thin keyboard is something that cannot be appreciated in a store standing over it.  You have to sit in front of it with a real chair in a real working position to appreciate the nice ergonomics.  My one gripe is that my thumb drive is too fat to fit in the USB sockets.&lt;br /&gt;&lt;br /&gt;And finally, the Apple educational discount and promotions were sweet.  After the rebates, I'll have a free Nano and printer, both of which I gave to the wife - score!&lt;br /&gt;&lt;br /&gt;Anyway, Joe Bob says, 5 stars (on a scale of 4) - check it out!&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-8317698346961722949?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/8317698346961722949/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=8317698346961722949' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/8317698346961722949'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/8317698346961722949'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2007/08/new-imac.html' title='New iMac'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-8502204744458197333</id><published>2007-06-13T16:19:00.000-07:00</published><updated>2007-06-13T16:32:28.634-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='family'/><category scheme='http://www.blogger.com/atom/ns#' term='google'/><title type='text'>Google Docs for Family Support</title><content type='html'>I talked before about &lt;a href="http://western-skies.blogspot.com/2007/01/google-docs-quick-and-dirty-wiki.html"&gt;using Google Docs as  a small-time wiki&lt;/a&gt;, but I've recently come up with another, slightly less geeky use for Google Docs.  My sister and I live in Oregon.  Our mother lives down in Orange County, CA.  She was recently diganosed with stage 4 lung cancer and was temporarily hospitalized and then released. &lt;br /&gt;&lt;br /&gt;My sister and I have been in the difficult position of trying to coordinate care from far.  We both work full-time, and so we tag-team on calling people.  As we call various professionals and friends, we learn new names and phone numbers of more people to call.  (Sounds like Amway, but it isn't.  :-)&lt;br /&gt;&lt;br /&gt;Anyway, I set up a Google spreadsheet with the names and numbers I was working from and shared it with my sister.  She added the information she had collected.  We also have columns for email addresses (where relevant) and notes about the person (e.g., a friend from church, the social worker from the hospice, etc.).&lt;br /&gt;&lt;br /&gt;The collaborative feature of Google Docs (and spreadsheets) is a life saver.  And, if you're away from the Internet, just print it out and take it with you - how 20th century.  Joe Bob says, four stars - check it out!&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-8502204744458197333?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/8502204744458197333/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=8502204744458197333' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/8502204744458197333'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/8502204744458197333'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2007/06/google-docs-for-family-support.html' title='Google Docs for Family Support'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-349960723799330259</id><published>2007-03-01T19:54:00.000-08:00</published><updated>2007-03-01T20:04:48.609-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='books'/><title type='text'>Book: Windows Forensics and Incident Recovery</title><content type='html'>&lt;a href="http://www.amazon.com/gp/product/0321200985?ie=UTF8&amp;tag=westernskies-20&amp;amp;link_code=as3&amp;camp=211189&amp;amp;creative=373489&amp;creativeASIN=0321200985"&gt;Windows Forensics and Incident Recovery&lt;/a&gt;&lt;br /&gt;by Harlan &lt;span class="misspell" suggestions="Carve,Carver,Garvey,Carvery,Cave"&gt;Carvey -ISBN 0-321-20098-5&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;This is a great book because I learned more than I thought I would from it.  Coming from a command-line Unix background, I tend to view Windows as excessively GUI-centric (maybe that's why it's called Windows?) and full of opaque Microsoft voodoo.  This books showed me that there are plenty of things to be learned from the Windows command line, and there are lots of transparent, open-source tools to expose the inner workings  of Windows.&lt;br /&gt;&lt;br /&gt;There are really three types of information in this book: how Windows works, tools to collect information about Windows, and the bigger task of forensic information extraction and processing.  There is a lot of information about basic operating systems concepts (files, processes, etc.) and how they are implemented in Windows.  I especially liked the presentation of user privileges - we typically only hear about those in the context of administrator versus non-administrator, but there is a listing of each of the individual privileges and what they mean.  The tools that the author presents are primarily command-line tools, and many of them are written in Perl - very approachable for an old Unix hack. (A second edition of this book would benefit from a treatment on Microsoft's &lt;a href="http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/wmic.mspx?mfr=true"&gt;&lt;span class="misspell" suggestions="MIC,MICK,MICA,MCI,MC"&gt;WMIC&lt;/span&gt;&lt;/a&gt; tool.)  With the basic groundwork laid, the author presents a bigger picture of how to use all of the tools in a forensic investigation.  He presents a series of dreams, which are a bit corny, but they serve as a sequence of case studies.  He also provides a "forensic server" to storing all the little bits of information that get collected - a bit like "real" tools like &lt;span class="misspell" suggestions="Encase,En Case,En-Case,Encased,Encases"&gt;EnCase&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Like the book &lt;a href="http://western-skies.blogspot.com/2006/06/book-file-system-forensic-analysis.html"&gt;File System Forensic Analysis&lt;/a&gt;, one of my favorite aspects of this book is that it provides a lot of practical information about applied operating systems - Windows.  The author provides links to a lot of tools and web pages, so this book serves as an excellent starting point to learn a lot more about Windows and forensic data recovery.  The text includes complete source code for the Perl tools, so a code-oriented reader can really see what the information is and where it comes from.&lt;br /&gt;&lt;br /&gt;If I had to criticize something in this book, I'd say that Chapter 9 on scanners and sniffers drifts a bit from the central theme of the book, but then I've found that to be pretty common in security books because so many of the topics are interrelated; you start pulling one thread on the sweater, and the next thing you know, you've unraveled the whole thing.&lt;br /&gt;All in all, this is a great starting point for learning about forensic data acquisition on the Windows platform.&lt;br /&gt;&lt;span class="misspell" suggestions="Carve,Carver,Garvey,Carvery,Cave"&gt;&lt;br /&gt;Enjoy,&lt;br /&gt;Charles.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;iframe src="http://rcm.amazon.com/e/cm?t=westernskies-20&amp;o=1&amp;amp;p=8&amp;l=as1&amp;amp;asins=0321200985&amp;fc1=000000&amp;amp;IS2=1&amp;lt1=_blank&amp;amp;lc1=0000FF&amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;f=ifr" style="width: 120px; height: 240px;" marginwidth="0" marginheight="0" frameborder="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-349960723799330259?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/349960723799330259/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=349960723799330259' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/349960723799330259'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/349960723799330259'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2007/03/book-windows-forensics-and-incident.html' title='Book: Windows Forensics and Incident Recovery'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-116840920243836961</id><published>2007-01-09T21:39:00.000-08:00</published><updated>2007-06-13T16:33:11.573-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='collaboration'/><category scheme='http://www.blogger.com/atom/ns#' term='google'/><title type='text'>Google Docs - Quick and Dirty Wiki</title><content type='html'>I've been using wikis for collaborative software development for at least five years.  I've typically used &lt;a href="http://twiki.org/"&gt;TWiki&lt;/a&gt;.  It's a pretty cool tool, but the set-up is non-trivial, especially for a small project.  Also, the last wiki I set up got spammed big time - it was on the Internet rather than a private intranet.&lt;br /&gt;Google recently bought out &lt;a href="http://www.jot.com/"&gt;JotSpot&lt;/a&gt; before I discovered it.  It sounds like a cool idea - they set it up for you, and I guess it could be configured to be totally private, which would eliminate the spam.  I'll be very curious to see what it looks like when it comes back online.&lt;br /&gt;In the meantime, I've discovered &lt;a href="http://docs.google.com/"&gt;Google Docs and Spreadsheets&lt;/a&gt; as a collaborative tool.  At first I thought, free Word and Excel - who cares?  I've already paid The Evil Empire for my software.  But when you add the Internet storage and collaboration features, it becomes very cool.  A shared document becomes a wiki page!&lt;br /&gt;I see two really nice features with Google documents compared to run-of-the-mill wikis: the formatting and editing is a word processor (implemented in Ajax), not another markup language, and the sharing is on a document-by-document, user-by-user basis.  In a small team, it's nice to allow Bob to see the document and Jane to edit it.  On another document, they can both edit it.  Of course, in a large team, configuring this one-by-one would suck.&lt;br /&gt;Another nice feature is that you can upload documents (from Word, OpenOffice, others), so someone can begin something with a word processor (maybe when s/he is offline) and convert it trivially into a pseudo-wiki page.  Sure you can cut and past from Word into a blog or wiki, but I hate the way some characters get mangled in the process.&lt;br /&gt;The Google spreadsheets are nice for collaborative project management.  I've been using &lt;a href="http://voo2do.com/"&gt;Voo2do&lt;/a&gt; for managing simple task lists.  It's nice, but the collaboration options are limited: you can share a password-protected, read-only view, but to allow someone else to edit, as near as I can tell, you have to grant them access to your whole account - not just the one task list you wanted to share.&lt;br /&gt;With Google spreadsheets, all you have to do is create a spreadsheet with the tasks (ala &lt;a href="http://www.joelonsoftware.com/articles/fog0000000245.html"&gt;Joel on Software&lt;/a&gt;), and share it, either read-only or read-write.&lt;br /&gt;I'm currently working on a small project with two other people, and I've just gotten into this.  So far, it's great.  More news when it happens.&lt;br /&gt;&lt;br /&gt;Enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-116840920243836961?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/116840920243836961/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=116840920243836961' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/116840920243836961'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/116840920243836961'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2007/01/google-docs-quick-and-dirty-wiki.html' title='Google Docs - Quick and Dirty Wiki'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-116330806241556352</id><published>2006-11-11T20:52:00.000-08:00</published><updated>2007-06-13T16:34:46.734-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><category scheme='http://www.blogger.com/atom/ns#' term='apple'/><title type='text'>Core2 Mac Mini</title><content type='html'>There has been a fair amount of speculation about when/if Apple will release a version of the Mac Mini using the Core 2 Duo processor.  For example:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.macnn.com/articles/06/11/08/core.2.duo.mac.mini/"&gt;Apple hints at Core 2 Duo Mac mini?&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://lowendmac.com/musings/06/1109.html"&gt;How Soon Will the Mac mini Go Core2?&lt;/a&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;Personally, I'm dying to see a Core2 Mini.  At the moment, I'm stuck with a 800 Mhz G4 iMac that just doesn't cut it any more, but I can't afford a 20" Core2 Duo iMac. &lt;br /&gt;&lt;br /&gt;For the sake of argument, why would Apple not update the Mini to the Core2?  Part of that depends where Apple really sees the Mini.  When the (G4) Mini first came out, one of the pitches was for PC developers to use it in addition to a PC via a KVM switch.  In this scenario, it made sense for Apple to make it beefy.&lt;br /&gt;&lt;br /&gt;When the first Intel Macs came out, the Mini had a Core processor (I'll call the Core processor the "Core1" just to be extra clear) just like the other Macs, in particular the iMac.  They wanted the Core archiecture, but there weren't many of those processors, so the Mini and the iMac were pretty similar.  Then the Core2 came out and Apple bumped the iMac to a Core2 but left the Mini at a Core1.&lt;br /&gt;&lt;br /&gt;I take this to indicate that Apple is trying to create some diversity in the product line - i.e., the need to differentiate the Mini from the iMac.  Thus, they need to keep the Mini crippled, and they're no longer pitching the Mini as a developer machine.  This is (unfortunately) like the IBM PC Jr back in the day.  Now, they have bumped both Mini models to a Core1 Duo, but it's still a Core1 not a Core2 - i.e., still crippled. &lt;br /&gt;&lt;br /&gt;The other possible motive (for Apple) of keeping the Mini at Core1 is profit margin.  When the Core2 came out, Intel slashed the price of the Core1, but Apple has not dropped the price of the Mini.  If Apple had a big stock of Core1 processors (especially Core1 Duos) when the Core2 came out (not likely given how shrewd Apple often is), this gives them a way to flush their Core1 inventory.  More likely, Apple is just making bank on the reduced cost of the inputs.&lt;br /&gt;&lt;br /&gt;So, I can see a few reasons why Apple may not bump the Mini to a Core2 very soon.  I hope I'm wrong it because I'd really like a Core2 Mini.  The MacWorld release timeframe that is being rumored would fit my budget very nicely.&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-116330806241556352?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/116330806241556352/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=116330806241556352' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/116330806241556352'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/116330806241556352'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2006/11/core2-mac-mini.html' title='Core2 Mac Mini'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-115646893013216697</id><published>2006-08-24T18:07:00.000-07:00</published><updated>2007-06-13T16:35:29.674-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='flex'/><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><title type='text'>Flex: Debug Flash Player on OS X</title><content type='html'>As noted in "Building and Deploying Flex2 Applications" (&lt;a href="http://livedocs.macromedia.com/flex/2/docs/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&amp;amp;file=00001528.html"&gt;Live Docs&lt;/a&gt;), the output of &lt;tt&gt;trace&lt;/tt&gt; statements can be configured in the standalone debug version of the Flash player.  The documentation describes the location of the &lt;tt&gt;mm.cfg&lt;/tt&gt; file on Mac OS X using Mac-style (non-Unix) path notation with colons to separate directories.&lt;br /&gt;&lt;br /&gt;I set up a config file, but for the life of me, I couldn't find the output file.  Then, I found an old, pre-Flex2 &lt;a href="http://weblogs.macromedia.com/cantrell/archives/2004/05/debugging_flex.cfm"&gt;blog post&lt;/a&gt; by Christian Cantrell which fills in two missing parts of the  documentation.  First of all, if no &lt;tt&gt;TraceOutputFileName&lt;/tt&gt; directive is given, the trace output will go to &lt;tt&gt;flashlog.txt&lt;/tt&gt; in the same directory as the config file - fair enough.  Once I removed the directive, I found the output file.&lt;br /&gt;&lt;br /&gt;Also, if a path name is given, the path must be specified in the old Mac-style notation (with colons) rather than Unix-style (with slashes).  I suppose that's why they specified the location of the config file in that notation, but the significance of the colons was lost on me.  One totally trivial tidbit correctly noted in Christian's blog post is that the directory name is "Macromedia" not "macromedia", as indicated by the docs.  (Since the Mac's HFS+ file system is basically case insensitive, it doesn't really matter.)&lt;br /&gt;&lt;br /&gt;Once I figured that stuff out, I could get my trace output and get on to fixing my bugs. &lt;br /&gt;&lt;br /&gt;I do have (at least) one gripe with the debug Flash player on the Mac compared to the PC - it doesn't keep a history of recent URLs.  So, every time you go to open an URL, you have to type it in again (or paste it from a browser, which does keep history.)  Even if you keep the player running, it still doesn't remember the last URL it opened.&lt;br /&gt;&lt;br /&gt;Enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-115646893013216697?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/115646893013216697/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=115646893013216697' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/115646893013216697'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/115646893013216697'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2006/08/flex-debug-flash-player-on-os-x.html' title='Flex: Debug Flash Player on OS X'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-115336444086049357</id><published>2006-07-19T19:56:00.000-07:00</published><updated>2006-08-17T21:00:55.816-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='flex'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Flex: Sending Messages from Server-Side Java Code</title><content type='html'>I've been trying to figure out how to send messages from the depths of my Java application out to Flex clients.  I'm not talking about messages that originate on a client, pass through the Java server, and then head back to the clients - that stuff is documented in the manual.  I mean there is a process going on in the server that needs to send messages to the clients.&lt;br /&gt;&lt;br /&gt;Of course, JMS and the JMS adapter would work, but I've been really leery of the complexity of JMS since it came out years ago.  It has the advantage that it would allow my application to be separated from the Flex server, which would work well in terms of scaling.  I may yet try JMS, but for the moment, I'm looking to avoid JMS.&lt;br /&gt;&lt;br /&gt;So, I was thinking that writing a message service adapter would be the key.  Adobe has a brief example of &lt;a href="http://livedocs.macromedia.com/flex/2/docs/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&amp;file=00001174.html"&gt;creating a custom Message Service adapter&lt;/a&gt;.  It seems to be a complete example, but it left me with lots of questions.  For example &lt;tt&gt;Message&lt;/tt&gt; is an interface, which concrete class do we use?  How do we construct it?  What all can we do with the &lt;tt&gt;MessageService&lt;/tt&gt;?  What value are we returning from &lt;tt&gt;invoke&lt;/tt&gt;?&lt;br /&gt;&lt;br /&gt;After some digging around in the sample code, I came across a couple of Java classes associated with the dashboard sample application.  So, I've taken the code from that example, paired it down a bit, and wrote a very simple, Soviet-style (butt-ass ugly but functional) Flex interface for it.&lt;br /&gt;&lt;br /&gt;Below is the server-side Java code.&lt;br /&gt;&lt;tt&gt;&lt;pre&gt;&lt;br /&gt;import java.util.*;&lt;br /&gt;import flex.messaging.MessageBroker;&lt;br /&gt;import flex.messaging.messages.AsyncMessage;&lt;br /&gt;import flex.messaging.util.UUIDUtils;&lt;br /&gt;&lt;br /&gt;public class FmsDateFeed&lt;br /&gt;{&lt;br /&gt;    private static FeedThread thread;&lt;br /&gt;    public FmsDateFeed()&lt;br /&gt;    {&lt;br /&gt;        System.out.println("FmsDateFeed.ctor: " + this);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public static void main(String[] args)&lt;br /&gt;    {&lt;br /&gt;        FmsDateFeed feed = new FmsDateFeed();&lt;br /&gt;        feed.toggle();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void toggle()&lt;br /&gt;    {&lt;br /&gt;        if (thread == null)&lt;br /&gt;        {&lt;br /&gt;            System.out.println("FmsDateFeed.toggle: starting...");&lt;br /&gt;            thread = new FeedThread();&lt;br /&gt;            thread.start();&lt;br /&gt;        }&lt;br /&gt;        else&lt;br /&gt;        {&lt;br /&gt;            System.out.println("FmsDateFeed.toggle: stopping...");&lt;br /&gt;            thread.running = false;&lt;br /&gt;            thread = null;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    public static class FeedThread extends Thread&lt;br /&gt;    {&lt;br /&gt;        public boolean running = true;&lt;br /&gt;        public void run()&lt;br /&gt;        {&lt;br /&gt;            MessageBroker msgBroker = MessageBroker.getMessageBroker(null);&lt;br /&gt;            String clientID = UUIDUtils.createUUID(false);&lt;br /&gt;            System.out.println("FmsDateFeed.run: msgBroker=" + msgBroker + ", clientID=" + clientID);&lt;br /&gt;&lt;br /&gt;            Random random = new Random();&lt;br /&gt;            while (running)&lt;br /&gt;            {&lt;br /&gt;                Date now = new Date();&lt;br /&gt;&lt;br /&gt;                AsyncMessage msg = new AsyncMessage();&lt;br /&gt;                msg.setDestination("time_msgs");&lt;br /&gt;                msg.setClientId(clientID);&lt;br /&gt;                msg.setMessageId(UUIDUtils.createUUID(false));&lt;br /&gt;                msg.setTimestamp(System.currentTimeMillis());&lt;br /&gt;                HashMap body = new HashMap();&lt;br /&gt;                body.put("userId", "daemon");&lt;br /&gt;                body.put("msg", now.toString());&lt;br /&gt;                msg.setBody(body);&lt;br /&gt;                System.out.println("sending message: " + body);&lt;br /&gt;                msgBroker.routeMessageToService(msg, null);&lt;br /&gt;                try&lt;br /&gt;                {&lt;br /&gt;                    long wait = random.nextInt(8000) + 3000;&lt;br /&gt;                    System.out.println("sleeping: " + wait);&lt;br /&gt;                    Thread.sleep(wait);&lt;br /&gt;                }&lt;br /&gt;                catch (InterruptedException e)   {  }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/tt&gt;&lt;br /&gt;The &lt;tt&gt;toggle&lt;/tt&gt; method is called from the client to turn the message stream on or off.   When messages are turned on, a thread is created and the &lt;tt&gt;run&lt;/tt&gt; method is called.  It just loops creating Java &lt;tt&gt;Date&lt;/tt&gt; objects and putting the String representation of the date into Flex messages - instances of &lt;tt&gt;AsynchMessage&lt;/tt&gt;.  The key for me was the &lt;tt&gt;routeMessageToService&lt;/tt&gt;  method on the &lt;tt&gt;MessageBroker&lt;/tt&gt; class.  When you have the class compiled, install the Java class file in &lt;tt&gt;samples/WEB_INF/classes&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;The client is pretty simple, by comparison.  It has two features: a button for turning the message stream on and off (via a RemoteObject call) and an event handler to process the incoming messages.&lt;br /&gt;&lt;tt&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&gt;&lt;br /&gt;&amp;lt;mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"&lt;br /&gt;    backgroundColor="#FFFFFF"&lt;br /&gt;    creationComplete="initComp()"&gt;&lt;br /&gt;    &amp;lt;mx:Script&gt;&lt;br /&gt;        public function initComp():void {&lt;br /&gt;   consumer.subscribe();&lt;br /&gt;        }&lt;br /&gt;        public function toggle():void {&lt;br /&gt;            feeder.toggle();&lt;br /&gt;        }&lt;br /&gt;        import mx.rpc.events.ResultEvent;&lt;br /&gt;        import mx.messaging.events.MessageEvent;&lt;br /&gt;        public function messageHandler(event:MessageEvent):void {&lt;br /&gt;        var body:Object = event.message.body;&lt;br /&gt;            output.text += body.userId + ": " + body.msg + "\n";&lt;br /&gt;        }&lt;br /&gt;    &amp;lt;/mx:Script&gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;mx:RemoteObject id="feeder" destination="time_msgs"&gt;&lt;br /&gt;        &amp;lt;mx:method name="toggle"/&gt;&lt;br /&gt;    &amp;lt;/mx:RemoteObject&gt;&lt;br /&gt; &amp;lt;mx:Consumer id="consumer" destination="time_msgs" message="messageHandler(event)"/&gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;mx:Form&gt;&lt;br /&gt;        &amp;lt;mx:FormItem&gt;&lt;br /&gt;            &amp;lt;mx:Button label="Toggle Date Feed" click="toggle()"/&gt;&lt;br /&gt;        &amp;lt;/mx:FormItem&gt;&lt;br /&gt;        &amp;lt;mx:FormItem label="Output Message"&gt;&lt;br /&gt;            &amp;lt;mx:TextArea id="output" width="250" height="150" /&gt;&lt;br /&gt;        &amp;lt;/mx:FormItem&gt;&lt;br /&gt;    &amp;lt;/mx:Form&gt;&lt;br /&gt;&amp;lt;/mx:Application&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/tt&gt;&lt;br /&gt;The interesting features are the configuration information for the RemoteObject and the message Consumer.  These correspond to destinations configured on the server (see below).  When the toggle button is pressed, we just call the &lt;tt&gt;toggle&lt;/tt&gt; ActionScript method, which make a call on our RemoteObject, &lt;tt&gt;feeder&lt;/tt&gt;; we don't care about a return value, which simplifies things.  &lt;br /&gt;&lt;br /&gt;We configure the Consumer to call our &lt;tt&gt;messageHandler&lt;/tt&gt; method when new messages arrive.  It just gets the message body and appends it to our text box.  Install this file in somewhere in the &lt;tt&gt;samples&lt;/tt&gt; directory - I created my own subdirectory for the dumb, little programs like this.&lt;br /&gt;&lt;br /&gt;To configure the server, edit &lt;tt&gt;messaging-config.xml&lt;/tt&gt; in &lt;tt&gt;samples/WEB-INF/flex&lt;/tt&gt; and clone the destination for "dashboard_chat" and call the new version "time_msgs".  You could change the Java and MXML to use the existing dashboard_chat destination (which is what I did initially), but a) you could end up with a conflict with the Flex demos, and b) writing to &lt;tt&gt;messaging-config.xml&lt;/tt&gt; (or any of those other config files) is a convenient way to get the server to restart and see your new Java class.&lt;br /&gt;&lt;br /&gt;Oh yeah, you also need to edit &lt;tt&gt;remoting-config.xml&lt;/tt&gt; to contain a RemoteObject destination also called "time_msgs".  (You could use separate names for the two destinations, and it would probably be less confusing, but I was too unimaginative.)&lt;br /&gt;&lt;br /&gt;If all goes well, you should get messages with the current time showing up randomly in the Flash client.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-115336444086049357?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/115336444086049357/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=115336444086049357' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/115336444086049357'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/115336444086049357'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2006/07/flex-sending-messages-from-server-side.html' title='Flex: Sending Messages from Server-Side Java Code'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29718960.post-115275321754808415</id><published>2006-07-12T17:56:00.000-07:00</published><updated>2010-02-02T10:19:22.745-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='flex'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Flex: The Second Simplest Example of RemoteObject</title><content type='html'>(&lt;span style="font-weight: bold;"&gt;Update&lt;/span&gt;: I wrote this some time ago, and I don't have access to the source code any more.  Therefore, I can't send it to you.  And, I don't know about newer versions of Flex.)&lt;br /&gt;&lt;br /&gt;In a &lt;a href="http://western-skies.blogspot.com/2006/07/flex-worlds-simplest-example-of.html"&gt;previous post&lt;/a&gt;, we developed what I claim to be the world's simplest example of using the RemoteObject facility in &lt;a href="http://www.adobe.com/products/flex/"&gt;Flex 2&lt;/a&gt; to invoke a method on a Java object using the RPC services.  In that example, we just had a button on a Flash application that called a method on the server.  All the method did was print a message.  Although we passed a message into the server method, that message was hard-coded in the ActionScript, and no results were passed back.&lt;br /&gt;&lt;br /&gt;In this post, we will build on that to pass some user data into the server and get a response back.  In theory, this ought to be very simple: the user data just comes from an input box, and the result will just be displayed in a text box.&lt;br /&gt;&lt;h2&gt;Java Code&lt;/h2&gt;&lt;br /&gt;Below is a simple function that you can add to the &lt;tt&gt;SimpleRemoteObject&lt;/tt&gt; from the previous example:&lt;br /&gt;&lt;tt&gt;&lt;pre&gt;&lt;br /&gt;public String echoMessage(String msg)&lt;br /&gt;{&lt;br /&gt; System.out.println("SimpleRemoteObject.echo: " + msg);&lt;br /&gt; return "The RemoteObject says: " + msg;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/tt&gt;&lt;br /&gt;As you can see, the method writes the message to the console (like before), and returns the message with a little text prepended to it.  Pretty simple.&lt;br /&gt;&lt;h2&gt;Flash Client&lt;/h2&gt;&lt;br /&gt;The user interface is pretty simple, and I just added it to the form in the previous example.  We have a &lt;tt&gt;TextInput&lt;/tt&gt; to enter data, a &lt;tt&gt;Button&lt;/tt&gt; to invoke the method, and &lt;tt&gt;TextArea&lt;/tt&gt; to display the result from the server.&lt;br /&gt;&lt;tt&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;mx:FormItem label="Input Message"&gt;&lt;br /&gt; &amp;lt;mx:TextInput id="input"/&gt;&lt;br /&gt;&amp;lt;/mx:FormItem&gt;&lt;br /&gt;&amp;lt;mx:FormItem&gt;&lt;br /&gt; &amp;lt;mx:Button label="Echo Message" click="echoMessage()"/&gt;&lt;br /&gt;&amp;lt;/mx:FormItem&gt;&lt;br /&gt;&amp;lt;mx:FormItem label="Output Message"&gt;&lt;br /&gt; &amp;lt;mx:TextArea id="output"/&gt;&lt;br /&gt;&amp;lt;/mx:FormItem&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/tt&gt;&lt;br /&gt;So far, so good.  The button calls an ActionScript method (&lt;tt&gt;echoMessage&lt;/tt&gt;) to call the server - just like the previous example:&lt;br /&gt;&lt;tt&gt;&lt;pre&gt;&lt;br /&gt;public function echoMessage():void {&lt;br /&gt; remoteObj.echoMessage(input.text);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/tt&gt;&lt;br /&gt;&lt;br /&gt;We just get the text from the TextInput object (&lt;tt&gt;input&lt;/tt&gt;) and call the method on the server. (Note that although I named the ActionScript method the same as the Java method - &lt;tt&gt;echoMessage&lt;/tt&gt; - this isn't necessary; I'm just not creative enough to think of anything else.)  But wait, something is missing: what about the message coming back from the server?  Based on my experience with Java (and dozens of other languages), I would expect to see code that looks like:&lt;br /&gt;&lt;tt&gt;&lt;br /&gt; output.text = remoteObj.echoMessage(input.text);&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;But, that's not how it works in Flash.  Flash makes RPC calls asynchronously.  This means that Flash doesn't wait for the result to come back from the server, and that's actually "a good thing."  Without asynchronous server calls, the Flash client would hang during a (potentially long) server call, and that would be a bad thing.&lt;br /&gt;&lt;br /&gt;OK, so how do we get the result back from the server?  This introduces some additional complexity, but it's still tractable.  It begins in the MXML to describe the server method:&lt;br /&gt;&lt;tt&gt;&lt;br /&gt;&amp;lt;mx:method name="echoMessage" result="displayResponse(event)"/&gt;&lt;br /&gt;&lt;/tt&gt;&lt;br /&gt;This says that when the &lt;tt&gt;echoMessage&lt;/tt&gt; method on the Java server object is called, and the result arrives at some later time, the &lt;tt&gt;displayResponse&lt;/tt&gt; ActionScript method will be called.&lt;br /&gt;&lt;br /&gt;This method is pretty simple, too:&lt;br /&gt;&lt;tt&gt;&lt;pre&gt;&lt;br /&gt;import mx.rpc.events.ResultEvent;&lt;br /&gt;public function displayResponse(event:ResultEvent):void {&lt;br /&gt; output.data = event.result;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/tt&gt;&lt;br /&gt;That's all there is.  Note that we don't even have to update the remoting-config.xml file on the server.  This is because we are not creating a new destination; we're just using the same Java class - &lt;tt&gt;SimpleRemoteObject&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;When you run the application in the browser, enter a message in the input area, click the button, and the response will eventually appear in the output area.&lt;br /&gt;&lt;br /&gt;If you need the complete code, let me know - post a comment.  At the moment, I'm too busy to put together a zip file and post it somewhere.&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-115275321754808415?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/115275321754808415/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=115275321754808415' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/115275321754808415'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/115275321754808415'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2006/07/flex-second-simplest-example-of.html' title='Flex: The Second Simplest Example of RemoteObject'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29718960.post-115274037097616395</id><published>2006-07-12T17:00:00.000-07:00</published><updated>2006-07-12T17:01:51.693-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='flex'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Flex: The World's Simplest Example of RemoteObject</title><content type='html'>Here is a very, very simple example of using the RemoteObject RPC services in &lt;a href="http://www.adobe.com/products/flex/"&gt;Flex 2&lt;/a&gt; to invoke methods on a Java object.  I came up with this because I was struggling to figure out all the stuff needed to do this.  In theory, it's pretty simple, but there are a number of components to deal with, and they all get put in different places on the server, and a bunch of those places look very similar to other places on the server.&lt;br /&gt;&lt;h2&gt;Introduction&lt;/h2&gt;&lt;br /&gt;It was especially difficult for me because I'm new to Flex, and I'm coming at it from a server-side background in Java.   I don't care about making pretty user interfaces (that's someone else's job) - I'm the guy who has to make the server code work.  However, most of the documentation assumes that you're coming at it from the other end - the client side.&lt;br /&gt;&lt;br /&gt;I couldn't find any simple examples of using RPC in Flex 2.0.  I foolishly started with &lt;a href="http://www.adobe.com/devnet/flex/articles/complex_data_03.html"&gt;Flex 1.5 example&lt;/a&gt; and wasted a bunch of time updating the syntax in it in order to get it to compile.&lt;br /&gt;&lt;br /&gt;After I got that to compile (from the command line - I'm old school), it wouldn't run.  After I got the Flash debugger working, I could see that the messaging destination didn't exist, but I couldn't figure out why.  So far as I could tell, I had configured it correctly, but there was no indication that things were making it to the server.    Finally, I gave up my command line and put the MXML file on the server, and just let the web-tier compiler do it for me.&lt;br /&gt;&lt;br /&gt;And, it just worked!  The documentation makes reference to using the SDK compiler versus the web-tier compiler, but it just didn't click with me.  But, it was still more complicated than I needed.  So, I created the following, to prove that I could do it, and that I knew all the voodoo needed.&lt;br /&gt;&lt;br /&gt;I will assume that you have the Flex Data Services demo server with Jrun installed an running.  I will specify all paths from the root of the jrun server.&lt;br /&gt;&lt;h2&gt;Java Code&lt;/h2&gt;&lt;br /&gt;Let's start with the simplest function in a Java file - basically, "hello world."&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;&lt;pre&gt;&lt;br /&gt;public class SimpleRemoteObject&lt;br /&gt;{&lt;br /&gt; public void writeToConsole(String msg)&lt;br /&gt; {&lt;br /&gt;     System.out.println("SimpleRemoteObject.write: " + msg);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/tt&gt;&lt;br /&gt;&lt;br /&gt;This will just write a message to the server console window.  (We don't even have to use any fancy Java logging.)&lt;br /&gt;&lt;br /&gt;Compile that file and put the &lt;tt&gt;SimpleRemoteObject.class&lt;/tt&gt; file in the directory  &lt;tt&gt;jrun4/servers/default/samples/WEB-INF/classes&lt;/tt&gt; on the server.  (Note that since the class is in the unnamed, default package, we put the class file in &lt;tt&gt;classes&lt;/tt&gt;, not a subdirectory.)&lt;br /&gt;&lt;h2&gt;Flash Client&lt;/h2&gt;&lt;br /&gt;Now, we need a simple Flash app.  Here's a simple MXML file:&lt;br /&gt;&lt;tt&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&gt;&lt;br /&gt;&amp;lt;mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"&lt;br /&gt; backgroundColor="#FFFFFF"&lt;br /&gt; initialize="initApp()"&gt;&lt;br /&gt; &amp;lt;mx:Script&gt;&lt;br /&gt;     public function initApp():void {&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     public function writeToConsole():void {&lt;br /&gt;         remoteObj.writeToConsole("hello from Flash client");&lt;br /&gt;     }&lt;br /&gt; &amp;lt;/mx:Script&gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;mx:RemoteObject id="remoteObj" destination="sro"&gt;&lt;br /&gt;     &amp;lt;mx:method name="writeToConsole"/&gt;&lt;br /&gt; &amp;lt;/mx:RemoteObject&gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;mx:Form&gt;&lt;br /&gt;     &amp;lt;mx:FormItem&gt;&lt;br /&gt;         &amp;lt;mx:Button label="Write To Server Console" click="writeToConsole()"/&gt;&lt;br /&gt;     &amp;lt;/mx:FormItem&gt;&lt;br /&gt; &amp;lt;/mx:Form&gt;&lt;br /&gt;&amp;lt;/mx:Application&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/tt&gt;&lt;br /&gt;Create a directory called &lt;tt&gt;sro&lt;/tt&gt; under &lt;tt&gt;jrun4/servers/default/samples&lt;/tt&gt; and put the MXML file there.&lt;br /&gt;&lt;br /&gt;Now, we can compile the file by loading it in the browser with a URL like:&lt;br /&gt;&lt;tt&gt;http://192.168.123.130:8700/samples/sro/SimpleRemoteObject.mxml&lt;/tt&gt;&lt;br /&gt;(The key is that the file is under &lt;tt&gt;/samples/sro&lt;/tt&gt; based on where we copied the file.)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Don't click the button yet!&lt;/b&gt;  We still have to configure the FMS destination.  Just make sure it compiles correctly.&lt;br /&gt;&lt;h2&gt;Configure the Server&lt;/h2&gt;&lt;br /&gt;Add the following XML code to &lt;tt&gt;jrun4/servers/default/samples/WEB-INF/flex/remoting-config.xml&lt;/tt&gt;.  Just put it within the service tag for the &lt;tt&gt;remoting-service&lt;/tt&gt; - e.g., near one of the other FMS destinations.&lt;br /&gt;&lt;tt&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;destination id="sro"&gt;&lt;br /&gt; &amp;lt;properties&gt;&lt;br /&gt;     &amp;lt;source&gt;SimpleRemoteObject&amp;lt;/source&gt;&lt;br /&gt; &amp;lt;/properties&gt;&lt;br /&gt;&amp;lt;/destination&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/tt&gt;&lt;br /&gt;And now, if you press the "Write to Server Console" button, the message, "hello from Flash client" will appear in the Jrun server window.&lt;br /&gt;&lt;br /&gt;That's it.  It really is as easy as Adobe says it is...&lt;br /&gt;once you figure it all out.&lt;br /&gt;&lt;br /&gt;enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-115274037097616395?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/115274037097616395/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=115274037097616395' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/115274037097616395'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/115274037097616395'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2006/07/flex-worlds-simplest-example-of.html' title='Flex: The World&apos;s Simplest Example of RemoteObject'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-29718960.post-115229655842470453</id><published>2006-07-07T11:19:00.000-07:00</published><updated>2006-09-09T14:03:41.580-07:00</updated><title type='text'>Tip: Managing Applications on OS X</title><content type='html'>I've heard that some people complain that Mac OS X doesn't have anything comparable to the "Start" button on Windows. I've never felt that way, but I have to admit, I'm amazed that some people always use the Finder to navigate to the Applications folder to launch application. If that's your way of starting applications, then I can see why you'd think you need a start button.&lt;br /&gt;&lt;br /&gt;Below are some really simple tips to manage the applications and get the "Start button" functionality using the existing Dock.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt; &lt;b&gt;Put Applications in the Dock&lt;/b&gt;: Begin by dragging the Applications folder to the dock.  Open a Finder window, grab the Applications folder, drag it down to the dock, and let go of it to the left of the vertical bar that separates the applications from the Trash Can.  Now, you have a "Start button."  To use it, bring the mouse down to the dock, position it over the Applications folder, click and &lt;b&gt;hold&lt;/b&gt; (for a second or two), and the list of applications will shoot up from the folder.  Move the mouse over the application you want to launch and (finally) let go of the mouse button.&lt;br /&gt;I've used this from the very beginning of when I started using OS X.  It's so simple, but it makes the system so much easier to use.  It drives me up the wall to work on a stock OS X system where you have to use the Finder to go to Applications to launch an application.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt; &lt;b&gt;Create local applications folder&lt;/b&gt;: Once you've installed more than a few applications on your Mac, the "start button" we created above will be too big - you'll have to scroll to find the application you're looking for.  What you need is to organize the applications in the Applications folder by creating some folders within the Applications folder.  Therefore, create a folder for your new applications.  I called my folder "Local Applications."  Anytime you install new applications, put them in there instead of Application.&lt;br /&gt;If you have a bunch of existing applications, it seems to be OK to just move them into your folder.   However, take it from me: do &lt;span style="font-weight: bold;"&gt;not &lt;/span&gt;move any of the Apple applications - when Software Update runs, it will install things in the original location. Now,  those applications are available from the "start button" under the name for your folder - e.g., "Local Applications."&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt; &lt;b&gt;Create a short list of favorite applications&lt;/b&gt;:  Even with the benefits of the organization we set up above, the list is still long, and it contains a bunch of applications that you hardly, if ever, use.  Create a new folder pretty much anywhere - e.g., in your home directory.  Open a separate window in the Finder and navigate over to Applications.  For any applications that you use regularly (either in Applications or Local Applications) create an alias of the application (right click/control click on the application icon and choose "Make alias") and drag the new alias into your new application folder.  I also include aliases to Applications, Utilities, and Local Applications in my folder.&lt;br /&gt;Finally, drag your new folder into the Dock (and optionally remove the original Applications folder you put there).  From this new "start button," you can quickly reach the applications you use regularly, and if you included Applications in your folder, you can reach everything else, too - the best of both worlds: quick access and complete access.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt; &lt;b&gt;Change the icon&lt;/b&gt;: Optionally you can  &lt;a href="http://www.apple.com/support/mac101/customize/6/"&gt;change the icon of your applications folder&lt;/a&gt; - I copied the icon from the original Applications folder into my personal applications folder, but you can use almost icon.&lt;/li&gt;&lt;/ol&gt;enjoy,&lt;br /&gt;Charles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-115229655842470453?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/115229655842470453/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=115229655842470453' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/115229655842470453'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/115229655842470453'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2006/07/tip-managing-applications-on-os-x.html' title='Tip: Managing Applications on OS X'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-115138069840220805</id><published>2006-06-26T20:56:00.000-07:00</published><updated>2007-03-02T07:27:17.203-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='books'/><title type='text'>Book: File System Forensic Analysis</title><content type='html'>&lt;a thref="http://www.amazon.com/exec/obidos/ASIN/0321268172/westernskies-20?creative=327641&amp;camp=14573&amp;amp;adid=10YKK6F5SQE49D4R085K&amp;link_code=as1"&gt;File System Forensics&lt;/a&gt; by Brian Carrier.  ISBN: 0321268172.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;To my way of thinking, this is a really good book about &lt;em&gt;file systems&lt;/em&gt;, that just happens to use forensics as a unifying theme and framework under which to study the file systems.  The book provides the most detailed coverage of file systems I've seen, short of reading the source code.  I used it as a textbook in an advanced operating systems class, but it is not really a textbook, per se.&lt;br /&gt;&lt;br /&gt;The author begins with an introduction to the concepts behind digital forensic investigations.  He continues with a ground-up introduction to disk drive technology and how disks are used in computer systems.  The introductory material concludes with a generic framework for discussing the components and characteristics of file systems.&lt;br /&gt;&lt;br /&gt;With all the groundwork laid, the meat of the book consists of detailed discussions of FAT, NTFS, Ext, and UFS file systems.  Each file system is presented at a high level first, followed by a detailed description of the structures on disk.  The high level information is presented with pictures and via output from the author's file system toolkit (The Sleuth Kit).  The details are presented with tables of structure members without resorting to C code, which makes it easier to see the trees rather than the forest, especially for non-programmers.&lt;br /&gt;&lt;br /&gt;I found the information about the Microsoft file systems (FAT and NTFS) especially useful, since there isn't much real documentation on those file systems available, and a lot of what is available seems like rumors spread at recess in a schoolyard.&lt;br /&gt;&lt;br /&gt;In conclusion, this is a really good, perhaps even the best, book on file systems, even if you're not into forensics.  If you're looking for serious details about file systems or forensic analysis of file systems, this is your book.&lt;br /&gt;&lt;br /&gt;Enjoy,&lt;br /&gt;Charles.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;iframe src="http://rcm.amazon.com/e/cm?t=westernskies-20&amp;amp;o=1&amp;p=8&amp;amp;l=as1&amp;asins=0321268172&amp;amp;fc1=000000&amp;IS2=1&amp;amp;lt1=_blank&amp;lc1=0000ff&amp;amp;bc1=000000&amp;bg1=ffffff&amp;amp;f=ifr" style="width: 120px; height: 240px;" marginwidth="0" marginheight="0" frameborder="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-115138069840220805?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/115138069840220805/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=115138069840220805' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/115138069840220805'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/115138069840220805'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2006/06/book-file-system-forensic-analysis.html' title='Book: File System Forensic Analysis'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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-29718960.post-115031345019601076</id><published>2006-06-14T12:29:00.000-07:00</published><updated>2006-06-26T20:52:33.003-07:00</updated><title type='text'>Welcome to Western Skies</title><content type='html'>Welcome to the Western Skies technology blog. The purpose is to share information related to the technologies that I am involved with.  Eventually, this will grow into the corporate web site for the Western Skies Technology Group with a real domain name, but that will require paying off the domain squatters that have the domains I'm interested in.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/29718960-115031345019601076?l=western-skies.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://western-skies.blogspot.com/feeds/115031345019601076/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=29718960&amp;postID=115031345019601076' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/115031345019601076'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/29718960/posts/default/115031345019601076'/><link rel='alternate' type='text/html' href='http://western-skies.blogspot.com/2006/06/welcome-to-western-skies.html' title='Welcome to Western Skies'/><author><name>Charles Anderson</name><uri>http://www.blogger.com/profile/02651484904301404333</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></feed>
