<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
 
 <title>Cubicle Muses</title>
 <subtitle>Keen insights from the inside of a box.</subtitle>
 
 <link href="http://cubiclemuses.com/cm" />
 <updated>2009-05-20T01:20:14Z</updated>
 <author>
   <name>J Aaron Farr</name>
 </author>
 <author>
   <name>William Taysom</name>
 </author>
 <id>http://cubiclemuses.com/cm/feed</id>

 
  
  <link rel="self" href="http://feeds.feedburner.com/cubiclemuses" type="application/atom+xml" /><entry>
    <title>2009 Open Source China Summit</title>
    <link href="http://feedproxy.google.com/~r/cubiclemuses/~3/IXL-SVV0Uk8/" />
    <id>http://cubiclemuses.com/cm/articles/2009/06/30/2009-open-source-china-summit/</id>
    <updated>2009-06-30T09:41:03Z</updated>
    <author>
      <name>J Aaron Farr</name>
    </author>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">
      <p>This was my third year attending the <a href="http://www.economist.com/displayStory.cfm?story_id=13740181">Open Source China, Open Source
World Summit</a>.  The schedule was similar - a day packed of 20
minutes “keynotes” followed by a half-day round table (which I had to
miss this year).  </p>
      <p>Despite being a regular attendee and occasional speaker, I have mixed
feelings about the summit.  Let’s be clear, it’s not a technical
event.  The speakers include CTOs and Directors of IBM, Sun, Intel,
Google, Red Flag, and so on.  Even Microsoft was there this year,
demoing Windows 7 of all things.</p>

<p>The intended topic was open source for mobile and netbook computing,
but somehow a fair bit of cloud computing made its way in too.  Some
of the talks were great.  I think Mark Shuttleworth’s point about
regularly scheduled releases is important.  Others were little more
than marketing show and tell.</p>

<p>Despite all that, I do think the summit has value.  It’s useful to get
these people together to compare notes, network and discuss
strategies.  Open source has <a href="http://www.economist.com/displayStory.cfm?story_id=13740181">grown up</a> and this is part of that
world, like it or not.  And for those wanting a quick introduction
into the state of open source in China, the summit’s worth attending
at least once.</p>

<p>For those looking for the technical side of open source in China,
there’s no better starting point than the <a href="http://www.beijinglug.org">Beijing Linux User
Group</a>.  The BLUG puts most other user groups to shame and has
become an incredible resource over the last few years.  Seriously,
it’s worth scheduling your visit to Beijing around one of their
events.</p>

<p>One final note: a few of us at Apache are hoping to run another event
in Beijing (and maybe Shanghai) again this year, likely at the end of
November.  Last year we did a single day of <a href="http://us.apachecon.com/c/accn2008">technical talks</a>
followed by a single day <a href="http://www.barcamp.org/BarCampBeijing">barcamp</a>.  We’re putting together ideas
of what to do now.  If we do another single day of talks, then I think
we need to be a bit more focused on which projects or technologies to
highlight.  It’s hard to cover much in just a single day.  Would half
or full day training sessions be more interesting?</p>

<p>I’d also like to see an even bigger BarCamp in Beijing this year.  I’m
really surprised that a Barcamp community hasn’t emerged out of
Beijing.  Or maybe it’s just doing a really good job of hiding.
Whatever the case, if you’d like to be involved in either an Apache
developer event in Beijing or the 2009 Beijing BarCamp, please send me
an [email][mailto:farra@apache.org].</p>

<h3>2009 Open Source China, Open Source World Summit Schedule</h3>

<p>I didn’t see the schedule published anywhere, so for the sake of
posterity, here was the first day.  Might help someone decide if
they’d like to attend in the future:</p>

<ul>
<li>Mobile Internet and Open Terminal, Prof Lu Shouqun, Chairman of COPU</li>
<li>The State of the Linux Ecosystem and Its Opportunity, Jim Zemlin, Director of Linux Foundation</li>
<li>An untitled talk by Mark Shuttleworth, Ubuntu founder</li>
<li>Community Matters, Louis Suarex-Potts, OpenOffice.org President</li>
<li>Cloud Computing and Smarter Planet, Dr. Thomas Li, CTO of IBM GCG</li>
<li>Create the Mobile Internet Future, Dr. Bob Lian, GM of Intel (AP) R&amp;D</li>
<li>Open Source Chances and Challenges for Nokia, Gunther Kottzieper, Director Open Source for Nokia</li>
<li>Android Platform, James Su, Google</li>
<li>Status of OSS and the Role of Public Services Platform, Dr. Qiu Shanqin, Director CSIP</li>
<li>Open Source Cloud Computing, Andrew Hu, President of Red Hat Greater China</li>
<li>Promoting OSS by Innvocation and Application, Han Nanping, GM of China Standard Software Co.</li>
<li>Increate Efficiency with Open Source, Jia Dong, CEO of Red Flag Software</li>
<li>Open Cloud Computing Platform, James Bai, Director Open Source Centre Sun Micro (China)</li>
<li>OSS Represents the Direction of the Service, Hu Caiyang, GM Red Flag Chinese 2000 Software</li>
<li>Openness at Microsoft, Dr. Sean Zhang, CTO Microsoft Greater China Region</li>
<li>Open Source Work of the Daoli Project, Dr, Mao Wenbo, Director of EMC Research China</li>
<li>Cloud Computing and IBM Cloud Offerings, Tian Yong, IBM Open Partnership Center</li>
<li>Moblin: The Open Source Mobile Computing Platform, Dr. Elton Yang, Engineering Director of Intel OTC (China)</li>
</ul>
     <xhtml:img xmlns:xhtml="http://www.w3.org/1999/xhtml" src="http://feeds.feedburner.com/~r/cubiclemuses/~4/IXL-SVV0Uk8" height="1" width="1" /></div></content>
  <feedburner:origLink>http://cubiclemuses.com/cm/articles/2009/06/30/2009-open-source-china-summit/</feedburner:origLink></entry>
  
  <entry>
    <title>Where I Put Stuff</title>
    <link href="http://feedproxy.google.com/~r/cubiclemuses/~3/zrYGlKifWek/" />
    <id>http://cubiclemuses.com/cm/articles/2009/05/24/where-i-put-stuff/</id>
    <updated>2009-05-24T17:04:25Z</updated>
    <author>
      <name>J Aaron Farr</name>
    </author>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">
      <p>Over this weekend I found myself searching for a particular bit of data that I knew I had, well, somewhere.  This prompted me to clean up some of my files and do some organizing.  Since I always like learning how others solve these sort of problems, I figured I’d share where I put my digital stuff.</p>
      <h3>Organize by type of information</h3>

<p>Where I put things depends on how I intend to use it.  Do I need to share the data regularly?  Do I just need to archive it?  With that in mind, I divide up my stuff into the following categories and I try to keep the data in one place per category.</p>

<h4>To Do Lists</h4>

<p>I use the <a href="http://orgmode.org/">emacs org-mode</a> to keep track of all my lists be it personal, work, or whatever.</p>

<h4>Projects</h4>

<p>If I have to share the information with others, then I tend to use a <a href="http://basecamphq.com/">Basecamp project</a>.  I’m often tempted to use <a href="http://sites.google.com/">Google Sites</a> and if I weren’t so invested in Basecamp, I might migrate.</p>

<p>If code is involved, then I use my private subversion repository for closed source code.  For open source code, I have stuff in Apache, GitHub and Google Code repositories and that’s pretty much my order of preference too.</p>

<p>I currently don’t have a good system for personal projects.  I’ve used Basecamp projects, Google Sites, <a href="http://backpackit.com/">Backpack</a>, personal wikis and other online solutions.  I’ve tried to keep everything in org-mode and subversion.  I’ve also considered products like <a href="http://flyingmeat.com/voodoopad/">VoodooPad</a> and <a href="http://www.devon-technologies.com/products/devonthink/">DevonThink</a>.  This is the messiest part of my digital space and I’d be happy to hear what works for others.</p>

<h4>Files</h4>

<p>I use an sftp account for important backups and file sharing.  I’ve thought about using <a href="http://www.getdropbox.com/">Dropbox</a> or <a href="http://www.zumodrive.com/">Zumodrive</a>, but considering how much space I use, I’m sticking with sftp for now.</p>

<p>Otherwise, everything is just thrown into my <code>Documents</code> folder.  There’s a small bit of organization there, but mostly I rely on desktop search to help me find what I’m looking for.</p>

<h4>Calendar</h4>

<p>iCal collects all the calendars I’m interested in and <a href="http://spanningsync.com/">Spanning Sync</a> publishes it to my Google account.  I subscribe to my Facebook events, my friend and coworker’s calendars, Basecamp milestone calendars and so on.  All of this ends up in iCal.  It’s great for me, but not necessarily good for anyone else who wants to follow where I am as there’s no one public calendar that keeps all my busy/free time.</p>

<h4>Music and Media</h4>

<p>iTunes for music.  iPhoto for photos.  The files themselves are stored on external drives.  For music, it’s a drive shared over my home network.  For photos, it’s on an external drive that I plug as needed.  I used to have decent backup systems for both, but now I have so much data that I need larger drives.  Don’t have an remote/online backup system.</p>

<p>Photos I want to share end up on <a href="http://flickr.com/photos/jaaronfarr">Flickr</a>.  I only use Facebook for photos taken at events planned via Facebook.</p>

<h4>Miscellaneous</h4>

<p>I’m happily using <a href="http://evernote.com/">Evernote</a> for all those bits of information which don’t seem to belong anywhere else.  This includes reminders, account information, registration codes, directions to places, whatever.  It’s my digital notebook.  I don’t use it for anything that needs more structure (ie- projects), but it’s been a great place to catch random data.  The fact that it syncs with my iPhone is critical.</p>

<h3>Your Solution</h3>

<p>So how do you organize your digital stuff?  Do you use a strict filing system or do you rely on search?  Online or offline?  A few tools or special tools for everything? </p>
     <xhtml:img xmlns:xhtml="http://www.w3.org/1999/xhtml" src="http://feeds.feedburner.com/~r/cubiclemuses/~4/zrYGlKifWek" height="1" width="1" /></div></content>
  <feedburner:origLink>http://cubiclemuses.com/cm/articles/2009/05/24/where-i-put-stuff/</feedburner:origLink></entry>
  
  <entry>
    <title>CoverStory on the iPhone</title>
    <link href="http://feedproxy.google.com/~r/cubiclemuses/~3/vX83y9I9XiU/" />
    <id>http://cubiclemuses.com/cm/articles/2009/05/14/coverstory-on-the-iphone/</id>
    <updated>2009-05-14T05:05:07Z</updated>
    <author>
      <name>William Taysom</name>
    </author>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">
      <p>Since <a href="http://www.kanchoo.com/">Kanchoo</a> is getting to be a serious app, it’s time to make rewrite, refactor, and to adopt <a href="http://code.google.com/p/google-toolbox-for-mac/wiki/iPhoneUnitTesting">automated testing</a>.  How do you know whether your tests cover all possible cases? That’s hard, but you can at least verify that all your code is covered.  Yes, today we’re talking about <a href="http://en.wikipedia.org/wiki/Code_coverage">code coverage</a>.</p>


	<p><a href="http://code.google.com/p/coverstory/">CoverStory</a> is an awesome application for inspecting <span class="caps">GCC</span>’s <a href="http://gcc.gnu.org/onlinedocs/gcc/Gcov-Intro.html">gcov</a> output.  As you would expect from <span class="caps">GCC</span>, setting up gcov is easy and obscure.  You need to:</p>


<ul>
<li>Add “-lgcov” to Other Linker Flags.</li>
<li>Set <span class="caps">GCC</span>_GENERATE_TEST_COVERAGE_FILES to <span class="caps">YES</span>.</li>
<li>Set <span class="caps">GCC</span>_INSTRUMENT_PROGRAM_FLOW_ARCS to <span class="caps">YES</span>.</li>
<li>Run your app, then open the “Objects-normal” folder in CoverStory.</li>
</ul>

	<p>Let’s go over these steps in more detail.  In Xcode, get info on the target you want to cover.  Switch to the Build tab.  Double click on the value of the “Other Linker Flags” setting.</p>


<img src="http://cubiclemuses.com/page_attachments/0000/0029/build-tab.png" alt="" />
<hr class="space" />

	<p>Add “-lgcov”.  OK.  Now add two user-defined settings: <span class="caps">GCC</span>_GENERATE_TEST_COVERAGE_FILES and <span class="caps">GCC</span>_INSTRUMENT_PROGRAM_FLOW_ARCS.  Set the value of both to <span class="caps">YES</span>.</p>


<img src="http://cubiclemuses.com/page_attachments/0000/0031/user-defined.png" alt="" />
<hr class="space" />

	<p>Build and run.  Now find the Objects-normal folder.  The path is something like:</p>


<ul>
<li>CoverageExample/build/CoverageExample.build/Debug-iphonesimulator/CoverageExample.build/Objects-normal</li>
</ul>

	<p>Or in general:</p>


<ul>
<li>${PROJECT_DIR}/build/${PRODUCT_NAME}.build/${CONFIGURATION}-${PLATFORM_NAME}/${PRODUCT_NAME}.build/Objects-normal</li>
</ul>

	<p>Open the Objects-normal folder in CoverStory: drag, drop, see the report, a summary showing the percent coverage of each file with a detail view showing the number of hits for each line in the gutter.  When the hit count is zero, the line is highlighted in red.</p>


	<p>Sometime lines of code were never meant to run: inconceivable, <a href="http://code.google.com/p/coverstory/wiki/NonFeasibleCode">non-feasible</a>.  Mark these lines with <span class="caps">COV</span>_NF_LINE comments or mark a block with <span class="caps">COV</span>_NF_START followed by <span class="caps">COV</span>_NF_END.  If non-feasible lines do get executed, CoverStory will warn you.</p>


	<p>May your code be ever covered and your tests perpetually passing.</p>
      
     <xhtml:img xmlns:xhtml="http://www.w3.org/1999/xhtml" src="http://feeds.feedburner.com/~r/cubiclemuses/~4/vX83y9I9XiU" height="1" width="1" /></div></content>
  <feedburner:origLink>http://cubiclemuses.com/cm/articles/2009/05/14/coverstory-on-the-iphone/</feedburner:origLink></entry>
  
  <entry>
    <title>A Community of Rockstars</title>
    <link href="http://feedproxy.google.com/~r/cubiclemuses/~3/ztV3wwTRbYs/" />
    <id>http://cubiclemuses.com/cm/articles/2009/04/28/a-community-of-rockstars/</id>
    <updated>2009-04-28T17:00:24Z</updated>
    <author>
      <name>J Aaron Farr</name>
    </author>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">
      <p>The <a href="http://www.slideshare.net/mattetti/couchdb-perform-like-a-pr0n-star">problem</a> with the Ruby on Rails community isn’t simply <a href="http://www.ultrasaurus.com/sarahblog/2009/04/gender-and-sex-at-gogaruco/">sexism</a>, <a href="http://dyepot-teapot.com/2009/04/25/dear-fellow-rubyists/">unprofessionalism</a>, or <a href="http://www.rubyrailways.com/rails-is-still-a-ghetto/">ghetto-ism</a>, but that Rails is, at its core, a culture which values individual ego more than community.  David and his posse have purposefully encouraged a tradition of <a href="http://www.loudthinking.com/posts/39-im-an-r-rated-individual">edginess</a>, individual expression, one-upmanship, and disregard for such fluffy, fake egalitarian notions as consensus, inclusion and <a href="http://www.flickr.com/photos/doesrails/128015501/">good manners</a>.  It is expressed in the take-it-or-leave-it, <a href="http://www.flickr.com/photos/urbanwide/244690884/">I-don’t-owe-you-anything</a> objectivism that guides Rails framework development and even many of the <a href="http://www.37signals.com/svn/archives2/getting_real_forget_feature_requests.php">businesses</a> built on it.  The result is a community which collaborates largely by aggressive competition and <a href="http://workingwithrails.com/">fierce meritocracy</a>.</p>
      <p>To be clear, I use Ruby on Rails for this website and several others.  A Rails hater, I am not.  However, technical merits aside, the culture of an open source community influences the character of those attracted to it and consequently who I work with, hire, train or sell to.  Thus I care to some degree what the public perception of the technology is.</p>

<p>But beyond that, I have spent the last six years as a contributor to projects in the Apache Software Foundation and the differences between the Apache culture and the Rails culture astound me.  Apache, like Rails, is a strict meritocracy, but I believe that may be where the similarities end.  There’s nothing wrong with giving credit where credit is due, but the Apache philosophy asserts that collaborative peer development trumps rockstars.  Rockstars are an anathema to the ASF culture.  In the long run, a large, diverse community of contributors provides a stability and quality that cannot be matched by a benevolent dictator who may face conflicting interests, may be unable to scale with the community, or who might <a href="http://www.wired.com/threatlevel/2008/04/reiser-guilty-o">murder his wife</a>.</p>

<p>Cultures which value diversity and collaboration over individual ego are required to cultivate an enticing environment.  It’s difficult to attract a wide range of contributors if the environment is constantly abrasive.  This is why you’ll find Apache members spouting off about the importance of consensus, inclusion, and equality amongst peers.  We’ll even go so far as to suggest <a href="http://www.jimjag.com/imo/index.php?/archives/182-Why-community-matters.html">community over code</a>.  Perhaps we must do so simply because such virtues are not necessarily in our nature.  Open source developers tend to be an ego-driven, strong minded, smart-ass bunch.</p>

<p>If it’s unsurprising that a community of rockstars would gravitate to a hip tool like git, which favors individual forks, compared to a staid tool like subversion, which forces developers to work together in a centralized repository, then it should be equally unsurprising that the rockstars don’t care that they <a href="http://twitter.com/dhh/status/1631100714">offend</a> or <a href="http://afreshcup.com/2009/04/28/a-painful-decision/">drive others away</a>.  Their culture doesn’t value building a community.  If it happens, great.  But they aren’t doing it <a href="http://www.infoq.com/interviews/David-Hansson">for you or anyone else</a>.  This is a community of ones.</p>

<p>That may work well for David and the Rails community for now.  And they seem willing to accept the consequences of being <a href="http://www.codinghorror.com/blog/archives/001065.html">douchebags</a>.  But I hope, for the sake of a technology I enjoy working with, that the community matures.  Because if it doesn’t, a pack of individuals will not stand the test of time and David may just get his wish of writing code for just himself.</p>
     <xhtml:img xmlns:xhtml="http://www.w3.org/1999/xhtml" src="http://feeds.feedburner.com/~r/cubiclemuses/~4/ztV3wwTRbYs" height="1" width="1" /></div></content>
  <feedburner:origLink>http://cubiclemuses.com/cm/articles/2009/04/28/a-community-of-rockstars/</feedburner:origLink></entry>
  
  <entry>
    <title>Short and Canonical URLs</title>
    <link href="http://feedproxy.google.com/~r/cubiclemuses/~3/jzFyyT_T-5g/" />
    <id>http://cubiclemuses.com/cm/articles/2009/04/12/short-and-canonical-urls/</id>
    <updated>2009-04-12T21:54:16Z</updated>
    <author>
      <name>J Aaron Farr</name>
    </author>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">
      <p>Slashdot just posted an article about <a href="http://developers.slashdot.org/article.pl?sid=09/04/12/1834205">using canonical URLs for URL shortening</a> which does a bad job in my opinion of explaining the problem.  So here’s a breakdown that I hope helps.</p>
      <h4>Multiple URLs</h4>

<p>Let’s take a step back and look at an earlier problem.  A particular <em>resource</em> on the internet might be <em>located</em> in multiple places.  Let’s say we have an article about swedish fish candy (<a href="http://googlewebmastercentral.blogspot.com/2009/02/specify-your-canonical.html">thanks, Google</a>).  This article might be found at any number of locations on my website:</p>

<ul>
<li>http://www.example.com/products/swedish-fish</li>
<li>http://www.example.com/product.php?item=swedish-fish</li>
<li>http://www.example.com/product.php?item=swedish-fish&amp;category=gummy-candy</li>
<li>http://www.example.com/product.php?item=swedish-fish&amp;trackingid=1234&amp;sessionid=5678</li>
<li>http://www.example.com/psf</li>
</ul>

<p>Suppose any one of those URLs will direct you to the same, or effectively the same article about swedish fish.  Wouldn’t it be nice if I, as the author of that article, could specify which URL is the <em>best</em> address?  This way when Google sees all of those different links, it treats them as links to a single, best address.</p>

<p>Turns out, Google <a href="http://googlewebmastercentral.blogspot.com/2009/02/specify-your-canonical.html">has a solution</a>.  All you need to do is add a single line of HTML code at the top of each of these articles that looks like this:</p>

<pre><code>&lt;link rel="canonical" href="http://www.example.com/product/swedish-fish" /&gt;
</code></pre>

<p>This tells Google when it processes those links and pages that they all really refer to this single <em>canonical</em> URL.  At least Ask, Microsoft and Yahoo also respect this directive.  So if we have multiple URLs for a single resource, we can tell other services which URL we designate is the <em>best</em> URL.</p>

<h4>Short URLs</h4>

<p>One useful alternate URL is a <em>shorter</em> version of the canonical URL.  Consider the following two URLs:</p>

<ul>
<li>http://tinyurl.com/db2myk</li>
<li>http://maps.google.com/maps?f=q&amp;source=s_q&amp;hl=en&amp;geocode=&amp;q=lamma+island,+hk&amp;ie=UTF8&amp;ll=22.238578,114.147263&amp;spn=0.264079,0.215607&amp;z=12</li>
</ul>

<p>Both URLs refer to the same map, but the first is much easier to pass along in an email, SMS, twitter post, etc.  Despite being useful, it also has <a href="http://joshua.schachter.org/2009/04/on-url-shorteners.html">all sorts of problems</a> including being opaque and a possible point of failure.</p>

<p>There’s a new idea going around that would let us have our short URLs and avoid these problems by using <a href="http://revcanonical.appspot.com/">rev=”canonical”</a>.  Rev?  Well, it turns out <code>rev</code> is the opposite of <code>rel</code> for <code>link</code> elements.  So that we might have the following:</p>

<pre><code>&lt;!-- included in the code at 'http://www.example.com/psf' --&gt;
&lt;link rel="canonical" href="http://www.example.com/product/swedish-fish" /&gt;

&lt;!-- included in the code at 'http://www.example.com/product/swedish-fish' --&gt;
&lt;link rev="canonical" href="http://www.example.com/psf" /&gt;
</code></pre>

<p>The first says, “Hello.  The preferred address for this resource is <code>http://www.example.com/product/swedish-fish</code>.  Have a nice day.”  The second says, “Hello.  I am the preferred address for <code>http://www.example.com/psf</code>.  Have a nice day.”</p>

<p>The proponents of “revcanonical,” as they’re tagging it, suggest that we can use this second scenario to let services know about a possible shorter URL for a given longer URL.  It also allows for websites to provide their own URL shortening service instead of relying on third parties like Tiny URL.  In this case, when someone submits the longer URL to a service like Twitter, Twitter could inspect the HTML at that URL, discover the suggested shorter URL and thus use and display the shorter address.  To reduce the processing overhead, there’s even a suggestion to use this <code>rev=canonical</code> information in <a href="http://shiflett.org/blog/2009/apr/a-rev-canonical-http-header">HTTP headers</a>.</p>

<h4>A solution to linkrot?</h4>

<p>I’ve long been a fan of Tiny URL.  I use it for emails and tweets regularly.  But I’m also keenly aware of the flaws and issues in introducing a third party URL shortening service.  I welcome any idea that helps solve this problem.</p>

<p>The trouble is, I’m not sure <code>revcanonical</code> is a good solution and this is beyond just the challenges of getting services like Twitter (let alone browsers) to support it.  First off, <code>rev</code> here means <em>reverse</em>.  In other words, the <em>reverse canonical</em>.  Just because some address is a reverse canonical address doesn’t mean that it’s necessarily shorter.  The <code>revcanonical</code> proposal requires us to assume this intent.</p>

<p>Even worse, <code>revcanonical</code> mixes up the idea of alternative URLs with the idea of a <em>canonical</em> URL.  The proposal would have us suggest that the following:</p>

<pre><code>&lt;!-- included in the code at 'http://www.example.com/product/swedish-fish' --&gt;
&lt;link rev="canonical" href="http://www.example.com/psf" /&gt;
</code></pre>

<p>Means ”<code>http://www.example.com/psf</code> is a shorter URL for <code>http://www.example.com/product/swedish-fish</code>” when in fact it means ”<code>http://www.example.com/product/swedish-fish</code> claims to be the canonical URL for <code>http://www.example.com/psf</code>.”  Think about that for a second.  It’s the difference between one person saying, “Yeah, Joe speaks for me” versus Joe saying, “Yeah, I speak for this whole group.”  To confirm Joe’s statement, we’d have to ask each person in the group.  Likewise, that means if one URL says it’s the canonical address for another, we’d have to check that second URL to make sure it agrees.  Otherwise, we open ourselves up to <a href="http://benramsey.com/archives/a-revcanonical-rebuttal/#comment-288475">highjacking</a>.</p>

<p>There are two other issues with this proposal.  First, while <code>rev</code> is a valid HTML 4 element, it isn’t in the latest <a href="http://dev.w3.org/html5/spec/Overview.html#the-link-element">HTML 5 drafts</a>.  That means the proposal is pushing forward something which will soon been invalid markup.  That alone should kill this particular idea immediately.</p>

<p>Finally, as <a href="http://benramsey.com/archives/a-revcanonical-rebuttal/">Ben Ramsey</a> pointed out, the proposal is confusing.  The difference between <code>rel</code> and <code>rev</code> is subtle and will definitely lead to misunderstanding and misinterpretation.  It was confusing enough that I felt it worthwhile to write this article just to make sure I understood it.  A good solution should be immediately apparent.</p>

<p>So, while I applaud the effort of those who are looking to solve our tiny url issues, I sincerely hope this proposal receives more inspection before wide adoption.  Personally, I’d much rather see something like a <code>rel="shorter"</code> attribute used on <code>link</code> and <code>a</code> elements.</p>
     <xhtml:img xmlns:xhtml="http://www.w3.org/1999/xhtml" src="http://feeds.feedburner.com/~r/cubiclemuses/~4/jzFyyT_T-5g" height="1" width="1" /></div></content>
  <feedburner:origLink>http://cubiclemuses.com/cm/articles/2009/04/12/short-and-canonical-urls/</feedburner:origLink></entry>
  
  <entry>
    <title>Rails with Passenger on Open Solaris and EC2</title>
    <link href="http://feedproxy.google.com/~r/cubiclemuses/~3/nGNie0UP9mk/" />
    <id>http://cubiclemuses.com/cm/articles/2009/04/09/rails-passenger-open-solaris-ec2/</id>
    <updated>2009-04-09T08:53:15Z</updated>
    <author>
      <name>J Aaron Farr</name>
    </author>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">
      <p>You can now run Sun’s Open Solaris images on EC2 without signing up for
their beta program.  The newly released “web stack” AMI includes Open Solaris 2008.11, 
Apache, MySQL and PHP:</p>

<pre><code>Open Solaris 2008.11 + AMP
32-bit AMI: ami-c7cf28ae
</code></pre>

<p>The bad news is that there’s still some work to do if you want to run Ruby on Rails.
The good news is that the most recent releases of Ruby on Rails (2.3) and Phusion
Passenger (2.1.3) include patches that make it much easier to run
on Open Solaris.  There’s still some work to do and this article aims to
give you all the steps needed.</p>

<p>My notes assume you have some experience with EC2, Open Solaris (or at
least some Unix/Linux variant) and Rails.  Please leave a comment below 
if anything is unclear.</p>

<p>This article was written using:</p>

<ul>
<li>Ruby on Rails 2.3</li>
<li>Passenger Phusion 2.1.3</li>
<li>Open Solaris 2008.11</li>
</ul>
      <h4>Installing basic GNU tools</h4>

<p>We’ll want to go ahead and install <code>gmake</code>, <code>gcc</code>, <code>svn</code> and <code>git</code>.
We need to compile the last one from source.  As this is the only
package we’re installing this way, I just install it directly into
<code>/usr</code>.  If you feel this is blasphemy of some sort, feel free to
install it into your favorite local directory by adding a parameter
such as <code>prefix=/opt/local</code>  to the <code>configure</code> step.</p>

<p>Steps:</p>

<ul>
<li>install gmake</li>
<li>install gcc</li>
<li>install subversion</li>
<li>install git</li>
</ul>

<p>Commands:</p>

<pre><code> $ pfexec pkg install SUNWgmake
 $ pfexec pkg install SUNWgcc
 $ pfexec pkg install SUNWsvn
 $ mkdir -p /opt/src
 $ cd /opt/src
 $ wget http://kernel.org/pub/software/scm/git/git-1.6.2.2.tar.gz
 $ tar xzf git-1.6.2.2.tar.gz
 $ cd git-1.6.2.2
 $ ./configure [--prefix=/opt/local]
 $ gmake
 $ pfexec make install
 $ git --version
</code></pre>

<h4>Installing Ruby on Rails</h4>

<p>Ruby 1.8.6 is already installed with Sun’s AMP stack.  However, we
need to upgrade ruby gems and apply a few patches.</p>

<p>Steps:</p>

<ul>
<li>update rubygems</li>
<li>add github gem server (may not be needed depending on what gems you use)</li>
<li>install rails</li>
<li>Modify path.  Should put this in your <code>profile</code> somewhere.</li>
</ul>

<p>Commands:</p>

<pre><code> $ gem update --version
 $ gem sources -a http://gems.github.com
 $ gem install rails
 $ PATH=/usr/ruby/1.8/bin:$PATH
</code></pre>

<p>If we want to install gems with native code, we’ll need to update our
<code>rbconfig.rb</code> file.  Luckily <a href="http://blogs.sun.com/prashant/entry/dtrace_support1">Prashant Srinivasan</a> has made it
simple for us.</p>

<pre><code> $ wget http://blogs.sun.com/prashant/resource/gcc/rbconfig.rb
 $ mv /usr/ruby/1.8/lib/ruby/1.8/i386-solaris2.11/rbconfig.rb /usr/ruby/1.8/lib/ruby/1.8/i386-solaris2.11/rbconfig.rb.original
 $ mv rbconfig.rb /usr/ruby/1.8/lib/ruby/1.8/i386-solaris2.11/rbconfig.rb
</code></pre>

<p>We can now install the database gems</p>

<pre><code> $ gem install mysql -- --with-mysql-dir=/usr/mysql/5.0
 $ gem install sqlite3-ruby
</code></pre>

<p>We also need to fix an issue with <code>iconv</code> that requires us to both
install the gnu version and change how we link to that library.
Details are on the <a href="http://woss.name/2008/10/16/edge-rails-pre-22-iconv-transliteration-and-solaris/">Rubaidh</a> blog and a <a href="https://rails.lighthouseapp.com/projects/8994/tickets/1396-framework-crashes-on-launch-on-solaris-with-invalid-encoding-asciiignoretranslit-utf-8">ticket is open</a> in the
Rails bug tracker.</p>

<pre><code> $ pfexec pkg install SUNWgnu-libiconv
 $ pfexec crle -u -E LD_PRELOAD=/usr/gnu/lib/preloadable_libiconv.so
 $ pfexec crle -s /lib/secure -s /usr/lib/secure -s /usr/gnu/lib
</code></pre>

<p>If you don’t like this method of updating your LD_PRELOAD parameter,
you can configure Phusion Passenger with <a href="http://blog.phusion.nl/2008/12/16/passing-environment-variables-to-ruby-from-phusion-passenger/">custom environmental
variables</a>.  This is a useful way to handle any path issues you
bump into.</p>

<h4>Installing Phusion Passenger (mod_rails)</h4>

<p>To install Passenger, we first need to install fastthread.
Unfortunately, the lastest gem has issues on Open Solaris, so we’ll
install version 1.0.1.  After that, we can proceed with installing
passenger.</p>

<pre><code> $ gem install fastthread --version 1.0.1
 $ gem install passenger
 $ passenger-install-apache2-module
</code></pre>

<p>Now you need to update your Apache httpd configuration:</p>

<pre><code> $ PASSENGER_CONF=/etc/apache2/2.2/conf.d/passenger.conf 
 $ echo "LoadModule passenger_module \ 
 $    /usr/ruby/1.8/lib/ruby/gems/1.8/gems/passenger-2.1.3/ext/apache2/mod_passenger.so"  \
      &gt; $PASSENGER_CONF
 $ echo "PassengerRoot /usr/ruby/1.8/lib/ruby/gems/1.8/gems/passenger-2.1.3" &gt;&gt; $PASSENGER_CONF
 $ echo "PassengerRuby /usr/ruby/1.8/bin/ruby"  &gt;&gt; $PASSENGER_CONF
</code></pre>

<h4>Testing</h4>

<p>Let’s create a simple rails app using the new Rails 2.3 templates:</p>

<pre><code> $ mkdir /var/apache2/2.2/apps
 $ cd /var/apache2/2.2/apps
 $ rails blog
 $ cd blog
 $ ./script/generate controller welcome index
 $ chown -R webservd:webservd /var/apache2/2.2/apps
</code></pre>

<p>Now we add the virtual host information for passenger:</p>

<pre><code>  $ vi /etc/apache2/2.2/conf.d/vhosts.conf

    &lt;VirtualHost *:80&gt;
     ServerName [YOUR-EC2-DNS-HERE]
     DocumentRoot /var/apache2/2.2/apps/blog/public

     &lt;Directory /var/apache2/2.2/apps/blog&gt;
      Options +FollowSymLinks -SymLinksIfOwnerMatch +MultiViews -Indexes -ExecCGI
      AllowOverride ALL
      Order allow,deny
      Allow from all
     &lt;/Directory&gt;

    &lt;/VirtualHost&gt;
</code></pre>

<p>Now we restart apache:</p>

<pre><code>   $ svcadm restart http:apache22
</code></pre>

<p>And we should be able to view our new rails app by going to the public
address for our EC2 server.  To confirm rails is actually configured
correctly, visit <code>/welcome</code> and you should see something like:</p>

<pre><code>Welcome#index

Find me in app/views/welcome/index.html.erb
</code></pre>

<p>I’ll leave setting up Capistrano as an exercise for the reader.  I’m
going to do some more testing with this setup and I may release a
<a href="http://wiki.opscode.com/display/chef/Home">Chef</a> configuration for it or my own custom AMIs if there’s interest.</p>
     <xhtml:img xmlns:xhtml="http://www.w3.org/1999/xhtml" src="http://feeds.feedburner.com/~r/cubiclemuses/~4/nGNie0UP9mk" height="1" width="1" /></div></content>
  <feedburner:origLink>http://cubiclemuses.com/cm/articles/2009/04/09/rails-passenger-open-solaris-ec2/</feedburner:origLink></entry>
  
  <entry>
    <title>Reflections on ApacheCon Europe 2009</title>
    <link href="http://feedproxy.google.com/~r/cubiclemuses/~3/oeEI5FWLtmI/" />
    <id>http://cubiclemuses.com/cm/articles/2009/04/01/reflections-on-apachecon-europe-2009/</id>
    <updated>2009-04-01T19:37:35Z</updated>
    <author>
      <name>J Aaron Farr</name>
    </author>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">
      <p>The story we wanted to tell at ApacheCon Europe was the 10th
anniversary of the Apache Software Foundation.  Last Wednesday night,
we had a cake and celebration.  Plans are in the works for a similar
party in Oakland at ApacheCon US this November.  But aside from the
official line, I wanted to share some other thoughts now that I’m back
mostly over my jetlag.</p>
      <p>From what I heard, the conference this time around was excellent.
Despite being there myself, I was only able to attend a few sessions.
Ten years old means the Foundation is growing up and that means a few
us spend out conference days in budget, press and planning meetings.</p>

<p>The two talks I did attend were about Apache Sling and Apache CouchDB.
I’m very interested in these two projects.  They’re much more similar
than I think most people realize.  CouchDB is getting more and more
notice, but Sling is a hidden gem.  By the end of the month, I hope to
put together some articles comparing the two.</p>

<p>I also want to put a portion of my REST training online.  Less than a
week before the conference, I came up with a new RESTful example that
I really like - Tic-Tac-Toe.  So stay tuned for that one.</p>

<h3>What’s Next For ApacheCon</h3>

<p>A lot of discussion at ApacheCon was about the nature of the
conference and how it should change.  Last week’s ApacheCon was very
much the same as it had been for years.  Looking at attendence
numbers, the economy, and general trends in events, there’s a feeling
that we have to evolve before we go extinct.</p>

<p>The real tension with a conference like ApacheCon is that many
committers want little more than a space with a good internet
connection (good food and drink is appreciated too).  The developers
just want a place to meet up with fellow project members and hack.  At
the same time, we have sponsors and users who want a professional
conference – somewhere they can come to learn, train and get their
manager to pay the bill.  That means it has to be worth it to the
manager and a week long hackathon generally doesn’t cut it.</p>

<p>There’s been plenty of proposals on the table on how to find the
balance.  I believe it will take us a few experiments to get there.
In fact, we’ve already been doing some of these experiments – the
Fast Feather tracks, the BarCamp Apache, the evening Get Togethers.
These are all baby steps to explore what works and what doesn’t.</p>

<p>At the planning meeting for ApacheCon US last weekend, we decided to
try even more experiments this fall.  We’re not yet quite ready to
make all of them public, but you should see notices going out within
the next few days.  I’m excited to see what happens and I hope the
larger Apache community, developers and users, are equally excited and
interested to participate.</p>
     <xhtml:img xmlns:xhtml="http://www.w3.org/1999/xhtml" src="http://feeds.feedburner.com/~r/cubiclemuses/~4/oeEI5FWLtmI" height="1" width="1" /></div></content>
  <feedburner:origLink>http://cubiclemuses.com/cm/articles/2009/04/01/reflections-on-apachecon-europe-2009/</feedburner:origLink></entry>
  
  <entry>
    <title>Live Tomorrow: The Apache Way</title>
    <link href="http://feedproxy.google.com/~r/cubiclemuses/~3/mWedDaVR-vQ/" />
    <id>http://cubiclemuses.com/cm/articles/2009/03/27/live-tomorrow-the-apache-way/</id>
    <updated>2009-03-27T11:54:22Z</updated>
    <author>
      <name>J Aaron Farr</name>
    </author>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">
      <p>How is the Apache Software Foundation different from <a href="https://github.com/">GitHub</a>?  Why is it we do what we do?</p>

<p>I’ll be trying to answer those questions tomorrow in my ApacheCon lunch session, “The Apache Way,” which will be <a href="http://streaming.linux-magazin.de/en/program_apachecon09.htm">streamed live</a> over the internet.  My session is free but requires registration.  So if you’re not at ApacheCon, checkout the <a href="http://www.timeanddate.com/worldclock/fixedtime.html?month=3&amp;day=26&amp;year=2009&amp;hour=12&amp;min=30&amp;sec=0&amp;p1=0">time in your timezone</a> and sign up.</p>

<p><em>Update</em>: The session will actually start at 1:30 UTC+1 (or in your <a href="http://www.timeanddate.com/worldclock/fixedtime.html?month=3&amp;day=26&amp;year=2009&amp;hour=12&amp;min=30&amp;sec=0&amp;p1=0">local timezone</a>)</p>
      
     <xhtml:img xmlns:xhtml="http://www.w3.org/1999/xhtml" src="http://feeds.feedburner.com/~r/cubiclemuses/~4/mWedDaVR-vQ" height="1" width="1" /></div></content>
  <feedburner:origLink>http://cubiclemuses.com/cm/articles/2009/03/27/live-tomorrow-the-apache-way/</feedburner:origLink></entry>
  
  <entry>
    <title>Keeping up with Apache(Con)</title>
    <link href="http://feedproxy.google.com/~r/cubiclemuses/~3/8WOkmU6qshg/" />
    <id>http://cubiclemuses.com/cm/articles/2009/03/25/keeping-up-with-apachecon/</id>
    <updated>2009-03-25T16:08:17Z</updated>
    <author>
      <name>J Aaron Farr</name>
    </author>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">
      <p><a href="http://eu.apachecon.com/c/aceu2009">ApacheCon Europe 2009</a> is underway.  The Hadoop and OSGi sessions have been packed, but I’ve been stuck in foundation meetings and unable to attend.  If you’re not at the conference, you can watch the keynotes and selected sessions <a href="http://www.eu.apachecon.com/c/aceu2009/about/videoStreaming">online</a> for free.  In fact, you can watch my session on Friday!</p>
      <p>My <a href="http://www.eu.apachecon.com/c/aceu2009/sessions/193">A Day of REST</a> training class on Monday went well.  I’m still pretty happy with the “RESTful Tic-Tac-Toe” example I came up with.  I’m hoping to turn that example into a series of articles on the blog here.</p>

<p>In other news, the Apache Foundation is <a href="https://blogs.apache.org/foundation/entry/the_asf_is_ten_years">10 years old today</a>!  We finally have a set of official blogs for the foundation running at <a href="https://blogs.apache.org">blogs.apache.org</a> that complements our committer blog aggregator, <a href="http://planet.apache.org/committers/">Planet Apache</a>, which recently moved.  These are in addition to our official <a href="http://twitter.com/theasf">foundation</a> and <a href="http://twitter.com/apachecon">conference</a> twitter accounts.</p>

<p>And finally, on a personal note, my wife Jenny joined me for the first few days of the conference.  As she was leaving for Hong Kong this morning, she kept mentioning how much she enjoyed Amsterdam and meeting the Apache committer community.  You can read some of her thoughts on our <a href="http://www.cubiclemuses.com/pg">Peregrinari</a> weblog.</p>
     <xhtml:img xmlns:xhtml="http://www.w3.org/1999/xhtml" src="http://feeds.feedburner.com/~r/cubiclemuses/~4/8WOkmU6qshg" height="1" width="1" /></div></content>
  <feedburner:origLink>http://cubiclemuses.com/cm/articles/2009/03/25/keeping-up-with-apachecon/</feedburner:origLink></entry>
  
  <entry>
    <title>Managing Your Social Networks</title>
    <link href="http://feedproxy.google.com/~r/cubiclemuses/~3/prlKQOhBpeY/" />
    <id>http://cubiclemuses.com/cm/articles/2009/03/16/managing-your-social-networks/</id>
    <updated>2009-03-16T10:19:40Z</updated>
    <author>
      <name>J Aaron Farr</name>
    </author>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">
      <p>Following my article about <a href="http://cubiclemuses.com/cm/articles/2009/03/07/how-twitter-became-irc-for-me/">twitter and irc</a>, a friend asked me
about how I manage my information on various social networks:</p>

<blockquote>
    <p>I kinda have an all or nothing approach to things. If I’m not going to do
    social networks, then I don’t want some old neglected pages out there, I
    want nothing. If I’m going to do this, I want to get on all the main
    networks, and have a smooth consistent web presence. I hope that can be done
    without having it turn into a full time job.</p>
</blockquote>

<p>From my experience, keeping various social network profiles up to date
<em>can</em> take a lot of time.  There are generally two strategies:</p>

<ul>
<li>Do it yourself, generally by preferring one network or service over others</li>
<li>Use an aggregator service</li>
</ul>

<p>There are pros and cons to both approaches.</p>
      <h3>Managing Your Social Network</h3>

<p>There are some advantages to managing your various social networks
yourself: more control, complete use of the services.  Aggregator
sites that sync and manage your online life are very new and you may
not want to be their guinea pig.  The key disadvange is that managing
several networks takes time and a real strategy, otherwise you’ll end
up with a mess on your hands.  Since most people tend to start with
from one network and slowly add new ones, this tangled web of
information is a typical result.</p>

<p>The simplest solution is to be selective.  Determine which services
you need or want and then select a specific service provider for each
one.  Sometimes a single network will solve multiple problems.  For
example, I’ve chosen to use Flickr for hosting photos and Twitter for
status updates.  However, Facebook provides both of these services and
some people prefer to just use Facebook.</p>

<p>If you keep things simple, then this may be as far as you need to go.
Just resist the urge to join multiple networks and refer everyone back
to your “official” home.  However, if you do find yourself on multiple
networks, then you’ll have to make some choices.</p>

<p>First, you need to consider why you’re using a particular network.  It
can be useful to partition your activities.  For example, you might
only use Facebook for close friends and family and use LinkedIn for
business contacts.  If you go this route, be sure to stick with it.
Don’t even mention your Facebook profile to business associates.  I
have one friend who specifically uses an alias for their social
networks to keep their real name from showing up in internet searches.</p>

<p>Secondly, several services have now built-in ways to import and export
your data automatically.  For example, there are Flickr and Twitter
applications for Facebook which allow you to integrate the services.
When doing this, keep in mind which service you want to be the
“master” copy and only directly update this service.  Allow the other
services to pick up your updates downstream.</p>

<p>Finally, sometimes you can just be a little creative.  For example, I
tend to use the same profile photo of myself across networks.  In some
cases, I can keep this centralized by pointing all the networks to an
image hosted by <a href="http://gravatar.com/">Gravitar</a>.  You can often pull
similar tricks by linking newsfeeds between sites.</p>

<h3>Social Network Aggregators</h3>

<p>If managing multiple social networks on your own seems like too much
work, then you’re not alone.  In the last year or so several network
aggregator services have popped up that help you keep your digital
life in sync.</p>

<p>Some aggregators focus more on collecting updates from all your
networks and presenting them to you in one place.  Others are actual
tools for synchronizing updates, profiles, and photos across multiple
networks.</p>

<p>I personally haven’t used any of these services.  But there are
several reviews available online:</p>

<ul>
<li><a href="http://www.crunchbase.com/company/friendfeed">FriendFeed</a></li>
<li><a href="http://www.crunchbase.com/company/spokeo-people-search">Spokeo</a></li>
<li><a href="http://www.crunchbase.com/company/socialthing">Social Thing</a></li>
<li><a href="http://www.crunchbase.com/company/mylifebrand">My Life Online</a></li>
<li>and a dozen or so more</li>
</ul>

<p>And I should add that each main social network (Facebook, Orkut,
LinkedIn, MySpace, etc.) has its own plan to become <em>the</em> one true
network in your life.  In some cases, their offerings may be good
enough.  From a technical point of view, as
<a href="http://www.opensocial.org/">OpenSocial</a> matures and sees greater
adoption, this may all be much easier in the future.  In the meantime,
if you want to use an aggregator, be prepared to deal with beta-level
software and a quickly changing landscape.</p>

<p>The reason I linked to the <a href="http://www.crunchbase.com/">CrunchBase</a> is
because I think it’s a great way to find this sort of information.
Often these services are so new that Wikipedia and even Google won’t
give you a clear idea of what’s out there.  Crunchbase tracks these
companies and, more importantly, their competitors.  So you can
quickly see what other offerings there are.</p>
     <xhtml:img xmlns:xhtml="http://www.w3.org/1999/xhtml" src="http://feeds.feedburner.com/~r/cubiclemuses/~4/prlKQOhBpeY" height="1" width="1" /></div></content>
  <feedburner:origLink>http://cubiclemuses.com/cm/articles/2009/03/16/managing-your-social-networks/</feedburner:origLink></entry>
  
  <entry>
    <title>Reversion of Control in Ruby Warrior</title>
    <link href="http://feedproxy.google.com/~r/cubiclemuses/~3/DpVia6smK3A/" />
    <id>http://cubiclemuses.com/cm/articles/2009/03/15/reversion-of-control-in-ruby-warrior/</id>
    <updated>2009-05-20T01:21:21Z</updated>
    <author>
      <name>William Taysom</name>
    </author>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">
      <p><a href="http://github.com/ryanb/ruby-warrior/tree/master">Ruby Warrior</a> is a clever rogue-like game where, instead of playing it directly, you implement a Ruby class with your player control logic.</p>

<pre>
class Player
  def play_turn(warrior)
    # add your code here
  end
end
</pre>
      <h1>Level 1</h1>

<p>At the start of each level, a README describes the horrors you will face.</p>

<pre>
Level 1

Silence. The room feels large, but empty. Luckily you have a map of this tower 
to help find the stairs.

Tip: Use warrior.direction_of_stairs to determine which direction stairs are 
located. Pass this to warrior.walk! to walk in that direction.

 ------
|      |
|@     |
|      |
|  &gt;   |
 ------

  &gt; = Stairs
  @ = Juez (20 HP)


Available Abilities:

  warrior.feel
    Returns a Space for the given direction (forward by default).

  warrior.direction_of_stairs
    Returns the direction (:left, :right, :forward, :backward) the stairs are 
from your location.

  warrior.walk!
    Move in given direction (forward by default).
</pre>

<p>Following the README's advice, clearing the first level is easy.</p>

<pre>
class Player
  def play_turn(warrior)
    warrior.walk! warrior.direction_of_stairs
  end
end
</pre>

<p>Or if you're like me and find that code to be unacceptably verbose, you are liable to write something like the following.</p>

<pre>
module Delegate
  def method_missing symbol, *args
    @delegate.send symbol, *args
  end
end

class Player
  include Delegate

  def play_turn warrior
    @delegate = warrior
    step
  end
end

class Player
  def step
    walk! direction_of_stairs
  end
end
</pre>

<p>Some programmers are lazy in the worst possible way.</p>

<p>When you play a level, you see a turn-by-turn transcript.</p>

<pre>
Starting Level 1
- turn 1 -
 ------
|      |
|@     |
|      |
|  &gt;   |
 ------
Juez walks right
- turn 2 -
 ------
|      |
|      |
|@     |
|  &gt;   |
 ------
Juez walks forward
- turn 3 -
 ------
|      |
|      |
| @    |
|  &gt;   |
 ------
Juez walks right
- turn 4 -
 ------
|      |
|      |
|      |
| @&gt;   |
 ------
Juez walks forward
Success! You have found the stairs.
Level Score: 0
Time Bonus: 16
Clear Bonus: 3
Total Score: 19
</pre>

<p>Onto the second level.</p>

<h1>Level 2</h1>

<p>The README shows that we are up against three sludges.  These undesirables do not move and, are, therefore easily dispatched.</p>

<pre>
Level 2

Another large room, but with several enemies blocking your way to the stairs.

Tip: Just like walking, you can attack! and feel in multiple directions 
(:forward, :left, :right, :backward).

 ----
| @s |
| sS&gt;|
 ----

  &gt; = Stairs
  @ = Juez (20 HP)
  s = Sludge (12 HP)
  S = Thick Sludge (24 HP)


Available Abilities:

  warrior.feel
    Returns a Space for the given direction (forward by default).

  warrior.rest!
    Gain 10% of max health back, but do nothing more.

  warrior.health
    Returns an integer representing your health.

  warrior.attack!
    Attack the unit in given direction (forward by default).

  warrior.direction_of_stairs
    Returns the direction (:left, :right, :forward, :backward) the stairs are 
from your location.

  warrior.walk!
    Move in given direction (forward by default).
</pre>

<p>How would you approach this challenge?</p>

<h2>Agaram's Approach</h2>
	
<p>A <a href="http://wiki.github.com/ryanb/ruby-warrior/solutions">pair of solutions</a> are posted.  Kartik Agaram proposed the following <a href="http://github.com/akkartik/brooks-ruby-warrior/blob/9d91fe535620f0a991b574d518a3599050291dd0/intermediate-tower/level-002/player.rb">solution</a>.  (I have edited it by removing comments and unused methods.)</p>

<pre>
class Player
  def initialize()
    @max_health = nil
    @prev_health = nil
    @warrior = nil
    @direction = :forward
    @health_history = []
    @direction_history = []
  end

  def play_turn(warrior)
    @max_health ||= warrior.health

    @warrior = warrior
    updateHistory

    return walk! if feel.stairs?
    return rest! if needRest &amp;&amp; !beingShotAt
    return attack! unless feel.empty?

    reverse_direction if walking_into_fire
    walk!
  end

  def needRest
    @warrior.health &lt; @max_health
  end

  def beingShotAt
    @warrior.health &lt; @prev_health
  end

  def updateHistory
    @prev_health = @curr_health
    @curr_health = @warrior.health
    @health_history &lt;&lt; @curr_health
    @direction = @warrior.direction_of_stairs
  end

  def walk!
    @warrior.walk! @direction
  end

  def attack!
    @warrior.attack! @direction
  end

  def rest!
    @warrior.rest!
  end

  def feel
    @warrior.feel @direction
  end

  def walking_into_fire
    return false if @direction_history[-1] != @direction_history[-2] ||
        @direction_history[-2] != @direction_history[-3]
    @health_history[-1] &lt; @health_history[-2] &amp;&amp;
      @health_history[-2] &lt; @health_history[-3]
  rescue
    false
  end

  def reverse_direction
    @direction = (@direction == :forward) ? :backward : :forward
  end
end
</pre>

<p>What is his strategy?  On each turn, Agaram makes a prioritized choice:</p>

<ul>
<li>If he is next to the stairs, then he takes them.</li>
<li>If he needs to rest and is safe to do so, then he rests.</li>
<li>If he feels something in the direction of the stairs, then he attacks it.</li>
<li>If he is "walking into fire", then he walks away from the stairs.</li>
<li>Otherwise he walks toward the stairs.</li>
</ul>

<p>How does Agaram decide whether he is "walking into fire"?  Though a little tough to read, the definition boils down to:</p>

<ul>
<li>For Agaram, "walking into fire" means that for the last two turns he has both lost health and faced the same direction.</li>
</ul>

When confronted with the map, how does Agaram's strategy play out?

<pre>
Starting Level 2
- turn 1 -
 ----
| @s |
| sS&gt;|
 ----
Agaram attacks Sludge
Sludge takes 5 damage, 7 health power left
Sludge attacks Agaram
Agaram takes 3 damage, 17 health power left
Sludge attacks Agaram
Agaram takes 3 damage, 14 health power left
</pre>

<p>Agaram attacks the Sludge to his east until it is good and dead.</p>

<pre>
- turn 3 -
 ----
| @s |
| sS&gt;|
 ----
Agaram attacks Sludge
Sludge takes 5 damage, -3 health power left
Sludge dies
Agaram earns 12 points
Sludge attacks Agaram
Agaram takes 3 damage, 5 health power left
- turn 4 -
 ----
| @  |
| sS&gt;|
 ----
Agaram walks backward
Sludge attacks and hits nothing
- turn 5 -
 ----
|@   |
| sS&gt;|
 ----
Agaram receives 2 health from resting, up to 7 health
</pre>

<p>He retreats and recovers.</p>

<pre>
- turn 12 -
 ----
|@   |
| sS&gt;|
 ----
Agaram receives 1 health from resting, up to 20 health
- turn 13 -
 ----
|@   |
| sS&gt;|
 ----
Agaram walks forward
- turn 14 -
 ----
| @  |
| sS&gt;|
 ----
Agaram walks forward
Sludge attacks and hits nothing
</pre>

<p>Another sludge stands in his way.</p>

<pre>
- turn 15 -
 ----
|  @ |
| sS&gt;|
 ----
Agaram attacks Thick Sludge
Thick Sludge takes 5 damage, 19 health power left
Thick Sludge attacks Agaram
Agaram takes 3 damage, 17 health power left
</pre>

<p>He fights the sludge.</p>

<pre>
- turn 19 -
 ----
|  @ |
| sS&gt;|
 ----
Agaram attacks Thick Sludge
Thick Sludge takes 5 damage, -1 health power left
Thick Sludge dies
Agaram earns 24 points
- turn 20 -
 ----
|  @ |
| s &gt;|
 ----
Agaram receives 2 health from resting, up to 10 health
</pre>

<p>He heals again.</p>

<pre>
- turn 25 -
 ----
|  @ |
| s &gt;|
 ----
Agaram receives 2 health from resting, up to 20 health
- turn 26 -
 ----
|  @ |
| s &gt;|
 ----
Agaram walks right
- turn 27 -
 ----
|    |
| s@&gt;|
 ----
Agaram walks forward
Sludge attacks and hits nothing
Success! You have found the stairs.
Level Score: 36
Time Bonus: 13
Total Score: 68
</pre>

<p>After recovering, Agaram finds his way to the stairs.</p>

<h2>Will's Approach</h2>

<p>Since Ruby Warrior requires that you write a <code>play_turn</code> method, the easiest way to dive into a solution is to come up with a turn-by-turn strategy saving little bits of state (<code>@direction_history</code> and <code>@direction_history</code>) as needed.</p>  <p>What if it were easy to express a step-by-step plan instead?  Then you would:</p>

<ul>
<li>Fight the Sludge.</li>
<li>Walk forward twice.</li>
<li>Walk right up the stairs.</li>
</ul>

<p>Piece of cake: ignore the Thick Sludge.</p>

<pre>
class Player
  def fight!
    attack! while feel.enemy?
  end

  def main
    fight!
    2.times{walk!}
    walk! :right
  end
end
</pre>

<p>There's only one little problem with this code.  The <tt>Player</tt> class expects turn-by-turn <a href="http://en.wikipedia.org/wiki/Inversion_of_Control">inverted control</a> in its <tt>play_turn</tt> method.  We want a player with good old fashioned step-by-step procedural control.  We have suffered inverted control frameworks for far too long.  Assert your rights.  Revert control.  Embrace the imperative.  Restore the natural sequence.  And iterate until your heart's content.  By Ruby, it shall be done:</p>

<pre>
require 'generator'

class Symbol
  def action?
    to_s[-1] == ?!
  end
end

class Player
  def initialize
    @generator = Generator.new do |g|
      g.yield nil
      main
    end
  end

  def play_turn warrior
    @warrior = warrior
    @generator.next
  end

  def method_missing symbol, *args
    @warrior.send symbol, *args
  ensure
    @generator.yield nil if symbol.action?
  end
end
</pre>

<p>Beauty.  Now I present you with a challenge.  My magic stems from the generator library.  What would you do if generators, coroutines, continuations, actors, threads, <tt>setjmp/longjmp</tt>, and all other natural concurrency constructs were unavailable?</p>
     <xhtml:img xmlns:xhtml="http://www.w3.org/1999/xhtml" src="http://feeds.feedburner.com/~r/cubiclemuses/~4/DpVia6smK3A" height="1" width="1" /></div></content>
  <feedburner:origLink>http://cubiclemuses.com/cm/articles/2009/03/15/reversion-of-control-in-ruby-warrior/</feedburner:origLink></entry>
  
  <entry>
    <title>How to use the iPhone Network Activity Spinner</title>
    <link href="http://feedproxy.google.com/~r/cubiclemuses/~3/7EIZAEcI_ec/" />
    <id>http://cubiclemuses.com/cm/articles/2009/03/12/how-to-use-the-iphone-network-activity-spinner/</id>
    <updated>2009-03-16T15:34:48Z</updated>
    <author>
      <name>William Taysom</name>
    </author>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">
      <p>As an iPhone developer, how do you get that little status bar spinner to appear?</p>


<img src="http://cubiclemuses.com/page_attachments/0000/0027/network-activity-spinner.png" alt="" />
<hr class="space" />

	<p>It’s piece of cake once you know the proper incantation.</p>


<pre>
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
</pre>

	<p>Of course, this doesn’t work, or may not appear to work.  It works fine on the device (iPhone or iPod touch) and it works fine in the iPhone Simulator if you are connected to the internet via an ethernet cable.  However, if you are using wireless, the activity indicator will not work on the iPhone Simulator.</p>


	<p>So watch out!  And enjoy your network activity spinner.  If you’d like to learn more, I’ll be teaching an <a href="http://cubiclemuses.com/cm/articles/2009/03/05/iphone-training-in-april/">iPhone Training Workshop</a> from April 22-24.</p>
      
     <xhtml:img xmlns:xhtml="http://www.w3.org/1999/xhtml" src="http://feeds.feedburner.com/~r/cubiclemuses/~4/7EIZAEcI_ec" height="1" width="1" /></div></content>
  <feedburner:origLink>http://cubiclemuses.com/cm/articles/2009/03/12/how-to-use-the-iphone-network-activity-spinner/</feedburner:origLink></entry>
  
 
 
</feed>
