<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/stylesheets/rss.css" type="text/css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Tom Moertel's Weblog: Category typo</title>
    <link>http://blog.moertel.com/articles/category/typo</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Quality rants on programming theory and stuff geeks like</description>
    <item>
      <title>Adding Haskell syntax highlighting to the Typo blogging system</title>
      <description>&lt;p&gt;Last night on &lt;a href="irc://irc.freenode.net/%23haskell"&gt;#haskell&lt;/a&gt;, &lt;a href="http://www.cse.unsw.edu.au/~dons/"&gt;Don
Stewart&lt;/a&gt; asked if I had seen
&lt;a href="http://www.cs.york.ac.uk/fp/darcs/hscolour/"&gt;HsColour&lt;/a&gt;
for rendering syntax-highlighted Haskell in &lt;span class="caps"&gt;HTML&lt;/span&gt;.  He had
used it recently, he noted in passing, &lt;a href="http://cgi.cse.unsw.edu.au/~dons/blog/2006/09/10#colours"&gt;to add syntax highlighting to planet.haskell.org&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Now, I can&amp;#8217;t be certain about this, but I suspect that Don&amp;#8217;s question
was cleverly designed to instill in me a subtle case of
syntax-highlighting envy.  For on &lt;a href="http://blog.moertel.com/"&gt;&lt;em&gt;my&lt;/em&gt; blog&lt;/a&gt;, Haskell code snippets
were rendered in dreadfully boring uncolored text.
But on &lt;a href="http://cgi.cse.unsw.edu.au/~dons/blog"&gt;&lt;em&gt;his&lt;/em&gt; blog&lt;/a&gt;, the
snippets dance in joyous polychromatic splendor.&lt;/p&gt;


	&lt;p&gt;Thus I was compelled to add Haskell syntax-highlighting to my blog.&lt;/p&gt;


	&lt;h3&gt; Adding Haskell syntax-highlighting to Typo&lt;/h3&gt;


	&lt;p&gt;My blog runs on the Ruby-on-Rails-powered &lt;a href="http://typosphere.org/"&gt;Typo&lt;/a&gt;
system, which &lt;a href="http://scottstuff.net/blog/articles/2005/08/23/introduction-to-typo-filters"&gt;allows for plug-in text filters&lt;/a&gt;.  One of the included filters, in fact, is a syntax-highlighting filter for snippets of Ruby, &lt;span class="caps"&gt;XML&lt;/span&gt;, and &lt;span class="caps"&gt;YAML&lt;/span&gt; code.  This filter is built upon the Ruby &lt;a href="http://syntax.rubyforge.org/"&gt;Syntax&lt;/a&gt; module, which wasn&amp;#8217;t exactly designed for Haskell syntax analysis.  So I set out to create a new plug-in filter based upon HsColour.&lt;/p&gt;


	&lt;p&gt;This task turned out to be easy.  All I did was duplicate
Typo&amp;#8217;s existing syntax-highlighting filter and swap out its filtering
code for the following:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="constant"&gt;IO&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;popen&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;HsColour -css&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;r+&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;f&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
  &lt;span class="ident"&gt;pid&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;fork&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="ident"&gt;f&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;write&lt;/span&gt; &lt;span class="ident"&gt;text&lt;/span&gt;&lt;span class="punct"&gt;;&lt;/span&gt; &lt;span class="ident"&gt;f&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;close&lt;/span&gt;&lt;span class="punct"&gt;;&lt;/span&gt; &lt;span class="ident"&gt;exit!&lt;/span&gt; &lt;span class="number"&gt;0&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;
  &lt;span class="ident"&gt;f&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;close_write&lt;/span&gt;
  &lt;span class="ident"&gt;text&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;f&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;read&lt;/span&gt;
  &lt;span class="constant"&gt;Process&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;waitpid&lt;/span&gt; &lt;span class="ident"&gt;pid&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;I also tweaked the post-processing regular expressions so that they
would whittle away the &lt;span class="caps"&gt;HTML&lt;/span&gt; filler before and after the
syntax-highlighted output of HsColour:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;text&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;gsub!&lt;/span&gt;&lt;span class="punct"&gt;(/&lt;/span&gt;&lt;span class="regex"&gt;.*&amp;lt;p()re&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;...)&lt;/span&gt;
&lt;span class="ident"&gt;text&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;gsub!&lt;/span&gt;&lt;span class="punct"&gt;(/&lt;/span&gt;&lt;span class="regex"&gt;&amp;lt;&lt;span class="escape"&gt;\/&lt;/span&gt;pre&amp;gt;.*&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;...)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;A few more tweaks and I was done.&lt;/p&gt;


	&lt;p&gt;Now I can wrap my Haskell code in &amp;lt;typo:haskell&amp;gt; tags and it, too, will
dance in joyous polychromatic splendor:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='varid'&gt;constructTable&lt;/span&gt; &lt;span class='varid'&gt;tspecs&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;
    &lt;span class='varid'&gt;ecolspecs&lt;/span&gt; &lt;span class='keyglyph'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='varid'&gt;during&lt;/span&gt; &lt;span class='str'&gt;"argument evaluation"&lt;/span&gt; &lt;span class='varop'&gt;$&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;
        &lt;span class='varid'&gt;toNvps&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;concat&lt;/span&gt; &lt;span class='varop'&gt;=&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='varid'&gt;mapM&lt;/span&gt; &lt;span class='varid'&gt;splice&lt;/span&gt; &lt;span class='varid'&gt;tspecs&lt;/span&gt;
    &lt;span class='keyword'&gt;let&lt;/span&gt; &lt;span class='varid'&gt;names&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;map&lt;/span&gt; &lt;span class='varid'&gt;fst&lt;/span&gt; &lt;span class='varid'&gt;ecolspecs&lt;/span&gt;
    &lt;span class='keyword'&gt;let&lt;/span&gt; &lt;span class='varid'&gt;evecs&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;map&lt;/span&gt; &lt;span class='varid'&gt;snd&lt;/span&gt; &lt;span class='varid'&gt;ecolspecs&lt;/span&gt;
    &lt;span class='varid'&gt;vecs&lt;/span&gt; &lt;span class='keyglyph'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='varid'&gt;argof&lt;/span&gt; &lt;span class='varid'&gt;nm&lt;/span&gt; &lt;span class='varop'&gt;$&lt;/span&gt; &lt;span class='varid'&gt;mapM&lt;/span&gt; &lt;span class='varid'&gt;evalVector&lt;/span&gt; &lt;span class='varid'&gt;evecs&lt;/span&gt;
    &lt;span class='keyword'&gt;let&lt;/span&gt; &lt;span class='varid'&gt;vlens&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;map&lt;/span&gt; &lt;span class='varid'&gt;vlen&lt;/span&gt; &lt;span class='varid'&gt;vecs&lt;/span&gt;
    &lt;span class='keyword'&gt;if&lt;/span&gt; &lt;span class='varid'&gt;length&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;group&lt;/span&gt; &lt;span class='varid'&gt;vlens&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varop'&gt;==&lt;/span&gt; &lt;span class='num'&gt;1&lt;/span&gt;
        &lt;span class='keyword'&gt;then&lt;/span&gt; &lt;span class='varid'&gt;return&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='conid'&gt;VTable&lt;/span&gt; &lt;span class='varop'&gt;$&lt;/span&gt; &lt;span class='varid'&gt;mkTable&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;zip&lt;/span&gt; &lt;span class='varid'&gt;names&lt;/span&gt; &lt;span class='varid'&gt;vecs&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
        &lt;span class='keyword'&gt;else&lt;/span&gt; &lt;span class='varid'&gt;throwError&lt;/span&gt; &lt;span class='varop'&gt;$&lt;/span&gt;
             &lt;span class='str'&gt;"table columns must be non-empty vectors of equal length"&lt;/span&gt;
  &lt;span class='keyword'&gt;where&lt;/span&gt;
    &lt;span class='varid'&gt;nm&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='str'&gt;"table(...) constructor"&lt;/span&gt;
    &lt;span class='varid'&gt;splice&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;TCol&lt;/span&gt; &lt;span class='varid'&gt;envp&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;  &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;return&lt;/span&gt; &lt;span class='keyglyph'&gt;[&lt;/span&gt;&lt;span class='varid'&gt;envp&lt;/span&gt;&lt;span class='keyglyph'&gt;]&lt;/span&gt;
    &lt;span class='varid'&gt;splice&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='conid'&gt;TSplice&lt;/span&gt; &lt;span class='varid'&gt;e&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;  &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='keyword'&gt;do&lt;/span&gt;
        &lt;span class='varid'&gt;val&lt;/span&gt; &lt;span class='keyglyph'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='varid'&gt;eval&lt;/span&gt; &lt;span class='varid'&gt;e&lt;/span&gt;
        &lt;span class='keyword'&gt;case&lt;/span&gt; &lt;span class='varid'&gt;val&lt;/span&gt; &lt;span class='keyword'&gt;of&lt;/span&gt;
            &lt;span class='conid'&gt;VTable&lt;/span&gt; &lt;span class='varid'&gt;t&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt;
                &lt;span class='varid'&gt;return&lt;/span&gt; &lt;span class='varop'&gt;$&lt;/span&gt; &lt;span class='varid'&gt;zipWith&lt;/span&gt; &lt;span class='varid'&gt;mkNVP&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;tcnames&lt;/span&gt; &lt;span class='varid'&gt;t&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;elems&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;tvecs&lt;/span&gt; &lt;span class='varid'&gt;t&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
            &lt;span class='conid'&gt;VList&lt;/span&gt; &lt;span class='varid'&gt;gl&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt;
                &lt;span class='varid'&gt;liftM&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;zipWith&lt;/span&gt; &lt;span class='varid'&gt;mkNVP&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;map&lt;/span&gt; &lt;span class='varid'&gt;name&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='varid'&gt;elems&lt;/span&gt; &lt;span class='varop'&gt;$&lt;/span&gt; &lt;span class='varid'&gt;glnames&lt;/span&gt; &lt;span class='varid'&gt;gl&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt; &lt;span class='varop'&gt;$&lt;/span&gt;
                &lt;span class='varid'&gt;mapM&lt;/span&gt; &lt;span class='varid'&gt;asVectorNull&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;elems&lt;/span&gt; &lt;span class='varop'&gt;$&lt;/span&gt; &lt;span class='varid'&gt;glvals&lt;/span&gt; &lt;span class='varid'&gt;gl&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
            &lt;span class='keyword'&gt;_&lt;/span&gt; &lt;span class='keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='varid'&gt;throwError&lt;/span&gt; &lt;span class='varop'&gt;$&lt;/span&gt;
                &lt;span class='str'&gt;"can't construct table columns from ("&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt;
                &lt;span class='varid'&gt;show&lt;/span&gt; &lt;span class='varid'&gt;val&lt;/span&gt; &lt;span class='varop'&gt;++&lt;/span&gt; &lt;span class='str'&gt;")"&lt;/span&gt;
    &lt;span class='varid'&gt;mkNVP&lt;/span&gt; &lt;span class='varid'&gt;n&lt;/span&gt; &lt;span class='varid'&gt;vec&lt;/span&gt; &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='conid'&gt;NVP&lt;/span&gt; &lt;span class='varid'&gt;n&lt;/span&gt; &lt;span class='layout'&gt;(&lt;/span&gt;&lt;span class='varid'&gt;mkNoPosExpr&lt;/span&gt; &lt;span class='varop'&gt;.&lt;/span&gt; &lt;span class='conid'&gt;EVal&lt;/span&gt; &lt;span class='varop'&gt;$&lt;/span&gt; &lt;span class='conid'&gt;VVector&lt;/span&gt; &lt;span class='varid'&gt;vec&lt;/span&gt;&lt;span class='layout'&gt;)&lt;/span&gt;
    &lt;span class='varid'&gt;name&lt;/span&gt; &lt;span class='str'&gt;""&lt;/span&gt;     &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='str'&gt;"NA"&lt;/span&gt;
    &lt;span class='varid'&gt;name&lt;/span&gt; &lt;span class='varid'&gt;n&lt;/span&gt;      &lt;span class='keyglyph'&gt;=&lt;/span&gt; &lt;span class='varid'&gt;n&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;If you want the filter code, here it is: &lt;a href="http://community.moertel.com/~thor/blog/haskell_controller.rb.txt"&gt;haskell_controller.rb&lt;/a&gt;.  Just drop it into &lt;code&gt;components/plugins/textfilters&lt;/code&gt; and restart Typo.  The corresponding &lt;span class="caps"&gt;CSS&lt;/span&gt; styles can be found in my &lt;a href="http://blog.moertel.com/stylesheets/user-styles.css"&gt;user-styles.css&lt;/a&gt;.&lt;/p&gt;</description>
      <pubDate>Wed, 01 Nov 2006 17:01:00 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:62648231-3b46-4d96-a657-69565f7ee784</guid>
      <author>Tom Moertel</author>
      <link>http://blog.moertel.com/articles/2006/11/01/adding-haskell-syntax-highlighting-to-the-typo-blogging-system</link>
      <category>haskell</category>
      <category>ruby</category>
      <category>typo</category>
      <category>typo</category>
      <category>ruby</category>
      <category>haskell</category>
      <category>hscolour</category>
      <trackback:ping>http://blog.moertel.com/articles/trackback/207</trackback:ping>
    </item>
    <item>
      <title>Database connection leak in Typo 4.0.3: problem solved</title>
      <description>&lt;p&gt;In &lt;a href="http://blog.moertel.com/articles/2006/08/24/typo-4-0-3-instability-and-a-minor-patch-for-sqlite3-ruby"&gt;an earlier post&lt;/a&gt; I wrote about stability
problems that have plagued my blog since upgrading from &lt;a href="http://typosphere.org"&gt;Typo&lt;/a&gt; 4.0.0 to 4.0.3.  I have finally traced the problem to its source, and here&amp;#8217;s the deal:&lt;/p&gt;


	&lt;p&gt;&lt;em&gt;If you&amp;#8217;re serving Typo up via &lt;a href="http://mongrel.rubyforge.org/index.html"&gt;Mongrel&lt;/a&gt;, do not configure ActiveRecord to allow concurrency.&lt;/em&gt;&lt;/p&gt;


	&lt;p&gt;One of the changes between Typo 4.0.0 and 4.0.3 is this
addition to the &lt;code&gt;environment.rb&lt;/code&gt; file:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;config.active_record.allow_concurrency = true
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;&lt;del&gt;Comment out this line, restart Typo, and the problem is solved.&lt;/del&gt;
Apply Changeset 1255, and the problem is solved.  (See
&lt;a href="#article165-update2"&gt;Update 2&lt;/a&gt;, below.)&lt;/p&gt;


	&lt;h3&gt;Discussion&lt;/h3&gt;


&lt;p&gt;When &lt;code&gt;ActiveRecord::Base.allow_concurrency&lt;/code&gt; is set to
&lt;code&gt;true&lt;/code&gt;, AR will give each thread its own database
connections and cache them in thread-localized storage.  The idea is
that, in a multi-threaded environment, this simple policy prevents
unsafe interactions between threads and the database.  (Imagine what
would happen if one thread &amp;#8220;borrowed&amp;#8221; a connection over which
another thread had opened a transaction.  Oops, there goes
transactional isolation.)&lt;/p&gt;

	&lt;p&gt;This policy, however, does place a burden on the owner of the threads to
make sure that each thread&amp;#8217;s local connection cache is cleared when
the thread is joined, a burden that is not, it would seem, being
carried by Typo under Mongrel.  As a result, Typo rapidly chews
through the allotment of file descriptors that the operating system
kindly had reserved for Mongrel:&lt;/p&gt;


	&lt;p&gt;&lt;img src="http://community.moertel.com/~thor/pix/20060824/blog-fd-usage-vs-time.png" title="Typo 4.0.3 on Mongrel w/ SQLite3 consumes about 1.7 file descriptors per minute when ActiveRecord is configured to allow concurrency" alt="Typo 4.0.3 on Mongrel w/ SQLite3 consumes about 1.7 file descriptors per minute when ActiveRecord is configured to allow concurrency" /&gt;&lt;/p&gt;


	&lt;p&gt;(On my Linux server, the Mongrel process gets an allotment of 1024
file descriptors.)&lt;/p&gt;


	&lt;p&gt;Lucky for us, this each-thread-gets-its-own-connections policy is unnecessary under
Mongrel because Mongrel, while being multi-threaded itself, serializes
all access to the Rails-based applications it serves up:&lt;/p&gt;


&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Q: Is [Mongrel] multi-threaded or can it handle concurrent requests?&lt;/strong&gt;&lt;/p&gt;

	&lt;p&gt;Mongrel is uses a pool of thread workers to do it&amp;#8217;s processing. This means that it is able to handle concurrent access and should be thread safe. This also means that you have to be more careful about how you use Mongrel. You can&amp;#8217;t just write your application assuming that there are no threads involved. ...&lt;/p&gt;


	&lt;p&gt;Ruby on Rails is not thread safe so there is a synchronized block around the calls to Dispatcher.dispatch. This means that everything is threaded right before and right after Rails runs. While Rails is running there is only one controller in operation at a time.&lt;/p&gt;


(Source: &lt;a href="http://mongrel.rubyforge.org/faq.html"&gt;Mongrel &lt;span class="caps"&gt;FAQ&lt;/span&gt; list&lt;/a&gt;)
&lt;/blockquote&gt;

Thus we can safely turn off (i.e., comment out in Typo&amp;#8217;s
&lt;code&gt;environment.rb&lt;/code&gt; file) ActiveRecord&amp;#8217;s allow-currency option
without having to worry about nasty concurrency or performance issues:

&lt;pre&gt;&lt;code&gt;# the following line is commented out
# config.active_record.allow_concurrency = true
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;For more on this subject, see &lt;a href="http://dev.rubyonrails.org/ticket/2162"&gt;Rails ticket
#2162&lt;/a&gt; and &lt;a href="http://dev.rubyonrails.org/ticket/2742"&gt;Rails ticket
#2742&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Now, here&amp;#8217;s my question: Are there any environments in which
Typo can run with the allow-concurrency option enabled and &lt;em&gt;not&lt;/em&gt;
leak database connections?  Inquiring minds want to know.&lt;/p&gt;


&lt;div class="update"&gt;

	&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Upon further investigation, turning off
concurrency might not be altogether without risk.  Some of the Typo
code that handles potentially long tasks, such as making trackbacks
and pings, spawns new threads in which to carry out its work.  I&amp;#8217;m
looking further into this risk.  Updates to come.&lt;/p&gt;


&lt;p id="article165-update2"&gt;&lt;strong&gt;Update 2:&lt;/strong&gt; Piers Cawley added &lt;a href="http://www.typosphere.org/trac/changeset/1255"&gt;Changeset
1255&lt;/a&gt;, which turns AR&amp;#8217;s
allow-concurrency flag back off and revises the ping code so that
it does not attempt concurrent database access.  Apply &lt;a href="http://www.typosphere.org/trac/changeset/1255?format=diff&amp;#38;new=1255"&gt;the patch version of
1255&lt;/a&gt;
and restart Typo to get the fix.  A tip of the hat to Piers for making
the quick fix when he was supposed to be on holiday.&lt;/p&gt;

&lt;/div&gt;</description>
      <pubDate>Thu, 24 Aug 2006 15:41:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:ef03f59b-8bc4-4744-b94d-2966da53dca2</guid>
      <author>Tom Moertel</author>
      <link>http://blog.moertel.com/articles/2006/08/24/database-connection-leak-in-typo-4-0-3-problem-solved</link>
      <category>ruby</category>
      <category>typo</category>
      <category>rails</category>
      <category>typo</category>
      <category>sqlite3</category>
      <category>rails</category>
      <category>activerecord</category>
      <category>concurrency</category>
      <trackback:ping>http://blog.moertel.com/articles/trackback/165</trackback:ping>
    </item>
    <item>
      <title>Typo-4.0.3 instability and a minor patch for sqlite3-ruby</title>
      <description>&lt;p&gt;Since I upgraded my blog from &lt;a href="http://typosphere.org/"&gt;Typo&lt;/a&gt; 4.0.0 to
4.0.3, it has been somewhat unstable.  About once a day it starts
responding with &amp;#8220;500 Internal Server Error&amp;#8221; and stays that way until I
restart it.&lt;/p&gt;


	&lt;p&gt;The root of the problem seems to be the database
connection, as evidenced by this exception showing up in the
production log:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;SQLite3::CantOpenException (could not open database)
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Unfortunately, the exception doesn&amp;#8217;t provide anything specific
to go on.&lt;/p&gt;


	&lt;p&gt;A quick look at the
&lt;a href="http://rubyforge.org/projects/sqlite-ruby/"&gt;sqlite3-ruby&lt;/a&gt; code
suggested that I was not going to get the specifics, either.  The Ruby-based wrapper
never calls &lt;a href="http://www.sqlite.org/capi3ref.html#sqlite3_errmsg"&gt;sqlite3_errmsg&lt;/a&gt; after a call to &lt;a href="http://www.sqlite.org/capi3ref.html#sqlite3_open"&gt;sqlite3_open&lt;/a&gt; fails on behalf of SQLite3::Database.new.&lt;/p&gt;


	&lt;p&gt;A quick patch, however, fixed the problem:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;--- sqlite3-ruby-1.1.0.orig/lib/sqlite3/database.rb
+++ sqlite3-ruby-1.1.0/lib/sqlite3/database.rb
@@ -109,7 +109,7 @@
       @statement_factory = options[:statement_factory] || Statement

       result, @handle = @driver.open( file_name, utf16 )
-      Error.check( result, nil, "could not open database" )
+      Error.check( result, self, "could not open database" )

       @closed = false
       @results_as_hash = options.fetch(:results_as_hash,false)
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;(Submitted as &lt;a href="http://rubyforge.org/tracker/index.php?func=detail&amp;#38;aid=5504&amp;#38;group_id=254&amp;#38;atid=1043"&gt;Ticket 5504&lt;/a&gt; on &lt;a href="http://rubyforge.org/"&gt;RubyForge&lt;/a&gt;.)&lt;/p&gt;


	&lt;p&gt;Before applying the patch, opening a database at a nonexistent path results in
a generic error message:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;$ ruby -r rubygems -e 'require_gem "sqlite3-ruby";
    SQLite3::Database.new("/no/such/path/db")'

&lt;/code&gt;... could not open database (SQLite3::CantOpenException) ...
&lt;/pre&gt;

	&lt;p&gt;After applying the patch, we get additional error information:&lt;/p&gt;


&lt;pre&gt;... could not open database: unable to open database file
    (SQLite3::CantOpenException) ...
&lt;/pre&gt;

	&lt;p&gt;With the patch in place, all I have to do is wait for Typo to start
acting up again.  Then I&amp;#8217;ll have some interesting information in the
log.&lt;/p&gt;


	&lt;p&gt;Until then, I&amp;#8217;m relying on &lt;a href="http://en.wikipedia.org/wiki/Crontab"&gt;cron&lt;/a&gt;
and a short monitoring script to restart Typo when it tips into
foolishness:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;#!/bin/bash

url=http://blog.moertel.com/admin
addrs=tom@moertel.com

response=$(GET -sd $url 2&amp;gt;&amp;#38;1)

if [ "$response" != "200 OK" ]; then
    { echo "Response was: $response"; echo; service typo restart; } |
    mail -s "Blog site not responding! (Restarting)" $addrs
fi
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;We&amp;#8217;ll see how it goes.&lt;/p&gt;


&lt;div class="update"&gt; &lt;strong&gt;Update:&lt;/strong&gt; That was fast.  The error popped up
again and this time the log told me something useful: &amp;#8220;unable to open
database file.&amp;#8221;  Now, why couldn&amp;#8217;t Typo open the database file,
especially since the file is perfectly fine and had been opened
successfully (many times) by the very same Typo process earlier?  Here&amp;#8217;s
a hint:

&lt;pre&gt;&lt;code&gt;$ ls /proc/28788/fd | wc -l
&lt;/code&gt;1023
&lt;/pre&gt;

	&lt;p&gt;Seems like there&amp;#8217;s a resource leak in Typo 4.0.3 (or Rails 1.1.6).
Under some conditions, instead of reusing existing database
connections, Typo keeps trying to open new ones.  Eventually, it uses
up its allotment of file descriptors and the operating system is forced
to say, &amp;#8220;That&amp;#8217;s enough, pal,&amp;#8221; (&lt;a href="http://www.wlug.org.nz/EMFILE"&gt;&lt;code&gt;EMFILE&lt;/code&gt;&lt;/a&gt;).&lt;/p&gt;


	&lt;p&gt;I&amp;#8217;ll look in to it more in the morning.&lt;/p&gt;


&lt;strong&gt;Update 2:&lt;/strong&gt; &lt;a href="http://blog.moertel.com/articles/2006/08/24/database-connection-leak-in-typo-4-0-3-problem-solved"&gt;Problem solved&lt;/a&gt;.
&lt;/div&gt;</description>
      <pubDate>Thu, 24 Aug 2006 00:41:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:2e527a1f-3415-4322-9f0f-244b45a3b695</guid>
      <author>Tom Moertel</author>
      <link>http://blog.moertel.com/articles/2006/08/24/typo-4-0-3-instability-and-a-minor-patch-for-sqlite3-ruby</link>
      <category>ruby</category>
      <category>typo</category>
      <category>rails</category>
      <category>sysadmin</category>
      <category>typo</category>
      <category>sqlite3</category>
      <category>rails</category>
      <trackback:ping>http://blog.moertel.com/articles/trackback/163</trackback:ping>
    </item>
    <item>
      <title>Adding reddit and del.icio.us buttons to articles in Typo</title>
      <description>&lt;p&gt;Here&amp;#8217;s quick patch I made to my &lt;a href="http://typosphere.org"&gt;Typo&lt;/a&gt; 4.0
installation to add &lt;a href="http://reddit.com"&gt;Reddit&lt;/a&gt; and
&lt;a href="http://del.icio.us/"&gt;del.icio.us&lt;/a&gt; buttons to articles.  Now one click
is all it takes to submit an article to either site.  (These buttons
appear on my blog at the end of each article.)&lt;/p&gt;


	&lt;p&gt;If you want to apply the patch, be sure to also place copies of the
button images into &lt;code&gt;public/images&lt;/code&gt;.  You can snag the
images from my site or from the Reddit and del.icio.us sites.&lt;/p&gt;


	&lt;p&gt;Here&amp;#8217;s the patch:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;--- typo.orig/app/helpers/articles_helper.rb    2006-07-24 11:04:27.000000000 -0400
+++ typo/app/helpers/articles_helper.rb    2006-08-09 17:06:51.000000000 -0400
@@ -73,7 +74,26 @@
       code &amp;lt;&amp;lt; tag_links(article)        unless article.tags.empty?
       code &amp;lt;&amp;lt; comments_link(article)    if article.allow_comments?
       code &amp;lt;&amp;lt; trackbacks_link(article)  if article.allow_pings?
-    end.join("&amp;amp;nbsp;&amp;lt;strong&amp;gt;|&amp;lt;/strong&amp;gt;&amp;amp;nbsp;")
+      code &amp;lt;&amp;lt; submit_this_article_links(article)
+    end.join("&amp;amp;nbsp;| ")
+  end
+
+  def submit_this_article_links(article)
+    u_url = u(url_of(article, false))
+    u_title = u(article.title)
+    [  # move me into a database table
+      [ "Submit to Reddit.com",
+        "http://reddit.com/submit?url=&amp;lt;URL&amp;gt;&amp;#38;title=&amp;lt;TITLE&amp;gt;",
+        image_tag("reddit.gif", :size =&amp;gt; "18x18", :border =&amp;gt; 0)
+      ],
+      [ "Save to del.icio.us",
+        "http://del.icio.us/post?v=2&amp;#38;url=&amp;lt;URL&amp;gt;&amp;#38;title=&amp;lt;TITLE&amp;gt;",
+        image_tag("delicious.gif", :size =&amp;gt; "16x16", :border =&amp;gt; 0)
+      ]
+    ].map do |submit_title, submit_url, image_tag|
+      submit_url = submit_url.gsub(/&amp;lt;URL&amp;gt;/, u_url).gsub(/&amp;lt;TITLE&amp;gt;/, u_title)
+      %(&amp;lt;a href="#{h submit_url}" title="#{h submit_title}: &amp;amp;#x201C;#{h article.title}&amp;amp;#x201D;"&amp;gt;#{image_tag}&amp;lt;/a&amp;gt;)
+    end.join("&amp;amp;nbsp;")
   end

   def category_links(article)
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The code is begging for a little refactoring love, but I&amp;#8217;m off for vacation
in about twenty minutes, so it will have to wait.&lt;/p&gt;</description>
      <pubDate>Wed, 09 Aug 2006 18:25:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:517cb441-e204-4713-94c5-321917af0d73</guid>
      <author>Tom Moertel</author>
      <link>http://blog.moertel.com/articles/2006/08/09/adding-reddit-and-del-icio-us-buttons-to-articles-in-typo</link>
      <category>site news</category>
      <category>typo</category>
      <category>hacks</category>
      <category>typo</category>
      <category>reddit</category>
      <category>delicous</category>
      <trackback:ping>http://blog.moertel.com/articles/trackback/152</trackback:ping>
    </item>
    <item>
      <title>Upgrading my blog to run Typo 4.0</title>
      <description>&lt;p&gt;If my blog looks a little weird right now, please bear with me. I am
in the process of upgrading from Typo 2.6.0 to Typo 4.0, and so far
the process has been somewhat painful.&lt;/p&gt;


	&lt;p&gt;The new Typo installer did not have much luck upgrading my blog to the
new version. After fighting and solving a succession of errors and
confidence-sapping problems, I decided to abandon the upgrade
process. Instead, I changed to the course most likely to result in a
stable configuration: to install a new blog and then move my content
over to it.&lt;/p&gt;


	&lt;p&gt;The content-moving process was easier than it might sound. I manually
migrated the old blog database to the new database format; dumped it
to a &lt;span class="caps"&gt;SQL&lt;/span&gt; file; edited the file to remove all but the &lt;span class="caps"&gt;INSERT&lt;/span&gt; statements
for articles, comments, pages, and so on; and then I loaded the
statements into the new database.&lt;/p&gt;


	&lt;p&gt;I did not copy over my configuration and sidebar information, however,
because I figured it would be safer to use the Typo-4.0 defaults,
those being the most tested. I also recreated my user account from
scratch.&lt;/p&gt;


	&lt;p&gt;So far the blog seems to be running stably, enough at least
for me to restore public access again.   But I still have more
restoration ahead.  Next I will work on restoring my espresso theme.&lt;/p&gt;


&lt;div class="update"&gt;
&lt;strong&gt;Update 2006-07-26:&lt;/strong&gt; I have now restored my espresso theme. For a while I was considering using &lt;a href="http://quotedprintable.com/pages/scribbish"&gt;Scribbish&lt;/a&gt;, which is delightfully clean by comparison, but it has not yet been updated to support much of Typo 4.0&amp;#8217;s goodness. Maybe later.
&lt;/div&gt;</description>
      <pubDate>Mon, 24 Jul 2006 13:34:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:3adc6c1c-9bfe-4c2a-b1c3-a346ce975100</guid>
      <author>Tom Moertel</author>
      <link>http://blog.moertel.com/articles/2006/07/24/upgrading-my-blog-run-to-typo-4-0</link>
      <category>site news</category>
      <category>typo</category>
      <category>typo</category>
      <trackback:ping>http://blog.moertel.com/articles/trackback/146</trackback:ping>
    </item>
    <item>
      <title>Improving Typo's spam protection</title>
      <description>&lt;p&gt;I noticed that my site has been picking up more comment spam recently.
&lt;a href="http://www.typosphere.org/"&gt;Typo&lt;/a&gt; has built-in spam protection, but for
some reason a few spam comments that ought to have been caught slipped
through its filters.  Curious, I investigated.&lt;/p&gt;


	&lt;p&gt;Most spam comments contain links to sites favored by the spammers.
The sites are almost always of the form &lt;em&gt;x.domain&lt;/em&gt;.com,
where &lt;em&gt;domain&lt;/em&gt; is one of a few higher-level domains and &lt;em&gt;x&lt;/em&gt; is drawn
from a large set of values from the realms of gambling, pornography,
and male enhancement.  It seems that the spammers pay for a few real
domains and then create a ton of subdomains under them.&lt;/p&gt;


	&lt;p&gt;One of the ways to detect comment spam is to find URIs in comments and
look up the sites they point to in &lt;span class="caps"&gt;DNS&lt;/span&gt;-based
&lt;acronym title="spam-URI realtime blackout lists"&gt;SURBL&lt;/acronym&gt;s,
such as &lt;a href="http://www.surbl.org/"&gt;multi.surbl.org&lt;/a&gt; and
&lt;a href="http://bsb.empty.us/"&gt;bsb.empty.us&lt;/a&gt;.  The thing is, when SURBLs list a
spammy site &lt;em&gt;x.domain&lt;/em&gt;.com, sometimes they list it under the full
hostname &lt;em&gt;x.domain&lt;/em&gt;.com and sometimes they list it
under the higher-level domain
&lt;em&gt;domain&lt;/em&gt;.com.  To be safe, Typo looks up both forms when it checks
for spam.&lt;/p&gt;


	&lt;p&gt;Here&amp;#8217;s the code it uses:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="constant"&gt;HOST_RBLS&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;rbl&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
  &lt;span class="keyword"&gt;begin&lt;/span&gt;
    &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;
        &lt;span class="constant"&gt;IPSocket&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;getaddress&lt;/span&gt;&lt;span class="punct"&gt;([&lt;/span&gt;&lt;span class="ident"&gt;host&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;rbl&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;join&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;.&lt;/span&gt;&lt;span class="punct"&gt;')),&lt;/span&gt;
        &lt;span class="constant"&gt;IPSocket&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;getaddress&lt;/span&gt;&lt;span class="punct"&gt;((&lt;/span&gt;&lt;span class="ident"&gt;domain&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;rbl&lt;/span&gt;&lt;span class="punct"&gt;]).&lt;/span&gt;&lt;span class="ident"&gt;join&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;.&lt;/span&gt;&lt;span class="punct"&gt;'))&lt;/span&gt;
       &lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;include?&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;127.0.0.2&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
      &lt;span class="ident"&gt;throw&lt;/span&gt; &lt;span class="symbol"&gt;:hit&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{rbl}&lt;/span&gt; positively resolved &lt;span class="expr"&gt;#{domain.join('.')}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;rescue&lt;/span&gt; &lt;span class="constant"&gt;SocketError&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;The code iterates over the list of SURBLs it has and queries each
twice &amp;#8211; once for the host and once for the domain in question &amp;#8211; saving
the results of the queries in an array.  Then if the array includes a
positive response (127.0.0.2), it throws a &amp;#8220;hit&amp;#8221; notice to the
calling code, which will block the associated comment.&lt;/p&gt;


	&lt;p&gt;Unfortunately, the code doesn&amp;#8217;t quite work as intended.  Although a
positive response for &lt;em&gt;either&lt;/em&gt; the host or the domain should register
as a hit, the code requires &lt;em&gt;both&lt;/em&gt; queries to return positive
responses.  As a result, the code yields a lot of false negatives
because most lists don&amp;#8217;t include both host and domain forms of spammy
sites; the required double positive is thus hard to obtain.&lt;/p&gt;


&lt;p&gt;The cause of the problem is the attempt to query for both forms of the
site before checking either response.  The queries are performed by
calling &lt;code&gt;IPSocket.getaddress&lt;/code&gt;, which performs a &lt;span class="caps"&gt;DNS&lt;/span&gt; query
for the &amp;#8220;A&amp;#8221; record associated with its argument.  If the record
exists, the call returns it; otherwise, the call raises a
&lt;code&gt;SocketError&lt;/code&gt; exception.&lt;/p&gt;

	&lt;p&gt;The exception is what causes the logic to break down.  When either the
host or domain is &lt;em&gt;not&lt;/em&gt; in the queried &lt;span class="caps"&gt;SURBL&lt;/span&gt;, which will almost always
be the case for reasons I explained earlier, one of the queries will
result in a &lt;code&gt;SocketError&lt;/code&gt; exception.  The exception will be
caught by the &lt;code&gt;rescue&lt;/code&gt; clause later in the code, but not
before the opportunity to test the other query&amp;#8217;s response and throw a
&amp;#8220;hit&amp;#8221; has been lost.&lt;/p&gt;


	&lt;p&gt;My fix was to replace the above code with a call to a new helper
method:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;query_rbls&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;HOST_RBLS&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;host&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;domain&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;join&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;.&lt;/span&gt;&lt;span class="punct"&gt;'))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;The helper, defined later, makes the actual queries:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;query_rbls&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;rbls&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;subdomains&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;rbls&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;rbl&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
    &lt;span class="ident"&gt;subdomains&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;uniq&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;d&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
      &lt;span class="keyword"&gt;begin&lt;/span&gt;
        &lt;span class="ident"&gt;response&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;IPSocket&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;getaddress&lt;/span&gt;&lt;span class="punct"&gt;([&lt;/span&gt;&lt;span class="ident"&gt;d&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;rbl&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;join&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;.&lt;/span&gt;&lt;span class="punct"&gt;'))&lt;/span&gt;
        &lt;span class="ident"&gt;throw&lt;/span&gt; &lt;span class="symbol"&gt;:hit&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{rbl}&lt;/span&gt; positively resolved &lt;span class="expr"&gt;#{d}&lt;/span&gt; =&amp;gt; &lt;span class="expr"&gt;#{response}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
      &lt;span class="keyword"&gt;rescue&lt;/span&gt; &lt;span class="constant"&gt;SocketError&lt;/span&gt;
        &lt;span class="comment"&gt;# NXDOMAIN response =&amp;gt; negative:  d is not in RBL&lt;/span&gt;
      &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="constant"&gt;false&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Because some SURBLs don&amp;#8217;t use 127.0.0.2 but some other &amp;#8220;A&amp;#8221; record to
indicate a positive response, my helper removes the hard-coded address
test.&lt;/p&gt;


	&lt;p&gt;I also made a few more improvements to the spam-protection
code.  The full set of changes is available as &lt;a href="http://www.typosphere.org/trac/ticket/657"&gt;Patch
657&lt;/a&gt; on the Typo Trac site.&lt;/p&gt;</description>
      <pubDate>Mon, 16 Jan 2006 01:34:00 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:a154474c903e93da6922f1a53a563f0a</guid>
      <author>Tom Moertel</author>
      <link>http://blog.moertel.com/articles/2006/01/16/improving-typos-spam-protection</link>
      <category>typo</category>
      <category>typo</category>
      <category>ruby</category>
      <category>spam</category>
      <trackback:ping>http://blog.moertel.com/articles/trackback/23</trackback:ping>
    </item>
    <item>
      <title>I have moved my blog over to Typo</title>
      <description>&lt;p&gt;&lt;a href="http://snipsnap.org/"&gt;SnipSnap&lt;/a&gt; no longer makes me happy, and I am switching my weblog over to the &lt;a href="http://typo.leetsoft.com/"&gt;Typo&lt;/a&gt; weblog system and moving it to &lt;a href="http://blog.moertel.com/"&gt;blog.moertel.com&lt;/a&gt;.  I like Rails, and Typo is Rails-based coding at its finest. And Typo has a future. Besides, I want another opportunity to take a perfectly good website theme and destroy it with my utter lack of design acumen.&lt;/p&gt;


	&lt;p&gt;As far as content goes, I will move my old posts over as time permits.  For now, you can read them on &lt;a href="http://community.moertel.com/"&gt;the old site&lt;/a&gt;, which will remain up. (The Community Projects are still hosted there.)&lt;/p&gt;


	&lt;p&gt;If you are subscribed to my old feeds, don&amp;#8217;t worry: Apache trickery will automagically redirect your &lt;span class="caps"&gt;RSS&lt;/span&gt; reader to my new feeds here.  If fact, if you are reading this, you are already getting the new stuff.&lt;/p&gt;


	&lt;p&gt;&amp;#8212;Tom&lt;/p&gt;</description>
      <pubDate>Thu, 25 Aug 2005 16:41:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:b28aad4b52981c07ffa35080b8152d97</guid>
      <author>Tom Moertel</author>
      <link>http://blog.moertel.com/articles/2005/08/25/i-have-moved-my-blog-over-to-typo</link>
      <category>site news</category>
      <category>typo</category>
      <trackback:ping>http://blog.moertel.com/articles/trackback/1</trackback:ping>
    </item>
  </channel>
</rss>
