<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>writequit (:wq)</title>
	
	<link>http://writequit.org/blog</link>
	<description>Tu fui, ego eris</description>
	<lastBuildDate>Wed, 11 Aug 2010 22:26:20 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/writequit/feed" /><feedburner:info uri="writequit/feed" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>writequit/feed</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item>
		<title>Automatically fold Clojure methods in Vim</title>
		<link>http://feedproxy.google.com/~r/writequit/feed/~3/MK5e68BXUzI/</link>
		<comments>http://writequit.org/blog/?p=413#comments</comments>
		<pubDate>Wed, 11 Aug 2010 22:09:34 +0000</pubDate>
		<dc:creator>Lee</dc:creator>
				<category><![CDATA[clojure]]></category>
		<category><![CDATA[folding]]></category>
		<category><![CDATA[vim]]></category>

		<guid isPermaLink="false">http://writequit.org/blog/?p=413</guid>
		<description><![CDATA[I&#8217;ve been trying to get this working for quite some time, I finally have a semi-working function to fold Clojure methods automatically. First, here&#8217;s a picture of what you can expect to see when using this (click for larger version): And here&#8217;s the code (stick this in your .vimrc): That&#8217;s it, easy as pie, enjoy [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been trying to get this working for quite some time, I finally have a semi-working function to fold Clojure methods automatically.</p>
<p>First, here&#8217;s a picture of what you can expect to see when using this (click for larger version):</p>
<p><a href="http://writequit.org/blog/wp-content/uploads/2010/08/cljfold.png"><img class="aligncenter size-large wp-image-414" title="cljfold" src="http://writequit.org/blog/wp-content/uploads/2010/08/cljfold-1024x640.png" alt="Click me!" width="600" border="false" height="340" /></a></p>
<p>And here&#8217;s the code (stick this in your .vimrc):</p>
<p><script src="http://gist.github.com/519858.js?file=gistfile1.vim"></script></p>
<p>That&#8217;s it, easy as pie, enjoy the folding for Clojure files.</p>
<p>There are a few bugs with this because I&#8217;ve never actually written a Vim plugin, so I kind of hacked my way through this until I got it working. I welcome any feedback from someone with vimscript development experience (I&#8217;m looking at you Brian Carper <img src='http://writequit.org/blog/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> )</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/writequit/feed?a=MK5e68BXUzI:dG4K00BiRtY:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/writequit/feed?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=MK5e68BXUzI:dG4K00BiRtY:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=MK5e68BXUzI:dG4K00BiRtY:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=MK5e68BXUzI:dG4K00BiRtY:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=MK5e68BXUzI:dG4K00BiRtY:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=MK5e68BXUzI:dG4K00BiRtY:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=MK5e68BXUzI:dG4K00BiRtY:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/writequit/feed/~4/MK5e68BXUzI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://writequit.org/blog/?feed=rss2&amp;p=413</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://writequit.org/blog/?p=413</feedburner:origLink></item>
		<item>
		<title>Does Clojure really need another set of introduction slides?</title>
		<link>http://feedproxy.google.com/~r/writequit/feed/~3/koWpg5M87iU/</link>
		<comments>http://writequit.org/blog/?p=404#comments</comments>
		<pubDate>Fri, 30 Apr 2010 03:52:11 +0000</pubDate>
		<dc:creator>Lee</dc:creator>
				<category><![CDATA[clojure]]></category>

		<guid isPermaLink="false">http://writequit.org/blog/?p=404</guid>
		<description><![CDATA[Well, I guess it couldn&#8217;t hurt, I looked at quite a few when coming up with mine (I recently gave an &#8216;Introduction to Clojure&#8217; tech talk to co-workers), so I figure they&#8217;ll be useful to someone in the future. You can download the slides here, or check them out on slideshare: Clojure Intro I&#8217;ve also [...]]]></description>
			<content:encoded><![CDATA[<p>Well, I guess it couldn&#8217;t hurt, I looked at quite a few when coming up with mine (I recently gave an &#8216;Introduction to Clojure&#8217; tech talk to co-workers), so I figure they&#8217;ll be useful to someone in the future.</p>
<p>You can download the slides <a href="http://writequit.org/files/clojure-intro.pdf">here</a>, or check them out on slideshare:</p>
<div id="__ss_3892962" style="width: 425px;"><strong><a title="Clojure Intro" href="http://www.slideshare.net/thnetos/clojure-intro">Clojure Intro</a></strong><object id="__sse3892962" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="425" height="355" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowScriptAccess" value="always" /><param name="src" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=clojure-intro-100428230814-phpapp02&amp;stripped_title=clojure-intro" /><param name="name" value="__sse3892962" /><param name="allowfullscreen" value="true" /><embed id="__sse3892962" type="application/x-shockwave-flash" width="425" height="355" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=clojure-intro-100428230814-phpapp02&amp;stripped_title=clojure-intro" name="__sse3892962" allowscriptaccess="always" allowfullscreen="true"></embed></object></div>
<p></p>
<p>I&#8217;ve also been testing the new 2.2 pre-release of VimClojure (actually using nailgun this time), and it is <em>sweet</em> so far.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/writequit/feed?a=koWpg5M87iU:7vEPDEebUIQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/writequit/feed?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=koWpg5M87iU:7vEPDEebUIQ:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=koWpg5M87iU:7vEPDEebUIQ:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=koWpg5M87iU:7vEPDEebUIQ:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=koWpg5M87iU:7vEPDEebUIQ:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=koWpg5M87iU:7vEPDEebUIQ:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=koWpg5M87iU:7vEPDEebUIQ:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/writequit/feed/~4/koWpg5M87iU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://writequit.org/blog/?feed=rss2&amp;p=404</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://writequit.org/blog/?p=404</feedburner:origLink></item>
		<item>
		<title>How I develop Clojure with Vim</title>
		<link>http://feedproxy.google.com/~r/writequit/feed/~3/vIhze9hePVY/</link>
		<comments>http://writequit.org/blog/?p=386#comments</comments>
		<pubDate>Mon, 15 Mar 2010 17:30:48 +0000</pubDate>
		<dc:creator>Lee</dc:creator>
				<category><![CDATA[clojure]]></category>
		<category><![CDATA[repl]]></category>
		<category><![CDATA[screen]]></category>
		<category><![CDATA[vim]]></category>

		<guid isPermaLink="false">http://writequit.org/blog/?p=386</guid>
		<description><![CDATA[Recently Lau Jensen wrote a post talking about the features of Emacs and why it increases the productivity of Clojure programmers. While I don&#8217;t disagree that lisp programming in general benefits greatly from using Emacs as an editor, there are simply people who are too heavily invested into Vim (like myself) for things like viper-mode [...]]]></description>
			<content:encoded><![CDATA[<p>Recently Lau Jensen wrote <a href="http://www.bestinclass.dk/index.php/2010/03/approaching-productivity/ ">a post talking about the features of Emacs</a> and why it increases the productivity of Clojure programmers. While I don&#8217;t disagree that lisp programming in general benefits greatly from using Emacs as an editor, there are simply people who are too heavily invested into Vim (like myself) for things like viper-mode to work for them. So, I thought I&#8217;d share how I do Clojure development with Vim. Throw in my 2 cents.</p>
<p>The key (for me) to editing Clojure code in Vim is a combination of two plugins, <a href="http://kotka.de/projects/clojure/vimclojure.html ">VimClojure</a> and <a href="http://technotales.wordpress.com/2007/10/03/like-slime-for-vim/ ">slime.vim</a> (<a href="http://technotales.wordpress.com/2007/10/03/like-slime-for-vim/ ">see associated blog post</a>). One of the difficult things is that slime.vim doesn&#8217;t actually exist anywhere on vim.org&#8217;s list of scripts, so it has to be downloaded from the aforementioned blog post. Stick it in the ~/.vim/plugins directory to install it.</p>
<p>First, VimClojure. I tend not to use Nailgun at all, some people like it, I don&#8217;t. So instead of the regular install for vimclojure, I copy over the files from the <strong>autoload</strong>, <strong>doc</strong>, <strong>ftdetect</strong>, <strong>ftplugin</strong>, <strong>indent</strong> and <strong>syntax</strong> folders to their respective Vim folders. If you think you&#8217;ll want the Nailgun functionality, you should use the <a href="http://kotka.de/projects/clojure/vimclojure.html">installation instructions provided by Kotarak</a>.</p>
<p>Now, add the settings you need for VimClojure to your .vimrc:</p>
<blockquote><p><code>" Settings for VimClojure<br />
let g:clj_highlight_builtins=1      " Highlight Clojure's builtins<br />
let g:clj_paren_rainbow=1           " Rainbow parentheses'!</code></p></blockquote>
<p>I have to say, rainbow parentheses&#8217; is one of the best features of vimclojure, making it easy to see exactly what parentheses closes which statement:</p>
<p><a href="http://writequit.org/blog/wp-content/uploads/2010/03/rainbow-paren.png"><img class="aligncenter size-full wp-image-389" title="rainbow-paren" src="http://writequit.org/blog/wp-content/uploads/2010/03/rainbow-paren.png" alt="" width="576" height="195" /></a></p>
<p>Now that VimClojure is set up, time to set up the integration with Clojure&#8217;s REPL, to do that I use slime.vim. Slime.vim uses <a href="http://www.gnu.org/software/screen/">screen</a> to send the input from your editor to any window in a running screen session, so to get started we&#8217;ll have to start up a screen session. To make it easier, you can name it something so you don&#8217;t have to look up the pid, I&#8217;ll call this session &#8220;clojure&#8221;:</p>
<blockquote><p><code>‹ ~ › : screen -S clojure</code></p></blockquote>
<p>If you didn&#8217;t name your session, or forgot what you named it, you can use <code>screen -ls</code> to look up all the screen sessions you&#8217;ve started:</p>
<blockquote><p><code>‹ ~ › : screen -ls<br />
There are screens on:<br />
41837.clojure   (Attached)<br />
8970.ttys000.Xanadu     (Attached)<br />
8990.ttys001.Xanadu     (Attached)<br />
9010.ttys002.Xanadu     (Attached)<br />
4 Sockets in /tmp/screens/S-hinmanm.<br />
</code></p></blockquote>
<p>Now, start a REPL in the screen terminal window (use &#8216;clj&#8217; or &#8216;lein REPL&#8217; or however you like to start a Clojure REPL). Next, open a clojure file with Vim, highlight a block of code (slime.vim will automatically select a paragraph if your cursor is in the middle of something like a defn), now, press <strong>Control-c + Control-c</strong> (Ctrl+c twice in a row). You should be prompted by Vim like this:</p>
<p><a href="http://writequit.org/blog/wp-content/uploads/2010/03/session-prompt.png"><img class="aligncenter size-full wp-image-390" title="session-prompt" src="http://writequit.org/blog/wp-content/uploads/2010/03/session-prompt.png" alt="" width="417" height="50" /></a></p>
<p>Enter the name of the screen term, if you named your session &#8220;clojure&#8221; you&#8217;d enter &#8220;clojure&#8221;, if you didn&#8217;t name it, use the pid number you see from the output of &#8216;screen -ls&#8217;, next it will ask for which window to send the output to:</p>
<p><a href="http://writequit.org/blog/wp-content/uploads/2010/03/window-prompt.png"><img class="aligncenter size-full wp-image-392" title="window-prompt" src="http://writequit.org/blog/wp-content/uploads/2010/03/window-prompt.png" alt="" width="290" height="45" /></a></p>
<p>If you&#8217;ve used screen before (and I&#8217;m assuming you have), this is the window number your REPL is running on. After you enter this information the plugin will send the paragraph/line of text to the REPL. From here on the session id and window will be cached, so hitting <strong>ctrl+c,ctrl+c</strong> again will immediately send whatever function the cursor is on to the REPL. You can also select a block of code using visual mode and use <strong>ctrl+c,ctrl+c</strong> to send everything selected to the REPL. If you used the wrong numbers, use <strong>ctrl+c,v</strong> (Control+c, then v) to have slime.vim ask you for the numbers again.</p>
<p>There you go, you now have a 1-way pipe from your Vim editor to any kind of REPL (be it Clojure, Ruby or Python). Here&#8217;s a couple of screenshots of the plugin in action:</p>
<p><a href="http://writequit.org/blog/wp-content/uploads/2010/03/terminal-split.png"><img class="aligncenter size-medium wp-image-391" title="terminal-split" src="http://writequit.org/blog/wp-content/uploads/2010/03/terminal-split-300x297.png" alt="" width="300" height="297" /></a></p>
<p><a href="http://writequit.org/blog/wp-content/uploads/2010/03/gui-split.png"><img class="aligncenter size-medium wp-image-387" title="gui-split" src="http://writequit.org/blog/wp-content/uploads/2010/03/gui-split-300x187.png" alt="" width="300" height="187" /></a></p>
<p>I know this doesn&#8217;t even come close to the amount of integration the Emacs has using SLIME, but for me, this is exactly what I want out of a Clojure development environment, develop some code and be able to easily send it to a REPL. Hopefully a Vim user or two out there will find this setup useful.</p>
<p><strong>UPDATE</strong>: If you&#8217;re interested in my full Vim setup for some reason, you can check it out <a href="http://github.com/dakrone/dakrone-dotfiles">here</a>.</p>
<p><strong>UPDATE 2</strong>: Want to automagically fold Clojure methods when using Vim? Check out <a href="http://writequit.org/blog/?p=413">this post</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/writequit/feed?a=vIhze9hePVY:pRHDhbh5qs0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/writequit/feed?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=vIhze9hePVY:pRHDhbh5qs0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=vIhze9hePVY:pRHDhbh5qs0:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=vIhze9hePVY:pRHDhbh5qs0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=vIhze9hePVY:pRHDhbh5qs0:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=vIhze9hePVY:pRHDhbh5qs0:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=vIhze9hePVY:pRHDhbh5qs0:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/writequit/feed/~4/vIhze9hePVY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://writequit.org/blog/?feed=rss2&amp;p=386</wfw:commentRss>
		<slash:comments>31</slash:comments>
		<feedburner:origLink>http://writequit.org/blog/?p=386</feedburner:origLink></item>
		<item>
		<title>Context searching using Clojure-OpenNLP</title>
		<link>http://feedproxy.google.com/~r/writequit/feed/~3/JdGK86diH6U/</link>
		<comments>http://writequit.org/blog/?p=351#comments</comments>
		<pubDate>Tue, 09 Mar 2010 18:31:00 +0000</pubDate>
		<dc:creator>Lee</dc:creator>
				<category><![CDATA[clojure]]></category>
		<category><![CDATA[nlp]]></category>
		<category><![CDATA[opennlp]]></category>
		<category><![CDATA[search]]></category>

		<guid isPermaLink="false">http://writequit.org/blog/?p=351</guid>
		<description><![CDATA[This is an addon to my previous post, &#8220;Natural Language Processing in Clojure with clojure-opennlp&#8220;. If you&#8217;re unfamiliar with NLP or the clojure-opennlp library, please read the previous post first. In that post, I told you I was going to use clojure-opennlp to enhance a searching engine, so, let&#8217;s start with the problem! The Problem [...]]]></description>
			<content:encoded><![CDATA[<p>This is an addon to my previous post, &#8220;<a href="http://writequit.org/blog/?p=365">Natural Language Processing in Clojure with clojure-opennlp</a>&#8220;. If you&#8217;re unfamiliar with NLP or the clojure-opennlp library, please read the previous post first.</p>
<p>In that post, I told you I was going to use clojure-opennlp to enhance a searching engine, so, let&#8217;s start with the problem!</p>
<h2>The Problem</h2>
<p>(Ideas first, code coming later. Be patient.)</p>
<p>So, let&#8217;s say you have a sentence:</p>
<blockquote><p>&#8220;The override system is meant to deactivate the accelerator when the brake pedal is pressed.&#8221;</p></blockquote>
<p>I took this sentence out of a NYTimes article talking about the recent Toyota recalls, just pretend it&#8217;s an interesting sentence.</p>
<p>Let&#8217;s say that you wanted to search for things containing the word &#8220;<strong>brake</strong>&#8220;; well, that&#8217;s easy for a computer to do right? But, let&#8217;s say you want to search for things <em>around</em> the word &#8220;<strong>brake</strong>&#8220;, wouldn&#8217;t that make the search better? You would be able to find a lot more articles/pages/books/whatever you might be interested in, instead of ones that only contained the word key word.</p>
<p>So, in a naïve (for a computer) pass for words around the key word, we can come up with this:</p>
<blockquote><p>&#8220;The override system is meant to deactivate the accelerator <span style="color: #ff0000;">when the brake pedal is</span> pressed.&#8221;</p></blockquote>
<p>Right. Well. That really isn&#8217;t helpful, it&#8217;s not like the words &#8220;when&#8221;, &#8220;the&#8221; or &#8220;is&#8221; are going to help us find other things related to this topic. We got lucky with &#8220;pedal&#8221;, that will definitely help find things that are interesting, but might not actually have the word brake in them.</p>
<p>What we really need, is something that can pick words out of the sentence that we can also search for. Almost any human could do this trivially, so here&#8217;s what I&#8217;d probably pick:</p>
<blockquote><p>&#8220;The <span style="color: #ff0000;">override</span> system is meant to <span style="color: #ff0000;">deactivate</span> the <span style="color: #ff0000;">accelerator</span> when the <span style="color: #ff0000;">brake</span> <span style="color: #ff0000;">pedal</span> is pressed.&#8221;</p></blockquote>
<p>See the words in red? Those are the important terms I&#8217;d probably search for if I were trying to find more information about this topic. Notice anything special about them? Turns out, <strong>they&#8217;re all nouns or verbs</strong>. This is where the NLP (Natural Language Processing) comes into play for this, given a sentence like the above, we can categorize it into it&#8217;s parts by doing what&#8217;s called POS-Tagging (POS == Parts Of Speech):</p>
<blockquote><p>["The" "DT"] ["override" "NN"] ["system" "NN"] ["is" "VBZ"] ["meant" "VBN"] ["to" "TO"] ["deactivate" "VB"] ["the" "DT"] ["accelerator" "NN"] ["when" "WRB"] ["the" "DT"] ["brake" "NN"] ["pedal" "NN"] ["is" "VBZ"] ["pressed" "VBN"] ["." "."]</p></blockquote>
<p>So next to each word, we can see what part of speech that word belongs to. Things starting with &#8220;NN&#8221; are nouns, things starting with &#8220;VB&#8221; are verbs. Doing this is non-trivial. (A full list of tags can be found <a href="http://bulba.sdsu.edu/jeanette/thesis/PennTags.html#Word">here</a>). That&#8217;s why there are software libraries written by people smarter than me for doing this sort of thing (*cough* opennlp *cough*). I&#8217;m just writing the Clojure wrappers for the library.</p>
<p>Anyway, back to the problem, so what I need to do is strip out all the non-noun and non-verb words in the sentence, that leaves us with this:</p>
<blockquote><p>["override" "NN"] ["system" "NN"] ["is" "VBZ"] ["meant" "VBN"] ["deactivate" "VB"] ["accelerator" "NN"] ["brake" "NN"] ["pedal" "NN"] ["is" "VBZ"] ["pressed" "VBN"]</p></blockquote>
<p>We&#8217;re getting closer, right? Now, searching for things like &#8220;is&#8221; probably won&#8217;t help, so let&#8217;s strip out all the words with less than 3 characters:</p>
<blockquote><p>["override" "NN"] ["system" "NN"] ["meant" "VBN"] ["deactivate" "VB"] ["accelerator" "NN"] ["brake" "NN"] ["pedal" "NN"] ["pressed" "VBN"]</p></blockquote>
<p>Now we get to a point where we have to make some kind of decision about what terms to use, for this project, I decided to weight the terms that were nearer to the original search term, only taking two of the closest words in each direction, after scoring this sentence you get:</p>
<blockquote><p>["override" <span style="color: #ff0000;">0</span>] ["system" <span style="color: #ff0000;">0</span>] ["meant" <span style="color: #ff0000;">0</span>] ["deactivate" <span style="color: #ff0000;">0.25</span>] ["accelerator" <span style="color: #ff0000;">0.5</span>] ["brake" <span style="color: #ff0000;">1</span>] ["pedal" <span style="color: #ff0000;">0.5</span>] ["pressed" <span style="color: #ff0000;">0.25</span>]</p></blockquote>
<p>The red next to each word indicates how heavily we&#8217;ll weight each word when we use it for subsequent searches. The score is divided by 2 for each unit of distance away from the original key term. Not perfect, but it works pretty well.</p>
<p>That was pretty easy to follow, right? Now imagine having a large body of text, and a term. First you&#8217;d generate a list of key words from sentences directly containing the term, score them each and store them in a big map. On a second pass, you can start scoring each sentence by using the map of words =&gt; scores you&#8217;ve already built. In this way, you can then rank sentences, <em>including those that don&#8217;t even contain the actual word you&#8217;ve searched for, but are still relevant to the original term</em>. Now, my friend, you have context searching.</p>
<p>Congratulations, that was a really long explanation. It ended up being a bit more like pseudocode, right? (or at least an idea of how to construct a program). Hopefully after understand the previous explanation, the code should be easy to read.</p>
<h2>The Code</h2>
<p>(note: this is very rough code, I know it&#8217;s not entirely idiomatic and has a ton of room for enhancement and parallelization, feel free to suggest improvements in the comments however!)</p>
<p><script src="http://gist.github.com/324944.js?file=contextfinder.clj"></script></p>
<p>The most important functions to check out are <code>(score-words [term words])</code> method, which returns a list of vectors of words and their score, and the <code>(get-scored-terms )</code> method, which returns a map of words as keys and scores as values for the entire text, given the initial term.</p>
<p>Here&#8217;s the output from the last few lines:</p>
<p><code><strong>contextfinder=&gt;</strong> <strong>(pprint (reverse (sort-by second (score-sentences mytext scorewords))))</strong><br />
(["The override system is meant to deactivate the accelerator when the brake pedal is pressed. " <span style="color: #ff0000;">13/4</span>]<br />
["The Obama administration is considering requiring all automobiles to contain a brake override system intended to prevent sudden acceleration episodes like those that have led to the recall of millions of Toyotas, the Transportation secretary, Ray LaHood, said Tuesday. " <span style="color: #ff0000;">5/2</span>]<br />
["Often called a \"smart pedal,\" the feature is already found on many automobiles sold worldwide, including models from BMW, Chrysler, Mercedes-Benz, Nissan and Volkswagen." <span style="color: #ff0000;">3/4</span>]<br />
["That will let the driver stop safely even if the cars throttle sticks open. " <span style="color: #ff0000;">0</span>])</code></p>
<p>I highlighted the score for each sentence in red, see how sentences such as the third in the list have a score, but don&#8217;t contain the word &#8220;brake&#8221;? Those would have been missed entirely without this kind of searching.</p>
<p><code><strong>contextfinder=&gt; (println (score-text mytext scorewords))</strong><br />
13/2</code></p>
<p>Score a whole block of text, self-explanatory.</p>
<p>Anyway, I&#8217;ve already spent hours writing the explanation for <strong>why</strong> you&#8217;d want to do this sort of searching, so I think I&#8217;ll save the explanation of the code for another post. Hopefully it&#8217;s clear enough to stand on its own. If you find this interesting, I encourage you to check out <a href="http://github.com/dakrone/clojure-opennlp">the clojure-opennlp bindings</a> and start building other cool linguistic tools!</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/writequit/feed?a=JdGK86diH6U:ZUvSz8bab08:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/writequit/feed?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=JdGK86diH6U:ZUvSz8bab08:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=JdGK86diH6U:ZUvSz8bab08:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=JdGK86diH6U:ZUvSz8bab08:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=JdGK86diH6U:ZUvSz8bab08:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=JdGK86diH6U:ZUvSz8bab08:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=JdGK86diH6U:ZUvSz8bab08:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/writequit/feed/~4/JdGK86diH6U" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://writequit.org/blog/?feed=rss2&amp;p=351</wfw:commentRss>
		<slash:comments>5</slash:comments>
		<feedburner:origLink>http://writequit.org/blog/?p=351</feedburner:origLink></item>
		<item>
		<title>Natural Language Processing in Clojure with clojure-opennlp</title>
		<link>http://feedproxy.google.com/~r/writequit/feed/~3/uZlNSSTgejE/</link>
		<comments>http://writequit.org/blog/?p=365#comments</comments>
		<pubDate>Mon, 08 Mar 2010 20:51:57 +0000</pubDate>
		<dc:creator>Lee</dc:creator>
				<category><![CDATA[clojure]]></category>
		<category><![CDATA[nlp]]></category>
		<category><![CDATA[opennlp]]></category>

		<guid isPermaLink="false">http://writequit.org/blog/?p=365</guid>
		<description><![CDATA[NOTE: I am not a linguist, please feel free to correct me in the comments if I use the wrong term! From Wikipedia: Natural Language processing (NLP) is a field of computer science and linguistics concerned with the interactions between computers and human (natural) languages. Natural language generation systems convert information from computer databases into [...]]]></description>
			<content:encoded><![CDATA[<p><strong>NOTE:</strong> I am not a linguist, <em>please</em> feel free to correct me in the comments if I use the wrong term!</p>
<p>From <a href="http://en.wikipedia.org/wiki/Natural_language_processing">Wikipedia</a>:</p>
<p><strong>Natural Language processing (NLP)</strong> is a field of computer science and linguistics concerned with the interactions between computers and human (natural) languages. Natural language generation systems convert information from computer databases into readable human language. Natural language understanding systems convert samples of human language into more formal representations such as parse trees or first-order logic structures that are easier for computer programs to manipulate. Many problems within NLP apply to both generation and understanding; for example, a computer must be able to model morphology (the structure of words) in order to understand an English sentence, and a model of morphology is also needed for producing a grammatically correct English sentence.</p>
<p><a href="http://github.com/dakrone/clojure-opennlp">Clojure-opennlp</a> is a library to interface with the OpenNLP (Open Natural Language Processing) library of functions, which provide linguistic tools to perform on various blocks of text. Once a linguistic interpretation of text is possible, a lot of really interesting applications present themselves. Let&#8217;s jump right in!</p>
<h2>Basic Example usage (from a REPL)</h2>
<blockquote><p><code>(use 'clojure.contrib.pprint) ; just for this example<br />
(use 'opennlp.nlp) ; make sure opennlp.jar is in your classpath</code></p></blockquote>
<p>You will need to make the processing functions using the model files. These assume you&#8217;re running from the root project directory of the git repository (where some models are included). You can also download the model files from the opennlp project at <a href="http://opennlp.sourceforge.net/models/">http://opennlp.sourceforge.net/models/</a></p>
<blockquote><p><code>user=&gt; (def get-sentences (make-sentence-detector "models/EnglishSD.bin.gz"))<br />
user=&gt; (def tokenize (make-tokenizer "models/EnglishTok.bin.gz"))<br />
user=&gt; (def pos-tag (make-pos-tagger "models/tag.bin.gz"))</code></p></blockquote>
<p>For name-finders in particular, it&#8217;s possible to have multiple model files:</p>
<blockquote><p><code>user=&gt; (def name-find (make-name-finder "models/namefind/person.bin.gz" "models/namefind/organization.bin.gz"))</code></p></blockquote>
<p>The <code>(make-&lt;whateverizer&gt; "modelfile.bin.gz")</code> functions return functions that perform the linguistic offering. I decided to have them return functions so multiple methods doing the same sort of action could be created with different model files (perhaps different language models and such) without having the pass the model file every time you wanted to process some text.</p>
<p>After creating the utility methods, we can use the functions to perform operations on text. For instance, since we defined the sentence-detector as &#8216;get-sentences&#8217;, we can us that method to split text by sentences:</p>
<blockquote><p><code>user=&gt; (pprint (get-sentences "First sentence. Second sentence? Here is another one. And so on and so forth - you get the idea..."))<br />
["First sentence. ", "Second sentence? ", "Here is another one. ",<br />
"And so on and so forth - you get the idea..."]<br />
nil</code></p></blockquote>
<p>Or split a sentence into tokens using the tokenize function:</p>
<blockquote><p><code>user=&gt; (pprint (tokenize "Mr. Smith gave a car to his son on Friday"))<br />
["Mr.", "Smith", "gave", "a", "car", "to", "his", "son", "on",<br />
"Friday"]<br />
nil</code></p></blockquote>
<p>Once we have a sequence of tokens, we can do what&#8217;s called POS Tagging. POS Tagging takes a list of words from only one sentence and applies an algorithms (using the morphology model) to determine what kind of tag to apply to each word:</p>
<blockquote><p><code>user=&gt; (pprint (pos-tag (tokenize "Mr. Smith gave a car to his son on Friday.")))<br />
(["Mr." "NNP"]<br />
["Smith" "NNP"]<br />
["gave" "VBD"]<br />
["a" "DT"]<br />
["car" "NN"]<br />
["to" "TO"]<br />
["his" "PRP$"]<br />
["son" "NN"]<br />
["on" "IN"]<br />
["Friday." "NNP"])<br />
nil</code></p></blockquote>
<p>You can check out <a href="http://bulba.sdsu.edu/jeanette/thesis/PennTags.html">a list of all the tags</a> if you want to know what they stand for.</p>
<p>The clojure-opennlp library also features a name finder, however it is extremely rudimentary at this point and won&#8217;t detect all names:</p>
<blockquote><p><code>user=&gt; (name-find (tokenize "My name is Lee, not John."))<br />
("Lee" "John")</code></p></blockquote>
<h2>Filters</h2>
<p>In the library, I also provide some simple filters that can be used to pare down a list of pos-tagged tokens using regular expressions. There are some preset filters available, as well as a macro for generating your own filters:</p>
<blockquote><p><code>(use 'opennlp.tools.filters)</code></p>
<p><code> </code><code>user=&gt; (pprint (nouns (pos-tag (tokenize "Mr. Smith gave a car to his son on Friday."))))<br />
(["Mr." "NNP"]<br />
["Smith" "NNP"]<br />
["car" "NN"]<br />
["son" "NN"]<br />
["Friday" "NNP"])<br />
nil<br />
user=&gt; (pprint (verbs (pos-tag (tokenize "Mr. Smith gave a car to his son on Friday."))))<br />
(["gave" "VBD"])<br />
nil</code></p></blockquote>
<p>Creating your own filter:</p>
<blockquote><p><code>user=&gt; (pos-filter determiners #"^DT")<br />
#'user/determiners<br />
user=&gt; (doc determiners)<br />
-------------------------<br />
user/determiners<br />
([elements__52__auto__])<br />
Given a list of pos-tagged elements, return only the determiners in a list.<br />
nil<br />
user=&gt; (pprint (determiners (pos-tag (tokenize "Mr. Smith gave a car to his son on Friday."))))<br />
(["a" "DT"])<br />
nil<br />
</code></p></blockquote>
<p>Check out the <a href="http://github.com/dakrone/clojure-opennlp/blob/master/src/opennlp/tools/filters.clj">filters.clj</a> file for a full list of out-of-the-box filters.</p>
<p>That&#8217;s about all there is in the library at the moment, so I hope that made sense. Unfortunately clojars.org does not provide a nice way to public documentation for a library, so the documentation in this post and on the github page will have to do for now.</p>
<p>This library is <a href="http://clojars.org/org.clojars.thnetos/opennlp">available on clojars</a> for inclusion in leiningen projects, or <a href="http://github.com/dakrone/clojure-opennlp">on github</a> if you&#8217;re interested in the source. This is a fairly new project, and not all OpenNLP features are exposed at the moment so feedback is definitely encouraged. In the next post I&#8217;ll explain an in-depth example of how these functions can be used to enhance a searching engine. <strong>EDIT</strong>: It&#8217;s up! Check out &#8220;<a href="http://writequit.org/blog/?p=351">Context searching using clojure-opennlp</a>.&#8221;</p>
<p><strong>UPDATE</strong>: Hiredman has let me know that the jar on clojars is missing the 3 dependencies used for the library. I&#8217;m busy working on writing pom.xml&#8217;s for the jars so I can upload them to clojars as dependencies. In the meantime, make sure you have <a href="http://github.com/dakrone/clojure-opennlp/tree/master/lib/">the 3 jars in the lib directory (of the github project)</a> in your classpath. Feel free to report any other issues on the github tracker or in the comments.</p>
<p><strong>UPDATE 2</strong>: I fixed the project.clj file and pushed new versions of opennlp.jar and the dependency jars. A regular &#8216;lein deps&#8217; should work now.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/writequit/feed?a=uZlNSSTgejE:-0MZTt2MxuU:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/writequit/feed?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=uZlNSSTgejE:-0MZTt2MxuU:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=uZlNSSTgejE:-0MZTt2MxuU:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=uZlNSSTgejE:-0MZTt2MxuU:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=uZlNSSTgejE:-0MZTt2MxuU:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=uZlNSSTgejE:-0MZTt2MxuU:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=uZlNSSTgejE:-0MZTt2MxuU:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/writequit/feed/~4/uZlNSSTgejE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://writequit.org/blog/?feed=rss2&amp;p=365</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://writequit.org/blog/?p=365</feedburner:origLink></item>
		<item>
		<title>Annoyance, colored diffs in perforce</title>
		<link>http://feedproxy.google.com/~r/writequit/feed/~3/RhA7l4UvRYA/</link>
		<comments>http://writequit.org/blog/?p=341#comments</comments>
		<pubDate>Mon, 01 Feb 2010 15:40:09 +0000</pubDate>
		<dc:creator>Lee</dc:creator>
				<category><![CDATA[color]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[perforce]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[terminal]]></category>

		<guid isPermaLink="false">http://writequit.org/blog/?p=341</guid>
		<description><![CDATA[Quick one-off here, let&#8217;s begin. Git has nice colored diffs, like this: Perforce does not: A simple script can remedy this: Here&#8217;s the script: Simply drop it somewhere in your $PATH and use it like so: p4 diff &#124; p4c.rb You can find it in my one-offs directory (it&#8217;s called p4c.rb). We recently switched from [...]]]></description>
			<content:encoded><![CDATA[<p>Quick one-off here, let&#8217;s begin.</p>
<p>Git has nice colored diffs, like this:</p>
<p><a href="http://writequit.org/blog/wp-content/uploads/2010/01/gitdiff.png"><img class="aligncenter size-medium wp-image-342" title="gitdiff" src="http://writequit.org/blog/wp-content/uploads/2010/01/gitdiff-300x92.png" alt="" width="300" height="92" /></a></p>
<p>Perforce does not:</p>
<p><a href="http://writequit.org/blog/wp-content/uploads/2010/01/p4diff.png"><img class="aligncenter size-medium wp-image-344" title="p4diff" src="http://writequit.org/blog/wp-content/uploads/2010/01/p4diff-300x71.png" alt="" width="300" height="71" /></a></p>
<p>A simple script can remedy this:</p>
<p><a href="http://writequit.org/blog/wp-content/uploads/2010/01/p4cdiff.png"><img class="aligncenter size-medium wp-image-343" title="p4cdiff" src="http://writequit.org/blog/wp-content/uploads/2010/01/p4cdiff-300x68.png" alt="" width="300" height="68" /></a></p>
<p>Here&#8217;s the script:</p>
<p><script src="http://gist.github.com/291489.js?file=p4c.rb"></script></p>
<p>Simply drop it somewhere in your $PATH and use it like so:</p>
<blockquote><p><code>p4 diff | p4c.rb</code></p></blockquote>
<p>You can find it in <a href="http://github.com/dakrone/one-offs">my one-offs directory</a> (it&#8217;s called <span style="text-decoration: underline;">p4c.rb</span>). We recently switched from subversion to perforce (<strong>definitely</strong> not my choice, I pushed for git), and so far it&#8217;s awful. I am definitely not a fan. This makes it a little better.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/writequit/feed?a=RhA7l4UvRYA:2AaiG_qzuU4:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/writequit/feed?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=RhA7l4UvRYA:2AaiG_qzuU4:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=RhA7l4UvRYA:2AaiG_qzuU4:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=RhA7l4UvRYA:2AaiG_qzuU4:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=RhA7l4UvRYA:2AaiG_qzuU4:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=RhA7l4UvRYA:2AaiG_qzuU4:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=RhA7l4UvRYA:2AaiG_qzuU4:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/writequit/feed/~4/RhA7l4UvRYA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://writequit.org/blog/?feed=rss2&amp;p=341</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://writequit.org/blog/?p=341</feedburner:origLink></item>
		<item>
		<title>CBench, simple benchmarking for Clojure</title>
		<link>http://feedproxy.google.com/~r/writequit/feed/~3/ilAzYbghqIQ/</link>
		<comments>http://writequit.org/blog/?p=332#comments</comments>
		<pubDate>Wed, 09 Dec 2009 23:38:41 +0000</pubDate>
		<dc:creator>Lee</dc:creator>
				<category><![CDATA[benchmark]]></category>
		<category><![CDATA[cbench]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[github]]></category>

		<guid isPermaLink="false">http://writequit.org/blog/?p=332</guid>
		<description><![CDATA[How many times have you written something like this in Clojure when you&#8217;re trying to benchmark some code: (time (dotimes [_ 10000] (my-function arg1 arg2 arg3)) I normally end up writing something equivalent to that all the time to test reflection vs. type-hinted Clojure code, subtle tweaks and other things. Well, I finally got fed [...]]]></description>
			<content:encoded><![CDATA[<p>How many times have you written something like this in <a href="http://clojure.org">Clojure</a> when you&#8217;re trying to benchmark some code:</p>
<blockquote><p><code>(time (dotimes [_ 10000] (my-function arg1 arg2 arg3))</code></p></blockquote>
<p>I normally end up writing something equivalent to that all the time to test reflection vs. type-hinted Clojure code, subtle tweaks and other things. Well, I finally got fed up extrapolating the information I wanted from the output of time (and time didn&#8217;t expressly return a number I could do anything with, just printed a string), so I wrote a small library for doing benchmarks a number of times. I called it CBench because I couldn&#8217;t think of anything that sounded Clojure-ish (bench-jure? clo-bench? etc).</p>
<p>Anyway, jumping straight in, here&#8217;s how it&#8217;s used, let&#8217;s say you have a couple of functions you want to test (super-simple examples):</p>
<blockquote><p><code>(defn inc-no-hint [n] (inc n))<br />
(defn inc-with-hints [#^Integer n] (inc n))<br />
</code></p></blockquote>
<p>With cbench, you can perform benchmarking with a number of iterations. CBench provides 2 functions: <span style="text-decoration: underline;"><strong>cbench</strong></span> and <span style="text-decoration: underline;"><strong>cbench-pp</strong></span>. cbench-pp performs exactly like cbench, but prints a nice display instead of returning a vector of results. In this example, we&#8217;ll use cbench-pp:</p>
<blockquote><p><code>(use 'cbench) ; cbench.jar must be in your classpath<br />
(cbench-pp 10000 #(inc-no-hint (rand-int 100)))<br />
(cbench-pp 10000 #(inc-with-hints (rand-int 100)))</code></p></blockquote>
<p>Run this in a REPL (or a script), and you&#8217;ll see this output:</p>
<blockquote><p><code>-----------------------------------<br />
| avg    | 0.0161 ms<br />
| min    | 0.0 ms<br />
| max    | 26.0 ms<br />
| stddev | 0.17861615575831605 ms<br />
| total  | 570 ms<br />
-----------------------------------<br />
-----------------------------------<br />
| avg    | 0.0012 ms<br />
| min    | 0.0 ms<br />
| max    | 8.0 ms<br />
| stddev | 0.04897999523196905 ms<br />
| total  | 238 ms<br />
-----------------------------------</code></p></blockquote>
<p>CBench gives the average time a run took, minimum, maximum, standard deviation and total time for running 10000 runs of each function. In this example we can see that type-hinting has made a &gt; 10x improvement in average run time (note: this is a contrived example which doesn&#8217;t actually mean much other than hinting is faster than non-hinting).</p>
<p>If we wanted only the results as numbers, use the cbench function, in a REPL you can see the output:</p>
<blockquote><p><code>user=&gt; (cbench 10000 #(inc-with-hints (rand-int 100)))<br />
[0.0032 22.0 0.0 0.07995998518952234 52]</code></p></blockquote>
<p>The result is a vector (in the same order as the pretty-print version).</p>
<p>If you&#8217;re interested, the library is available from <a href="http://clojars.org/org.clojars.thnetos/cbench">Clojars.org here</a>, you can <a href="http://github.com/dakrone/cbench/raw/master/cbench.jar">get just the jar</a>, or you can check out the source code at the <a href="http://github.com/dakrone/cbench/">Github project page</a>. Feel free to drop me an email, IM or github message if you like/dislike the library.</p>
<p>Oh yea, and on a non-technical note, I started a Tumblr blog so I can paste things I find interesting of a non-technical sort. If you&#8217;re into that sort of thing, feel free to <a href="http://writequit.tumblr.com">check it out</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/writequit/feed?a=ilAzYbghqIQ:oKCd4bQtM3A:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/writequit/feed?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=ilAzYbghqIQ:oKCd4bQtM3A:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=ilAzYbghqIQ:oKCd4bQtM3A:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=ilAzYbghqIQ:oKCd4bQtM3A:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=ilAzYbghqIQ:oKCd4bQtM3A:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=ilAzYbghqIQ:oKCd4bQtM3A:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=ilAzYbghqIQ:oKCd4bQtM3A:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/writequit/feed/~4/ilAzYbghqIQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://writequit.org/blog/?feed=rss2&amp;p=332</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://writequit.org/blog/?p=332</feedburner:origLink></item>
		<item>
		<title>Building a Google Wave robot in Clojure</title>
		<link>http://feedproxy.google.com/~r/writequit/feed/~3/0FIkS1KrKhA/</link>
		<comments>http://writequit.org/blog/?p=323#comments</comments>
		<pubDate>Thu, 29 Oct 2009 23:55:13 +0000</pubDate>
		<dc:creator>Lee</dc:creator>
				<category><![CDATA[appspot]]></category>
		<category><![CDATA[clojure]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[wave]]></category>

		<guid isPermaLink="false">http://writequit.org/blog/?p=323</guid>
		<description><![CDATA[I&#8217;ve seen a few different posts circulating around on how to build a robot for Wave in Clojure, so I&#8217;ll throw mine in the pool. I started off creating a text-replacement robot in Java, but decided to switch it over to Clojure and to make something semi useful. I ended up making a robot to [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve seen a few different posts circulating around on how to build a robot for <a href="http://google.com/wave">Wave</a> in <a href="http://clojure.org">Clojure</a>, so I&#8217;ll throw mine in the pool.</p>
<p>I started off creating a <a href="http://code.google.com/apis/wave/extensions/robots/java-tutorial.html">text-replacement robot in Java</a>, but decided to switch it over to Clojure and to make something semi useful. I ended up making a robot to calculate Dungeons &amp; Dragons dice rolls (so something like &#8217;3d8&#8242; means roll an 8-sided die 3 times and add the results). The idea being you could type something like:</p>
<p>&#8220;I cast Magic Missle, 2d6&#8243;</p>
<p>and this robot would replace it with the text:</p>
<p>&#8220;I cast Magic Missle, 2d6 (5)&#8221;</p>
<p>Where 5 is the number that was given. See screenshot below:</p>
<p><a href="http://writequit.org/blog/wp-content/uploads/2009/10/clojurebot.png"><img class="aligncenter size-full wp-image-324" title="clojurebot" src="http://writequit.org/blog/wp-content/uploads/2009/10/clojurebot.png" border="0" alt="clojurebot" width="75%" /></a></p>
<p>So, let&#8217;s go through how to make this robot. I&#8217;m going to end up skipping most of the gritty details of getting the actual robot set up and refer you to <a href="http://spanx.wordpress.com/2009/07/23/clojure-robot-on-google-wave/">this well-written post about the subject</a>, <span style="color: #ff0000;">be sure to follow all the instructions and you should have a usable clojure-bot for Google Wave</span>. This post will cover a basic explanation of the (basic) code used for the actual robot.</p>
<p>Finished reading the other post and playing with the code? Cool, here&#8217;s what my <code>servlet.clj</code> looks like:</p>
<p><script src="http://gist.github.com/221909.js"></script></p>
<p>So, let&#8217;s go through each function and explain it.</p>
<blockquote>
<pre>(ns bibly.servlet
  (:gen-class :extends com.google.wave.api.AbstractRobotServlet)
  (:import
    [com.google.appengine.api.users UserServiceFactory]
    [com.google.wave.api Blip Event EventType RobotMessageBundle TextView Wavelet])
  (:require
            ))</pre>
</blockquote>
<p>The (ns bibly.servlet) code puts us into the bibly.servlet namespace and inside that namespace, we&#8217;re doing 3 things:</p>
<p>1. Generating a class that extends Google&#8217;s AbstractRobotServlet class. (Exactly what you would do in order to build a robot in Java).<br />
2. Importing Google&#8217;s java object<br />
3. Requiring the parts of the clojure-contrib library that we need.</p>
<blockquote>
<pre>(defn blip-submitted-events
  [events]
  (filter (fn [e] (= (EventType/BLIP_SUBMITTED) (.getType e))) events))</pre>
</blockquote>
<p>This function (taken directly from spanx) is a filter that returns only the events that match EventType.BLIP_SUBMITTED.</p>
<blockquote>
<pre>(defn roll-die
  "Roll a die with  sides."
  [sides]
  (+ 1 (rand-int sides)))</pre>
</blockquote>
<p>This function returns a dice roll (Integer) for a die with &lt;sides&gt; sides. (I removed the commented out line)</p>
<blockquote>
<pre>(defn calculate-rolls
  "Given a re-pattern match group, calculate the dice roll"
  [txt]
  (let [string (first txt)
        dice (Integer. (second txt))
        sides (Integer. (nth txt 2))]
    (str string " (" (reduce + (take dice (repeatedly #(roll-die sides)))) ")")))</pre>
</blockquote>
<p>Calualte-rolls is the main function for determining the roll, a vector is passed in, that looks like <code>["1d6" "1" "6"]</code>, this function then assigns each of the 3 values to a variable. Calculate-rolls then <strong>repeatedly</strong> calls <code>(roll-die sides)</code> <strong>dice</strong> times, reducing the list of results by adding them together. For example, if this function were passed ["2d4" "2" "4"] , it would take a list of 2 (dice) rolls of a die with 4 (sides), and add them together to get the new value.</p>
<p>After reducing to the result integer, a string concatenating the result to the new string is returned. So for the example vector <code>["1d6" "1" "6"]</code> (roll a 6-sided die once), the result would be a string: <code>"1d6 (4)"</code>.</p>
<blockquote>
<pre>(defn roll
  "Given a text DnD dice roll, replace it with the calculated result."

  (str-utils2/replace text (re-pattern #"(\d+)d(\d+)") calculate-rolls))</pre>
</blockquote>
<p>The roll function takes a string containing a XdY statement, and expands the roll inside of the string.</p>
<blockquote>
<pre>(defn replace-rolls
  "Replace all the rolls in a given blip."
  [blip]
  (let [view (.getDocument blip)
        text (.getText view)]
    (.replace view (roll text))))</pre>
</blockquote>
<p>Replace-rolls does the exact thing roll does for a string, just doing it for a given blip. First we get the document contained by a blip, and the text in that document, then replace it with the text that the <code>(roll "...")</code> function returns.</p>
<blockquote>
<pre>(defn -processEvents
  [this bundle]
  (let [wavelet (.getWavelet bundle)]
    (doseq [event (blip-submitted-events (.getEvents bundle))]
      (replace-rolls (.getBlip event)))))</pre>
</blockquote>
<p>Finally, the -processEvents function, which is the function google wave automatically calls when a capability matching those in capabilities.xml happens, is this function we perform the <code>(replace-rolls ...)</code> function on the list of events filtered by the <code>(blip-submitted-events ...)</code> function.</p>
<p>Well, I hope this example makes sense. Again, 95% of the work for this goes to <a href="http://spanx.wordpress.com/2009/07/23/clojure-robot-on-google-wave/">Spanx</a>&#8216;s post for getting the initial setup, I figured it would be nice to have another example explaining the actual Clojure code for a simple robot&#8217;s inner workings.</p>
<p>You can download the code for this DnD robot from <a href="http://github.com/dakrone/biblybot/">my github project</a>, or Spanx&#8217;s censorbot example from <a href="http://github.com/indmill/censorbot">his github project</a>.</p>
<p>This example isn&#8217;t perfect, it needs a lot of work before it&#8217;s actually useful, but I thought it was neat.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/writequit/feed?a=0FIkS1KrKhA:2oLwkhA2Zy0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/writequit/feed?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=0FIkS1KrKhA:2oLwkhA2Zy0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=0FIkS1KrKhA:2oLwkhA2Zy0:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=0FIkS1KrKhA:2oLwkhA2Zy0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=0FIkS1KrKhA:2oLwkhA2Zy0:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=0FIkS1KrKhA:2oLwkhA2Zy0:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=0FIkS1KrKhA:2oLwkhA2Zy0:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/writequit/feed/~4/0FIkS1KrKhA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://writequit.org/blog/?feed=rss2&amp;p=323</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://writequit.org/blog/?p=323</feedburner:origLink></item>
		<item>
		<title>Process pooling with a Rinda Tuplespace</title>
		<link>http://feedproxy.google.com/~r/writequit/feed/~3/OVFPbBux0G4/</link>
		<comments>http://writequit.org/blog/?p=315#comments</comments>
		<pubDate>Tue, 25 Aug 2009 22:28:49 +0000</pubDate>
		<dc:creator>Lee</dc:creator>
				<category><![CDATA[forkify]]></category>
		<category><![CDATA[rinda]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[tuplespace]]></category>

		<guid isPermaLink="false">http://writequit.org/blog/?p=315</guid>
		<description><![CDATA[I going to talk about how I&#8217;m doing the process pooling in Forkify in this post, so let&#8217;s get started. Feel free to look up the code or fork the project from the Github Forkify project. The case for pool forking So, why even do pooling instead of serial forking? Let&#8217;s look at an example: [...]]]></description>
			<content:encoded><![CDATA[<p>I going to talk about how I&#8217;m doing the process pooling in <a href="http://writequit.org/blog/?p=300">Forkify</a> in this post, so let&#8217;s get started.</p>
<p>Feel free to look up the code or fork the project from the <a href="http://github.com/dakrone/forkify/tree/master">Github Forkify project</a>.</p>
<h2>The case for pool forking</h2>
<p>So, why even do pooling instead of serial forking? Let&#8217;s look at an example:</p>
<blockquote><p><code>[1, 2, 6, 1, 2, 3].forkify(3) { |n| sleep(n); }</code></p></blockquote>
<p>What happens in the background when this is run &#8211; forkify will fork 3 processes at a time, each one sleeping for the array&#8217;s number, so for the first pass 3 processes will be created, sleeping for 1 second, 2 seconds and 6 seconds (respectively). Forkify will then do a Process.waitpid(&lt;pid&gt;) on all 3 of the processes.</p>
<p>It will end up waiting a tiny bit over 6 seconds (because the longest process will take 6 seconds to finish).</p>
<p>Next, it will create 3 more processes, which will sleep for 1, 2 and 3 seconds respectively.</p>
<p>This will take a bit over 3 seconds.</p>
<p>So, the total time will end up being a little over 9 (6 + 3) seconds (the extra is overhead). Seen here:</p>
<blockquote><p><code>% time ruby -I lib -rforkify -e '[1, 2, 6, 1, 2, 3].forkify(3) { |n| sleep(n); }'<br />
0.08s user 0.10s system 1% cpu <strong>9.131 total</strong></code></p></blockquote>
<h2>How it works with a pool</h2>
<p>Let&#8217;s take the same example and see how it works for pool forking:</p>
<blockquote><p><code>[1, 2, 6, 1, 2, 3].forkify(:procs =&gt; 3, :method =&gt; :pool) { |n| sleep(n); }</code></p></blockquote>
<p>First, 3 processes will be created to perform duties, they will be given 1, 2 and 6 seconds to sleep for. The parent thread will immediately wait for them to finish. The first process will sleep for 1 second, check for work, grab another &#8217;1&#8242; from the <a href="http://en.wikipedia.org/wiki/Tuple_space">Tuplespace</a> and start doing the work immediately. This will continue with the second process (which will finish after 2 seconds and grab more &#8220;work to be done&#8221; from the Tuplespace).</p>
<p>This ends up taking less time because you don&#8217;t block waiting for 1 process that takes a tremendous amount of time while the others have been finished for a while:</p>
<blockquote><p><code>% time ruby -I lib -rforkify -e '[1, 2, 6, 1, 2, 3].forkify(:procs =&gt; 3, :method =&gt; :pool) { |n| sleep(n); }'<br />
0.12s user 0.11s system 2% cpu <strong>8.380 total</strong></code></p></blockquote>
<p>Not a lot of difference huh? A lot of the different has to do with the overhead for creating a Tuplespace and sharing it between processes, here&#8217;s a better example (pool first, then serial):</p>
<blockquote><p><code>% time ruby -I lib -rforkify -e '[1, 1, 6, 1, 5, 1].forkify(:procs =&gt; 3, <strong>:method =&gt; :pool</strong>) { |n| sleep(n); }'<br />
0.12s user 0.10s system 3% cpu <strong>7.157 total</strong></code></p>
<p><code> </code><code>% time ruby -I lib -rforkify -e '[1, 1, 6, 1, 5, 1].forkify(3) { |n| sleep(n); }'<br />
0.08s user 0.10s system 1% cpu <strong>11.112 total</strong></code></p></blockquote>
<p>Imagine if the array had 100 items in it, but only a few took a really long time to process, as the differences increase, pool forking makes more sense to do.</p>
<h2>How it works in the code</h2>
<p>The Parent&#8217;s job:</p>
<p><script src="http://gist.github.com/175063.js"></script> (This is extremely stripped down to illustrate what&#8217;s happening)</p>
<p>The key here is to make sure that all the work items are in the TupleSpace <strong>before</strong> forking any children, so they don&#8217;t pull while we&#8217;re in the middle of writing and mess up the order, this is why I write all the tuples before starting the DRb service with the TupleSpace object.</p>
<p>After starting the children, I only need to wait on 3 pids, then I retrieve the results from the same TupleSpace in the correct order (regardless of the order they were added in)</p>
<p>The Child&#8217;s job:  <script src="http://gist.github.com/175066.js"></script></p>
<p>(Again stripped down to essentials)</p>
<p>The interesting parts of this are the TupleSpaceProxy and being able to write objects to a TupleSpace without any kind of mutex. Rinda&#8217;s TupleSpaces take care of doing operations multi thread/process-safely, so I don&#8217;t have to worry about synchronizing the writing/taking of items out of the TupleSpace.</p>
<p>The child pulls items out of the TupleSpace, calls the block on them and writes the result tuple back into the same TupleSpace, since it&#8217;s shared over DRb the parent will be able to see all of the result tuples when it grabs the results.</p>
<p>Are there problems with this code? <strong>Yes</strong> &#8211; hardcoding a port is a bad idea and I&#8217;ve run into some issues with deadlock if 2 pooled forkifys are run immediately after each other (even a &#8216;puts &#8220;foo&#8221;&#8216; in between them fixes the problem, which makes me crazy when debugging). I also imagine that while the forkify itself works with processes, it is (ironically) not actually thread or process safe (because of the DRb hardcoded port amongst other things).</p>
<p>So, does anyone have any ideas of how I can do a producer/consumer pool-forking library? Please let me know <img src='http://writequit.org/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Sadly there is a criminally-small amount of <a href="http://www.ruby-doc.org/stdlib/libdoc/rinda/rdoc/index.html">Ruby Rinda documentation</a> available online right now (most of it is for RingServers instead of TupleSpaces)</p>
<p><a href="http://github.com/dakrone/forkify/tree/master">Check out the full forkify_pool method</a> and let me know if you have any suggestions. Pool forking requires Ruby 1.9 right now because some of the Rinda stuff doesn&#8217;t work in 1.8.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/writequit/feed?a=OVFPbBux0G4:leHrL9O9vt0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/writequit/feed?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=OVFPbBux0G4:leHrL9O9vt0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=OVFPbBux0G4:leHrL9O9vt0:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=OVFPbBux0G4:leHrL9O9vt0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=OVFPbBux0G4:leHrL9O9vt0:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=OVFPbBux0G4:leHrL9O9vt0:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=OVFPbBux0G4:leHrL9O9vt0:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/writequit/feed/~4/OVFPbBux0G4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://writequit.org/blog/?feed=rss2&amp;p=315</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://writequit.org/blog/?p=315</feedburner:origLink></item>
		<item>
		<title>How to run FastRI on Ruby 1.9.1</title>
		<link>http://feedproxy.google.com/~r/writequit/feed/~3/y49S0TbM8L4/</link>
		<comments>http://writequit.org/blog/?p=307#comments</comments>
		<pubDate>Tue, 07 Jul 2009 02:27:13 +0000</pubDate>
		<dc:creator>Lee</dc:creator>
				<category><![CDATA[1.9]]></category>
		<category><![CDATA[1.9.1]]></category>
		<category><![CDATA[fastri]]></category>
		<category><![CDATA[fri]]></category>
		<category><![CDATA[patch]]></category>
		<category><![CDATA[qri]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://writequit.org/blog/?p=307</guid>
		<description><![CDATA[Alrighty, FastRI is a sweet program written by Mauricio Fernandez (of eigenclass.org, which is down currently for some reason) for doing RI (Ruby Documentation) lookups very quickly, it supports doing all sorts of neat things like running a DRb server for lookups and other cool things Anyway, if you found this, you probably don&#8217;t want to [...]]]></description>
			<content:encoded><![CDATA[<p>Alrighty, <a href="http://eigenclass.org/hiki/fastri">FastRI</a> is a sweet program written by Mauricio Fernandez (of <a href="http://eigenclass.org">eigenclass.org</a>, which is down currently for some reason) for doing RI (Ruby Documentation) lookups very quickly, it supports doing all sorts of neat things like running a DRb server for lookups and other cool things <img src='http://writequit.org/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Anyway, if you found this, you probably don&#8217;t want to listen to me blabber, you want to know how to get it running on Ruby 1.9.x, so I humbly present a patch!</p>
<p><span style="text-decoration: line-through;"><a href="http://writequit.org/misc/files/fastri-0.3.1-ruby1.9.1.v2.patch">Download the patch here (older version) version 2</a></span></p>
<p><a href="http://writequit.org/misc/files/fastri-0.3.1-ruby1.9.1.v3.patch">Download the patch here, version 3</a>.</p>
<p>First, download the <a href="http://rubyforge.org/frs/?group_id=2545&amp;release_id=18774">FastRI tarball (version 0.3.1 is latest at the time of this writing) from rubyforge</a>.</p>
<p>Here&#8217;s how to install the patch:</p>
<blockquote><p><code>% tar zxf fastri-0.3.1.tar.gz<br />
% cd fastri-0.3.1<br />
% patch -p1 &lt; ../fastri-0.3.1-ruby1.9.1.v2.patch<br />
patching file bin/fastri-server<br />
patching file lib/fastri/ri_index.rb<br />
patching file lib/fastri/ri_service.rb<br />
patching file lib/fastri/util.rb<br />
patching file test/test_functional_ri_service.rb<br />
% sudo ruby setup.rb</code></p></blockquote>
<p>And you&#8217;re done! Now you&#8217;ll need to make sure to do a &#8216;<code>fastri-server -b</code>&#8216; to build the cache, and from there you can use FastRI the same as it was in Ruby 1.8, see:</p>
<blockquote><p><code>[hinmanm@Xanadu:~]% qri String.each_codepoint<br />
-------------------------------------------------- String#each_codepoint<br />
str.each_codepoint {|integer| block }    =&gt; str<br />
From<br />
------------------------------------------------------------------------<br />
Passes the Integer ordinal of each character in str, also known as<br />
a codepoint when applied to Unicode strings to the given block.<br />
"hello\u0639".each_codepoint {|c| print c, ' ' }<br />
produces:<br />
104 101 108 108 111 1593</code></p></blockquote>
<h1>Notes/Caveats/Disclaimers &amp; Warnings:</h1>
<p>This patch is a WORK IN PROGRESS, it may hang, crash, steal your wallet and/or delete files. I hacked it up in a day looking at FastRI because I really like using &#8216;qri&#8217; for everything and was consistently annoyed by getting docs intended for 1.8. I assume no responsibility for these things.</p>
<p>Also, note that all tests don&#8217;t pass with this patch, I&#8217;m still working on it.</p>
<p>Feel free to leave any feedback for me <img src='http://writequit.org/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><strong>UPDATE</strong>:<br />
New version of the patch that fixes doing a lookup on a base class instead of a method. so&#8230; version 3 right now. (link above)</p>
<p><strong>UPDATE2</strong>:<br />
I created a github project for fastri to build a gem, so you can install the gem (without patching!) using this command:</p>
<blockquote>
<pre>sudo gem install dakrone-fastri -s http://gems.github.com</pre>
</blockquote>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/writequit/feed?a=y49S0TbM8L4:8QnqONRUxBg:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/writequit/feed?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=y49S0TbM8L4:8QnqONRUxBg:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=y49S0TbM8L4:8QnqONRUxBg:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=y49S0TbM8L4:8QnqONRUxBg:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=y49S0TbM8L4:8QnqONRUxBg:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/writequit/feed?a=y49S0TbM8L4:8QnqONRUxBg:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/writequit/feed?i=y49S0TbM8L4:8QnqONRUxBg:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/writequit/feed/~4/y49S0TbM8L4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://writequit.org/blog/?feed=rss2&amp;p=307</wfw:commentRss>
		<slash:comments>13</slash:comments>
		<feedburner:origLink>http://writequit.org/blog/?p=307</feedburner:origLink></item>
	</channel>
</rss>
