<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Ethan Fast &#187; Clojure</title>
	<atom:link href="http://blog.ethanjfast.com/tag/clojure/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.ethanjfast.com</link>
	<description>Lambdas, Hacks, and Fiction</description>
	<lastBuildDate>Fri, 27 Aug 2010 12:50:02 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<item>
		<title>Analyzing Word Frequencies with Clojure, Enlive and Incanter</title>
		<link>http://blog.ethanjfast.com/2010/03/analyzing-word-frequencies-with-clojure-enlive-and-incanter/</link>
		<comments>http://blog.ethanjfast.com/2010/03/analyzing-word-frequencies-with-clojure-enlive-and-incanter/#comments</comments>
		<pubDate>Mon, 08 Mar 2010 18:39:48 +0000</pubDate>
		<dc:creator>Ethan</dc:creator>
				<category><![CDATA[Clojure]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Enlive]]></category>
		<category><![CDATA[Incanter]]></category>
		<category><![CDATA[Wordy]]></category>

		<guid isPermaLink="false">http://blog.ethanjfast.com/?p=381</guid>
		<description><![CDATA[I&#8217;ve long been interested in getting a better feel for Incanter, a statistical computing and graphical environment for Clojure. So gifted with the fleeting favors of my muse (otherwise known as free time), I thought I&#8217;d put together a small library &#8212; although it&#8217;s not quite a library, yet &#8212; for analyzing word-use patterns on blogs and webpages. To [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve long been interested in getting a better feel for <a href="http://incanter.org/">Incanter</a>, a statistical computing and graphical environment for Clojure. So gifted with the fleeting favors of my muse (otherwise known as <em>free time</em>), I thought I&#8217;d put together a small library &#8212; although it&#8217;s not quite a library, yet &#8212; for analyzing word-use patterns on blogs and webpages.</p>
<p>To do this, I drew a bit of help from <a href="http://github.com/cgrand/enlive">Enlive</a>, which functions primarily as a templating library, but has a few features useful for screen-scraping. This was perhaps a bit of overkill, as I only ended up using one of it&#8217;s functions, <em>html-resource</em>, which takes an URL as input, and outputs an hash that nicely represents a web-page&#8217;s structure.</p>
<p>What I ended up is <a href="http://github.com/Ejhfast/wordy">wordy</a>, which at the moment can do a simple word-count frequency analysis on a given page. That is, it counts how often words used, filtering (if desired) on word length. In just a bit, I&#8217;ll get into some of the more interesting aspects of coding it  up, but first,  here is a simple use case.</p>
<p>Running the following in slime&#8230;<br />
<code>(graph-words "http://ethanjfast.com" 5 5 1)</code></p>
<p style="text-align: center;"><img class="aligncenter" title="As applied to this blog." src="/images/ethanjfast.com.png" alt="" width="500" /></p>
<p style="text-align: left;">Where the parameters correspond to:</p>
<ul>
<li>ethanjfast.com -&gt; web page to look at</li>
<li>5 -&gt; minimum length (letter count) of word for first anaylsis</li>
<li>5 -&gt; minimum length of word for last anaylsis</li>
<li>1 -&gt; the amount of word length to increment by between the first and last anaylsis</li>
</ul>
<p>To make this a bit clearer, consider a different run:<br />
<code>(graph-words "http://ycombinator.posterous.com" 3 10 3)</code></p>
<p style="text-align: center;"><img class="aligncenter" title="Ycombinator Run" src="/images/ycom2.png" alt="" width="500" /></p>
<p style="text-align: left;">Here wordy does three analyses, with minimum word lengths of 3, 6, and 9 respectively. Clearly, I have some work to do insofar as these graphs look rather pathetic, but it was nice to get incanter working.</p>
<p style="text-align: left;">Now, onto some implementation details. Most of the code is quite simple, so I&#8217;ll just go through a few functions that may have some value to someone learning Clojure. For instance, here is <em>rec-map</em>, a function which recursively traverses the map/list structure returned by <em>html-resource</em>.</p>
<script src="http://gist.github.com/325414.js"></script>
<p>Basically, this function filters out all page content that doesn&#8217;t match specific tags (getting rid of links, css, javascript, ect.) But at first glance, you might wonder why I used <em>trampoline</em> rather than <em>recur</em>. After all, <em>trampoline</em> is used to recurse between two different functions, and it looks very much like <em>rec-map</em> is calling itself. Well, the trick is that I am calling <em>trampoline</em> inside the function passed to map, so <em>recur</em> will fail spectacularly (and in a very confusing manner). So watch out for recursion within anonymous functions!</p>
<p>Here is another bit of code, where I create the graph with Incanter.</p>
<script src="http://gist.github.com/325432.js"></script>
<p>The :group-by parameter is slightly unintuitive. To use it, you make a new vector of labels, each label mapping to a counterpart in the data vector. All data with the same label are then put into the same group (e.g for data ["You" "Me" "I"] [3 2 4] one might use the label vector [0 1 1] to group &#8220;Me&#8221; and &#8220;I&#8221; together). The rest is fairly self-explanatory, but I&#8217;ll mention one thing that I didn&#8217;t know until this morning. You can&#8217;t nest the # function shortcut. For instance, the following would not work:</p>
<p><code>(map #(map #(first %1) %1) lst)</code></p>
<p>It&#8217;s rather obvious in retrospect, I know. But I was dumb enough to try it. That&#8217;s all for now, and the code is available on <a href="http://github.com/Ejhfast/wordy">github</a>.</p>
 <img src="http://blog.ethanjfast.com/wp-content/plugins/feed-statistics.php?view=1&post_id=381" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.ethanjfast.com/2010/03/analyzing-word-frequencies-with-clojure-enlive-and-incanter/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Gajure Now on Clojars</title>
		<link>http://blog.ethanjfast.com/2010/02/gajure-now-on-clojars/</link>
		<comments>http://blog.ethanjfast.com/2010/02/gajure-now-on-clojars/#comments</comments>
		<pubDate>Mon, 22 Feb 2010 18:39:03 +0000</pubDate>
		<dc:creator>Ethan</dc:creator>
				<category><![CDATA[Clojure]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Gajure]]></category>
		<category><![CDATA[Genetic Algorithms]]></category>

		<guid isPermaLink="false">http://blog.ethanjfast.com/?p=351</guid>
		<description><![CDATA[Gajure, my small genetic algorithm framework, is now up on Clojars. Hopefully, this should make it much more convenient to use in a real project. I also added Leiningen support, and if you use Clojure with any frequency, I&#8217;d recommend checking that out.]]></description>
			<content:encoded><![CDATA[<p><a href="http://github.com/Ejhfast/Gajure">Gajure</a>, my small genetic algorithm framework, is now up on <a href="http://clojars.org/gajure">Clojars</a>. Hopefully, this should make it much more convenient to use in a real project. I also added <a href="http://github.com/technomancy/leiningen">Leiningen</a> support, and if you use Clojure with any frequency, I&#8217;d recommend checking that out.</p>
 <img src="http://blog.ethanjfast.com/wp-content/plugins/feed-statistics.php?view=1&post_id=351" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.ethanjfast.com/2010/02/gajure-now-on-clojars/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Clojure :pre and :post</title>
		<link>http://blog.ethanjfast.com/2009/12/clojure-pre-and-post/</link>
		<comments>http://blog.ethanjfast.com/2009/12/clojure-pre-and-post/#comments</comments>
		<pubDate>Wed, 23 Dec 2009 14:54:11 +0000</pubDate>
		<dc:creator>Ethan</dc:creator>
				<category><![CDATA[Clojure]]></category>
		<category><![CDATA[Functional Programming]]></category>
		<category><![CDATA[Gajure]]></category>
		<category><![CDATA[Genetic Algorithms]]></category>

		<guid isPermaLink="false">http://blog.ethanjfast.com/?p=248</guid>
		<description><![CDATA[Courtesy of Hacker News, this morning I stumbled upon a blog post mentioning :pre and :post assertions, a new feature in version 1.1 of Clojure. Given the rather messy nature of several functions in Gajure (my toy genetic algorithm framework), it seemed to me that I had an ideal opportunity to make use of this [...]]]></description>
			<content:encoded><![CDATA[<p>Courtesy of Hacker News, this morning I stumbled upon a <a href="http://blog.fogus.me/2009/12/21/clojures-pre-and-post/">blog post</a> mentioning :pre and :post assertions, a new feature in version 1.1 of Clojure. Given the rather messy nature of several functions in <a href="http://github.com/Ejhfast/Gajure">Gajure</a> (my toy genetic algorithm framework), it seemed to me that I had an ideal opportunity to make use of this new functionality.</p>
<p>For instance, although the function <em>run-ga</em> only takes two parameters, both of them are hashes. Naturally, each must contain a few keys for the genetic algorithm to run properly. Using preconditions, it&#8217;s easy to ensure that the function&#8217;s parameters contain these required keys. For instance:</p>
<pre>
(defn keys-not-nil [lst hash]
  (reduce #(and %1 %2) (map #(not (nil? (hash %))) lst)))
</pre>
<p>This checks each key in a list of keys, and returns false if one or more of these keys maps to a value of nil. Obviously, I could go further here, but checking for non-nil values seemed a reasonable (and easy) generalization (e.g. if <em>:init-fn</em> or <em>:mut-r</em> map to nil, then the <em>ga-run</em> function will have a problem). Now, making use of the :pre tag.</p>
<pre>
(defn run-ga
[func-map setting-map]
{:pre [(and
  (keys-not-nil
    (list :init-fn :fit-fn :mut-fn :sel-fn :cross-fn)
    func-map)
  (keys-not-nil
    (list :pop-sz :gen :children :mut-r)
    setting-map))]}
... actual algorithm ...)
</pre>
<p>So I can now enforce the (arbitrary) required keys, and return assertion errors on some improper uses of <em>ga-run</em>. For a more specific example, look to the algorithm&#8217;s mutation function.</p>
<pre>
(defn generic-mutation
  "Randomly mutates lists with elements from other lists in the population."
  [list prob]
  {:pre [(and (>= prob 1) (<= prob 100))]
   :post [(list? %)]}
  (map
   (fn [s-list]
     (map
      (fn [test]
        (if (> prob (rand-int 100))
          (let [r-s (rand-int (count list))
                r-t (rand-int (count (nth list r-s)))]
            (nth (nth list r-s)
                 r-t))
          test))
      s-list))
   list))
</pre>
<p>Here, the :pre tag ensures that the value of <em>prob</em> is between one and one hundred. Similarly, :post asserts that the function returns a list (although I haven&#8217;t mentioned it, the :post tag operates much like :pre, using a function&#8217;s return value within its assertion). So in spite of my trivial examples, perhaps you can begin to appreciate how these tags can be used to create safer and more predictable code.</p>
 <img src="http://blog.ethanjfast.com/wp-content/plugins/feed-statistics.php?view=1&post_id=248" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.ethanjfast.com/2009/12/clojure-pre-and-post/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>On Parallelism</title>
		<link>http://blog.ethanjfast.com/2009/10/on-parallelism/</link>
		<comments>http://blog.ethanjfast.com/2009/10/on-parallelism/#comments</comments>
		<pubDate>Wed, 07 Oct 2009 13:50:38 +0000</pubDate>
		<dc:creator>Ethan</dc:creator>
				<category><![CDATA[Clojure]]></category>
		<category><![CDATA[Functional Programming]]></category>
		<category><![CDATA[Gajure]]></category>
		<category><![CDATA[Genetic Algorithms]]></category>

		<guid isPermaLink="false">http://blog.ethanjfast.com/?p=70</guid>
		<description><![CDATA[Recently, I read an article describing someone&#8217;s experiments in parallel genetic programming, and so I decided to run my own. As has been mentioned, I am quite fond of functional languages; for me, easy parallelism is simply a pleasant bonus. I do think its worth noting, however, that while functional programming may be generally awesome, throwing [...]]]></description>
			<content:encoded><![CDATA[<p>Recently, I read an article describing someone&#8217;s <a href="http://jan.rychter.com/enblog/2009/8/26/experiments-with-parallel-genetic-programming-in-clojure.html">experiments in parallel genetic programming</a>, and so I decided to run my own. As has been mentioned, I am <a href="http://blog.ethanjfast.com/2009/09/ga-framework/">quite fond</a> of functional languages; for me, easy parallelism is simply a pleasant bonus. I do think its worth noting, however, that while functional programming may be generally awesome, throwing in massive amounts of parallelism is often overkill (certainly when one runs his programs on a lowly Macbook).</p>
<p>Take <a href="http://github.com/Ejhfast/Gajure">Gajure</a>, my unfeature-full framework for creating genetic algorithms. On a whim, I changed out most <em>map</em> functions with <em>pmap</em>, its parallel counterpart, and ran the example code included on github. This took literally two seconds &#8212; for instance, something like roulette-select was changed by two characters:</p>
<pre>(defn roulette-select
  "Select num individuals from pop, with an individual's
   fitness porportional to selection likelihood."
  [pop fit-fn num]
  (let [pop-fits (pmap fit-fn pop)
        inc-fits (iterate (fn [[pfit idx]]
                          [(+ (nth pop-fits
                           (+ idx 1)) pfit) (+ idx 1)])
                          [(first pop-fits) 0])
        max-fitness (apply + pop-fits)
        pick-one (fn [num] (second (first (drop-while
                                         #(&lt; (first %) num)
                                         inc-fits))))]
    (pmap (fn [x] (nth pop (pick-one (rand-int max-fitness))))
               (range num))))</pre>
<p>On the face of things, a genetic algorithm would seem to be a perfect target for parallelism. Within a single generation, fitness computations and mutation operations can be run for each population member completely independent of its compatriots. Alas, such performance gains were not realized &#8212; not, at least, on my humble dual-core machine.</p>
<p>The bottom line: running time more than <strong>doubled</strong> for evolving &#8220;hello world.&#8221; What previously took 1450 ms takes 3162 ms with the new implementation. I will be gathering more representative statistics later on, but probably, the overhead involved in creating parallel mappings outweighs any benefits, given that I only have two processors (on that note, I&#8217;d be curious to know how much nicer things would run in Erlang, where the threads are more lightweight). Another contributing factor is simply the inane simplicity of the problem space; in an ideal case, each fitness evaluation would be doing a bit more work.</p>
<p>So in some sense, my dimwitted &#8220;hello world&#8221; example represents a worse case for the parallel implementation, particularly when run on my relatively underpowered machine. With that, I&#8217;m committing the <em>pmap</em> changes to github under a separate branch, <a href="http://github.com/Ejhfast/Gajure/tree/parallel">here</a>.</p>
 <img src="http://blog.ethanjfast.com/wp-content/plugins/feed-statistics.php?view=1&post_id=70" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.ethanjfast.com/2009/10/on-parallelism/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>A Genetic Algorithm Framework in Clojure</title>
		<link>http://blog.ethanjfast.com/2009/09/ga-framework/</link>
		<comments>http://blog.ethanjfast.com/2009/09/ga-framework/#comments</comments>
		<pubDate>Thu, 03 Sep 2009 18:51:22 +0000</pubDate>
		<dc:creator>Ethan</dc:creator>
				<category><![CDATA[Clojure]]></category>
		<category><![CDATA[Framework]]></category>
		<category><![CDATA[Functional Programming]]></category>
		<category><![CDATA[Gajure]]></category>
		<category><![CDATA[Genetic Algorithms]]></category>

		<guid isPermaLink="false">http://blog.ethanjfast.com/?p=18</guid>
		<description><![CDATA[ functional languages. They are wonderfully powerful, and can easily abstract away a basic algorithm that one might apply to many kinds of problems. With this in mind, I decided to build a framework for constructing genetic algorithms in Clojure.]]></description>
			<content:encoded><![CDATA[<p>I love functional languages. They are wonderfully powerful, and can easily abstract away a basic algorithm that one might apply to many kinds of problems. With this in mind, I decided to build a framework for constructing genetic algorithms in Clojure.  While the definition of <em>framework</em> is surely debatable, what I mean by this (mostly) is that I built something I can reuse. For instance, the first thing I did with with my framework was optimize test suite subsets as part of a program repair technique &#8212; but as you will see, this is far from the only thing it can do!  First, I planned out in pseudocode how I wanted my framework to run. For my readers unfamiliar with them, genetic algorithms apply an evolutionary model to complex problems, attempting to <em>evolve</em> solutions from what is initially a population of random states. But really, a genetic algorithm is just a process, and (at least for my purposes) it boils down to this:</p>
<pre>(defn genetic-algorithm [some-params]
  (initialize-population)
    (loop (generations-that-remain)
      (if (no-generations-left)
         (print-stuff-and-exit)
         (pass-again-to-loop
          (mutate-population
            (crossover-population
              (select-population
               (population))))))</pre>
<p>Since Clojure is a functional language, we can pass problem-specific functions to this process, and it will give us a result. For instance, I might want to define my genetic algorithm such that it accepts functions for initializing population members, sorting them (fitness function), crossing them over, and finally, mutating them. Of course, it should also take parameters that convey setting information, like the number of generations to run, or the mutation rate. Here is what I came up with:</p>
<pre>defn run-ga
  [func-map setting-map]
  (let [ipop ((:init-fn func-map) (:pop-sz setting-map))]
    (loop [pop ipop
           num (:gen setting-map)]
      (if (zero? num)
        (do
          (println (first (sort-by (:fit-fn func-map) &gt; pop ))))
            (let [total-left (- (:pop-sz setting-map)
                                      (:children setting-map))]
              (do
                (println (first (sort-by (:fit-fn func-map) &gt; pop ))))
              (recur
               (concat
                ((:mut-fn func-map)
                 (do-crossover
                  ((:sel-fn func-map)
                   pop
                   (:fit-fn func-map)
                   (* (:children setting-map) 2))
                  (:cross-fn func-map)
                  2)
                 (:mut-r setting-map))
                ((:init-fn func-map) total-left))
               (dec num)))))))</pre>
<p>It takes two maps as its parameters, func-map and setting-map. These serve as easy ways to pass in sets of functions and settings for a given problem. The algorithm follows the basic pseudocode layout I showed earlier, and if you want a more detailed description of its parameters, check it out at <a href="http://github.com/Ejhfast/Gajure/blob/51a0473cc8d0bdc92bbb951abd2aebebd90a8f6e/ga.clj">github</a>.  There is one function in run-ga &#8212; <em>do-crossover</em> &#8212; that is not passed as a parameter, but is rather defined elsewhere. What it does is take a list of parents, and run the problem-specific crossover function provided as a parameter to the algorithm. Its code is also on github, but I will display it here as well.</p>
<pre>(defn do-crossover
  [p-list cross-fn num-parents]
  (map cross-fn (partition num-parents p-list)))</pre>
<p>But now, lets move on to an example problem, and put the framework through its paces! I will pick a very easy problem &#8212; lets evolve &#8220;helloworld&#8221;.  To begin, I will define some aspects of the problem space. The supposed DNA of &#8220;helloworld&#8221; is nothing but a list of characters:</p>
<pre>(def dna (map str
              ['q 'w 'e 'r 't 'y 'u 'i 'o 'p 'a 's 'd 'f 'g 'h 'j 'k 'l
               'z 'x 'c 'v 'b 'n 'm]))</pre>
<p>I also wrote a few helper functions for the genetic algorithm framework, <em>rand-from-list</em> and <em>rand-pop</em>. These are generally useful for creating random populations. The first will return a &#8220;random&#8221; list from a list of elements, made up of the elements in that list. The second will return a list of these random lists. Here they are:</p>
<pre>(defn rand-from-list
  [lst num]
  (let [total-el (count lst)]
    (map (fn [x] (nth lst (rand-int total-el))) (range 0 num))))

(defn rand-pop
  [lst num num-pop]
  (map (fn [x] (rand-from-list lst num)) (range 0 num-pop)))</pre>
<p>Now, lets apply them to dna. A function that initializes a random population of strings might look like this (we are limiting our population to strings of 10 characters):</p>
<pre>(defn some-strings [num]
 (rand-pop dna 10 num))</pre>
<p>This is actually not what I end up doing (in the func-map I end up using a <em>partial</em>) but it is effectively the same thing. On to crossover and mutation:</p>
<pre>(defn list-crossover
  [[s1 s2]]
  (let [point (rand-int
               (min (count s1)
                    (count s2)))]
    (concat (take point s1)
            (drop point s2))))

(defn generic-mutation
  [list prob]
  (map
   (fn [s-list]
     (map
      (fn [test]
        (if (&gt; prob (rand-int 100))
          (let [r-s (rand-int (count list))
                r-t (rand-int (count (nth list r-s)))]
            (nth (nth list r-s)
                 r-t))
          test))
      s-list))
   list))</pre>
<p>These are defined for you by the framework (optionally, if you want to use them). The function <em>list-crossover</em> chooses a cross-point, x, on two lists, and creates a new list made up of the first x elements of one list, and the last (length &#8211; x) elements of the other. Mutation was hard to make generic (and so it is very much imperfect), but it uses the base elements of other population members as an approximation for all the &#8220;genetic material&#8221; that can be swapped in or out of a mutated member. These functions work on most kinds of list populations. In many cases, however, you may need more complex behavior, so they are not hard-coded into the algorithm itself.   Although nearly done, we still lack what is perhaps the most important part, the fitness function. This can be defined in many ways, but I use a system of one point for every directly matching character in the string. Like follows:</p>
<pre>(defn hello-fitness
     [lst]
     (reduce
      +
      (map #(if (= %1 %2) 1 0)
           lst
           '("h" "e" "l" "l" "o" "w" "o" "r" "l" "d"))))</pre>
<p>So, now we can define the maps:</p>
<pre>(def func-map {:fit-fn hello-fitness :mut-fn generic-mutation
               :sel-fn roulette-select :init-fn (partial rand-pop dna 10)
               :cross-fn list-crossover})

(def set-map {:pop-sz 100 :children 50 :mut-r 1 :gen 100})</pre>
<p>Note that roulette-select is another helper created for the framework. Its a simple function, and selects population members with a likelihood proportional to the fitness of each. For the curious, here it is:</p>
<pre>(defn roulette-select
  [pop fit-fn num]
  (let [pop-fits (map fit-fn pop)
        inc-fits (iterate (fn [[pfit idx]]
                             [(+ (nth pop-fits (+ idx 1)) pfit) (+ idx 1)])
                          [(first pop-fits) 0])
        max-fitness (apply + pop-fits)
        pick-one (fn [num] (second (first (drop-while #(&lt; (first %) num)
                        inc-fits))))]
    (map (fn [x] (nth pop (pick-one (rand-int max-fitness)))) (range num))))</pre>
<p>Now, we are finished, so run the algorithm!</p>
<pre>(run-ga func-map set-map)</pre>
<p>Again, all this code (and some missing detail) is available at <a href="http://github.com/Ejhfast/Gajure/tree/51a0473cc8d0bdc92bbb951abd2aebebd90a8f6e">github</a>. Hopefully you found this useful!</p>
 <img src="http://blog.ethanjfast.com/wp-content/plugins/feed-statistics.php?view=1&post_id=18" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.ethanjfast.com/2009/09/ga-framework/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
