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

<channel>
	<title>An Experiment in Bloggery &#187; Programming</title>
	<atom:link href="http://kevin.sb.org/category/programming/feed/" rel="self" type="application/rss+xml" />
	<link>http://kevin.sb.org</link>
	<description>The occasional view into my life</description>
	<lastBuildDate>Wed, 30 Jun 2010 18:48:33 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>ExecTweets on the App Store</title>
		<link>http://kevin.sb.org/2009/05/18/exectweets-on-the-app-store/</link>
		<comments>http://kevin.sb.org/2009/05/18/exectweets-on-the-app-store/#comments</comments>
		<pubDate>Mon, 18 May 2009 21:10:42 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[ExecTweets]]></category>
		<category><![CDATA[Twitter]]></category>

		<guid isPermaLink="false">http://kevin.sb.org/?p=180</guid>
		<description><![CDATA[My last iPhone contract app, ExecTweets for iPhone, is now on the App Store. This is the project that drove the creation of FeedParser (an open source Obj-C RSS parser). Anyway, it&#8217;s free, and if you like reading about business advice from top business execs, check it out!]]></description>
			<content:encoded><![CDATA[<p>My last iPhone contract app, <a href="http://exectweets.com">ExecTweets</a> for iPhone, is now on the <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=314677692&#038;mt=8">App Store</a>. This is the project that drove the creation of <a href="http://github.com/kballard/feedparser">FeedParser</a> (an open source Obj-C RSS parser). Anyway, it&#8217;s free, and if you like reading about business advice from top business execs, check it out!</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2009/05/18/exectweets-on-the-app-store/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Guarding against `‌` and Kernel#system() in your tests</title>
		<link>http://kevin.sb.org/2008/05/14/guarding-against-shelling-out-in-your-tests/</link>
		<comments>http://kevin.sb.org/2008/05/14/guarding-against-shelling-out-in-your-tests/#comments</comments>
		<pubDate>Wed, 14 May 2008 08:35:34 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[RSpec]]></category>
		<category><![CDATA[tests]]></category>

		<guid isPermaLink="false">http://kevin.sb.org/?p=154</guid>
		<description><![CDATA[Update: I've refactored the code significantly and introduced the ability to explicitly unguard methods from within specs. One problem I find myself having when writing tests is ensuring that no execution ever leaves my little test sandbox. For example, when writing tests for github-gem I keep looking through the code to find every place a [...]]]></description>
			<content:encoded><![CDATA[<p><b>Update:</b> I've refactored the code significantly and introduced the ability to explicitly unguard methods from within specs.</p>
<p>One problem I find myself having when writing tests is ensuring that no execution ever leaves my little test sandbox. For example, when writing tests for <a href="http://github.com/kballard/github-gem">github-gem</a> I keep looking through the code to find every place a function ends up `shelling out` and it's tiresome and error-prone. I finally decided I was going about this backwards. Testing is supposed to find problems for me, right? So why not raise an error whenever `` or Kernel#system() is called and let the tests tell me what else I need to mock?</p>
<p>Put the following code in your spec_helper.rb file and an exception will be raised whenever `` or Kernel#system() is called during a test:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
</pre></td><td class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> <span style="color:#9966CC; font-weight:bold;">Module</span>
  <span style="color:#9966CC; font-weight:bold;">def</span> metaclass
    <span style="color:#9966CC; font-weight:bold;">class</span> <span style="color:#006600; font-weight:bold;">&lt;&lt;</span> <span style="color:#0000FF; font-weight:bold;">self</span>;self;end
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">module</span> <span style="color:#6666ff; font-weight:bold;">Spec::Example::ExampleGroupSubclassMethods</span>
  <span style="color:#9966CC; font-weight:bold;">def</span> add_guard<span style="color:#006600; font-weight:bold;">&#40;</span>klass, name, is_class = <span style="color:#0000FF; font-weight:bold;">false</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    guarded = <span style="color:#0000FF; font-weight:bold;">nil</span> <span style="color:#008000; font-style:italic;"># define variable now for scoping</span>
    target = <span style="color:#006600; font-weight:bold;">&#40;</span>is_class ? klass.<span style="color:#9900CC;">metaclass</span> : klass<span style="color:#006600; font-weight:bold;">&#41;</span>
    sep = <span style="color:#006600; font-weight:bold;">&#40;</span>is_class ? <span style="color:#996600;">&quot;.&quot;</span> : <span style="color:#996600;">&quot;#&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    target.<span style="color:#9900CC;">class_eval</span> <span style="color:#9966CC; font-weight:bold;">do</span>
      guarded = instance_method<span style="color:#006600; font-weight:bold;">&#40;</span>name<span style="color:#006600; font-weight:bold;">&#41;</span>
      define_method name <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|*</span>args<span style="color:#006600; font-weight:bold;">|</span>
        <span style="color:#CC0066; font-weight:bold;">raise</span> <span style="color:#996600;">&quot;Testing guards violated: Cannot call #{klass}#{sep}#{name}&quot;</span>
      <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#0066ff; font-weight:bold;">@guards</span> <span style="color:#006600; font-weight:bold;">||</span>= <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#93;</span>
    <span style="color:#0066ff; font-weight:bold;">@guards</span> <span style="color:#006600; font-weight:bold;">&lt;&lt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span>klass, name, is_class, guarded<span style="color:#006600; font-weight:bold;">&#93;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> add_class_guard<span style="color:#006600; font-weight:bold;">&#40;</span>klass, name<span style="color:#006600; font-weight:bold;">&#41;</span>
    add_guard<span style="color:#006600; font-weight:bold;">&#40;</span>klass, name, <span style="color:#0000FF; font-weight:bold;">true</span><span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> unguard<span style="color:#006600; font-weight:bold;">&#40;</span>klass, name, is_class = <span style="color:#0000FF; font-weight:bold;">false</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    row = <span style="color:#0066ff; font-weight:bold;">@guards</span>.<span style="color:#9900CC;">find</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">|</span><span style="color:#006600; font-weight:bold;">&#40;</span>k,n,i<span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">|</span> k == klass <span style="color:#9966CC; font-weight:bold;">and</span> n == name <span style="color:#9966CC; font-weight:bold;">and</span> i == is_class <span style="color:#006600; font-weight:bold;">&#125;</span>
    <span style="color:#CC0066; font-weight:bold;">raise</span> <span style="color:#996600;">&quot;#{klass}#{is_class ? '.' : '#'}#{name} is not guarded&quot;</span> <span style="color:#9966CC; font-weight:bold;">if</span> row.<span style="color:#0000FF; font-weight:bold;">nil</span>?
    <span style="color:#006600; font-weight:bold;">&#40;</span>is_class ? klass.<span style="color:#9900CC;">metaclass</span> : klass<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">class_eval</span> <span style="color:#9966CC; font-weight:bold;">do</span>
      define_method name, row.<span style="color:#9900CC;">last</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#0066ff; font-weight:bold;">@guards</span>.<span style="color:#9900CC;">delete</span> row
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> class_unguard<span style="color:#006600; font-weight:bold;">&#40;</span>klass, name<span style="color:#006600; font-weight:bold;">&#41;</span>
    unguard<span style="color:#006600; font-weight:bold;">&#40;</span>klass, name, <span style="color:#0000FF; font-weight:bold;">true</span><span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> unguard_all
    <span style="color:#0066ff; font-weight:bold;">@guards</span> <span style="color:#006600; font-weight:bold;">||</span>= <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#93;</span>
    <span style="color:#0066ff; font-weight:bold;">@guards</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>klass, name, is_class, guarded<span style="color:#006600; font-weight:bold;">|</span>
      <span style="color:#006600; font-weight:bold;">&#40;</span>is_class ? klass.<span style="color:#9900CC;">metaclass</span> : klass<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">class_eval</span> <span style="color:#9966CC; font-weight:bold;">do</span>
        define_method name, guarded
      <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
    <span style="color:#0066ff; font-weight:bold;">@guards</span>.<span style="color:#9900CC;">clear</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#6666ff; font-weight:bold;">Spec::Runner</span>.<span style="color:#9900CC;">configure</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>configuration<span style="color:#006600; font-weight:bold;">|</span>
  configuration.<span style="color:#9900CC;">prepend_before</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:all</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
    <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9966CC; font-weight:bold;">class</span>.<span style="color:#9900CC;">send</span> <span style="color:#ff3333; font-weight:bold;">:include</span>, <span style="color:#6666ff; font-weight:bold;">Spec::Example::ExampleGroupSubclassMethods</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  configuration.<span style="color:#9900CC;">prepend_before</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:each</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
    add_guard <span style="color:#CC00FF; font-weight:bold;">Kernel</span>, :<span style="color:#996600;">'`'</span>
    add_guard <span style="color:#CC00FF; font-weight:bold;">Kernel</span>, <span style="color:#ff3333; font-weight:bold;">:system</span>
    add_class_guard <span style="color:#CC00FF; font-weight:bold;">Process</span>, <span style="color:#ff3333; font-weight:bold;">:fork</span>
    add_class_guard Open3, <span style="color:#ff3333; font-weight:bold;">:popen3</span> <span style="color:#9966CC; font-weight:bold;">if</span> <span style="color:#9966CC; font-weight:bold;">defined</span>? Open3
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  configuration.<span style="color:#9900CC;">append_after</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:each</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
    unguard_all
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></td></tr></table></div>

<p>Note: if you want, you can write <code style="color:#996600">:`</code> instead of <code style="color:#996600">:'`'</code>, but my syntax highlighter here doesn't like that.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2008/05/14/guarding-against-shelling-out-in-your-tests/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>GrabUp released</title>
		<link>http://kevin.sb.org/2008/04/16/grabup-released/</link>
		<comments>http://kevin.sb.org/2008/04/16/grabup-released/#comments</comments>
		<pubDate>Wed, 16 Apr 2008 06:44:55 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[GrabUp]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://kevin.sb.org/?p=151</guid>
		<description><![CDATA[Recently I was contracted to write some software, and it&#8217;s just now been released. It&#8217;s called GrabUp. Basically, the whole purpose here is for zero-click sharing of screenshots. GrabUp is a daemon that sits in the background and waits for you to take a screenshot, then it instantly uploads it to the GrabUp servers and [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I was contracted to write some software, and it&#8217;s just now been released. It&#8217;s called <a href="http://www.grabup.com">GrabUp</a>. Basically, the whole purpose here is for zero-click sharing of screenshots. <a href="http://www.grabup.com">GrabUp</a> is a daemon that sits in the background and waits for you to take a screenshot, then it instantly uploads it to the GrabUp servers and puts the URL on your clipboard. It has a nice status item to let you know when it&#8217;s done. If you have GrabUp running and you want to share an image, just take the screenshot and then paste the URL anywhere. So far, GrabUp has been seen in <a href="http://www.tuaw.com/2008/04/15/grabup/" title="The Unofficial Apple Weblog">TUAW</a> and we also got a rather nice <a href="http://dbachrach.com/blog/2008/04/15/grabup-simply-amazing/" title="GrabUp: Simply Amazing">blog post</a> reviewing it.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2008/04/16/grabup-released/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>SafariSource v1.7.4 compatible with Safari Tidy</title>
		<link>http://kevin.sb.org/2008/03/18/safarisource-v174-compatible-with-safari-tidy/</link>
		<comments>http://kevin.sb.org/2008/03/18/safarisource-v174-compatible-with-safari-tidy/#comments</comments>
		<pubDate>Tue, 18 Mar 2008 22:10:47 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[safari]]></category>
		<category><![CDATA[Safari Tidy]]></category>
		<category><![CDATA[SafariSource]]></category>

		<guid isPermaLink="false">http://kevin.sb.org/2008/03/18/safarisource-v174-compatible-with-safari-tidy/</guid>
		<description><![CDATA[I&#8217;ve just pushed a new version of SafariSource out the door which is once again compatible with Safari Tidy. Please let me know if you have any problems. You can download it here. Note that this requires version 0.2.5 of Safari Tidy, which was just released today.]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve just pushed a new version of <a href="http://www.tildesoft.com/Misc.html#SafariSource">SafariSource</a> out the door which is once again compatible with <a href="http://zappatic.net/safaritidy/">Safari Tidy</a>. Please let me know if you have any problems. You can download it <a href="http://www.tildesoft.com/Files/SafariSource.zip">here</a>.</p>

<p>Note that this requires version 0.2.5 of Safari Tidy, which was just released today.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2008/03/18/safarisource-v174-compatible-with-safari-tidy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>git-svn mirrors of MacPorts and TextMate</title>
		<link>http://kevin.sb.org/2008/03/09/git-svn-mirrors-of-macports-and-textmate/</link>
		<comments>http://kevin.sb.org/2008/03/09/git-svn-mirrors-of-macports-and-textmate/#comments</comments>
		<pubDate>Mon, 10 Mar 2008 02:09:21 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[GitHub]]></category>
		<category><![CDATA[MacPorts]]></category>
		<category><![CDATA[TextMate]]></category>

		<guid isPermaLink="false">http://kevin.sb.org/2008/03/09/git-svn-mirrors-of-macports-and-textmate/</guid>
		<description><![CDATA[For those interested, I am currently maintaining git mirrors of the MacPorts and TextMate Bundles svn repositories on GitHub. I update these periodically, but at the moment only the master branch is published. MacPorts TextMate Bundles]]></description>
			<content:encoded><![CDATA[<p>For those interested, I am currently maintaining git mirrors of the <a href="http://www.macports.org">MacPorts</a> and <a href="http://www.macromates.com">TextMate Bundles</a> svn repositories on <a href="http://www.github.com">GitHub</a>. I update these periodically, but at the moment only the master branch is published.</p>

<ul>
<li><a href="http://github.com/kballard/macports/">MacPorts</a></li>
<li><a href="http://github.com/kballard/textmate-bundles/">TextMate Bundles</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2008/03/09/git-svn-mirrors-of-macports-and-textmate/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>SafariSource update</title>
		<link>http://kevin.sb.org/2007/06/24/safarisource-update/</link>
		<comments>http://kevin.sb.org/2007/06/24/safarisource-update/#comments</comments>
		<pubDate>Sun, 24 Jun 2007 16:26:00 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Czech]]></category>
		<category><![CDATA[safari]]></category>
		<category><![CDATA[SafariSource]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://47ea8264-01aa-4d0b-8dea-979c0858ffd8</guid>
		<description><![CDATA[I just released a new version of SafariSource which supports Safari 3.0 last night. This morning I received a Czech localization from Jakub Formanek, so I just released SafariSource v1.7.1. with the new localization. So if you&#8217;re using Safari 3.0, or if you&#8217;re Czech, go ahead and download SafariSource. If you&#8217;re using Safari 2.x, please [...]]]></description>
			<content:encoded><![CDATA[<p>I just released a new version of SafariSource which supports Safari 3.0 last night. This morning I received a Czech localization from Jakub Formanek, so I just released SafariSource v1.7.1. with the new localization.</p>

<p>So if you&#8217;re using Safari 3.0, or if you&#8217;re Czech, go ahead and download <a href="http://www.tildesoft.com/Files/SafariSource.zip">SafariSource</a>. If you&#8217;re using Safari 2.x, please let me know it still works as I can&#8217;t test that with 3.0 installed.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2007/06/24/safarisource-update/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>tcltumblr 0.1</title>
		<link>http://kevin.sb.org/2007/04/28/tcltumblr-0-1/</link>
		<comments>http://kevin.sb.org/2007/04/28/tcltumblr-0-1/#comments</comments>
		<pubDate>Sat, 28 Apr 2007 09:01:00 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tcl]]></category>
		<category><![CDATA[tumblr]]></category>

		<guid isPermaLink="false">http://79a08f5b-8b87-4474-b34b-fa52b0f62111</guid>
		<description><![CDATA[tcltumblr 0.1 is available for immediate use. It is a Tcl library that provides access to the Tumblr API. Download]]></description>
			<content:encoded><![CDATA[<p><a href="http://kevin.sb.org/pages/tcltumblr">tcltumblr</a> 0.1 is available for immediate use. It is a Tcl library that provides access to the <a href="http://www.tumblr.com">Tumblr</a> <a href="http://www.tumblr.com/api">API</a>.</p>

<p><a href="/files/tcltumblr0.1.tgz">Download</a></p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2007/04/28/tcltumblr-0-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Resurrection of Typosphere</title>
		<link>http://kevin.sb.org/2007/01/22/the-resurrection-of-typosphere/</link>
		<comments>http://kevin.sb.org/2007/01/22/the-resurrection-of-typosphere/#comments</comments>
		<pubDate>Mon, 22 Jan 2007 19:34:00 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[DreamHost]]></category>
		<category><![CDATA[irc]]></category>
		<category><![CDATA[Planet Argon]]></category>
		<category><![CDATA[spam]]></category>
		<category><![CDATA[subversion]]></category>
		<category><![CDATA[trac]]></category>
		<category><![CDATA[typo]]></category>
		<category><![CDATA[Typosphere]]></category>

		<guid isPermaLink="false">http://54f021aa-61c3-4e07-82f3-51e46c740bca</guid>
		<description><![CDATA[After months of absence, Typosphere has returned from the dead! We migrated off of Planet Argon and onto DreamHost, where we should have more control. We also upgraded to Trac 0.10.3 and turned off anonymous editing (users now have to register to file a ticket). This should (hopefully) prevent the issue that lead to Typosphere [...]]]></description>
			<content:encoded><![CDATA[<p>After months of absence, <a href="http://www.typosphere.org">Typosphere</a> has returned from the dead!</p>

<p>We migrated off of <a href="http://www.planetargon.com">Planet Argon</a> and onto <a href="http://www.dreamhost.com">DreamHost</a>, where we should have more control.
We also upgraded to <a href="http://trac.edgewall.org">Trac</a> 0.10.3 and turned off anonymous editing (users now have to register to file a ticket).
This should (hopefully) prevent the issue that lead to Typosphere dying in the first place.</p>

<div class="highlight">
<p>One important thing to note is that as part of this process, we also moved the subversion repository.
Unfortunately, the old repository was hosted as an svn:// URI using the typosphere.org domain, which meant
there was no way to preserve this URI (since we can&#8217;t run long-lived background daemons on DreamHost). The
new URI uses http and a new subdomain, so if necessary we can move the repository without moving the website.</p>

<p style="text-align: left">The new repository URL is <a href="http://svn.typosphere.org/typo/trunk">http://svn.typosphere.org/typo/trunk</a>.</p>
</div>

<p><span id="more-136"></span></p>

<p>The issue, as near as I can tell, is Typosphere started getting spammed massively. At this time none of the
developers (and that includes me) was really paying attention to Typo, as we were busy with other things. So
for about a month Typosphere Trac got so full of spam that, well, it was more spam in one location than
I&#8217;ve ever seen in the rest of my life. This managed to trip a bug in Trac that caused it to start sucking
CPU and RAM, and so Planet Argon turned off Trac for our account.</p>

<p>Some time later, the other developers and I started trying to resurrect Typosphere. Unfortunately, at about
this time the systems administrator for Planet Argon was preparing to leave the company, so any attempts at
contacting him to resolve the issue went unanswered. I eventually called Planet Argon (which is how I learned
that the systems administrator had, in fact, left that very day) and spoke to the new systems administrator. He
agreed to try and fix Trac for us, but after hearing nothing for a few days, I decided it would be better to seek
hosting elsewhere.</p>

<p>Luckily, I had access to a <a href="http://www.dreamhost.com">DreamHost</a> account with plenty of spare bandwidth and disk space,
so we decided to move there. For the most part the migration went smoothly, until I started up Trac and discovered
exactly how much spam was in there.</p>

<p>This problem stumped me for about 2 weeks. I spent several hours trying to clean it by hand one day, and after those
several hours I couldn&#8217;t tell the difference. So, yesterday, I finally sat down to try and solve the problem.</p>

<p>With the help of the fine folks on the <a href="irc://chat.freenode.net/#trac">#trac</a> IRC channel, especially coderanger, I wrote a script which deleted
every single ticket change after a certain timestamp (corresponding to the first spam comment). Unfortunately, there
were probably a handful of legitimate changes lost, but there really was no other alternative. In any case, this script
worked flawlessly, and Trac was de-spammed. To prevent this from happening in the future, I turned off anonymous
editing and installed a plugin which allows users to register for an account. Hopefully the requirement of registration
will block most spam.</p>

<p>There was one interesting aspect to this that puzzled me until yesterday. The vast majority of the spam I saw contained
words that I had placed into the blacklist ages ago. I couldn&#8217;t figure out why the spam protection wasn&#8217;t working.
And then yesterday I discovered the reason. The blacklist is kept on a page called BadContent. The first code block
on that page consists of regular expressions, one per line, that each match a blacklisted expression. Unfortunately,
I forgot to mark this page read-only. So what happened was one of the random spam attempts happened to target this
page. The spammer replaced the content with his own code block containing a vast number of <code>&lt;a href&gt;</code> tags linking
to spammy websites. This had the effect of replacing the entire blacklist with a bunch of regular expressions matching
<code>&lt;a href&gt;</code> tags. This meant that all of the stuff that was previously blacklisted was no longer being blocked, opening
the floodgates for all sorts of spam.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2007/01/22/the-resurrection-of-typosphere/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Haml: A new markup format for Rails</title>
		<link>http://kevin.sb.org/2007/01/19/haml-a-new-markup-format-for-rails/</link>
		<comments>http://kevin.sb.org/2007/01/19/haml-a-new-markup-format-for-rails/#comments</comments>
		<pubDate>Fri, 19 Jan 2007 07:38:00 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Haml]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[markup]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[XHTML]]></category>

		<guid isPermaLink="false">http://bb44e772-6a69-431f-8024-0b7918fd09d1</guid>
		<description><![CDATA[Haml is a new markup format for Ruby on Rails apps that just hit 1.0. At first glance it looks pretty odd, but it turns out to be really easy to write in, and it&#8217;s shorter and, actually, easier to read than the equivalent eRB. I think I&#8217;m going to convert Typo to use Haml [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://haml.hamptoncatlin.com/">Haml</a> is a new markup format for Ruby on Rails apps that just hit 1.0. At first glance
it looks pretty odd, but it turns out to be really easy to write in, and it&#8217;s shorter and,
actually, easier to read than the equivalent eRB.</p>

<p>I think I&#8217;m going to convert <a href="http://www.typosphere.org">Typo</a> to use <a href="http://haml.hamptoncatlin.com/">Haml</a> for all its templates. I already did Azure&#8217;s layout
file and it was pretty simple.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2007/01/19/haml-a-new-markup-format-for-rails/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Method Swizzling reimplemented</title>
		<link>http://kevin.sb.org/2006/12/30/method-swizzling-reimplemented/</link>
		<comments>http://kevin.sb.org/2006/12/30/method-swizzling-reimplemented/#comments</comments>
		<pubDate>Sun, 31 Dec 2006 00:36:00 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Method Swizzling]]></category>
		<category><![CDATA[objc]]></category>

		<guid isPermaLink="false">http://755af07c-abcf-4e90-a7ea-729102b32de8</guid>
		<description><![CDATA[Update: This code was written pre-Leopard, and as such doesn&#8217;t run under ObjC 2. See JRSwizzle for an updated version that runs under Leopard and Snow Leopard. Method Swizzling is one common technique of people writing hacks, such as Safari Plugins. Unfortunately, it&#8217;s always suffered from a flaw, wherein swizzling inherited methods affects all classes [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Update</strong>: This code was written pre-Leopard, and as such doesn&#8217;t run under ObjC 2. See <a href="http://github.com/rentzsch/jrswizzle">JRSwizzle</a> for an updated version that runs under Leopard and Snow Leopard.</p>

<p>Method Swizzling is one common technique of people writing hacks, such as <a href="http://www.pimpmysafari.com" title="Pimp My Safari">Safari Plugins</a>.
Unfortunately, it&#8217;s always suffered from a flaw, wherein swizzling inherited methods affects all
classes which inherit that method (including the base class), rather than the intended subclass.
This problem is discussed on the <a href="http://www.cocoadev.com/index.pl?MethodSwizzling">CocoaDev Method Swizzling</a> page.</p>

<p>As part of writing <a href="http://kevin.sb.org/articles/2006/12/27/yubnubsearch-simbl-bundle">YubNubSearch</a>, I decided to solve this problem.</p>

<p>First I looked into dynamic subclass generation + posing. Unfortunately, this has a big problem. In
this technique, calling the original implementation would naturally be done through a <code>[super foo]</code> call.
Unfortunately, when the compiler sees <code>super</code>, it hardcodes a reference to the superclass at which to
start the search. This means you cannot write this code in, say, a category on NSObject, then pull up the IMP
into a dynamically-generated subclass and have it work. So that throws out that idea.</p>

<p>The other idea I had, which I eventually went with, was to copy inherited methods into the subclass that you
wish to swizzle, before swizzling. It turned out to be fairly easy, and still has the same semantics as the old,
flawed technique for calling the original implementation.</p>

<p>You can download my implementation <a href="http://www.tildesoft.com/Files/MethodSwizzle.tgz">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2006/12/30/method-swizzling-reimplemented/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>
<!-- WP Super Cache is installed but broken. The path to wp-cache-phase1.php in wp-content/advanced-cache.php must be fixed! -->