<?xml version="1.0"?>
<rss version="2.0">
   <channel>
      <title>Just Read The Directions</title>
      <link>http://blog.darnowsky.com/</link>
      <description>Articles on programming by Phil Darnowsky.</description>
      <language>en-us</language>

      <lastBuildDate>Tue Jan 18 21:24:25 -0500 2011</lastBuildDate>
      <docs>http://blogs.law.harvard.edu/tech/rss</docs>
      <managingEditor>phil@darnowsky.com</managingEditor>
      <webMaster>phil@darnowsky.com</webMaster>

      
        <item>
          <title>Parallelized A* search</title>
          <link>http://blog.darnowsky.com/2010/12/30/parallelized-astar-search.html</link>
          <pubDate>Thu Dec 30 00:00:00 -0500 2010</pubDate>
          <description><![CDATA[<p class="update_notice">Updated January 18, 2011 to fix inconsistent mileage figures in examples.</p>

<h3>Sequential A*</h3>

<p>
Everyone knows and loves the <a href="http://http://en.wikipedia.org/wiki/A*_search">A* search</a>. If you're familiar with it and want to <a href="#parallelized_astar">jump ahead to parallelizing it</a>, please feel free.
</p>

<p>
For those who aren't familiar with A* and don't want to read the complete treatment above, A* is a type of best-first search. It uses a heuristic function to estimate the distance between any node under consideration and the goal. Essentially, A* uses extra information about the problem domain to make informed choices when it considers where to go next.
</p>

<p>
Take for example the problem of a programmer who lives in San Francisco who has accepted a job in Boston. She's packed all her stuff in a moving van which gets terrible gas mileage, so she's taken out the highway map to find the shortest route between the cities.
</p>

<p>
Since she's a programmer, her map shows an abstract version of (a country remarkably similar to) the United States: only cities and highways are portrayed, in the form of vertices and edges of a weighted <a href="http://en.wikipedia.org/wiki/Graph_%28mathematics%29">graph</a>.
</p>

<div class="large_diagram">
  <img src="/assets/graph_map_of_us.png"/>
</div>

<p>
She sees that, starting in San Francisco, she has four choices for the first leg of her trip: she can drive to Portland, Reno, Las Vegas, or Los Angeles. From Portland, she can continue to Reno (backtracking to SF being forbidden); from Reno, she can go to Portland, Denver or Las Vegas; from Las Vegas, to Reno, Denver, Phoenix or Los Angeles; and from Los Angeles to Las Vegas or Phoenix. This is starting to get complicated, so she draws a tree to help her evaluate her options:
</p>

<div class="large_diagram">
  <img src="/assets/dectree1.png"/>
</div>

<p>
Looking at this, she and we can see that going from San Francisco to Reno to Las Vegas would be a trip of 670 miles. She could keep systematically enumerating the possible next moves from each city in a <a href="http://en.wikipedia.org/wiki/Breadth_first_search">breadth first search</a>, and it certainly will find a route to Boston, but it's not guaranteed to be the best possible route, and it may take quite a while to find any kind of solution.
</p>

<p>
Then inspiration strikes. She takes out a ruler and measures the straight-line distance from each city to Boston, never mind if there's actually a direct road or not. The first few make the map look like:
</p>

<div class="large_diagram">
  <img src="/assets/graph_map_of_us_with_direct_distances.png"/>
</div>

<p>
Now she knows as above that a trip from San Francisco to Reno to Las Vegas will be 670 miles. But now she can also estimate that the balance of the trip, from Las Vegas to Boston by some route, will be another 2370 miles. Adding those together gives her an estimate of 3040 miles for the length of the shortest trip that starts by going from San Francisco to Reno to Las Vegas and ends up in Boston.
</p>

<p>
At every step in the A* search, she picks the next city with the smallest total estimate route length. So at the beginning her search tree is as simple as can be:
</p>

<div class="large_diagram">
  <img src="/assets/dectree2.png"/>
</div>

<p>
The only state she knows of is when she is in San Francisco. She has traveled 0 miles to get there and has an estimated 2700 miles left to Boston. Adding these together gives her a total estimated trip length from here of 2700 miles.
</p>

<p>
In A*, you always expand the unexpanded state with the lowest <strong>total</strong> estimate. Since there's only one possible state, it'll have to do for a start. Our heroine looks at the possibilities from this state and comes up with:
</p>

<div class="large_diagram">
  <img src="/assets/dectree3.png"/>
</div>

<p>
Looking at the unexpanded states, she notes that the route beginning by driving from San Francisco to Reno has the lowest estimated total cost. Being a methodical type, she asks herself "Is Reno Boston?" If you happen to have visited both cities, you already know the answer to this. So she repeats the process again, considering where she could go from Reno:
</p>

<div class="large_diagram">
  <img src="/assets/dectree4.png"/>
</div>

<p>
At this point she has six possible routes to consider, and she sees that the route from San Francisco to Reno to Denver has the lowest estimated total cost. Denver is not Boston either, so she repeats the process again, and again, until a route to Boston emerges.
</p>

<p>
Note that, while we're imagining examining the tree directly for our next move, in practice you use a <a href="http://en.wikipedia.org/wiki/Priority_queue">priority queue</a> instead. A priority queue is just a list of items, each of which has a numerical value called a "priority" associated with it. When you add new items to the list, instead of just sticking them on the end, you put each in the list so that the list stays in ascending order of priority. In A*, the priority value we use is the estimated total distance. 
</p>

<p>
So at the start we'd have a priority queue with just one item in it:

<table>
  <tr><th>Node</th><th>Estimated Total Distance</th></tr>
  <tr><td>San Francisco</td><td>2700</td></tr>
</table>
</p>

<p>
San Francisco is at the head of the queue, so we take that off, expand it, and add the results back into the queue:

<table>
  <tr><th>Node</th><th>Estimated Total Distance</th></tr>
  <tr><td>San Francisco to Reno</td><td>2740</td></tr>
  <tr><td>San Francisco to Las Vegas</td><td>2930</td></tr>
  <tr><td>San Francisco to Los Angeles</td><td>2980</td></tr>
  <tr><td>San Francisco to Portland</td><td>3170</td></tr>
</table>
</p>

<p>
Now Reno is at the head, so we take that off, expand it, and add the results back in:
<table>
  <tr><th>Node</th><th>Estimated Total Distance</th></tr>
  <tr><td>San Francisco to Las Vegas</td><td>2930</td></tr>
  <tr><td>San Francisco to Los Angeles</td><td>2980</td></tr>
  <tr><td>San Francisco to Reno to Denver</td><td>3020</td></tr>
  <tr><td>San Francisco to Reno to Las Vegas</td><td>3040</td></tr>
  <tr><td>San Francisco to Portland</td><td>3170</td></tr>
  <tr><td>San Francisco to Reno to Portland</td><td>3280</td></tr>
</table>
</p>

<p>
In the next iteration, we'd expand routes that start by going from San Francisco to Las Vegas, and so on until we find our way to Boston.
</p>

<p>
A proof is beyond the scope of this article, but as long as the estimating function is "optimistic" (to use the formal term, <em>admissible</em>), that route is guaranteed to be the best possible one. An optimistic estimating function can underestimate the remaining cost of a route, or get it exactly correct, but isn't allowed to ever overestimate that cost. The straight-line estimation we're using here is certainly optimistic: no matter what route you take from Point A to Point B, you're never going to beat the straight-line distance between them.
</p>

<p>
To recap, her strategy for picking the best route by A* is:
<ol>
  <li>Take the state at the head of the priority queue off of it. It's guaranteed, of all the states we know, to have the smallest estimated total distance.</li>
  <li>If that state corresponds to being in Boston, we've found our route and can stop.</li>
  <li>Otherwise, look at the map and find which cities we can go to without doubling back on our route. Calculate their estimated total distances by adding the known distance it takes to get there to the estimated remaining distance to Boston. Based on those estimated total distances, add them to the appropriate place in the priority queue.</li>
  <li>Go back to the top and repeat until we've gotten to Boston.</li>
</ol>
</p>

<a name="parallelized_astar"><h3>Parallelized A*</h3></a>

<p>
A lot of the work of A* can profitably be done in parallel if we have multiple CPUs to work with. Suppose that we have three CPUs available: instead of picking the lowest estimated total cost node and expanding just that, we pick the three lowest estimated total cost nodes and assign each to a CPU.
</p>

<p>
To return to the example above, the first step (expanding the "San Francisco" state) would still work the same, since there's only one node to look at. But on the second iteration, we can expand three nodes at once, going from:
</p>

<div class="large_diagram">
  <img src="/assets/dectree3.png"/>
</div>

<p>
to:
</p>

<div class="large_diagram">
  <img src="/assets/dectree5.png"/>
</div>

<p>
This lends itself to a manager/worker architecture. The manager keeps the priority queue of states and assigns work to the workers. The workers expand the states and pass results back to the manager. A diagram of messages passing between processes in our example might look like:
</p>

<div class="large_diagram">
  <img src="/assets/parallel_astar_msd_1.png"/>
</div>

<p>
Notice that we're not assuming any relationship between the order in which we assign work to workers and the order in which they actually finish. We just pass out work in an arbitrary order and add results to the queue whenever they come in.
</p>

<p>
There's a trap here. Since you don't know the order that results will come back to the manager, it's theoretically possible for it to find a solution that's not the best possible solution. In fact, if you're really unlucky, it may find the worst possible solution.
</p>

<p>
We need to do a little more work to ensure that we get the best solution. Rather than stopping when we find a solution, we take the cost of that solution, and consider it as an upper bound on the cost of the best possible solution. This means we can throw out any unexpanded node with an estimated total cost greater than that bound. Recall that our estimation function is allowed to underestimate the cost of a path, but never to overestimate it. Hence if the estimate is greater than this upper bound, the actual cost is guaranteed to also be greater.
</p>

<p>
When we ask a worker to expand a node, we can also pass it this upper bound. The worker then expands the node as normal, but filters out any results with estimated total cost greater than the upper bound. The manager never sees these, and never adds them to the queue in the first place.
</p>

<p>
With these rules in place, we know we're done when the queue is empty and all workers are idle (and thus we're not expecting any new results). At this point, the best solution we know of is the best one there is.
</p>

<p>
To recap the parallelized algorithm:
<ol>
  <li>Assign nodes off the top of the queue to workers until all workers are busy or the queue is empty (assuming none of your starting nodes are solutions).</li>
  <li>When a worker responds, add its results to the queue in the proper order, removing any with an estimated cost greater than the upper bound on cost (originally infinity).</li>
  <li>Take the node off the top of the queue. If it's a solution, remember its cost as the upper bound on cost. If not, give it to the newly-freed worker to expand.</li>
  <li>Repeat until all workers are idle and the queue is empty. The best solution the manager knows of is now the best solution there is.</li>
</ol>
</p>

<p>
For those interested in playing with code to illustrate this algorithm, I've uploaded <a href="https://github.com/phildarnowsky/parallel_astar">an example implementation in Erlang</a> to Github, under an MIT license. It's very pre-alpha, just meant for a proof of concept. If I think of a practical use for it, I'll be cleaning it up. Of course, if you beat me to it, you're welcome to do the same, especially as the chances of me actually making a production-quality library out of this are slim.
</p>
]]></description>
        </item>
      
        <item>
          <title>A minheap library in Erlang</title>
          <link>http://blog.darnowsky.com/2010/08/10/minheap-library-in-erlang.html</link>
          <pubDate>Tue Aug 10 00:00:00 -0400 2010</pubDate>
          <description><![CDATA[<p>
I've recently released a library in Erlang that implements a <a href="http://en.wikipedia.org/wiki/Priority_queue">priority queue</a> using a <a href="http://en.wikipedia.org/wiki/Heap_%28data_structure%29">minheap</a>. It's a small library, but worth mentioning because I wasn't able to find such a thing last time I Googled around for one. I developed this for some tinkering with a variation on <a href="http://en.wikipedia.org/wiki/A*_search_algorithm">A* search</a> that <strike>I will write about soon</strike> you can now <a href="/2010/12/30/parallelized-astar-search.html">read about here</a>.
</p>

<p>
This is also the first library that I have written using <a href="http://www.erlang.org/doc/apps/eunit/index.html">EUnit</a>, a testing framework for Erlang. My first cut at this library was plagued by odd and obscure bugs, so I threw it out and rewrote it from scratch using EUnit for <a href="http://en.wikipedia.org/wiki/Test-driven_development">TDD</a>, which it turned out to be well suited for.
</p>

<p>
The library is available <a href="http://github.com/phildarnowsky/erlang_minheap">here on GitHub</a>. Since it's my understanding that Erlangers (Erlangists? Erlangueons?) prefer to use Mercurial, <strike>I'll also make a Mercurial repo available later this week, once I've had time to learn how to use it</strike> it's also available <a href="http://bitbucket.org/PhilDarnowsky/erlang_minheap">via Mercurial on bitbucket.org</a>.
</p>

<p>
Advice (especially about how to better use EUnit), criticism, and offers of excellent things are as welcome as always.
</p>
]]></description>
        </item>
      
        <item>
          <title>Slides from my presentation on Selenium at Boston.rb</title>
          <link>http://blog.darnowsky.com/2010/07/27/slides-from-selenium-presentation-at-bostonrb.html</link>
          <pubDate>Tue Jul 27 00:00:00 -0400 2010</pubDate>
          <description><![CDATA[<p>
In January 2010, I gave a talk on <a href="http://seleniumhq.org/projects/remote-control/">Selenium Remote Control</a> at <a href="http://www.bostonrb.org">Boston.rb</a>. I later posted the slides to the Boston.rb mailing list, but now it's occurred to me to put them online <a href="/assets/selenium_boston_rb.pdf">here (232 kb, PDF format)</a>. If there's demand for it, I'd also be willing to post the <a href="http://www.latex-project.org">LaTeX</a> source, which turns out to be an easy way to generate presentations.
</p>
]]></description>
        </item>
      
        <item>
          <title>The Dopp-down menu: A simple autocomplete widget with some twists</title>
          <link>http://blog.darnowsky.com/2010/07/18/the-dopp-down-menu-a-simple-autocomplete-widget-with-some-twists.html</link>
          <pubDate>Sun Jul 18 00:00:00 -0400 2010</pubDate>
          <description><![CDATA[<p>
  The redoubtable and formidable <a href="http://blog.sarahdopp.com/">Sarah Dopp</a> blogged a few months ago about <a href="http://www.sarahdopp.com/blog/2010/designing-a-better-drop-down-menu-for-gender/">designing a better drop-down menu for gender</a>, and shortly thereafter posted <a href="http://www.sarahdopp.com/blog/2010/the-dopp-down-menu-kidding-early-mockup/">a followup with a mockup of same</a>. The mockup certainly is lovely, but as an unrepentant propellerhead, I'm prejudiced in favor of things that are ugly but do something when you mess with them. (This is not a criticism: designers, you need us, and we need you, but that's a subject for another day.)
</p>

<p>
Thus, over the course of a few weeks, I put on my JavaScript hat whenever I had a free hour, and whipped up what I couldn't resist calling <a href="http://github.com/phildarnowsky/dopp_down_menu">the Dopp-down menu</a>. It's essentially a small (218 LOC), simple, but flexible autocomplete widget, built on top of <a href="http://jquery.com">jQuery</a>. In the simplest case, if you follow the conventions it's expecting, you just need to give it:
  <ul>
    <li>a selector to a text field to watch and complete;</li>
    <li>a selector to an element to populate with suggestions;</li>
    <li>and a URL that can return search results.</li>
  </ul>
</p>

<p>
  With just a few more options, you can also have an element that gets filled in with the most popular choices, to get the user started.
</p>

<p>
  Here's an example of how you call it, deliberately written to show off a number of options, taken from <a href="http://github.com/phildarnowsky/dopp_down_menu_demo">the demo application</a>:
  <div class="codeblock">
    <code>&lt;script type="text/javascript"&gt;
  $(document).ready(function() {
    dopp_down_menu(
      '#direct_entry_field',
      '#suggestions',
      '/search',
      {
        search_query_param: 'name',
        suggestion_link_class: 'suggestion_link',
        highlighted_link_class: 'highlighted',
        suggestion_link_post_insert_hook: 
          function(_, div) {
            div.append('&lt;br/&gt;')
          },
        popular_choice_url: '/popular_animals',
        popular_choice_div_selector: '#popular_choices',
        show_popularity_in_popular_choices: true
      }
    );
  });
&lt;/script&gt;</code>
  </div>
</p>

<p>
  It's true that <a href="http://jqueryui.com">jQuery UI</a> has its own <a href="http://docs.jquery.com/UI/Autocomplete">perfectly good autocomplete widget</a>. But here's one thing to consider: the unminified version of dopp_down_menu.js is 10K, just over half the size of the minified version of jQuery UI's autocomplete widget. Minified, dopp_down_menu.js squishes down to a svelte 6K. Also, as far as I know, jQuery UI autocomplete doesn't support the "popular choices" functionality that the Dopp-down menu does.
</p>

<p>
So please give it a try! I <strike>will add some documentation soon (promise)</strike> <span class="update">have now documented the API</span>, and as always, feedback and pull requests are most welcome.
</p>
]]></description>
        </item>
      
        <item>
          <title>Announcing has_named_bootstraps</title>
          <link>http://blog.darnowsky.com/2010/06/26/announcing-has_named_bootstraps.html</link>
          <pubDate>Sat Jun 26 00:00:00 -0400 2010</pubDate>
          <description><![CDATA[<p>
  Most nontrivial Web apps will require some amount of bootstrap data to be present in the database. Classic examples are lists of countries, US states, or postal codes. In my work at <a href="http://www.childrenshospital.org">Children's Hospital Boston</a>, we frequently deal with lists of clinics or diagnoses. If you're using <a href="//http://en.wikipedia.org/wiki/Rbac">role based access control (RBAC)</a>, you'll need different roles to be preloaded.
</p>

<p>
  You might write part of the logic for RBAC like this:
</p>

<div class="codeblock">
  <code>class AdminController &lt; ApplicationController
  before_filter :require_admin_user

  ...

  private

  def require_admin_user
    admin_role = Role.find_by_name 'admin'
    unless current_user.roles.include?(admin_role)
      flash.now[:error] = "You're not authorized to do that."
      redirect_to peon_path
    end
  end</code>
</div>

<p>
  But what's wrong with doing it this way?
  <ul>
    <li>You end up repeating <code>Role.find_by_name(...)</code> a million times. Of course, in practice, you'd write methods with names like <code>is_admin?</code>, <code>is_moderator?</code>, <code>is_regular_user?</code>. But these all have the same structure and vary only in what role they're concerned with, indicating that we have a chance to DRY things up.</li>
    <li>You're hardcoding strings. One of the first things I learned in programming, and quite likely one of the first things you learned, is that this always leads to trouble eventually. A role's name will change, or you'll type "administrator" where you meant "admin", or any of innumerable variations.</li>
    <li>You'll often want to refer to values bootstrapped in this way all together, perhaps in a <code>&lt;select&gt;</code> or a listing on an index page. Of course you can always <code>find(:all)</code> and grab every instance of that model, but I find that you often want to treat the bootstrapped values differently from other instances that might get created.</li>
  </ul>
</p>

<p>
  <a href="http://www.chak.org/">Dan Chak</a>, in his book <a href="http://www.amazon.com/gp/product/0596515200?ie=UTF8&tag=jusreathedir-20&linkCode=as2&camp=1789&creative=9325&creativeASIN=0596515200">Enterprise Rails</a><img src="http://www.assoc-amazon.com/e/ir?t=jusreathedir-20&l=as2&o=1&a=0596515200" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />, suggests that you create a constant to refer to this kind of data. I don't agree with everything in this book, but I do believe that this particular advice is on the money. So our example from above might turn into:
</p>

<div class="codeblock">
  <code>def require_admin_user
  unless current_user.roles.include?(Role::ADMIN)
    flash.now[:error] = "You're not authorized to do that."
    redirect_to peon_path
  end
end</code>
</div>

<p>This could still be DRYer, but it's definitely a step in the right direction.</p>

<p>Having defined a few gazillion of these constants in some of my code, I wrote and recently open-sourced a gem called <a href="http://rubygems.org/gems/has_named_bootstraps">has_named_bootstraps</a> (with <a href="http://github.com/chb/has_named_bootstraps">source on GitHub</a>) that automates defining these constants. There are plenty of options to play with, but the most basic case just looks like:</p>

<div class="codeblock">
  <code>class Department < ActiveRecord::Base
  has_named_bootstraps(
    :R_AND_D         => 'R&D',
    :MARKETING       => 'Marketing',
    :HANDSOME_DEVILS => 'Web Development'
  )
end</code>
</div>

<p>The constants <code>R_AND_D</code>, <code>MARKETING</code>, and <code>HANDSOME_DEVILS</code> are now all defined on <code>Department</code>.</p>

<p>Feedback, bug reports and pull requests are all most welcome. I'm eager to hear what you think.</p>

]]></description>
        </item>
      
        <item>
          <title>Adding namespaced methods dynamically to a Class</title>
          <link>http://blog.darnowsky.com/2009/03/07/adding-namespaced-methods-dynamically-to-a-class.html</link>
          <pubDate>Sat Mar 07 00:00:00 -0500 2009</pubDate>
          <description><![CDATA[<p>
  I'm working on a module that is meant to add some methods to a class when included.  There's a standard idiom to do this:
</p>

<div class="codeblock">
    <code>module NiftyCapabilities  
  def self.included(other)    
    other.extend(ClassMethods)  
  end  
    
  module ClassMethods    
    def grab_banana
      # ...    
    end  
  end
end
    
class Monkey
  include NiftyCapabilities
end</code>
</div>

  <p>When <code>include NiftyCapabilities</code> is evaluated in <code>Monkey</code>, the hook <code>NiftyCapabilities.included</code> is called with <code>Monkey</code> passed as a parameter.  <code>NiftyCapabilities.included</code> then calls <code>Monkey.extend(ClassMethods)</code>, which adds the <em>instance</em> methods of <code>NiftyCapabilities::ClassMethods</code> to the <em>class</em> <code>Monkey</code>.  Since a class method in Ruby is just an instance method of a <code>Class</code> object, the instance methods in <code>NiftyCapabilities::ClassMethods</code> are now class methods on <code>Monkey</code>.  Hooray for first class classes.</p>

  <p>This standard idiom is great as far as it goes, but for this library I have one additional goal: to be as unobtrusive as possible.  I'm concerned that if I add a <code>Monkey.grab_banana</code> method via this idiom I'll overwrite an pre-existing <code>grab_banana</code> method with unfortunate results.</p>
  <p>The solution here is to borrow a principle from unobtrusive Javascript: you should add no more than one symbol to the global namespace.  In this context, for "global namespace" read "class namespace."  The natural way to do this is to add an inner module to <code>Monkey</code> and define these new methods in that inner module.  Here's how:</p>

  <div class="codeblock">
    <code>module NiftyCapabilities  
  def self.included(other)    
    other.class_eval &lt;&lt;-END_CLASS_EVAL      

      module NiftyCapabilities        
        def self.grab_banana        
          # ...        
        end      
      end    
      
    END_CLASS_EVAL  
  end 
end

class Monkey  
  include NiftyCapabilities
end</code>
</div>

<p>Now when <code>NiftyCapabilities.included(Monkey)</code> is called, that here doc is evaluated in the context of the class <code>Monkey</code>.  The result is as if we had written:</p>

<div class="codeblock">
  <code>class Monkey
  module NiftyCapabilities
    def self.grab_banana
      # ...
    end
  end
end</code>
</div>

<p>Let's flesh out our banana-grabbing capabilities to absolutely satisfy ourselves that the modules created are perfectly cromulent inner modules of our classes:</p>
<div class="codeblock"><code>module NiftyCapabilities
  def self.included(other)
    other.class_eval &lt;&lt;-END_CLASS_EVAL
      module NiftyCapabilities
        # Don't use module variables in real code if you can help 
        # it, OK?

        @@banana_count = 0 

        def self.grab_banana
          @@banana_count += 1 
        end
    
        def self.banana_count
          @@banana_count
        end
      end
    END_CLASS_EVAL
  end 
end

class Monkey
  include NiftyCapabilities
end

class Gorilla
  include NiftyCapabilities
end
</code></div>

<p>Which we can try out like so:</p>
<div class="codeblock">
<code>user@rubybox$ irb
irb(main):001:0&gt; require 'namespaced_methods'
=&gt; true
irb(main):002:0&gt; Monkey::NiftyCapabilities.banana_count
=&gt; 0
irb(main):003:0&gt; Gorilla::NiftyCapabilities.banana_count
=&gt; 0
irb(main):004:0&gt; Monkey::NiftyCapabilities.grab_banana
=&gt; 1
irb(main):005:0&gt; Monkey::NiftyCapabilities.banana_count
=&gt; 1
irb(main):006:0&gt; Gorilla::NiftyCapabilities.banana_count
=&gt; 0</code></div>
]]></description>
        </item>
      
   </channel>
</rss>

