<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Logan Koester</title>
 <link href="http://blog.logankoester.com/atom.xml" rel="self"/>
 <link href="http://blog.logankoester.com/"/>
 <updated>2011-08-30T15:39:48-07:00</updated>
 <id>http://blog.logankoester.com/</id>
 <author>
   <name>Logan Koester</name>
   <email>logan@logankoester.com</email>
 </author>

 
 <entry>
   <title>errship</title>
   <link href="http://blog.logankoester.com/errship.html"/>
   <updated>2011-08-30T00:00:00-07:00</updated>
   <id>http://blog.logankoester.com/errship</id>
   <content type="html">&lt;h2 id='errship'&gt;errship&lt;/h2&gt;
&lt;p class='publish_date'&gt; 30 Aug 2011&lt;/p&gt;&lt;img src='/images/hindenburg.gif' alt='Hindenburg' /&gt;
&lt;p&gt;The static error pages Rails comes with are nice for getting started - you can’t break them, no matter what. But without your layout and navigation wrapped around them, they create a frustrating trap for your users.&lt;/p&gt;

&lt;p&gt;The obvious solution is to render your layout into the static file, but what happens when you make a change?&lt;/p&gt;

&lt;p&gt;Worse, what if you run a network of many Rails applications? Should they share one error page style? Should they all have their own?&lt;/p&gt;

&lt;p&gt;You could hire your nephew to keep them all up to date&amp;#8230; or you can use Errship.&lt;/p&gt;

&lt;p&gt;Errship is a Rails 3.1 engine for rendering error pages inside your layout. It supports i18n, custom exceptions, and Airbrake (Hoptoad) error tracking.&lt;/p&gt;

&lt;p&gt;You can also use the flashback method to set an error message and redirect :back safely - if a RedirectBackError is raised, the user is dropped off at the nearest error page and given the flash message anyway.&lt;/p&gt;

&lt;p&gt;Check it out on Github at &lt;a href='https://github.com/agoragames/errship'&gt;https://github.com/agoragames/errship&lt;/a&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Soonatra - 'Coming Soon' pages on Sinatra</title>
   <link href="http://blog.logankoester.com/soonatra-coming-soon-pages-on-sinatra.html"/>
   <updated>2011-07-20T00:00:00-07:00</updated>
   <id>http://blog.logankoester.com/soonatra-coming-soon-pages-on-sinatra</id>
   <content type="html">&lt;h2 id='soonatra__coming_soon_pages_on_sinatra'&gt;Soonatra - &amp;#8216;Coming Soon&amp;#8217; pages on Sinatra&lt;/h2&gt;
&lt;p class='publish_date'&gt; 20 Jul 2011&lt;/p&gt;
&lt;p&gt;I was recently tasked with creating a &amp;#8220;coming soon&amp;#8221; page for a new project at work. The requirements were the usual:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some description of the project features&lt;/li&gt;

&lt;li&gt;A form to signup for an email list / invites&lt;/li&gt;

&lt;li&gt;Display a few posts from an RSS feed&lt;/li&gt;

&lt;li&gt;Show some screenshots of what we&amp;#8217;re building to collect early feedback&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We&amp;#8217;ve also been increasing our focus on A/B testing (aka &amp;#8220;split testing&amp;#8221;), so I wanted a way to try out different headlines and see which angle users find most interesting.&lt;/p&gt;

&lt;p&gt;This all sounds well and good, but it is very frustrating to take time away from the beginning of an exciting new project to invest in a page that will only be online for a few short weeks.&lt;/p&gt;

&lt;p&gt;I decided I don&amp;#8217;t ever want to do it again, so I created &lt;a href='https://github.com/agoragames/soonatra'&gt;Soonatra&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href='https://github.com/agoragames/soonatra'&gt;Soonatra&lt;/a&gt; is a simple &lt;a href='http://www.sinatrarb.com/'&gt;Sinatra&lt;/a&gt; based framework for creating these pages quickly.&lt;/p&gt;

&lt;p&gt;&lt;a href='https://github.com/agoragames/soonatra'&gt;Soonatra&lt;/a&gt; reduces the steps involved to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a mailing list (we&amp;#8217;re using &lt;a href='http://mailchimp.com/'&gt;Mailchimp&lt;/a&gt;)&lt;/li&gt;

&lt;li&gt;Choose some colors/graphics that fit well with your brand&lt;/li&gt;

&lt;li&gt;Write the page copy and set an RSS feed url.&lt;/li&gt;

&lt;li&gt;Deploy to a free &lt;a href='http://heroku.com/'&gt;Heroku&lt;/a&gt; account and park your domain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is easy to extend and manage multiple themes thanks to &lt;a href='http://compass-style.org/'&gt;Compass&lt;/a&gt;, and does not require a database, instead using &lt;a href='http://redis.io/'&gt;Redis&lt;/a&gt; for RSS feed consumption and tracking A/B test results.&lt;/p&gt;

&lt;p&gt;You can fork the git repo and have your site up and running in minutes.&lt;/p&gt;

&lt;p&gt;See &lt;a href='https://github.com/agoragames/soonatra/blob/master/README.textile'&gt;README.textile&lt;/a&gt; for all the juicy details.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>FeedzirraRedis</title>
   <link href="http://blog.logankoester.com/feedzirraredis.html"/>
   <updated>2011-07-20T00:00:00-07:00</updated>
   <id>http://blog.logankoester.com/feedzirraredis</id>
   <content type="html">&lt;h2 id='feedzirraredis'&gt;FeedzirraRedis&lt;/h2&gt;
&lt;p class='publish_date'&gt; 20 Jul 2011&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;ve ever wanted to include some data from an RSS/Atom feed on a page from Ruby, you&amp;#8217;ve probably run into this problem:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It&amp;#8217;s completely unreasonable to hammer the feed provider with a request every time the page is rendered, but it&amp;#8217;s no more reasonable to use a big relational database like MySQL just to cache some stupid tweets or blog posts, especially if your application wouldn&amp;#8217;t otherwise need one.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But apparently this layer of persistance has been deemed out-of-scope by the creators of popular RSS consumer libraries such as &lt;a href='https://github.com/pauldix/feedzirra'&gt;Feedzirra&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So I wrote a little gem called &lt;a href='https://github.com/logankoester/feedzirra-redis/'&gt;feedzirra-redis&lt;/a&gt; to take care of this as transparently as possible. You can use it just like you would &lt;a href='https://github.com/pauldix/feedzirra'&gt;Feedzirra&lt;/a&gt; normally, but your feeds and entries do not disappear at the end of the script, so you can do the dirty work from a Rakefile via cron instead of in the web request/response cycle while your users impatiently twiddle their thumbs.&lt;/p&gt;

&lt;h3 id='installation'&gt;Installation&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;$ gem install feedzirra-redis&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;See the &lt;a href='https://github.com/logankoester/feedzirra-redis/blob/master/README.markdown'&gt;README&lt;/a&gt; and &lt;a href='https://github.com/logankoester/feedzirra-redis/blob/master/test/test_feedzirra-redis.rb'&gt;test suite&lt;/a&gt; for example usage.&lt;/p&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>A Dynamic DNS client in Ruby</title>
   <link href="http://blog.logankoester.com/a-dynamic-dns-client-in-ruby.html"/>
   <updated>2011-03-17T00:00:00-07:00</updated>
   <id>http://blog.logankoester.com/a-dynamic-dns-client-in-ruby</id>
   <content type="html">&lt;h2&gt;A Dynamic &lt;span class=&quot;caps&quot;&gt;DNS&lt;/span&gt; client in Ruby&lt;/h2&gt;
&lt;p class=&quot;publish_date&quot;&gt;17 Mar 2011&lt;/p&gt;
&lt;p&gt;Back in 2008 I wrote a Ruby gem for updating your IP address at &lt;a href=&quot;http://afraid.org&quot;&gt;afraid.org&lt;/a&gt;, the free &lt;a href=&quot;http://en.wikipedia.org/wiki/Dynamic_DNS&quot;&gt;Dynamic &lt;span class=&quot;caps&quot;&gt;DNS&lt;/span&gt;&lt;/a&gt; service. For whatever reason I moved onto other things, and never published the gem. It&amp;#8217;s pretty basic but serves my needs, and may serve yours, so I&amp;#8217;ve fixed it up and pushed version 0.1.2 today.&lt;/p&gt;
&lt;h3&gt;Installation&lt;/h3&gt;
&lt;pre&gt;&lt;code lang=&quot;bash&quot;&gt;$ gem install updateafraid&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Usage&lt;/h3&gt;
&lt;pre&gt;&lt;code lang=&quot;bash&quot;&gt;$ updateafraid --help
Help for commands:
  -user       (Required, takes 1 argument)
                  Your Afraid.org username
  -pass       (Required, takes 1 argument)
                  Your Afraid.org password
  -domain     (Optional, takes 1 argument)
                  Update IP address for one domain: -domain &amp;lt;name&amp;gt;
  -all        (Optional, takes 0 arguments)
                  Update IP address for all domains in your account
  -h          (Optional, takes 0 arguments)
                  Help&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code is hosted at &lt;a href=&quot;https://github.com/logankoester/updateafraid&quot;&gt;github.com/logankoester/updateafraid&lt;/a&gt; under an &lt;span class=&quot;caps&quot;&gt;MIT&lt;/span&gt; License.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Switching to Jekyll</title>
   <link href="http://blog.logankoester.com/switching-to-jekyll.html"/>
   <updated>2010-12-17T00:00:00-08:00</updated>
   <id>http://blog.logankoester.com/switching-to-jekyll</id>
   <content type="html">&lt;h2&gt;Switching to Jekyll&lt;/h2&gt;
&lt;p class=&quot;publish_date&quot;&gt;17 Dec 2010&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://wordpress.org&quot;&gt;Wordpress&lt;/a&gt; has served me pretty well for over 5 years now, but it&amp;#8217;s time for a change.&lt;/p&gt;
&lt;p&gt;Over those 5 years, I&amp;#8217;ve been writing less and less. I&amp;#8217;m not entirely sure of the reason, but I think it just comes down to friction. Editing text in a browser sucks, I had to log in, ran into layout problems a lot with simple things like code highlighting and inserting an image&amp;#8230;&lt;/p&gt;
&lt;p&gt;Anyway, I&amp;#8217;ve had my eye on Jekyll since it was announced, and I finally decided to try it out. I haven&amp;#8217;t even completed my first post yet, and I&amp;#8217;m already glad that I did.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;I can post &lt;a href=&quot;https://github.com/csexton/jekyll.vim&quot;&gt;straight from Vim.&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;My blog is version controlled with &lt;a href=&quot;http://git-scm.com/&quot;&gt;Git&lt;/a&gt; in plaintext files, not tucked away in a gigantic database&lt;/li&gt;
  &lt;li&gt;It&amp;#8217;s &lt;em&gt;fast&lt;/em&gt;. Seriously, static html vs php feels noticably faster even on a local system.&lt;/p&gt;
  &lt;li&gt;I can extend it with simple Ruby&amp;#8230; writing a Wordpress plugin is a pain in the ass (like most things &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;).&lt;/p&gt;
&lt;/ul&gt;
&lt;p&gt;If I can get &lt;a href=&quot;http://haml-lang.com/&quot;&gt;Haml&lt;/a&gt; working as well, I&amp;#8217;ll be the happiest blogger on earth.&lt;/p&gt;
&lt;p&gt;One potential downside for people who just want to get a site up quickly without a big design effort is that (as far as I know) there isn&amp;#8217;t a central repository of free themes available. I borrowed this &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; from Dan Hixon&amp;#8217;s &lt;a href=&quot;http://danhixon.github.com/&quot;&gt;überduper&lt;/a&gt;. I couldn&amp;#8217;t find a license, but it is in a &lt;a href=&quot;https://github.com/danhixon/danhixon.github.com&quot;&gt;public GitHub repository&lt;/a&gt; so I hope he doesn&amp;#8217;t mind sharing.&lt;/p&gt;
&lt;p&gt;I haven&amp;#8217;t migrated all my WordPress posts over yet, but I&amp;#8217;ll work on getting the most useful or popular ones back online when I have some time.&lt;/p&gt;
&lt;p&gt;In conclusion, if you haven&amp;#8217;t tried &lt;a href=&quot;https://github.com/mojombo/jekyll&quot;&gt;Jekyll&lt;/a&gt; yet or want something a little lighter than your current blogging engine, definitely give it a shot!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Bundler + Watchr</title>
   <link href="http://blog.logankoester.com/bundler-watchr.html"/>
   <updated>2010-08-20T00:00:00-07:00</updated>
   <id>http://blog.logankoester.com/bundler-watchr</id>
   <content type="html">&lt;h2&gt;Bundler + Watchr&lt;/h2&gt;
&lt;p class=&quot;publish_date&quot;&gt;20 Aug 2010&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re using test-driven development (and it&amp;#8217;s definitely a cliche by now, but if you&amp;#8217;re not &amp;#8211; you should be), I highly recommend &lt;a href=&quot;http://github.com/mynyml/watchr&quot;&gt;Watchr&lt;/a&gt; to run your test suite. The concept is simple: whenever you save a file, it runs the related tests for you. It&amp;#8217;s basically a modernized &lt;a href=&quot;http://www.zenspider.com/ZSS/Products/ZenTest/&quot;&gt;autotest&lt;/a&gt;, and I couldn&amp;#8217;t live without it. It&amp;#8217;s totally the best workflow ever.&lt;/p&gt;
&lt;p&gt;Lately I&amp;#8217;ve been switching my Ruby projects to the new &lt;a href=&quot;http://gembundler.com/&quot;&gt;Bundler&lt;/a&gt; system for managing gem dependencies. With Bundler, whenever you add a gem into your Gemfile, you have to then run &amp;#8220;bundle install&amp;#8221; to grab it. If you&amp;#8217;re already using Watchr to autorun your tests, it is trivial to automate this.&lt;/p&gt;
&lt;p&gt;Just add this line to your test/test.watchr (or whatever you call it).&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;  watch('Gemfile') { puts `bundle install` }&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Add a gem to your Gemfile, hit save&amp;#8230; gem installed!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Does it take you a while to get started in the morning?</title>
   <link href="http://blog.logankoester.com/does-it-take-you-a-while-to-get-started-in-the-morning.html"/>
   <updated>2010-05-18T00:00:00-07:00</updated>
   <id>http://blog.logankoester.com/does-it-take-you-a-while-to-get-started-in-the-morning</id>
   <content type="html">&lt;h2&gt;Does it take you a while to get started in the morning?&lt;/h2&gt;
&lt;p class=&quot;publish_date&quot;&gt;18 May 2010&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;
&lt;br /&gt;
It does for me. When I actually am ready to sit down and do some Rails hacking, I still have to fire up a couple irb consoles, open my editor, make sure Redis is running, start a resque worker, autotest, log tails, etc etc etc&amp;#8230; I&amp;#8217;d really rather get right to it, wouldn&amp;#8217;t you?&lt;/p&gt;
&lt;pre&gt;&lt;code lang=&quot;bash&quot;&gt;$ rake day:begin&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ahhh, that&amp;#8217;s much better!&lt;/p&gt;
&lt;pre&gt;&lt;code lang=&quot;ruby&quot;&gt;
namespace :day do
  task :begin =&amp;gt; [:gvim, :console, :logs, :watchr, :server, :resque]

  task :console do
    puts &quot;Opening IRB console...&quot;
    `gnome-terminal --window-with-profile=railsconsole -x script/console`
  end

  task :logs do
    puts &quot;Opening log files...&quot;
    `gnome-terminal --window-with-profile=rails -t &quot;Rails Logs&quot; -x tail -f log/*`
  end

  task :watchr do
    puts &quot;Starting test watchr...&quot;
    `gnome-terminal --window-with-profile=rails -t &quot;Test Watchr&quot; -x rake watchr:test`
  end

  task :gvim do
    puts &quot;Starting gvim...&quot;
    sh 'gvim'
  end

  task :server do
    puts &quot;Starting application server...&quot;
    `gnome-terminal --window-with-profile=rails -t &quot;Application Server&quot; -x script/server`
  end

  task :resque do
    puts &quot;Starting resque web... (http://localhost:5678)&quot;
    `resque-web 2&amp;gt; /dev/null`
    puts &quot;Starting resque worker...&quot;
    `gnome-terminal --window-with-profile=rails -t &quot;Resque Worker&quot; -x rake day:quick_resque_worker`
  end

  task :quick_resque_worker do
    sh &quot;QUEUE=* rake resque:work&quot;
  end
end

namespace :watchr do
  task :test do
    sh &quot;watchr test/test.watchr&quot;
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Into my Rakefile it goes! And if you like that, be sure to check out &lt;a href=&quot;http://github.com/trydionel/git-pivotal&quot;&gt;git-pivotal&lt;/a&gt; &amp;#8211; grab the next thing to do and give it its own branch with just one more command. Anyone feeling clever enough to implement a rake day:end as well?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Planning</title>
   <link href="http://blog.logankoester.com/planning.html"/>
   <updated>2010-02-05T00:00:00-08:00</updated>
   <id>http://blog.logankoester.com/planning</id>
   <content type="html">&lt;h2&gt;Planning&lt;/h2&gt;
&lt;p class=&quot;publish_date&quot;&gt;05 Feb 2010&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;alignnone size-full wp-image-265&quot; title=&quot;Planning&quot; src=&quot;http://blog.logankoester.com/wp-content/uploads/2010/02/planning.png&quot; alt=&quot;Planning&quot; width=&quot;573&quot; height=&quot;360&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Sometimes I wonder why I bother&amp;#8230;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Bayesian Classification on Rails</title>
   <link href="http://blog.logankoester.com/bayesian-classification-on-rails.html"/>
   <updated>2010-01-26T00:00:00-08:00</updated>
   <id>http://blog.logankoester.com/bayesian-classification-on-rails</id>
   <content type="html">&lt;h2&gt;Bayesian Classification on Rails&lt;/h2&gt;
&lt;p class=&quot;publish_date&quot;&gt;26 Jan 2010&lt;/p&gt;
&lt;p&gt;A project I&amp;#8217;ve been working on watches &lt;a href=&quot;http://twitter.com&quot;&gt;Twitter&lt;/a&gt; for some search keywords, with the goal of finding new customers, jobs, items for sale, etc. For example, a computer repair shop might want to watch for the keywords &amp;#8220;laptop&amp;#8221; and &amp;#8220;broken&amp;#8221;, and then reply to tweets where they think they can help.&lt;/p&gt;
&lt;p&gt;But as anyone who uses Twitter can attest, even with some very specific search terms, language filtering and geocoding, there is going to be a lot of white noise. I decided to take this one step further.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Naive_Bayes_classifier&quot;&gt;Bayesian classification&lt;/a&gt; (your garden-variety spam filter) in ruby is quite easy, thanks to &lt;a href=&quot;http://github.com/aurelian/ruby-stemmer&quot;&gt;ruby-stemmer&lt;/a&gt; and the excellent &lt;a href=&quot;http://github.com/logankoester/classifier&quot;&gt;classifier gem&lt;/a&gt;. The canonical example:&lt;br /&gt;
&lt;pre&gt;&lt;code lang=&quot;ruby&quot;&gt;require 'classifier'
b = Classifier::Bayes.new :categories =&amp;gt; ['Interesting', 'Uninteresting']
b.train_interesting &quot;here are some good words. I hope you love them&quot;
b.train_uninteresting &quot;here are some bad words, I hate you&quot;
b.classify &quot;I hate bad words and you&quot; # returns 'Uninteresting'&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Of course, if you&amp;#8217;re implementing this in a &lt;a href=&quot;http://rubyonrails.org/&quot;&gt;Rails&lt;/a&gt; application, chances are you want the classifier to learn from real data over time. In my case, I want it to learn that a tweet is uninteresting when I delete it, and I want it to learn that a tweet is interesting when I visit the Tweet#show action.&lt;/p&gt;
&lt;p&gt;It seems the usual method is to &lt;a href=&quot;http://en.wikipedia.org/wiki/Marshalling_%28computer_science%29&quot;&gt;marshal&lt;/a&gt; the classifier object with &lt;a href=&quot;http://madeleine.rubyforge.org/&quot;&gt;madeleine&lt;/a&gt;, which creates a new snapshot file each time you train it. This is both easy and fast, but we&amp;#8217;re going to end up with thousands or millions of snapshot files in no time flat. Additionally, all bets are off if we have a few users who are really into cheap viagra. We need to give each User his own classifier and let him train it over time.&lt;/p&gt;
&lt;p&gt;First, let&amp;#8217;s set up our environment. Grab the latest &lt;a href=&quot;http://github.com/aurelian/ruby-stemmer&quot;&gt;ruby-stemmer&lt;/a&gt; and &lt;a href=&quot;http://github.com/logankoester/classifier&quot;&gt;classifier&lt;/a&gt; gems from Github, and build them from source. I recommend this because the gem versions I got on my first try were way out of date and quite broken, and because you&amp;#8217;ll need a classifier fork with my remove_stemmer method to marshal your classifiers using ActiveRecord.&lt;/p&gt;
&lt;pre&gt;&lt;code lang=&quot;bash&quot;&gt;$ git clone git://github.com/aurelian/ruby-stemmer.git
$ cd ruby-stemmer
$ rake compile
$ sudo rake install
$ cd ..

$ git clone git://github.com/logankoester/classifier.git
$ cd classifier
$ sudo rake install

$ sudo gem install twitter&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Generate a fresh rails app if you want to follow along.&lt;br /&gt;
&lt;pre&gt;&lt;code lang=&quot;bash&quot;&gt;$ rails classifier_rails_example
$ script/generate resource user id:integer classifier:text
$ script/generate resource keyword id:integer user_id:integer text:string
$ script/generate resource tweet id:integer keyword_id:integer user_id:integer \
  text:string read:boolean interesting:boolean
$ script/generate migration ChangeClassifierDefaults&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Alternatively, you can clone the code from this tutorial with:&lt;br /&gt;
&lt;pre&gt;&lt;code lang=&quot;bash&quot;&gt;$ git clone git@github.com:logankoester/classifier_rails_example.git&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Now edit the migration you just created to look like this:&lt;br /&gt;
&lt;pre&gt;&lt;code lang=&quot;ruby&quot;&gt;class ChangeClassifierDefaults &amp;lt; ActiveRecord::Migration
  def self.up
    change_column :tweets, :interesting, :boolean, :default =&amp;gt; false
    change_column :tweets, :read, :boolean, :default =&amp;gt; false
    change_column :keywords, :text, :string, :default =&amp;gt; &quot;&quot;
  end&lt;/p&gt;
def self.down
change_column :keywords, :text
change_column :tweets, :read
change_column :tweets, :interesting
end
&lt;p&gt;end&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;&amp;#8230;and run it&lt;br /&gt;
&lt;pre&gt;&lt;code lang=&quot;bash&quot;&gt;$ rake db:migrate&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Open your config/environment.rb file, and add the following gems to the Initializer block.&lt;/p&gt;
&lt;pre&gt;&lt;code lang=&quot;ruby&quot;&gt;config.gem 'ruby-stemmer', :lib =&amp;gt; 'lingua/stemmer'
config.gem 'luisparravicini-classifier', :lib =&amp;gt; 'classifier'
config.gem 'twitter'&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can use ActiveRecord&amp;#8217;s built-in &lt;span class=&quot;caps&quot;&gt;YAML&lt;/span&gt; serialization to store the classifier.&lt;/p&gt;
&lt;pre&gt;&lt;code lang=&quot;ruby&quot;&gt;class User &amp;lt; ActiveRecord::Base
  has_many :tweets
  has_many :keywords

  serialize     :classifier, Classifier::Bayes
  before_create :initialize_classifier
  before_update :remove_stemmer

private

  def initialize_classifier
    self.classifier = Classifier::Bayes.new(
      :categories =&amp;gt; ['Interesting', 'Uninteresting']
    )
    remove_stemmer
  end

  def remove_stemmer
    self.classifier.remove_stemmer
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The remove_stemmer method requires a little explanation. When a Classifier is initialized, it also creates a Stemmer object to use, which ordinarily gets marshalled along with its Classifier. But when demarshalled later, the Stemmer object (which is really just a C extension) will get caught with its shorts down, and either throw an error like &amp;#8220;Stemmer is not initialized&amp;#8221;, or in older versions, simply segfault your rails environment!&lt;/p&gt;
&lt;p&gt;The solution is simple; my fork implements a remove_stemmer method on Classifier::Base, which will force the stemmer to be reinitialized the next time it is needed. Call this method before you marshal your classifier, and your troubles will melt away.&lt;/p&gt;
&lt;p&gt;Moving on to the Tweet model, we want to classify each tweet when it is created.&lt;/p&gt;
&lt;pre&gt;&lt;code lang=&quot;ruby&quot;&gt;class Tweet &amp;lt; ActiveRecord::Base
  belongs_to :user
  belongs_to :keyword

  before_save :classify
  
  def classify
    text = self.text.gsub /#{self.keyword.text}/, ''
    if self.user.classifier.classify(text) == 'Interesting'
      self.interesting = true
    end
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, we don&amp;#8217;t want to throw off the results by including a word which is going to occur in every tweet, so we remove the search term from the text prior to classification.&lt;/p&gt;
&lt;p&gt;Add a little method to your Keyword model to grab new tweets from the &lt;a href=&quot;http://apiwiki.twitter.com/Twitter-Search-API-Method%3A-search&quot;&gt;Twitter Search &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code lang=&quot;ruby&quot;&gt;class Keyword &amp;lt; ActiveRecord::Base
  belongs_to :user
  has_many   :tweets, :dependent =&amp;gt; :destroy

  after_save :search

  def search
    search = Twitter::Search.new(self.text).fetch
    search.results.each do |r|
      t = Tweet.create(
        :keyword =&amp;gt; self,
        :user_id =&amp;gt; self.user,
        :text =&amp;gt; r.text
      )
      t.save
    end
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Almost done! Now we need to train our sweet new classifier. I&amp;#8217;ve opted to do this entirely from the controller, so that messing around in the console won&amp;#8217;t inadvertently have an impact on the machine&amp;#8217;s learning. We also want to mark the tweet in question as already read, so that the lesson is only learned once.&lt;/p&gt;
&lt;pre&gt;&lt;code lang=&quot;ruby&quot;&gt;class TweetsController &amp;lt; ApplicationController

  def show
    @tweet = Tweet.find(params[:id])
    unless @tweet.read?
      current_user.classifier.train_interesting(
        @tweet.text.gsub(/#{@tweet.keyword.text}/, '')
      )
      current_user.save
      @tweet.read = true
      @tweet.save
    end
  end


  def destroy
    if @tweet = Tweet.find(params[:id])
      if @tweet.destroy
        current_user.classifier.train_uninteresting(
          @tweet.text.gsub(/#{@tweet.keyword.text}/, '')
        )
        current_user.save
      end
    end
  end

end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And there you have it&amp;#8230; a simple machine learning solution for extracting awesome tweets. Let&amp;#8217;s try it out!&lt;/p&gt;
&lt;p&gt;Fire up a script/console session.&lt;/p&gt;
&lt;pre&gt;&lt;code lang=&quot;ruby&quot;&gt;Loading development environment (Rails 2.3.5)
&amp;gt;&amp;gt; u = User.create
=&amp;gt; #&amp;lt;User id: 1, classifier: #&amp;lt;Classifier::Bayes:0xb64f2354 
  @categories={:Uninteresting=&amp;gt;{}, :Interesting=&amp;gt;{}}, total_words0, 
  stemmernil, options{:encoding=&amp;gt;&quot;UTF_8&quot;, 
  :categories=&amp;gt;[&quot;Interesting&quot;, &quot;Uninteresting&quot;], 
  :language=&amp;gt;&quot;en&quot;}, created_at: &quot;2010-01-26 22:17:19&quot;, 
  updated_at: &quot;2010-01-26 22:17:19&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, our new user has a Bayesian Classifier waiting around to learn what kind of tweets he likes.&lt;/p&gt;
&lt;pre&gt;&lt;code lang=&quot;ruby&quot;&gt;
&amp;gt;&amp;gt; u.keywords.create(:text =&amp;gt; &quot;robots&quot;)
=&amp;gt; #&amp;lt;Keyword id: 1, user_id: 1, text: &quot;robots&quot;, created_at: &quot;2010-01-26 22:20:55&quot;, 
  updated_at: &quot;2010-01-26 22:20:55&quot;&amp;gt;
&amp;gt;&amp;gt; Tweet.all.size
=&amp;gt; 15&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can use the following oneliners from script/console to play around with the training:&lt;/p&gt;
&lt;pre&gt;&lt;code lang=&quot;ruby&quot;&gt;Keyword.all.each {|k| k.search} # Rerun all searches to grab and classify more results

# Any tweet with the word &quot;cyborgs&quot; is interesting
Tweet.all.each { |t| 
  u.classifier.train_interesting(t.text) if t.text.downcase.include? &quot;cyborgs&quot;
}

# Any tweet with the word &quot;discount&quot; is uninteresting
Tweet.all.each { |t| 
  u.classifier.train_uninteresting(t.text) if t.text.downcase.include? &quot;discount&quot;
} 

# Print the interesting tweets and count them
Tweet.find_all_by_interesting(true).each do |t| pp t.text }.size 

# Rerun the classification on every tweet
Tweet.all.each {|t| t.classify }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, this technique can be applied to sorting pretty much any kind of text. Interesting/uninteresting tweets are just one example from my life. Start hacking!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Fun with ion3</title>
   <link href="http://blog.logankoester.com/fun-with-ion3.html"/>
   <updated>2009-10-07T00:00:00-07:00</updated>
   <id>http://blog.logankoester.com/fun-with-ion3</id>
   <content type="html">&lt;h2&gt;Fun with ion3&lt;/h2&gt;
&lt;p class=&quot;publish_date&quot;&gt;07 Oct 2009&lt;/p&gt;
&lt;blockquote&gt;
&lt;a href=&quot;http://www.modeemi.fi/~tuomov/ion/intro.html&quot;&gt;Ion&lt;/a&gt;™ is a tiling tabbed window manager designed with keyboard users in mind.
&lt;/blockquote&gt;
&lt;p&gt;In recent years I&amp;#8217;ve been a &lt;a href=&quot;http://www.gnome.org/&quot;&gt;&lt;span class=&quot;caps&quot;&gt;GNOME&lt;/span&gt;&lt;/a&gt; / &lt;a href=&quot;http://www.compiz-fusion.org/&quot;&gt;Compiz&lt;/a&gt; guy, but while I&amp;#8217;ve enjoyed it&amp;#8217;s tight integration with &lt;a href=&quot;http://www.ubuntu.com/&quot;&gt;Ubuntu&lt;/a&gt; and flashy effects, I&amp;#8217;ve always missed the simplicity of so-called minimalist window managers, mainly &lt;a href=&quot;http://www.fvwm.org/&quot;&gt;fvwm&lt;/a&gt;. These days, however, practically everything I do happens inside a &lt;a href=&quot;http://www.mozilla.com/en-US/firefox/&quot;&gt;Firefox&lt;/a&gt;, &lt;a href=&quot;http://www.vim.org/&quot;&gt;gvim&lt;/a&gt;, or &lt;a href=&quot;http://directory.fsf.org/project/gnome-terminal/&quot;&gt;gnome-terminal&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I want keyboard-driven. I want scriptable. And I don&amp;#8217;t want windows hiding behind other windows. Ever.&lt;/p&gt;
&lt;p&gt;Enter &lt;a href=&quot;http://www.modeemi.fi/~tuomov/ion/intro.html&quot;&gt;ion3&lt;/a&gt;. I&amp;#8217;ve only been using it for the last 24 hours, and even though I haven&amp;#8217;t memorized all of the keymaps, or learned how to code in &lt;a href=&quot;http://www.lua.org/&quot;&gt;Lua&lt;/a&gt; (yet!), I already love it. So far the only problem I&amp;#8217;ve not been able to overcome is a bug in the latest &lt;a href=&quot;http://www.adobe.com/products/flashplayer/&quot;&gt;Adobe Flash&lt;/a&gt; that breaks fullscreen video. This isn&amp;#8217;t specific to ion3 &amp;#8211; it&amp;#8217;s a problem with any focus-follows-mouse system. I &lt;a href=&quot;http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=462690#50&quot;&gt;hear there is a workound&lt;/a&gt;, but it didn&amp;#8217;t seem to work for me. I consider it a microscopic trade-off for such an efficient window manager. Many of my previously sluggish applications now run incredibly fast, and with a couple days of practice I&amp;#8217;ll be working faster too.&lt;br /&gt;
&lt;h3&gt;Installation&lt;/h3&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code lang=&quot;bash&quot;&gt;$ sudo apt-get install ion3 ion3-dev ion3-scripts ion3-doc&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now just log out, choose &lt;strong&gt;ion3&lt;/strong&gt; and start a new session. The first time you log in you&amp;#8217;ll be greeted with the man page, which I highly suggest reading. If you try not to &amp;#8220;cheat&amp;#8221; by using the mouse, you&amp;#8217;ll pick up almost everything in a couple of hours, and from there you&amp;#8217;ll find yourself navigating faster and faster until you don&amp;#8217;t have to think about it at all. Just like vim.&lt;br /&gt;
Ion is both simple and well-documented, so it would be pointless for me to write introductory tutorial. Instead, here are a couple tricks I&amp;#8217;ve discovered.&lt;/p&gt;
&lt;h3&gt;Modifying your configuration&lt;/h3&gt;
&lt;p&gt;One of the first things you&amp;#8217;re going to want to do when you&amp;#8217;re done messing around is change a few settings. For the most part, this is done in a file called &lt;em&gt;cfg_ion.lua&lt;/em&gt;. Copy the system-wide file (I found mine at &lt;em&gt;/etc/X11/ion3/cfg_ion.lua&lt;/em&gt;) to  ~/.ion3/cfg_ion.lua and open it with a text editor.&lt;/p&gt;
&lt;pre&gt;&lt;code lang=&quot;bash&quot;&gt;
$ mkdir ~/.ion3
$ cp `locate cfg_ion.lua | head -1` ~/.ion3/cfg_ion.lua
$ gvim ~/ion3/cfg_ion.lua
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You&amp;#8217;ll need to restart Ion for your changes to take effect. Don&amp;#8217;t worry, all your applications will stay open; only the window manager needs to be restarted. Hit &lt;strong&gt;F12&lt;/strong&gt; and type &lt;em&gt;session/restart.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I messed this file up a few times experimenting, and I&amp;#8217;ll probably mess it up a few more. If you screw up this file like I did, your &lt;strong&gt;F12&lt;/strong&gt; shortcut can disappear, and you&amp;#8217;ll need another way to restart Ion after you&amp;#8217;ve fixed it. Keep a terminal open whenever you&amp;#8217;re editing, because you may not be able to launch one. The trick to restart Ion from the console is simple:&lt;br /&gt;
&lt;pre&gt;&lt;code lang=&quot;bash&quot;&gt;
$ ps -e | grep ion3 # 21108 ?        00:00:16 ion3
$ kill -USR1 21108
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;h3&gt;Remapping Mod1&lt;/h3&gt;
&lt;p&gt;The &lt;strong&gt;Mod1&lt;/strong&gt; key is used to initiate most interactions with Ion. On most systems, this is &lt;strong&gt;Alt&lt;/strong&gt;. This is usually a very bad choice, because a lot of other applications need the &lt;strong&gt;Alt&lt;/strong&gt; key for other things. I tried the Flying Window key, but it turns out it&amp;#8217;s in a very uncomfortable place on the keyboard. The number keys are used a lot. Try reaching &lt;strong&gt;Win+6&lt;/strong&gt;, and you&amp;#8217;ll see what I mean. &lt;strong&gt;CapsLock&lt;/strong&gt; has been working great for me, and as an added bonus, makes it much more work to shout on &lt;span class=&quot;caps&quot;&gt;IRC&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Check your keymaps with &lt;strong&gt;xmodmap -pm&lt;/strong&gt;. On my system, &lt;strong&gt;Mod3&lt;/strong&gt; was unused, so I remapped &lt;strong&gt;CapsLock&lt;/strong&gt; to that.&lt;/p&gt;
&lt;p&gt;Edit (or create) &lt;em&gt;~/.Xmodmaprc&lt;/em&gt; and insert these lines at the bottom&amp;#8230;&lt;br /&gt;
&lt;pre&gt;&lt;code lang=&quot;bash&quot;&gt;
remove Lock = Caps_Lock
add Mod3 = Caps_Lock
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Then run it&amp;#8230;&lt;br /&gt;
&lt;pre&gt;&lt;code lang=&quot;bash&quot;&gt;/usr/bin/X11/xmodmap ~/.Xmodmaprc&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Also add this line to &lt;em&gt;~/.Xsession&lt;/em&gt; so it is run automatically whenever you start X.&lt;/p&gt;
&lt;p&gt;If your &lt;strong&gt;xmodmap -pm&lt;/strong&gt; now reads&amp;#8230;&lt;/p&gt;
&lt;pre&gt;&lt;code lang=&quot;lua&quot;&gt;mod3        Caps_Lock (0x42)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;then you&amp;#8217;re in luck! Now you just need to edit the &lt;span class=&quot;caps&quot;&gt;META&lt;/span&gt; variable near the top of your &lt;span style=&quot;text-decoration: underline;&quot;&gt;&lt;em&gt;cfg_ion.lua&lt;/em&gt;&lt;/span&gt; to reflect the change &lt;br /&gt;
&lt;pre&gt;&lt;code lang=&quot;lua&quot;&gt;META=&quot;Mod3+&quot;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
and restart.&lt;/p&gt;
&lt;p&gt;All done! I hope you enjoy learning and using Ion3 as much as I have. I don&amp;#8217;t think I&amp;#8217;ll be switching again any time soon.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Human Readable Text Compression</title>
   <link href="http://blog.logankoester.com/human-readable-text-compression.html"/>
   <updated>2009-06-13T00:00:00-07:00</updated>
   <id>http://blog.logankoester.com/human-readable-text-compression</id>
   <content type="html">&lt;h2&gt;Human Readable Text Compression&lt;/h2&gt;
&lt;p class=&quot;publish_date&quot;&gt;13 Jun 2009&lt;/p&gt;
&lt;h3&gt;As a Web Service&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://tweetshrink.com&quot;&gt;TweetShrink&lt;/a&gt;, a web service from &lt;a href=&quot;http://trnsfr.com/&quot;&gt;&lt;span class=&quot;caps&quot;&gt;TRNSFR&lt;/span&gt;&lt;/a&gt;, uses a database of common instant / text messaging abbreviations to reduce the number of characters in a tweet. It&amp;#8217;s essentially a human-readable compression algorithm. For example, &amp;#8220;&lt;strong&gt;Some text to shrink&lt;/strong&gt;&amp;#8221; becomes &amp;#8220;&lt;strong&gt;sum text 2 shrnk&lt;/strong&gt;&amp;#8221; when passed through their &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;But it doesn&amp;#8217;t enforce Twitter&amp;#8217;s 140 character limit, which means it can be used beyond Twitter for whatever you like. Back in March I released the &lt;a href=&quot;http://blog.logankoester.com/tweetshrink-gem-for-ruby&quot;&gt;tweetshrink gem for Ruby&lt;/a&gt;, and today I&amp;#8217;ve updated it to 0.2 which includes a command line interface.&lt;/p&gt;
&lt;h3&gt;From the command line&lt;/h3&gt;
&lt;p&gt;First, make sure you have Ruby and Rubygems installed. On Debian-based operating systems (such as &lt;a href=&quot;http://www.ubuntu.com/&quot;&gt;Ubuntu&lt;/a&gt;), this goes a little something like&lt;/p&gt;
&lt;pre&gt;&lt;code lang=&quot;bash&quot;&gt;$ sudo apt-get install ruby rubygems&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now install the gem from it&amp;#8217;s &lt;a href=&quot;http://github.com/logankoester/tweetshrink/tree/master&quot;&gt;GitHub repository&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code lang=&quot;bash&quot;&gt;
$ sudo gem sources -a http://gems.github.com # (only need to do this once)
$ sudo gem install logankoester-tweetshrink
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can use it from the command line like this:&lt;/p&gt;
&lt;pre&gt;&lt;code lang=&quot;bash&quot;&gt;
$ echo &quot;Some text to shrink&quot; | tweetshrink
# Or with a file...
$ tweetshrink ./file_to_shrink.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;From vim&lt;/h3&gt;
&lt;p&gt;Or, you can integrate it with vim for ultimate text shrinking convenience. Just add the following to your &lt;strong&gt;.vimrc&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;
&quot; Tweetshrink text filter (:tws) &quot;
&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;
autocmd BufEnter * vmap ,tws !tweetshrink&amp;lt;CR&amp;gt;
autocmd BufEnter * nmap ,tws !!tweetshrink&amp;lt;CR&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you can shrink a single line by hitting &lt;strong&gt;,tws&lt;/strong&gt; in &lt;em&gt;Normal&lt;/em&gt; mode, or shrink a whole a visual block.&lt;/p&gt;
&lt;p&gt;Of course, this is just as easy to integrate with &lt;em&gt;your&lt;/em&gt; favorite text editor; I just happen to use vim.&lt;/p&gt;
&lt;h3&gt;On the Web&lt;/h3&gt;
&lt;p&gt;When I integrated this feature with my blog &amp;amp; tweet scheduler &lt;a href=&quot;http://pinglater.fm&quot;&gt;PingLater.fm&lt;/a&gt;, I realized TweetShrink didn&amp;#8217;t have a favicon. I needed an icon to use for the button, so I created these &amp;#8211; feel free to use them for whatever.&lt;br /&gt;
[gallery link=&amp;#8220;file&amp;#8221; columns=&amp;#8220;4&amp;#8221;]&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>PingLater.fm</title>
   <link href="http://blog.logankoester.com/pinglaterfm.html"/>
   <updated>2009-06-07T00:00:00-07:00</updated>
   <id>http://blog.logankoester.com/pinglaterfm</id>
   <content type="html">&lt;h2&gt;PingLater.fm&lt;/h2&gt;
&lt;p class=&quot;publish_date&quot;&gt;07 Jun 2009&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve spent the last couple of days working hard on a new app for managing your web presence.&lt;/p&gt;
&lt;p&gt;There is a service called &lt;a href=&quot;http://ping.fm&quot;&gt;Ping.fm&lt;/a&gt; for broadcasting updates to your blogs, Twitter, Facebook, and other social networks all at once, from one place.&lt;/p&gt;
&lt;p&gt;This can save you a lot of time if you&amp;#8217;re trying to manage a brand or keep up with different groups of friends, and it makes it easier to prevent your presence on these sites from becoming stale.&lt;/p&gt;
&lt;p&gt;The application I&amp;#8217;m calling &lt;a href=&quot;http://pinglater.fm&quot;&gt;PingLater.fm&lt;/a&gt; takes it one step further. Now you can set up pings to be sent at a specified time in the future. You could schedule a product highlight for each day of the month, release new blog posts while you&amp;#8217;re off on vacation, or whatever else you want to use a service like this for.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s free for now while I gather feedback and optimize the code, but free users will eventually be limited to 3 pings scheduled at a time.&lt;/p&gt;
&lt;p&gt;I have a number of premium features in mind (&lt;span class=&quot;caps&quot;&gt;RSS&lt;/span&gt; posting, image/video, iPhone&amp;#8230;) to make it a really indispensable tool  for pro bloggers and internet marketing people.&lt;/p&gt;
&lt;p&gt;But we&amp;#8217;ll get to that. For now, I just want to hear from you. Let me know what I can do to make this useful for you!&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://pinglater.fm&quot;&gt;Click here to try it out!&lt;/a&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Deploying Sinatra to a sub-URI using Passenger</title>
   <link href="http://blog.logankoester.com/deploying-sinatra-to-a-sub-uri-using-passenger.html"/>
   <updated>2009-04-08T00:00:00-07:00</updated>
   <id>http://blog.logankoester.com/deploying-sinatra-to-a-sub-uri-using-passenger</id>
   <content type="html">&lt;h2&gt;Deploying Sinatra to a sub-&lt;span class=&quot;caps&quot;&gt;URI&lt;/span&gt; using Passenger&lt;/h2&gt;
&lt;p class=&quot;publish_date&quot;&gt;08 Apr 2009&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s not hard, but it turns out there&amp;#8217;s a trick to it. I&amp;#8217;ve run into this problem twice now, so I figure it should be documented. This is the solution if your &amp;#8220;/&amp;#8221; route is resulting in &amp;#8220;Not Found&amp;#8221; or an Apache directory listing.&lt;/p&gt;
&lt;p&gt;You can read more about the problem at &lt;a href=&quot;http://blog.ardekantur.com/2008/07/phusion-rack-sinatra-and-sub-domains/&quot;&gt;Ardekantur&amp;#8217;s &amp;#8220;Phusion, Rack, Sinatra, and sub-domains&amp;#8221;&lt;/a&gt;, but here&amp;#8217;s my quick solution:&lt;br /&gt;
&lt;br /&gt;
1. Disable &lt;strong&gt;mod_autoindex&lt;/strong&gt; if it is enabled.&lt;br /&gt;
2. Make sure your &lt;strong&gt;RackBaseURI&lt;/strong&gt; does not have a trailing slash.&lt;br /&gt;
3. Add this &lt;strong&gt;before_filter&lt;/strong&gt; to your Sinatra app:&lt;br /&gt;
&lt;pre&gt;&lt;code lang=&quot;ruby&quot;&gt;before do
  request.env['PATH_INFO'] = '/' if request.env['PATH_INFO'].empty?
end
&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;I suppose an alternative solution would be feasible using Rack middleware, but this is what I&amp;#8217;m using. Thanks to &lt;a href=&quot;http://ryanfunduk.com/&quot;&gt;Ryan Funduk&lt;/a&gt; for helping me figure this stuff out.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Setting up rTorrent with Firefox</title>
   <link href="http://blog.logankoester.com/setting-up-rtorrent-with-firefox.html"/>
   <updated>2009-03-14T00:00:00-07:00</updated>
   <id>http://blog.logankoester.com/setting-up-rtorrent-with-firefox</id>
   <content type="html">&lt;h2&gt;Setting up rTorrent with Firefox&lt;/h2&gt;
&lt;p class=&quot;publish_date&quot;&gt;14 Mar 2009&lt;/p&gt;
&lt;p&gt;Being the closest thing we have to a native &lt;a href=&quot;http://www.utorrent.com/&quot;&gt;uTorrent&lt;/a&gt; in Linux, I really like &lt;a href=&quot;http://deluge-torrent.org/&quot;&gt;Deluge&lt;/a&gt;. But, at least for me, it uses a seemingly impossible amount system resources. Since a &lt;a href=&quot;http://en.wikipedia.org/wiki/BitTorrent_client&quot;&gt;Bittorrent client&lt;/a&gt; is the kind of thing I want to leave running in the background, I needed a lighter alternative.&lt;/p&gt;
&lt;p&gt;I don&amp;#8217;t see any real need for a graphical interface when ultimately all it&amp;#8217;s doing is moving bits around on a network, so I went with &lt;a href=&quot;http://libtorrent.rakshasa.no/&quot;&gt;rTorrent&lt;/a&gt;. One of the benefits of using command-line software is that you can use &lt;a href=&quot;http://en.wikipedia.org/wiki/Secure_Shell&quot;&gt;&lt;span class=&quot;caps&quot;&gt;SSH&lt;/span&gt;&lt;/a&gt; and &lt;a href=&quot;http://www.gnu.org/software/screen/&quot;&gt;screen&lt;/a&gt; to control it over the network&amp;#8230; we don&amp;#8217;t need no fancypants &lt;span class=&quot;caps&quot;&gt;AJAX&lt;/span&gt; interface for this!&lt;/p&gt;
&lt;h3&gt;Part 1 &amp;#8211; rTorrent&lt;/h3&gt;
&lt;p&gt;If you&amp;#8217;re using Ubuntu, you can get rTorrent from the repositories, like so&amp;#8230;&lt;br /&gt;
&lt;pre&gt;&lt;code lang=&quot;Bash&quot;&gt;sudo apt-get install rtorrent&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;Now that you&amp;#8217;ve got the software, you&amp;#8217;re going to need to configure it. rTorrent looks for a configuration file called &lt;strong&gt;.rtorrent.rc&lt;/strong&gt; in your home directory. Don&amp;#8217;t panic. Just save the &lt;a href=&quot;http://libtorrent.rakshasa.no/browser/trunk/rtorrent/doc/rtorrent.rc?rev=latest&amp;amp;format=raw&quot;&gt;sample&lt;/a&gt; as &lt;strong&gt;~/.rtorrent.rc&lt;/strong&gt; and open it up in your favorite text editor.&lt;/p&gt;
&lt;p&gt;You don&amp;#8217;t need to worry about most of the stuff in this file, but you can if you want to. Here&amp;#8217;s how I have it set up:&lt;/p&gt;
&lt;pre&gt;&lt;code lang=&quot;python&quot;&gt;
# Maximum and minimum number of peers to connect to per torrent.
# I like to limit this because I'm often connected through cheap
# wireless routers that have trouble with lots of connections.
min_peers = 40
max_peers = 450

# Same as above but for seeding completed torrents (-1 = same as downloading)
#min_peers_seed = 10
max_peers_seed = 50

# Maximum number of simultanious uploads per torrent.
max_uploads = 30

# Where do you want your downloads to go?
directory = ~/downloads

# You can put this anywhere you like, but I put it here.
# Remember that you'll have to create this directory
session = ~/.rtorrent/session

# Watch a directory for new torrents, and stop those that have been
# deleted.
# This will be important when we're setting up Firefox.
schedule = watch_directory,5,5,load_start=~/downloads/torrents/*.torrent
schedule = untied_directory,5,5,stop_untied=

# Port range to use for listening.
# Remember if you're connected through a NAT router, you'll
# need to forward these ports.
port_range = 50471-50479

# Enable peer exchange (for torrents not marked private)
peer_exchange = yes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;
&lt;h3&gt;Part 2 &amp;#8211; Save Link In Folder&lt;/h3&gt;&lt;br /&gt;
Okay, so you&amp;#8217;ve got rTorrent all set up now, and configured to watch for new &lt;strong&gt;.torrent files in a directory (mine is &lt;em&gt;~/downloads/torrents/&lt;/strong&gt;.torrent&lt;/em&gt;). Now let&amp;#8217;s configure Firefox. There&amp;#8217;s an extension by &lt;a href=&quot;http://mozext.achimonline.de/&quot;&gt;Achim Seufert&lt;/a&gt; called &lt;a href=&quot;http://addons.mozilla.org/en-US/firefox/addon/613&quot;&gt;Save Link In Folder&lt;/a&gt;. You&amp;#8217;ll want to install this.&lt;/p&gt;
&lt;p&gt;After your browser restarts, go to &lt;em&gt;Tools &amp;gt; Add-ons &amp;gt; Save Link In Folder &amp;gt; Preferences&lt;/em&gt; and add a new folder, like this&amp;#8230;&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;alignnone size-full wp-image-80&quot; title=&quot;Save Link In Folder - Torrents&quot; src=&quot;http://blog.logankoester.com/wp-content/uploads/2009/03/savelinkinfolder.png&quot; alt=&quot;Save Link In Folder - Torrents&quot; width=&quot;463&quot; height=&quot;448&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Remember &amp;#8211; the download directory must be the one you told rTorrent to watch!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;alignnone size-full wp-image-82&quot; title=&quot;Downloading a torrent&quot; src=&quot;http://blog.logankoester.com/wp-content/uploads/2009/03/downloadingtorrents.png&quot; alt=&quot;Downloading a torrent&quot; width=&quot;463&quot; height=&quot;365&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Now when you click a torrent link, just save it instead of opening it with Deluge. If rTorrent is running it will notice the new torrent, and get to work! You can even queue up torrents while rTorrent is off, for downloading later.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m definitely an rTorrent noob, having just set this up tonight, but so far I like it a lot, and no longer have the performance issues I had using Deluge. This configuration would also be ideal for setting up a seedbox / media center machine, if you set up all your Firefoxes to save torrent files to a network mount on the server.&lt;/p&gt;
&lt;h3&gt;Links&lt;/h3&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://libtorrent.rakshasa.no/&quot;&gt;rTorrent&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://libtorrent.rakshasa.no/wiki/RTorrentUserGuide&quot;&gt;rTorrent user guide&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://libtorrent.rakshasa.no/rtorrent/rtorrent.1.html&quot;&gt;rTorrent man page&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://addons.mozilla.org/en-US/firefox/addon/613&quot;&gt;Save Link In Folder&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <title>TweetShrink gem for Ruby</title>
   <link href="http://blog.logankoester.com/tweetshrink-gem-for-ruby.html"/>
   <updated>2009-03-06T00:00:00-08:00</updated>
   <id>http://blog.logankoester.com/tweetshrink-gem-for-ruby</id>
   <content type="html">&lt;h2&gt;TweetShrink gem for Ruby&lt;/h2&gt;
&lt;p class=&quot;publish_date&quot;&gt;06 Mar 2009&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://tweetshrink.com&quot;&gt;TweetShrink&amp;#8217;s&lt;/a&gt; &lt;a href=&quot;http://tweetshrink.com/api&quot;&gt;&lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;&lt;/a&gt; is so simple that this gem barely adds anything on top of &lt;a href=&quot;http://github.com/jnunemaker/httparty/tree/master&quot;&gt;HTTParty&lt;/a&gt;, but here it is.&lt;/p&gt;
&lt;pre&gt;&lt;code lang=&quot;ruby&quot;&gt;require 'rubygems'
require 'tweetshrink'

t = TweetShrink.shrink &quot;One wonders why&quot;
# t['difference'] =&amp;gt; 4
# t['text'] =&amp;gt; &quot;1 wonders y&quot;
# t['original_text'] =&amp;gt; &quot;One wonders why&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can get it from my github account, &lt;a href=&quot;http://github.com/logankoester/tweetshrink/tree/master&quot;&gt;here&lt;/a&gt;, or via rubygems like&lt;/p&gt;
&lt;pre&gt;&lt;code lang=&quot;bash&quot;&gt;$ sudo gem install logankoester-tweetshrink&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Enjoy.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Installing Linux Mint 6 on your Asus EeePC 901</title>
   <link href="http://blog.logankoester.com/installing-linux-mint-6-on-your-asus-eeepc-901.html"/>
   <updated>2009-01-08T00:00:00-08:00</updated>
   <id>http://blog.logankoester.com/installing-linux-mint-6-on-your-asus-eeepc-901</id>
   <content type="html">&lt;h2&gt;Installing Linux Mint 6 on your Asus EeePC 901&lt;/h2&gt;
&lt;p class=&quot;publish_date&quot;&gt;08 Jan 2009&lt;/p&gt;
&lt;p&gt;I was a fan of &lt;a title=&quot;http://www.geteasypeasy.com/&quot; href=&quot;http://&quot;&gt;ubuntu-eee&lt;/a&gt; (now known as EasyPeasy) for a long time, but after upgrading to EasyPeasy 1.0 on my &lt;a href=&quot;http://www.amazon.com/exec/obidos/ASIN/B001BYB620/logakoes-20/ref=nosim/&quot;&gt;20gb &lt;span class=&quot;caps&quot;&gt;EEE&lt;/span&gt; 901&lt;/a&gt; ($379.99) tonight, I&amp;#8217;ve decided it&amp;#8217;s time to move on, and I&amp;#8217;m happy I chose &lt;a href=&quot;http://www.linuxmint.com/&quot;&gt;Linux Mint&lt;/a&gt;. Here&amp;#8217;s what I&amp;#8217;ve done so far to get it running great:&lt;br /&gt;
&lt;h3&gt;Install Linux Mint&lt;/h3&gt;&lt;br /&gt;
Since the EeePC has no optical media drive, you will need a &lt;span class=&quot;caps&quot;&gt;USB&lt;/span&gt; flash drive to install Mint. Download the Linux Mint .iso file and use &lt;a href=&quot;http://lubi.sourceforge.net/unetbootin.html&quot;&gt;UNetbootin&lt;/a&gt; to burn it to your &lt;span class=&quot;caps&quot;&gt;USB&lt;/span&gt; disk, then plug it into your Eee.&lt;/p&gt;
&lt;p&gt;Turn on the machine and hit &lt;strong&gt;F2&lt;/strong&gt; to enter the &lt;span class=&quot;caps&quot;&gt;BIOS&lt;/span&gt; setup. Set the boot priority to try the &lt;span class=&quot;caps&quot;&gt;USB&lt;/span&gt; disk first. You may also want to make sure the webcam/bluetooth is turned on, while you&amp;#8217;re here. Save your changes and reboot, and Mint will guide you through the rest of the installation.&lt;/p&gt;
&lt;p&gt;When it asks you how you want to partition your disk, choose &lt;strong&gt;Guided &amp;#8211; use entire disk&lt;/strong&gt; and let it use the larger of the two SSDs.&lt;br /&gt;
&lt;h3&gt;Install the EeePC kernel&lt;/h3&gt;&lt;br /&gt;
As usual with Linux installations, most of your hardware will work from the get-go, but not everything. The first thing you&amp;#8217;ll want to do is get the wireless card working. Plug in an ethernet cable, and then follow &lt;a href=&quot;http://www.array.org/ubuntu/setup-intrepid.html&quot;&gt;these instructions&lt;/a&gt;. I recommend the &lt;em&gt;lean&lt;/em&gt; kernel, and uninstalling the generic one since it will just be wasting precious disk space.&lt;br /&gt;
&lt;h3&gt;Enable Desktop Effects&lt;/h3&gt;&lt;br /&gt;
Mint makes this easy for you by taking care of installing the correct drivers for your video card. All you should need to do is turn &lt;a href=&quot;http://www.freedesktop.org/wiki/Software/Compiz&quot;&gt;Compiz&lt;/a&gt; on in &lt;strong&gt;Preferences &amp;gt; Appearance &amp;gt; Desktop Effects&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;aligncenter size-full wp-image-23&quot; title=&quot;Enabling Desktop Effects in GNOME&quot; src=&quot;http://blog.logankoester.com/wp-content/uploads/2009/01/desktop_effects.png&quot; alt=&quot;Enabling Desktop Effects in GNOME&quot; width=&quot;606&quot; height=&quot;545&quot; /&gt;&lt;br /&gt;
&lt;h3&gt;Allow tall windows to move past the top of the screen&lt;/h3&gt;&lt;br /&gt;
Sooner or later you&amp;#8217;re going to run into a window that is too tall to display on the 9&amp;quot; screen, and cannot be resized. The solution is to open up a terminal and run this command:&lt;br /&gt;
&lt;pre&gt;$ gconftool-2 &amp;#8212;set /apps/compiz/plugins/move/allscreens/options/constrain_y &amp;#8212;type bool 0&lt;/pre&gt;&lt;br /&gt;
This will allow you to move these windows past the top of the screen (use ALT+Drag anywhere in the window. There are a number of other useful gconftool hacks on &lt;a href=&quot;https://help.ubuntu.com/community/EeePC/Using&quot;&gt;Ubuntu&amp;#8217;s EeePC page&lt;/a&gt;.&lt;br /&gt;
&lt;h3&gt;Create $&lt;span class=&quot;caps&quot;&gt;HOME&lt;/span&gt;/bin directory&lt;/h3&gt;&lt;br /&gt;
You&amp;#8217;re going to want a place to store little scripts and tools where they can be executed on the command line.&lt;br /&gt;
&lt;pre&gt;$ mkdir &lt;sub&gt;/bin&lt;/pre&gt;&lt;br /&gt;
Now add it to your &lt;span class=&quot;caps&quot;&gt;PATH&lt;/span&gt; so &lt;a href=&quot;http://en.wikipedia.org/wiki/Bash&quot;&gt;bash&lt;/a&gt; can find it. Open up your ~/.bashrc file and append&lt;br /&gt;
&lt;pre&gt;if [ -d ~/bin ] ; then&lt;br /&gt;
  &lt;span class=&quot;caps&quot;&gt;PATH&lt;/span&gt;=&lt;/sub&gt;/bin:&amp;#8220;${PATH}&amp;#8221;&lt;br /&gt;
fi&lt;/pre&gt;&lt;br /&gt;
&lt;h3&gt;Make the &lt;span class=&quot;caps&quot;&gt;LCD&lt;/span&gt; ultra bright!&lt;/h3&gt;&lt;br /&gt;
This hack is really cool. I found it on the &lt;a href=&quot;http://www.ubuntu-eee.com/wiki/index.php5?title=How_to:_Ultra_Bright_LCD&quot;&gt;EasyPeasy wiki&lt;/a&gt;. Create a new file called &lt;strong&gt;ultra-bright&lt;/strong&gt; in $&lt;span class=&quot;caps&quot;&gt;HOME&lt;/span&gt;/bin and paste in this line, then save.&lt;br /&gt;
&lt;pre&gt;sudo setpci -s 00:02.1 f4.b=ff&lt;/pre&gt;&lt;br /&gt;
You will need to make it executable, so&lt;br /&gt;
&lt;pre&gt;$ chmod +x ~/bin/ultra-bright&lt;/pre&gt;&lt;br /&gt;
Now you can run&lt;br /&gt;
&lt;pre&gt;$ ultra-bright&lt;/pre&gt;&lt;br /&gt;
to turn on the extra brightness, and use the bright/dim function keys to reset it. If you&amp;#8217;re like me, you&amp;#8217;ll want the extra brightness turned on all the time, so go ahead and create an entry for it in &lt;strong&gt;Preferences &amp;gt; Sessions&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;aligncenter size-full wp-image-19&quot; title=&quot;Making the screen ultra bright when you log in&quot; src=&quot;http://blog.logankoester.com/wp-content/uploads/2009/01/ultrabright_sessions.png&quot; alt=&quot;Making the screen ultra bright when you log in&quot; width=&quot;484&quot; height=&quot;398&quot; /&gt;&lt;br /&gt;
&lt;h3&gt;Enable the WiFi / Bluetooth / webcam toggle and performance tuner&lt;/h3&gt;&lt;br /&gt;
For this you&amp;#8217;ll need a package called &lt;strong&gt;eee-control&lt;/strong&gt;. You&amp;#8217;ve already installed the Eee kernel, so this package should be available to you from the repository you added to your Software Sources.&lt;br /&gt;
&lt;pre&gt;$ sudo apt-get install eee-control&lt;/pre&gt;&lt;br /&gt;
Alternatively, you can download the Ubuntu package from &lt;a href=&quot;http://greg.geekmind.org/eee-control/#download&quot;&gt;the website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now you can find this nifty utility in your &lt;strong&gt;Administration&lt;/strong&gt; menu. Unless you need the extra battery life, I recommend setting performance to &amp;#8220;super&amp;#8221;. To make use of your webcam, install the &lt;a href=&quot;http://live.gnome.org/Cheese&quot;&gt;&lt;strong&gt;cheese&lt;/strong&gt;&lt;/a&gt; and/or &lt;a href=&quot;http://www.skype.com/&quot;&gt;&lt;strong&gt;skype&lt;/strong&gt;&lt;/a&gt; packages.&lt;br /&gt;
&lt;h3&gt;Make sure text is being rendered crystal clear&lt;/h3&gt;&lt;br /&gt;
Open &lt;strong&gt;Preferences &amp;gt; Appearance&lt;/strong&gt; &amp;gt; &lt;strong&gt;Fonts &lt;/strong&gt;and select &amp;#8220;Subpixel smoothing (LCDs)&amp;#8221;. Then click &lt;strong&gt;Details&amp;#8230;&lt;/strong&gt; and set &lt;strong&gt;Hinting&lt;/strong&gt; to &amp;#8220;Full&amp;#8221;. If you&amp;#8217;re like me you absolutely hate Ubuntu&amp;#8217;s default monospace font. I prefer &lt;a href=&quot;http://fractal.csie.org/~eric/wiki/Terminus_font&quot;&gt;Terminus&lt;/a&gt;. To switch, install the &lt;strong&gt;xfonts-terminus&lt;/strong&gt; package and make it the default Fixed Width font.&lt;br /&gt;
&lt;h3&gt;Boost &lt;span class=&quot;caps&quot;&gt;GNOME&lt;/span&gt; Performance with /etc/hosts&lt;/h3&gt;&lt;br /&gt;
Following &lt;a href=&quot;http://linuxmint.com/wiki/index.php/Boost_Gnome_Performance_by_tweaking_/etc/hosts&quot;&gt;this guide&lt;/a&gt; will help improve your system performance, and it takes about 2 seconds.&lt;br /&gt;
&lt;h3&gt;Installing Avant Window Navigator&lt;/h3&gt;&lt;br /&gt;
&lt;a href=&quot;https://launchpad.net/awn&quot;&gt;&lt;span class=&quot;caps&quot;&gt;AWN&lt;/span&gt;&lt;/a&gt; is similar to the Dock on Mac OS X.&lt;br /&gt;
&lt;pre&gt;$ sudo apt-get install avant-window-navigator&lt;/pre&gt;&lt;br /&gt;
Right-click the panel at the bottom of your screen and check &amp;#8220;Allow Panel to be Moved&amp;#8221;. Drag it to the top of your screen, right-click and lock it again. Now launch &lt;strong&gt;Accessories &amp;gt; Avant Window Navigator&lt;/strong&gt;. It&amp;#8217;s kind of ugly and huge by default, but we can fix that.&lt;/p&gt;
&lt;p&gt;Right-click on &lt;span class=&quot;caps&quot;&gt;AWN&lt;/span&gt; and click &lt;strong&gt;Preferences&lt;/strong&gt;. Turn on &amp;#8220;Auto hide bar when not in use&amp;#8221;, then switch to the &lt;strong&gt;Bar Appearance&lt;/strong&gt; tab and change &lt;em&gt;Bar Height&lt;/em&gt; to something more reasonable, like 32.&lt;/p&gt;
&lt;p&gt;Now you&amp;#8217;ll want to get rid of the Window List at the top of the screen. Right-click on it and select &amp;#8220;Remove from Panel&amp;#8221;. Gone! Now there is lots of room for program shortcuts and silly panel applets.&lt;br /&gt;
&lt;h2&gt;That&amp;#8217;s it!&lt;/h2&gt;&lt;br /&gt;
You now have a usable OS on your Asus EeePC, which means you are both cooler and more attractive than every other clown with a clunky Xandros-based netbook. Thanks for following my guide. Let me know in the comments section how your installation experience went and if you have any other &lt;span class=&quot;caps&quot;&gt;EEE&lt;/span&gt; tricks worth sharing.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>slashhardcore.rb is a station tuner for Digitally Imported radio</title>
   <link href="http://blog.logankoester.com/slashhardcore.html"/>
   <updated>2007-08-29T00:00:00-07:00</updated>
   <id>http://blog.logankoester.com/slashhardcore</id>
   <content type="html">&lt;h2&gt;slashhardcore.rb is a station tuner for Digitally Imported radio&lt;/h2&gt;
&lt;p class=&quot;publish_date&quot;&gt;29 Aug 2007&lt;/p&gt;
&lt;p class=&quot;new&quot;&gt;I updated this script! Forgot to bind the /hardcore command before. Grab it &lt;a href=&quot;http://logankoester.com/files/slashhardcore.rb&quot;&gt;now&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;I was surprised how easy it is to write an &lt;a href=&quot;http://www.xchat.org/&quot;&gt;XChat&lt;/a&gt; plugin in &lt;a href=&quot;http://www.ruby-lang.org/en/&quot;&gt;Ruby&lt;/a&gt;, even though it would be cooler to see a the xchat-ruby bindings pimped out &lt;a href=&quot;http://en.wikipedia.org/wiki/Domain-specific_programming_language&quot;&gt;&lt;span class=&quot;caps&quot;&gt;DSL&lt;/span&gt;&lt;/a&gt; style&amp;#8230;oh well.&lt;br /&gt;
&lt;p class=&quot;download&quot;&gt;Download &lt;a href=&quot;http://logankoester.com/files/slashhardcore.rb&quot;&gt;slashhardcore.rb&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;
&lt;p class=&quot;information&quot;&gt;Windows users must modify &lt;strong&gt;@launcher&lt;/strong&gt; to the path to their Winamp, Firefox, IE, or other shoutcast-compatible player.&lt;/p&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code lang=&quot;ruby&quot;&gt;
# slashhardcore.rb - A faster way to tune in than the playlist bot.
# Should work on Windows if you set a valid browser/winamp location.
#
# Usage: Put in your $HOME/.xchat2 directory to autoload, and restart xchat,
# or type &quot;/load /path/to/slashhardcore.rb&quot;
#
# Commands: /pls &amp;lt;station, /stations (list stations), /hardcore
#
# Author: Logan Koester &amp;lt;logan@logankoester.com&amp;gt;

include XChatRuby

class SlashHardcore &amp;lt; XChatRubyPlugin

	attr_accessor :launcher

	def initialize( plugin )
		@launcher = &quot;/usr/bin/firefox&quot;
		hook_command( &quot;pls&quot;, XCHAT_PRI_NORM,
			method ( :pls ),
			&quot;Use /pls &amp;lt;station&amp;gt; to tune in. Use /stations to check list
			of stations at di.fm&quot;
		)
		hook_command( &quot;stations&quot;, XCHAT_PRI_NORM,
			method ( :stations_list ),
			&quot;Fetches an updated list of DI.fm stations&quot;
		)
		hook_command( &quot;hardcore&quot;, XCHAT_PRI_NORM,
			method ( :hardcore ),
			&quot;Tunes into the happyhardcore.com radio stream&quot;
		)
		puts_fmt &quot;Digitally Imported!&quot;
	end

	# Alias for /pls hardcore
	def hardcore (words, words_eol, data)
		puts_fmt &quot;Hardcore is good for you!&quot;
		play &quot;hardcore&quot;
		return XCHAT_EAT_ALL
	end

	# Tunes you in using your browses's default application
	# for *.pls files
	def pls (words, words_eol, data)
		station = words[1]
		puts_fmt &quot;Tuning into #{station} (using #{@launcher})&quot;
		@plugin.command( &quot;/msg #candyball test&quot; )
		play station
		return XCHAT_EAT_ALL
	end

	def play (station)
		exec &quot;#{@launcher} http://di.fm/mp3/#{station}.pls&quot; if fork == nil
	end

	# Returns the playlist filenames of playlists at di.fm
	def stations_list (words, words_eol, data)
		require 'open-uri'
		uri = &quot;http://www.di.fm/mobile/?type=mp3&quot;
		index = URI.parse uri
		list = index.read.to_s.scan(/=&quot;\/mp3\/(.*)\.pls/).flatten
		puts_fmt list.join &quot;, &quot; # CSV string
		return XCHAT_EAT_ALL
	end
end
&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 
</feed>

