<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:posterous="http://posterous.com/help/rss/1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
  <channel>
    <title>Continuous development</title>
    <link>http://exviva.posterous.com</link>
    <description>Web development notes</description>
    <generator>posterous.com</generator>
    <link xmlns="http://www.w3.org/2005/Atom" href="http://posterous.com/api/sup_update#9e1e6eb8a" type="application/json" rel="http://api.friendfeed.com/2008/03#sup" />
    
    
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/exviva" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="exviva" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://posterous.superfeedr.com/" /><item>
      <pubDate>Sun, 03 Oct 2010 17:02:00 -0700</pubDate>
      <title>Zend Framework app's PHPUnit suite 3x faster</title>
      <link>http://exviva.posterous.com/zend-framework-apps-phpunit-suite-3x-faster</link>
      <guid>http://exviva.posterous.com/zend-framework-apps-phpunit-suite-3x-faster</guid>
      <description>&lt;p&gt;
	&lt;h2&gt;The background&lt;/h2&gt;

&lt;p&gt;My regular readers may have already noticed I don&amp;rsquo;t even dare writing code without &lt;code&gt;TDD&lt;/code&gt;/&lt;code&gt;BDD&lt;/code&gt;-ing it from left to right. Unfortunately, my current job is based on Zend Framework. I say &amp;ldquo;unfortunately&amp;rdquo;, as (amongst other drawbacks) ZF&amp;rsquo;s architecture is far from professional in terms of testability.&lt;/p&gt;

&lt;p&gt;We currently have 600+ PHPUnit test cases, most of them for models and controllers, but quite some also for view helpers, bootstrap and even some views. The whole suite is taking around 90 seconds to run on my machine against a MySQL database (modelled with &lt;code&gt;Zend_Db*&lt;/code&gt; in an active record/table data gateway manner).&lt;/p&gt;

&lt;p&gt;In this post I&amp;rsquo;ll be showing how I managed to decrease the time &lt;strong&gt;from ~90 seconds to ~30 seconds&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;The problem&lt;/h2&gt;

&lt;p&gt;As I&amp;rsquo;ve mentioned before, Zend Framework isn&amp;rsquo;t really encouraging developers to do TDD (on the other hand, this shouldn&amp;rsquo;t be a surprise in the PHP community). The application architecture is based on singletons all around (front controller, session, layout, helper broker, registry, etc.), the bootstrap doesn&amp;rsquo;t &amp;ldquo;separate the cacheable from the non-cacheable&amp;rdquo;, there&amp;rsquo;s no built-in support for dependency injection, the ORM is cumbersome to stub out.&lt;/p&gt;

&lt;p&gt;Our approach used to involve calling &lt;code&gt;Our_Db_Table_Abstract::truncate()&lt;/code&gt; on each table used by the given test case. Not only was this inelegant, mundane to maintain and easy to forget, but as it later turned out, it was the biggest performance bottleneck. We&amp;rsquo;d either put it at the end of the test case &amp;ndash; which would not be executed if the assertion failed and we&amp;rsquo;d end up with a dirty db &amp;ndash; or we&amp;rsquo;d put it in &lt;code&gt;tearDown()&lt;/code&gt; &amp;ndash; which meant it ran even if a particular test didn&amp;rsquo;t use the given table.&lt;/p&gt;

&lt;p&gt;Another problem was controller tests. We needed to explicitly declare, which tables would be used by the test. Even with extra-simple syntax, it was still terribly inelegant. And if we&amp;rsquo;d forget about one table&amp;hellip;&lt;/p&gt;

&lt;p&gt;This is how it would look like in model tests:&lt;/p&gt;

&lt;p&gt;&lt;script src="https://gist.github.com/609080.js?file=ModelTest.php"&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;And in the controller:&lt;/p&gt;

&lt;p&gt;&lt;script src="https://gist.github.com/609080.js?file=ControllerTest.php"&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;As you can see, there&amp;rsquo;s a lot of verbosity, duplication and noise in the code. We need to do plenty of &amp;ldquo;plumbing&amp;rdquo; for the tasks that should be automatic.&lt;/p&gt;

&lt;h2&gt;The solution&lt;/h2&gt;

&lt;p&gt;The solution I came up with was inspired by Rails, and other frameworks. It can be summarized as: wrap each test case in a transaction, rolling it back after the test case.&lt;/p&gt;

&lt;p&gt;I implemented the solution using a PHPUnit listener, hooking up to &lt;code&gt;startTest()&lt;/code&gt; and &lt;code&gt;endTest()&lt;/code&gt; callbacks. Here&amp;rsquo;s the appropriate code fragment:&lt;/p&gt;

&lt;p&gt;&lt;script src="https://gist.github.com/609080.js?file=DatabaseTransaction.php"&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;These callbacks wrap a single test case, so the cycle is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;startTest()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setUp()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;test*()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tearDown()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;endTest()&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;And here&amp;rsquo;s the appropriate fragment of &lt;code&gt;phpunit.xml&lt;/code&gt; (we&amp;rsquo;re using PHPUnit 3.5):&lt;/p&gt;

&lt;p&gt;&lt;script src="https://gist.github.com/609080.js?file=phpunit.xml"&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Excellent, that&amp;rsquo;s an elegant solution with a properly separated concern. I got rid of all the ugly &lt;code&gt;truncate()&lt;/code&gt;s and sped up the tests significantly.&lt;/p&gt;

&lt;h2&gt;Caveats&lt;/h2&gt;

&lt;p&gt;Of course, life&amp;rsquo;s not &lt;strong&gt;that&lt;/strong&gt; full of sunshine and bunnies.&lt;/p&gt;

&lt;h3&gt;Problem #1&lt;/h3&gt;

&lt;p&gt;First problem I encountered, was bootstrapping the application inside the cycle mentioned above (anywhere within steps 2-4). This happens in controller, view, view helper and bootstrap test cases. Let&amp;rsquo;s go through a controller test case. We:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;startTest()&lt;/code&gt;, which begins a transaction&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setUp()&lt;/code&gt;, which bootstraps the application, which in turn &lt;strong&gt;puts a new &amp;lsquo;database&amp;rsquo; object in &lt;code&gt;Zend_Registry&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;endTest()&lt;/code&gt; calls &lt;code&gt;rollBack()&lt;/code&gt;, which explodes with &lt;code&gt;No active transaction&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;This basically means that we&amp;rsquo;re running &lt;code&gt;beginTransaction()&lt;/code&gt; and &lt;code&gt;rollBack()&lt;/code&gt; on a different database connection.&lt;/p&gt;

&lt;p&gt;One solution for this problem is to use a persistent PDO connection. This will most likely cause both methods to run on two different PHP objects, but same connection resource. To do this, just add the following setting to your database config:&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;params.persistent = true&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;I wanted something more robust, though, so I &lt;code&gt;rollBack()&lt;/code&gt; manually right before bootstrapping and &lt;code&gt;beginTransaction()&lt;/code&gt; immediately afterwards. It&amp;rsquo;s plumbing again, but at least it&amp;rsquo;s abstracted in a base class. Here&amp;rsquo;s an example:&lt;/p&gt;

&lt;p&gt;&lt;script src="https://gist.github.com/609080.js?file=ControllerTestCase.php"&gt;&lt;/script&gt;&lt;/p&gt;

&lt;h3&gt;Problem #2&lt;/h3&gt;

&lt;p&gt;Second caveat was quite obvious. Some of our tables were using MyISAM (which doesn&amp;rsquo;t support transactions), not InnoDB. I solved it by creating an appropriate migration, like so:&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;ALTER &lt;span class="r"&gt;TABLE&lt;/span&gt; Country &lt;span class="r"&gt;ENGINE&lt;/span&gt; = InnoDB;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;Problem #3&lt;/h3&gt;

&lt;p&gt;Some tests were still failing after all these changes. The problem was that they were assuming primary key values for newly created rows, i.e. expected a new row to have an ID of 1. This was true when we were truncating, but is no longer true for rollbacks, since autoincrement counters are not reset. I refactored it in a following way:&lt;/p&gt;

&lt;p&gt;&lt;script src="https://gist.github.com/609080.js?file=ContentTranslationsControllerTest.php"&gt;&lt;/script&gt;&lt;/p&gt;

&lt;h3&gt;Problem #4&lt;/h3&gt;

&lt;p&gt;Not really a problem for me, but I should probably mention this. We could observe the performance boost on all developers' machines with Ubuntu. Some of our colleagues are using Windows, and they had a very small gain in speed (around 5 seconds). But their benchmarks are generally tilted, since sometimes the suite would finish under 2 minutes, and sometimes after 5+ minutes. YMMV.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;There you go, with a conceptually simple and elegant solution you can achieve quite a dramatic improvement in performance of PHPUnit suite for a Zend Framework application. My next idea is to cache the bootstrap input (i.e. routing). What&amp;rsquo;s yours?&lt;/p&gt;

&lt;p&gt;And here&amp;rsquo;s the evidence for sceptics:&lt;/p&gt;

&lt;p&gt;Before:&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="other"&gt;$&lt;/span&gt; phpunit
PHPUnit &lt;span class="number"&gt;3&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="number"&gt;5&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;0&lt;/span&gt; by Sebastian Bergmann&lt;span class="other"&gt;.&lt;/span&gt;

&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;  &lt;span class="number"&gt;60&lt;/span&gt; &lt;span class="other"&gt;/&lt;/span&gt; &lt;span class="number"&gt;630&lt;/span&gt;
&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt; &lt;span class="number"&gt;120&lt;/span&gt; &lt;span class="other"&gt;/&lt;/span&gt; &lt;span class="number"&gt;630&lt;/span&gt;
&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;S&lt;span class="other"&gt;.&lt;/span&gt;SSSS&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;S&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;SS&lt;span class="other"&gt;.&lt;/span&gt; &lt;span class="number"&gt;180&lt;/span&gt; &lt;span class="other"&gt;/&lt;/span&gt; &lt;span class="number"&gt;630&lt;/span&gt;
S&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt; &lt;span class="number"&gt;240&lt;/span&gt; &lt;span class="other"&gt;/&lt;/span&gt; &lt;span class="number"&gt;630&lt;/span&gt;
&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;S&lt;span class="other"&gt;.&lt;/span&gt;S&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt; &lt;span class="number"&gt;300&lt;/span&gt; &lt;span class="other"&gt;/&lt;/span&gt; &lt;span class="number"&gt;630&lt;/span&gt;
&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt; &lt;span class="number"&gt;360&lt;/span&gt; &lt;span class="other"&gt;/&lt;/span&gt; &lt;span class="number"&gt;630&lt;/span&gt;
&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;SS&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;F&lt;span class="other"&gt;.&lt;/span&gt;S&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;S&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt; &lt;span class="number"&gt;420&lt;/span&gt; &lt;span class="other"&gt;/&lt;/span&gt; &lt;span class="number"&gt;630&lt;/span&gt;
&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;S&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt; &lt;span class="number"&gt;480&lt;/span&gt; &lt;span class="other"&gt;/&lt;/span&gt; &lt;span class="number"&gt;630&lt;/span&gt;
&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;I&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt; &lt;span class="number"&gt;540&lt;/span&gt; &lt;span class="other"&gt;/&lt;/span&gt; &lt;span class="number"&gt;630&lt;/span&gt;
&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;S&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt; &lt;span class="number"&gt;600&lt;/span&gt; &lt;span class="other"&gt;/&lt;/span&gt; &lt;span class="number"&gt;630&lt;/span&gt;
&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;

Time&lt;span class="other"&gt;:&lt;/span&gt; &lt;span class="other"&gt;0&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="other"&gt;:&lt;/span&gt;&lt;span class="number"&gt;24&lt;/span&gt;&lt;span class="other"&gt;,&lt;/span&gt; Memory&lt;span class="other"&gt;:&lt;/span&gt; &lt;span class="number"&gt;136&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="number"&gt;75&lt;/span&gt;Mb

FAILURES&lt;span class="other"&gt;!&lt;/span&gt;
Tests&lt;span class="other"&gt;:&lt;/span&gt; &lt;span class="number"&gt;630&lt;/span&gt;&lt;span class="other"&gt;,&lt;/span&gt; Assertions&lt;span class="other"&gt;:&lt;/span&gt; &lt;span class="number"&gt;830&lt;/span&gt;&lt;span class="other"&gt;,&lt;/span&gt; Failures&lt;span class="other"&gt;:&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="other"&gt;,&lt;/span&gt; Incomplete&lt;span class="other"&gt;:&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="other"&gt;,&lt;/span&gt; Skipped&lt;span class="other"&gt;:&lt;/span&gt; &lt;span class="number"&gt;17&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;After:&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="other"&gt;$&lt;/span&gt; phpunit 
PHPUnit &lt;span class="number"&gt;3&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="number"&gt;5&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;0&lt;/span&gt; by Sebastian Bergmann&lt;span class="other"&gt;.&lt;/span&gt;

&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;  &lt;span class="number"&gt;60&lt;/span&gt; &lt;span class="other"&gt;/&lt;/span&gt; &lt;span class="number"&gt;630&lt;/span&gt;
&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt; &lt;span class="number"&gt;120&lt;/span&gt; &lt;span class="other"&gt;/&lt;/span&gt; &lt;span class="number"&gt;630&lt;/span&gt;
&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;S&lt;span class="other"&gt;.&lt;/span&gt;SSSS&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;S&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;SS&lt;span class="other"&gt;.&lt;/span&gt; &lt;span class="number"&gt;180&lt;/span&gt; &lt;span class="other"&gt;/&lt;/span&gt; &lt;span class="number"&gt;630&lt;/span&gt;
S&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt; &lt;span class="number"&gt;240&lt;/span&gt; &lt;span class="other"&gt;/&lt;/span&gt; &lt;span class="number"&gt;630&lt;/span&gt;
&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;S&lt;span class="other"&gt;.&lt;/span&gt;S&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt; &lt;span class="number"&gt;300&lt;/span&gt; &lt;span class="other"&gt;/&lt;/span&gt; &lt;span class="number"&gt;630&lt;/span&gt;
&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt; &lt;span class="number"&gt;360&lt;/span&gt; &lt;span class="other"&gt;/&lt;/span&gt; &lt;span class="number"&gt;630&lt;/span&gt;
&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;SS&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;F&lt;span class="other"&gt;.&lt;/span&gt;S&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;S&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt; &lt;span class="number"&gt;420&lt;/span&gt; &lt;span class="other"&gt;/&lt;/span&gt; &lt;span class="number"&gt;630&lt;/span&gt;
&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;S&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt; &lt;span class="number"&gt;480&lt;/span&gt; &lt;span class="other"&gt;/&lt;/span&gt; &lt;span class="number"&gt;630&lt;/span&gt;
&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;I&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt; &lt;span class="number"&gt;540&lt;/span&gt; &lt;span class="other"&gt;/&lt;/span&gt; &lt;span class="number"&gt;630&lt;/span&gt;
&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;S&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt; &lt;span class="number"&gt;600&lt;/span&gt; &lt;span class="other"&gt;/&lt;/span&gt; &lt;span class="number"&gt;630&lt;/span&gt;
&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;

Time&lt;span class="other"&gt;:&lt;/span&gt; &lt;span class="number"&gt;29&lt;/span&gt; seconds&lt;span class="other"&gt;,&lt;/span&gt; Memory&lt;span class="other"&gt;:&lt;/span&gt; &lt;span class="number"&gt;131&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;span class="number"&gt;50&lt;/span&gt;Mb

FAILURES&lt;span class="other"&gt;!&lt;/span&gt;
Tests&lt;span class="other"&gt;:&lt;/span&gt; &lt;span class="number"&gt;630&lt;/span&gt;&lt;span class="other"&gt;,&lt;/span&gt; Assertions&lt;span class="other"&gt;:&lt;/span&gt; &lt;span class="number"&gt;830&lt;/span&gt;&lt;span class="other"&gt;,&lt;/span&gt; Failures&lt;span class="other"&gt;:&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="other"&gt;,&lt;/span&gt; Incomplete&lt;span class="other"&gt;:&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="other"&gt;,&lt;/span&gt; Skipped&lt;span class="other"&gt;:&lt;/span&gt; &lt;span class="number"&gt;17&lt;/span&gt;&lt;span class="other"&gt;.&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://exviva.posterous.com/zend-framework-apps-phpunit-suite-3x-faster"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://exviva.posterous.com/zend-framework-apps-phpunit-suite-3x-faster#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/exviva/~4/WC_NZFXLtV8" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://files.posterous.com/user_profile_pics/1344557/Ja_200x200.jpg</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5AkZcR93KE2B</posterous:profileUrl>
        <posterous:firstName>Olek</posterous:firstName>
        <posterous:lastName>Janiszewski</posterous:lastName>
        <posterous:nickName>Olek</posterous:nickName>
        <posterous:displayName>Olek Janiszewski</posterous:displayName>
      </posterous:author>
    </item>
    <item>
      <pubDate>Sat, 28 Aug 2010 05:06:00 -0700</pubDate>
      <title>Autotest-like PHPUnit runner for a Zend Framework application</title>
      <link>http://exviva.posterous.com/autotest-like-phpunit-runner-for-a-zend-frame</link>
      <guid>http://exviva.posterous.com/autotest-like-phpunit-runner-for-a-zend-frame</guid>
      <description>&lt;p&gt;
	&lt;p&gt;Whenever working on a Ruby project, I&amp;rsquo;d run &lt;a href="/running-autotest-with-rails-3"&gt;&lt;code&gt;autotest&lt;/code&gt; with &lt;code&gt;test_notifier&lt;/code&gt;&lt;/a&gt; to get immediate feedback on my code. Unfortunately, I don&amp;rsquo;t know a similar utility integrated with Zend Framework and PHPUnit, so I came up with my own, using the &lt;code&gt;watchr&lt;/code&gt; gem.&lt;/p&gt;

&lt;h3&gt;Pseudo-autotest for PHPUnit&lt;/h3&gt;

&lt;p&gt;My solution is not as well designed and portable as &lt;code&gt;test_notifier&lt;/code&gt;, and it doesn&amp;rsquo;t play as nicely with my Zend application as &lt;code&gt;autotest&lt;/code&gt; does with &lt;code&gt;RSpec&lt;/code&gt; and &lt;code&gt;Rails&lt;/code&gt;. It&amp;rsquo;s more of a quick hack to cover my needs 80% of the time.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;watchr&lt;/code&gt; gem watches changes to files inside a directory and provides a DSL to define tasks to perform on changes of certain files.&lt;/p&gt;

&lt;p&gt;First of all, I needed a mapping between my code files and test files for the following rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I just want to match files ending with &lt;code&gt;.php&lt;/code&gt;, or &lt;code&gt;Test.php&lt;/code&gt; for &lt;code&gt;tests/&lt;/code&gt; directory&lt;/li&gt;
&lt;li&gt;application code lives in &lt;code&gt;application/&lt;/code&gt;, tests are in &lt;code&gt;tests/application&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;library code lives in &lt;code&gt;library/My&lt;/code&gt;, tests live in &lt;code&gt;tests/library&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Here are the rules in &lt;code&gt;watchr&lt;/code&gt; syntax:&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;watch &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;^tests/.*Test&lt;/span&gt;&lt;span class="k"&gt;\.&lt;/span&gt;&lt;span class="k"&gt;php&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt; |match|
  phpunit match[&lt;span class="i"&gt;0&lt;/span&gt;]
&lt;span class="r"&gt;end&lt;/span&gt;

watch &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;^library/My/(.*)&lt;/span&gt;&lt;span class="k"&gt;\.&lt;/span&gt;&lt;span class="k"&gt;php&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt; |match|
  phpunit &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;tests/library/&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;match[&lt;span class="i"&gt;1&lt;/span&gt;]&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;Test.php&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;

watch &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;^application/(.*)&lt;/span&gt;&lt;span class="k"&gt;\.&lt;/span&gt;&lt;span class="k"&gt;php&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt; |match|
  phpunit &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;tests/application/&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;match[&lt;span class="i"&gt;1&lt;/span&gt;]&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;Test.php&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;phpunit&lt;/code&gt; is a method defined later that runs the PHPUnit test.&lt;/p&gt;

&lt;h3&gt;Bubble notifications with Ubuntu&amp;rsquo;s notify-osd&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;phpunit&lt;/code&gt; method could as well be as simple as:&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;phpunit&lt;/span&gt; file
  system(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;phpunit &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;file&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="co"&gt;File&lt;/span&gt;.exists?(file)
&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;But I wanted not to have to switch to the terminal on every save, instead, I wanted to show a sexy notification bubble. This actually involved more effort than I had previously imagined, but now I have different icons and meaningful messages depending on the test result.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m using &lt;code&gt;open3&lt;/code&gt; to capture &lt;code&gt;PHPUnit&lt;/code&gt;&amp;rsquo;s output and echo it without delay on the terminal. Here&amp;rsquo;s the code:&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;say&lt;/span&gt; what
  puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="k"&gt;   [&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="co"&gt;Time&lt;/span&gt;.now.strftime(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;%H:%M:%S&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;] &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;what&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;

&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;phpunit&lt;/span&gt; file
  &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="co"&gt;File&lt;/span&gt;.exists? file
    cmd = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;phpunit &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;file&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="c"&gt;# redirect stderr to stdout&lt;/span&gt;
    say &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;About to run `&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;cmd&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;`&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    _, out, _ = &lt;span class="co"&gt;Open3&lt;/span&gt;.popen3(cmd) &lt;span class="c"&gt;# care only about stdout&lt;/span&gt;

    previous = last = &lt;span class="pc"&gt;nil&lt;/span&gt;

    &lt;span class="r"&gt;until&lt;/span&gt; out.eof?
      previous = last &lt;span class="c"&gt;# remember last two lines of the PHPUnit output&lt;/span&gt;
      puts last = out.gets
    &lt;span class="r"&gt;end&lt;/span&gt;

    file_name = &lt;span class="co"&gt;File&lt;/span&gt;.basename(file)
    image, summary, message = &lt;span class="r"&gt;case&lt;/span&gt;
    &lt;span class="r"&gt;when&lt;/span&gt; last =~ &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="ch"&gt;\A&lt;/span&gt;&lt;span class="k"&gt;OK&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt; &lt;span class="c"&gt;# PHPUnit is green&lt;/span&gt;
      [&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;dialog-ok&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, file_name, last.gsub(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;OK (&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;).gsub(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)]
    &lt;span class="r"&gt;when&lt;/span&gt; previous =~ &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="ch"&gt;\A&lt;/span&gt;&lt;span class="k"&gt;OK, but incomplete or skipped tests&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt; &lt;span class="c"&gt;# PHPUnit is yellow&lt;/span&gt;
      [&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;dialog-question&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, file_name, last]
    &lt;span class="r"&gt;when&lt;/span&gt; last =~ &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="ch"&gt;\A&lt;/span&gt;&lt;span class="k"&gt;PHP&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt; &lt;span class="c"&gt;# PHP Fatal error, PHPUnit process crashed&lt;/span&gt;
      [&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;dialog-error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;Fatal error!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, last]
    &lt;span class="r"&gt;else&lt;/span&gt; &lt;span class="c"&gt;# PHPUnit is red&lt;/span&gt;
      [&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;dialog-warning&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, previous, last]
    &lt;span class="r"&gt;end&lt;/span&gt;

    &lt;span class="c"&gt;# `--hint=string:x-canonical-private-synchronous:` is a workaround for `-t`&lt;/span&gt;
    &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;notify-send  --hint=string:x-canonical-private-synchronous: -i &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;image&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; &amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;summary&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;message&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;&amp;quot;&lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;
    say &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;waiting...&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;I wanted the bubble to hide quickly, and found the &lt;code&gt;-t&lt;/code&gt; option to specify expire time, but due to &lt;a href="https://bugs.launchpad.net/ubuntu/+source/notify-osd/+bug/390508"&gt;this ridiculous design decision&lt;/a&gt;, I had to use a workaround.  Now, when my tests pass, I&amp;rsquo;m seeing:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://posterous.com/getfile/files.posterous.com/temp-2010-08-28/wybABroJlrboozuaxFlAAugzpBEfubzmhnrCcnegmGdHsotFFipcrkAcCeHC/success.png" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;Yellow is:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://posterous.com/getfile/files.posterous.com/temp-2010-08-28/hszsJhelJtyCjqIlytEmeiGImxEJzodHEuyJEqkdHFAxICxjDHFdjnytGgfo/skipped.png" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;Red is:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://posterous.com/getfile/files.posterous.com/temp-2010-08-28/BictkugEimjEHmhdfCgsdeuFpiAzaHchbzoivkIierlyesqFcsBwFpgyiEqA/failure.png" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;And PHP fatal error is:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://posterous.com/getfile/files.posterous.com/temp-2010-08-28/HybdICaAkqmlAjDoaAwiihsgGCgEqAfpelEIBHnpabHFtqHigBCvkwuFAkbw/fatal.png" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;Which tools do you use to make your PHPUnit experience more pleasant?&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://exviva.posterous.com/autotest-like-phpunit-runner-for-a-zend-frame"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://exviva.posterous.com/autotest-like-phpunit-runner-for-a-zend-frame#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/exviva/~4/9m5FopyzmOI" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://files.posterous.com/user_profile_pics/1344557/Ja_200x200.jpg</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5AkZcR93KE2B</posterous:profileUrl>
        <posterous:firstName>Olek</posterous:firstName>
        <posterous:lastName>Janiszewski</posterous:lastName>
        <posterous:nickName>Olek</posterous:nickName>
        <posterous:displayName>Olek Janiszewski</posterous:displayName>
      </posterous:author>
      <media:content type="image/png" height="81" width="331" url="http://getfile4.posterous.com/getfile/files.posterous.com/temp-2010-08-28/wybABroJlrboozuaxFlAAugzpBEfubzmhnrCcnegmGdHsotFFipcrkAcCeHC/success.png">
        <media:thumbnail height="81" width="331" url="http://getfile8.posterous.com/getfile/files.posterous.com/temp-2010-08-28/wybABroJlrboozuaxFlAAugzpBEfubzmhnrCcnegmGdHsotFFipcrkAcCeHC/success.png.scaled500.png" />
      </media:content>
      <media:content type="image/png" height="80" width="330" url="http://getfile4.posterous.com/getfile/files.posterous.com/temp-2010-08-28/hszsJhelJtyCjqIlytEmeiGImxEJzodHEuyJEqkdHFAxICxjDHFdjnytGgfo/skipped.png">
        <media:thumbnail height="80" width="330" url="http://getfile0.posterous.com/getfile/files.posterous.com/temp-2010-08-28/hszsJhelJtyCjqIlytEmeiGImxEJzodHEuyJEqkdHFAxICxjDHFdjnytGgfo/skipped.png.scaled500.png" />
      </media:content>
      <media:content type="image/png" height="85" width="330" url="http://getfile6.posterous.com/getfile/files.posterous.com/temp-2010-08-28/BictkugEimjEHmhdfCgsdeuFpiAzaHchbzoivkIierlyesqFcsBwFpgyiEqA/failure.png">
        <media:thumbnail height="85" width="330" url="http://getfile5.posterous.com/getfile/files.posterous.com/temp-2010-08-28/BictkugEimjEHmhdfCgsdeuFpiAzaHchbzoivkIierlyesqFcsBwFpgyiEqA/failure.png.scaled500.png" />
      </media:content>
      <media:content type="image/png" height="113" width="328" url="http://getfile3.posterous.com/getfile/files.posterous.com/temp-2010-08-28/HybdICaAkqmlAjDoaAwiihsgGCgEqAfpelEIBHnpabHFtqHigBCvkwuFAkbw/fatal.png">
        <media:thumbnail height="113" width="328" url="http://getfile2.posterous.com/getfile/files.posterous.com/temp-2010-08-28/HybdICaAkqmlAjDoaAwiihsgGCgEqAfpelEIBHnpabHFtqHigBCvkwuFAkbw/fatal.png.scaled500.png" />
      </media:content>
    </item>
    <item>
      <pubDate>Sat, 28 Aug 2010 02:17:00 -0700</pubDate>
      <title>View specs with Rails 3, RSpec 2b20 and Webrat</title>
      <link>http://exviva.posterous.com/view-specs-with-rails-3-rspec-2b20-and-webrat</link>
      <guid>http://exviva.posterous.com/view-specs-with-rails-3-rspec-2b20-and-webrat</guid>
      <description>&lt;p&gt;
	&lt;h3&gt;undefined method &amp;lsquo;has_selector?&amp;rsquo; for String&lt;/h3&gt;

&lt;p&gt;After a recent update of my gems (caused by upgrading from Rails 3 RC to Rails 3 RC2), I got quite a lot of this type of errors:&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;Failure/Error: rendered.should have_selector(:img, :src =&amp;gt; @photo.image.url(:preview))
  undefined method `has_selector?' for String
  # ./spec/views/photos/show.html.haml_spec.rb:13&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;After some digging I found that in rspec-rails 2b20 &lt;a href="http://github.com/rspec/rspec-rails/blob/master/Upgrade.markdown"&gt;Webrat is no longer required by default&lt;/a&gt;. You can choose between Webrat and Capybara, but you &lt;strong&gt;have to&lt;/strong&gt; add either gem to your &lt;code&gt;Gemfile&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After adding &lt;code&gt;gem 'webrat'&lt;/code&gt; to my &lt;code&gt;Gemfile&lt;/code&gt;, the &lt;code&gt;have_selector&lt;/code&gt; matcher works as expected.&lt;/p&gt;

&lt;p&gt;PS. I also changed &lt;code&gt;mysql&lt;/code&gt; to &lt;code&gt;mysql2&lt;/code&gt;, as recommended by Rails and added the bundler task to Capistrano recipe (&lt;code&gt;require 'bundler/capistrano'&lt;/code&gt; on top of &lt;code&gt;config/deploy.rb&lt;/code&gt;).&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://exviva.posterous.com/view-specs-with-rails-3-rspec-2b20-and-webrat"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://exviva.posterous.com/view-specs-with-rails-3-rspec-2b20-and-webrat#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/exviva/~4/2p9b1WaXCbw" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://files.posterous.com/user_profile_pics/1344557/Ja_200x200.jpg</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5AkZcR93KE2B</posterous:profileUrl>
        <posterous:firstName>Olek</posterous:firstName>
        <posterous:lastName>Janiszewski</posterous:lastName>
        <posterous:nickName>Olek</posterous:nickName>
        <posterous:displayName>Olek Janiszewski</posterous:displayName>
      </posterous:author>
    </item>
    <item>
      <pubDate>Wed, 28 Jul 2010 06:44:00 -0700</pubDate>
      <title>Upgrading a Rails 3 beta 4 application to Rails 3 RC</title>
      <link>http://exviva.posterous.com/upgrading-a-rails-3-beta-4-application-to-rai</link>
      <guid>http://exviva.posterous.com/upgrading-a-rails-3-beta-4-application-to-rai</guid>
      <description>&lt;p&gt;
	&lt;p&gt;As soon as I&amp;rsquo;ve heard that &lt;a href="http://weblog.rubyonrails.org/2010/7/26/rails-3-0-release-candidate"&gt;Rails 3 RC is out&lt;/a&gt;, I decided to upgrade my application. I have to admit it was less smooth than I&amp;rsquo;d imagined, mostly due to Bundler, but after a while I got it to work.&lt;/p&gt;

&lt;h2&gt;Bundler adventures&lt;/h2&gt;

&lt;p&gt;First thing I did was changing my &lt;code&gt;Gemfile&lt;/code&gt; from&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;gem &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;rails&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;3.0.0.beta4&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;to&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;gem &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;rails&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;3.0.0.rc&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;and ran&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;# we're not using production's mysql gem in development
bundle install --without production&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;getting&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;No compatible versions could be found for required dependencies:
Conflict on: &amp;quot;bundler&amp;quot;:
* bundler (0.9.26) activated by bundler (= 0.9.26, runtime)
* bundler (&amp;gt;= 1.0.0.rc.1, runtime) required by rails (= 3.0.0.rc, runtime)
All possible versions of origin requirements conflict.&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;I installed new Bundler:&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;sudo gem uninstall bundler
sudo gem install bundler --pre&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;and successfully retried &lt;code&gt;bundle install --without production&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First surprise was that Bundler tried to install the gems along other system gems (I was actually hoping to have them in my &lt;code&gt;~/.bundle/&lt;/code&gt;). It seems that &lt;code&gt;~/.bundle/&lt;/code&gt; is no longer used by Bundler (unless you explicitly tell &lt;code&gt;bundle install&lt;/code&gt; to install the gems there). It asked me:&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;Enter your password to install the bundled RubyGems to your system:&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Well, I&amp;rsquo;m fine with this on my development machine, but what about my production server, where the application user is not in &lt;code&gt;sudoers&lt;/code&gt;. Ah, yet another dimension of complexity&amp;hellip;&lt;/p&gt;

&lt;p&gt;Second surprise &amp;ndash; new Bundler left a &lt;code&gt;Gemfile.lock&lt;/code&gt; (not really what I expected, kind of annoying &amp;ndash; anyone care to explain to me the rationale behind it?).&lt;/p&gt;

&lt;h2&gt;Changes in default skeleton files&lt;/h2&gt;

&lt;p&gt;I ran all the specs and got the following:&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;DEPRECATION WARNING: Calling a method in Rails::Application is deprecated,
  please call it directly in your application constant My::Application.
  (called from method_missing at /usr/lib/ruby/gems/1.8/gems/railties-3.0.0.rc/lib/rails/application.rb:77)

You did not specify how you would like Rails to report deprecation
  notices for your test environment, please set config.active_support.deprecation
  to :stderr at config/environments/test.rb

DEPRECATION WARNING: You are using the old router DSL which will be
  removed in Rails 3.1. Please check how to update your routes file at: http://www.engineyard.com/blog/2010/the-lowdown-on-routes-in-rails-3/.
  (called from initialize at /usr/lib/ruby/gems/1.8/gems/actionpack-3.0.0.rc/lib/action_dispatch/routing/deprecated_mapper.rb:33)

/usr/lib/ruby/gems/1.8/gems/activemodel-3.0.0.rc/lib/active_model/validations/validates.rb:87:in `validates':
  Unknown validator: 'email' (ArgumentError)&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Five things here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;calling &lt;code&gt;Rails.application&lt;/code&gt; and &lt;code&gt;Rails::Application&lt;/code&gt; was deprecated in favour of &lt;code&gt;My::Application&lt;/code&gt;, so I replaced it in all &lt;code&gt;config/*&lt;/code&gt; files and &lt;code&gt;Rakefile&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;a new config option &lt;code&gt;config.active_support.deprecation&lt;/code&gt; was added&lt;/li&gt;
&lt;li&gt;generally the files in &lt;code&gt;config/&lt;/code&gt; have undergone some changes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lib/&lt;/code&gt; directory was no longer autoloaded&lt;/li&gt;
&lt;li&gt;&lt;code&gt;routes.draw&lt;/code&gt; now expects a block with arity of zero, not one, so I got rid of &lt;code&gt;|map|&lt;/code&gt; in &lt;code&gt;config/routes.rb&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;Below are the most important parts you&amp;rsquo;ll need to change. For a full list of changes, just generate a new app and &lt;code&gt;diff&lt;/code&gt; everything inside the &lt;code&gt;config/&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;&lt;div class="data type-diff"&gt;
    
      &lt;table class="lines" cellspacing="0" cellpadding="0"&gt;
        &lt;tr&gt;
          &lt;td&gt;
            &lt;pre class="line_numbers"&gt;&lt;span rel="#L1" id="L1"&gt;1&lt;/span&gt;
&lt;span rel="#L2" id="L2"&gt;2&lt;/span&gt;
&lt;span rel="#L3" id="L3"&gt;3&lt;/span&gt;
&lt;span rel="#L4" id="L4"&gt;4&lt;/span&gt;
&lt;span rel="#L5" id="L5"&gt;5&lt;/span&gt;
&lt;span rel="#L6" id="L6"&gt;6&lt;/span&gt;
&lt;span rel="#L7" id="L7"&gt;7&lt;/span&gt;
&lt;span rel="#L8" id="L8"&gt;8&lt;/span&gt;
&lt;span rel="#L9" id="L9"&gt;9&lt;/span&gt;
&lt;span rel="#L10" id="L10"&gt;10&lt;/span&gt;
&lt;span rel="#L11" id="L11"&gt;11&lt;/span&gt;
&lt;span rel="#L12" id="L12"&gt;12&lt;/span&gt;
&lt;span rel="#L13" id="L13"&gt;13&lt;/span&gt;
&lt;span rel="#L14" id="L14"&gt;14&lt;/span&gt;
&lt;span rel="#L15" id="L15"&gt;15&lt;/span&gt;
&lt;span rel="#L16" id="L16"&gt;16&lt;/span&gt;
&lt;span rel="#L17" id="L17"&gt;17&lt;/span&gt;
&lt;span rel="#L18" id="L18"&gt;18&lt;/span&gt;
&lt;span rel="#L19" id="L19"&gt;19&lt;/span&gt;
&lt;span rel="#L20" id="L20"&gt;20&lt;/span&gt;
&lt;span rel="#L21" id="L21"&gt;21&lt;/span&gt;
&lt;span rel="#L22" id="L22"&gt;22&lt;/span&gt;
&lt;span rel="#L23" id="L23"&gt;23&lt;/span&gt;
&lt;span rel="#L24" id="L24"&gt;24&lt;/span&gt;
&lt;span rel="#L25" id="L25"&gt;25&lt;/span&gt;
&lt;span rel="#L26" id="L26"&gt;26&lt;/span&gt;
&lt;span rel="#L27" id="L27"&gt;27&lt;/span&gt;
&lt;span rel="#L28" id="L28"&gt;28&lt;/span&gt;
&lt;span rel="#L29" id="L29"&gt;29&lt;/span&gt;
&lt;span rel="#L30" id="L30"&gt;30&lt;/span&gt;
&lt;span rel="#L31" id="L31"&gt;31&lt;/span&gt;
&lt;span rel="#L32" id="L32"&gt;32&lt;/span&gt;
&lt;span rel="#L33" id="L33"&gt;33&lt;/span&gt;
&lt;span rel="#L34" id="L34"&gt;34&lt;/span&gt;
&lt;span rel="#L35" id="L35"&gt;35&lt;/span&gt;
&lt;span rel="#L36" id="L36"&gt;36&lt;/span&gt;
&lt;span rel="#L37" id="L37"&gt;37&lt;/span&gt;
&lt;span rel="#L38" id="L38"&gt;38&lt;/span&gt;
&lt;span rel="#L39" id="L39"&gt;39&lt;/span&gt;
&lt;span rel="#L40" id="L40"&gt;40&lt;/span&gt;
&lt;span rel="#L41" id="L41"&gt;41&lt;/span&gt;
&lt;span rel="#L42" id="L42"&gt;42&lt;/span&gt;
&lt;span rel="#L43" id="L43"&gt;43&lt;/span&gt;
&lt;span rel="#L44" id="L44"&gt;44&lt;/span&gt;
&lt;span rel="#L45" id="L45"&gt;45&lt;/span&gt;
&lt;span rel="#L46" id="L46"&gt;46&lt;/span&gt;
&lt;span rel="#L47" id="L47"&gt;47&lt;/span&gt;
&lt;span rel="#L48" id="L48"&gt;48&lt;/span&gt;
&lt;span rel="#L49" id="L49"&gt;49&lt;/span&gt;
&lt;span rel="#L50" id="L50"&gt;50&lt;/span&gt;
&lt;span rel="#L51" id="L51"&gt;51&lt;/span&gt;
&lt;span rel="#L52" id="L52"&gt;52&lt;/span&gt;
&lt;span rel="#L53" id="L53"&gt;53&lt;/span&gt;
&lt;span rel="#L54" id="L54"&gt;54&lt;/span&gt;
&lt;span rel="#L55" id="L55"&gt;55&lt;/span&gt;
&lt;span rel="#L56" id="L56"&gt;56&lt;/span&gt;
&lt;span rel="#L57" id="L57"&gt;57&lt;/span&gt;
&lt;span rel="#L58" id="L58"&gt;58&lt;/span&gt;
&lt;span rel="#L59" id="L59"&gt;59&lt;/span&gt;
&lt;span rel="#L60" id="L60"&gt;60&lt;/span&gt;
&lt;span rel="#L61" id="L61"&gt;61&lt;/span&gt;
&lt;span rel="#L62" id="L62"&gt;62&lt;/span&gt;
&lt;span rel="#L63" id="L63"&gt;63&lt;/span&gt;
&lt;span rel="#L64" id="L64"&gt;64&lt;/span&gt;
&lt;span rel="#L65" id="L65"&gt;65&lt;/span&gt;
&lt;span rel="#L66" id="L66"&gt;66&lt;/span&gt;
&lt;span rel="#L67" id="L67"&gt;67&lt;/span&gt;
&lt;span rel="#L68" id="L68"&gt;68&lt;/span&gt;
&lt;span rel="#L69" id="L69"&gt;69&lt;/span&gt;
&lt;/pre&gt;
          &lt;/td&gt;
          &lt;td width="100%"&gt;
            
              
                &lt;div class="highlight"&gt;&lt;pre /&gt;&lt;div class="line" id="LC1"&gt;Rakefile&lt;/div&gt;&lt;div class="line" id="LC2"&gt;&lt;span class="gd"&gt;-Rails::Application.load_tasks&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC3"&gt;&lt;span class="gi"&gt;+My::Application.load_tasks&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC4"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC5"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC6"&gt;config/application.rb&lt;/div&gt;&lt;div class="line" id="LC7"&gt;&lt;span class="gd"&gt;-Bundler.require :default, Rails.env&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC8"&gt;&lt;span class="gi"&gt;+Bundler.require(:default, Rails.env) if defined?(Bundler)&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC9"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC10"&gt;&lt;span class="gd"&gt;-    # config.load_paths += %W( #{config.root}/extras )&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC11"&gt;&lt;span class="gi"&gt;+    config.autoload_paths += %W( #{config.root}/lib )&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC12"&gt;&lt;span class="gi"&gt;+    # config.action_view.javascript_expansions[:defaults] = %w(jquery rails)&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC13"&gt;&lt;span class="gi"&gt;+    config.encoding = &amp;quot;utf-8&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC14"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC15"&gt;&lt;span class="gd"&gt;-    config.filter_parameters &amp;lt;&amp;lt; :password&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC16"&gt;&lt;span class="gi"&gt;+    config.filter_parameters += [:password]&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC17"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC18"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC19"&gt;config/boot.rb&lt;/div&gt;&lt;div class="line" id="LC20"&gt;&lt;span class="gi"&gt;+require &amp;#39;rubygems&amp;#39;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC21"&gt;&lt;span class="gi"&gt;+gemfile = File.expand_path(&amp;#39;../../Gemfile&amp;#39;, __FILE__)&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC22"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC23"&gt;&lt;span class="gd"&gt;-  require File.expand_path(&amp;#39;../../.bundle/environment&amp;#39;, __FILE__)&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC24"&gt;&lt;span class="gd"&gt;-rescue LoadError&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC25"&gt;&lt;span class="gd"&gt;-  require &amp;#39;rubygems&amp;#39;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC26"&gt;&lt;span class="gi"&gt;+  ENV[&amp;#39;BUNDLE_GEMFILE&amp;#39;] = gemfile&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC27"&gt;&lt;span class="gi"&gt;+rescue Bundler::GemNotFound =&amp;gt; e&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC28"&gt;&lt;span class="gi"&gt;+  STDERR.puts e.message&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC29"&gt;&lt;span class="gi"&gt;+  STDERR.puts &amp;quot;Try running `bundle install`.&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC30"&gt;&lt;span class="gi"&gt;+  exit!&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC31"&gt;&lt;span class="gi"&gt;+end if File.exist?(gemfile)&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC32"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC33"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC34"&gt;config/environments/development.rb&lt;/div&gt;&lt;div class="line" id="LC35"&gt;&lt;span class="gi"&gt;+  config.active_support.deprecation = :log&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC36"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC37"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC38"&gt;config/environments/production.rb&lt;/div&gt;&lt;div class="line" id="LC39"&gt;&lt;span class="gi"&gt;+  # Specifies the header that your server uses for sending files&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC40"&gt;&lt;span class="gi"&gt;+  config.action_dispatch.x_sendfile_header = &amp;quot;X-Sendfile&amp;quot;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC41"&gt;&lt;span class="gi"&gt;+&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC42"&gt;&lt;span class="gi"&gt;+  # For nginx:&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC43"&gt;&lt;span class="gi"&gt;+  # config.action_dispatch.x_sendfile_header = &amp;#39;X-Accel-Redirect&amp;#39;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC44"&gt;&lt;span class="gi"&gt;+&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC45"&gt;&lt;span class="gi"&gt;+  # If you have no front-end server that supports something like X-Sendfile,&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC46"&gt;&lt;span class="gi"&gt;+  # just comment this out and Rails will serve the files&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC47"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC48"&gt;&lt;span class="gi"&gt;+  config.i18n.fallbacks = true&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC49"&gt;&lt;span class="gi"&gt;+  config.active_support.deprecation = :notify&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC50"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC51"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC52"&gt;config/environments/test.rb&lt;/div&gt;&lt;div class="line" id="LC53"&gt;&lt;span class="gi"&gt;+  config.action_dispatch.show_exceptions = false&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC54"&gt;&lt;span class="gi"&gt;+  config.active_support.deprecation = :stderr&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC55"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC56"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC57"&gt;config/initializers/secret_token.rb&lt;/div&gt;&lt;div class="line" id="LC58"&gt;&lt;span class="gd"&gt;-Rails.application.config.secret_token = &amp;#39;(...)&amp;#39;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC59"&gt;&lt;span class="gi"&gt;+My::Application.config.secret_token = &amp;#39;(...)&amp;#39;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC60"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC61"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC62"&gt;config/initializers/session_store.rb&lt;/div&gt;&lt;div class="line" id="LC63"&gt;&lt;span class="gd"&gt;-Rails.application.config.session_store :cookie_store, :key =&amp;gt; &amp;#39;_my_session&amp;#39;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC64"&gt;&lt;span class="gi"&gt;+My::Application.config.session_store :cookie_store, :key =&amp;gt; &amp;#39;_my_session&amp;#39;&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC65"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC66"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="line" id="LC67"&gt;config/routes.rb&lt;/div&gt;&lt;div class="line" id="LC68"&gt;&lt;span class="gd"&gt;-My::Application.routes.draw do |map|&lt;/span&gt;&lt;/div&gt;&lt;div class="line" id="LC69"&gt;&lt;span class="gi"&gt;+My::Application.routes.draw do&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/div&gt;
              
            
          &lt;/td&gt;
        &lt;/tr&gt;
      &lt;/table&gt;
    
  &lt;/div&gt;&lt;/p&gt;

&lt;h2&gt;Mission complete&lt;/h2&gt;

&lt;p&gt;After those fixes, all specs went through, I didn&amp;rsquo;t get any deprecation warnings or errors. Welcome, Rails 3 RC!&lt;/p&gt;

&lt;p&gt;I also had some adventures deploying this on production, but that&amp;rsquo;s a story for a separate article, so stay tuned.&lt;/p&gt;

&lt;h3&gt;On a side note&lt;/h3&gt;

&lt;p&gt;Could anyone clear this up for me why some gems' executables end up in &lt;code&gt;/usr/bin/&lt;/code&gt; while others in &lt;code&gt;/usr/lib/ruby/gems/1.8/bin/&lt;/code&gt;? I can&amp;rsquo;t notice the pattern&amp;hellip;&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://exviva.posterous.com/upgrading-a-rails-3-beta-4-application-to-rai"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://exviva.posterous.com/upgrading-a-rails-3-beta-4-application-to-rai#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/exviva/~4/IEOTcsuD99I" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://files.posterous.com/user_profile_pics/1344557/Ja_200x200.jpg</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5AkZcR93KE2B</posterous:profileUrl>
        <posterous:firstName>Olek</posterous:firstName>
        <posterous:lastName>Janiszewski</posterous:lastName>
        <posterous:nickName>Olek</posterous:nickName>
        <posterous:displayName>Olek Janiszewski</posterous:displayName>
      </posterous:author>
    </item>
    <item>
      <pubDate>Sat, 17 Jul 2010 16:15:00 -0700</pubDate>
      <title>Speccing partials in Rails 3 and RSpec 2</title>
      <link>http://exviva.posterous.com/speccing-partials-in-rails-3-and-rspec-2</link>
      <guid>http://exviva.posterous.com/speccing-partials-in-rails-3-and-rspec-2</guid>
      <description>&lt;p&gt;
	&lt;p&gt;Typically with &lt;code&gt;RSpec 2&lt;/code&gt; and &lt;code&gt;Rails 3&lt;/code&gt;, when I spec a view, I&amp;rsquo;d do something like:&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;describe &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;posts/show.html.haml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
  it &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;should render post title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
    assign(&lt;span class="sy"&gt;:post&lt;/span&gt;, stub_model(&lt;span class="co"&gt;Post&lt;/span&gt;, &lt;span class="sy"&gt;:title&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;Abracadabra&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;))
    render
    rendered.should have_selector(&lt;span class="sy"&gt;:h1&lt;/span&gt;, &lt;span class="sy"&gt;:content&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;Abracadabra&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;) &lt;span class="c"&gt;# and/or 'view.should ...'&lt;/span&gt;
  &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;In this example, &lt;code&gt;assign(key, value)&lt;/code&gt; is used to provide a &lt;code&gt;@post&lt;/code&gt; variable to the template.&lt;/p&gt;

&lt;p&gt;The big question, however, is how would I assign locals for a specced partial? The answer I found (with my new best friend, &lt;code&gt;bundle open actionpack&lt;/code&gt;) is the following:&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;describe &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;posts/_post.html.haml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
  it &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;should render post title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
    post = stub_model(&lt;span class="co"&gt;Post&lt;/span&gt;, &lt;span class="sy"&gt;:title&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;Abracadabra&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)
    render post, &lt;span class="sy"&gt;:foo&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;
    rendered.should have_selector(&lt;span class="sy"&gt;:h1&lt;/span&gt;, &lt;span class="sy"&gt;:content&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;Abracadabra&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)
  &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Here, I&amp;rsquo;m just calling &lt;code&gt;render&lt;/code&gt; identically to how I would in a view, the partial name gets inferred from the model&amp;rsquo;s metadata, the second argument is an optional hash of other locals. So, in this example, the partial has access to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;post # =&amp;gt; #&amp;lt;Post id: nil, title: "Abracadabra", ...&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;foo  # =&amp;gt; "bar"&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;What if the partial doesn&amp;rsquo;t have a corresponding model class? That&amp;rsquo;s simple:&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;describe &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;posts/_form.html.haml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
  it &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;should render an input for post title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
    post = stub_model(&lt;span class="co"&gt;Post&lt;/span&gt;)
    render &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:post&lt;/span&gt; =&amp;gt; post, &lt;span class="sy"&gt;:foo&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;
    rendered.should have_selector(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;input#post_title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)
  &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Here, since the first argument of &lt;code&gt;render&lt;/code&gt; is a &lt;code&gt;String&lt;/code&gt;, Rails treats it as an explicit partial name and just provides the local variables &lt;code&gt;post&lt;/code&gt; and &lt;code&gt;foo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One tiny thing that&amp;rsquo;s bothering me about this, is having to pass in &lt;code&gt;'form'&lt;/code&gt; to &lt;code&gt;render&lt;/code&gt; when it easily could&amp;rsquo;ve been inferred by the description &lt;code&gt;'posts/_form.html.haml'&lt;/code&gt;. Well, I guess I&amp;rsquo;ll just have to live with it.&lt;/p&gt;

&lt;h2&gt;By the way: view helpers not included in the spec&amp;rsquo;s &lt;code&gt;view&lt;/code&gt; object&lt;/h2&gt;

&lt;p&gt;If you&amp;rsquo;re running into this issue (like me) where your helpers are not &lt;code&gt;include&lt;/code&gt;&amp;rsquo;d in the specced view and you&amp;rsquo;re getting all these &lt;code&gt;undefined method&lt;/code&gt; errors, it&amp;rsquo;s a &lt;a href="http://github.com/rspec/rspec-rails/issues/#issue/119"&gt;known bug&lt;/a&gt;. A quick hackish solution is to explicitly &lt;code&gt;view.extend MyHelper&lt;/code&gt; in the examples.&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://exviva.posterous.com/speccing-partials-in-rails-3-and-rspec-2"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://exviva.posterous.com/speccing-partials-in-rails-3-and-rspec-2#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/exviva/~4/-sbslLqejCU" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://files.posterous.com/user_profile_pics/1344557/Ja_200x200.jpg</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5AkZcR93KE2B</posterous:profileUrl>
        <posterous:firstName>Olek</posterous:firstName>
        <posterous:lastName>Janiszewski</posterous:lastName>
        <posterous:nickName>Olek</posterous:nickName>
        <posterous:displayName>Olek Janiszewski</posterous:displayName>
      </posterous:author>
    </item>
    <item>
      <pubDate>Sat, 17 Jul 2010 06:05:00 -0700</pubDate>
      <title>Rails 3 and ZenTest</title>
      <link>http://exviva.posterous.com/running-autotest-with-rails-3</link>
      <guid>http://exviva.posterous.com/running-autotest-with-rails-3</guid>
      <description>&lt;p&gt;
	&lt;h2&gt;The background&lt;/h2&gt;

&lt;p&gt;I used to work exclusively with Rails 2.x until about a year ago, then I took on a PHP project (ugh&amp;hellip;), so when my friend recently offered me to do a quasi-startup project together, I didn&amp;rsquo;t think twice and convinced him to use Rails (I think Rails 3.0.0.beta1 one out at that point).&lt;/p&gt;

&lt;p&gt;It took us quite some time to get through all the obstacles related with the general beta-lity of our environment (Rails3, RSpec2, Bundler, Paperclip, some other plugins with undetermined Rails 3 compatibility), especially considering that my friend needed a Rails crash-course and I needed to undust all my Rails skills and working habits.&lt;/p&gt;

&lt;h2&gt;The problem&lt;/h2&gt;

&lt;p&gt;One thing I really missed in my workflow was ZenTest and &lt;code&gt;autotest&lt;/code&gt; (which I believe used to be &lt;code&gt;autospec&lt;/code&gt; for RSpec, but now got unified with &lt;code&gt;autotest&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Unfortunately, a trivial &lt;code&gt;gem install ZenTest&lt;/code&gt; didn&amp;rsquo;t do the trick, since all the app&amp;rsquo;s gems were managed by Bundler. This is what&amp;rsquo;s been happening:&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;$ autotest
loading autotest/rails_rspec2
Autotest style autotest/rails_rspec2 doesn't seem to exist. Aborting.&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;even though we &lt;strong&gt;did&lt;/strong&gt; have the following in &lt;code&gt;autotest/discover.rb&lt;/code&gt;:&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="co"&gt;Autotest&lt;/span&gt;.add_discovery { &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;rails&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }
&lt;span class="co"&gt;Autotest&lt;/span&gt;.add_discovery { &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;rspec2&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;We needed a way to run a command with the whole environment set up by Bundler.&lt;/p&gt;

&lt;h2&gt;The solution&lt;/h2&gt;

&lt;p&gt;That&amp;rsquo;s when we stumbled upon &lt;code&gt;bundle exec&lt;/code&gt;. The docs say it all &amp;ndash; &lt;code&gt;"Run the command in context of the bundle"&lt;/code&gt;. And in deed:&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;$ bundle exec autotest
/usr/lib/ruby/1.8/pathname.rb:263: warning: `*' interpreted as argument prefix
/usr/lib/ruby/gems/1.8/gems/bundler-0.9.26/lib/bundler.rb:72: warning: instance variable @setup not initialized
/usr/lib/ruby/gems/1.8/gems/bundler-0.9.26/lib/bundler/runtime.rb:145: warning: method redefined; discarding old path
loading autotest/rails_rspec2
(...)

............*..*..................................................*.........


Finished in 0.57859 seconds
76 examples, 0 failures, 3 pending&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Hurray!&lt;/p&gt;

&lt;p&gt;Additionally, installing bubble notifications was a breeze &amp;ndash; we just added &lt;code&gt;gem 'test_notifier'&lt;/code&gt; to our &lt;code&gt;Gemfile&lt;/code&gt;. It&amp;rsquo;s a nifty little gem with multiplatform support and out-of-the-box awesomeness. You can read more about it &lt;a href="http://github.com/fnando/test_notifier"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You&amp;rsquo;ll need to install appropriate libs and modify &lt;code&gt;~/.autotest&lt;/code&gt;, but it&amp;rsquo;s all written in the gems' &lt;code&gt;README&lt;/code&gt;, so go ahead and check it out.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s what &lt;code&gt;test_notifier&lt;/code&gt; gives you:&lt;/p&gt;

&lt;p&gt;&lt;div class='p_embed p_image_embed'&gt;
&lt;img alt="Test_notifier" height="91" src="http://posterous.com/getfile/files.posterous.com/temp-2010-07-17/JqHHjxoIfGrryCanhJoChrFkBgbHotxqdFcpayfIdaABIjyBFlGbrHDCbIwd/test_notifier.png.scaled500.png" width="333" /&gt;
&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;Finally! No need to switch to the terminal after every save.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;After a fair amount of effort spent setting up a comfortable and productive Rails 3 environment, I can say I&amp;rsquo;m almost there. There&amp;rsquo;s still room for improvement, but my confidence is slowly coming back, so one day I&amp;rsquo;ll get there.&lt;/p&gt;

&lt;p&gt;Just for the record, here&amp;rsquo;s my environment:&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;# Gemfile&lt;/span&gt;
gem &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;rails&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;3.0.0.beta4&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;

group &lt;span class="sy"&gt;:test&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
  gem &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;rspec-rails&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;= 2.0.0.beta.1&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  gem &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;ZenTest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;
  gem &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;test_notifier&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;.&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;$ bundle show
  * ZenTest (4.3.3)
  * bundler (0.9.26)
  * rspec (2.0.0.beta.17)
  * rspec-core (2.0.0.beta.17)
  * rspec-expectations (2.0.0.beta.17)
  * rspec-mocks (2.0.0.beta.17)
  * rspec-rails (2.0.0.beta.17)
  * test_notifier (0.1.4)&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;Bonus tip&lt;/h3&gt;

&lt;p&gt;I fell in love with &lt;code&gt;bundle open&lt;/code&gt; to inspect gems' sources. I&amp;rsquo;ve had so many revelations reading it! Give it a try and you won&amp;rsquo;t regret it.&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://exviva.posterous.com/running-autotest-with-rails-3"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://exviva.posterous.com/running-autotest-with-rails-3#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/exviva/~4/wE0eLatLZ5I" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://files.posterous.com/user_profile_pics/1344557/Ja_200x200.jpg</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5AkZcR93KE2B</posterous:profileUrl>
        <posterous:firstName>Olek</posterous:firstName>
        <posterous:lastName>Janiszewski</posterous:lastName>
        <posterous:nickName>Olek</posterous:nickName>
        <posterous:displayName>Olek Janiszewski</posterous:displayName>
      </posterous:author>
      <media:content type="image/png" height="91" width="333" url="http://getfile3.posterous.com/getfile/files.posterous.com/temp-2010-07-17/JqHHjxoIfGrryCanhJoChrFkBgbHotxqdFcpayfIdaABIjyBFlGbrHDCbIwd/test_notifier.png">
        <media:thumbnail height="91" width="333" url="http://getfile7.posterous.com/getfile/files.posterous.com/temp-2010-07-17/JqHHjxoIfGrryCanhJoChrFkBgbHotxqdFcpayfIdaABIjyBFlGbrHDCbIwd/test_notifier.png.scaled500.png" />
      </media:content>
    </item>
    <item>
      <pubDate>Sat, 10 Jul 2010 15:23:00 -0700</pubDate>
      <title>Tricky _flash partial in Rails</title>
      <link>http://exviva.posterous.com/tricky-flash-partial-in-rails</link>
      <guid>http://exviva.posterous.com/tricky-flash-partial-in-rails</guid>
      <description>&lt;p&gt;
	&lt;p&gt;In one of my projects, we&amp;rsquo;re using two different layouts, and I wanted to share the flash rendering between them.&lt;/p&gt;

&lt;p&gt;I achieved it with just a typical HAML snippet:&lt;/p&gt;

&lt;p&gt;&lt;script src="https://gist.github.com/471083.js?file=_flash.html.haml"&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;To my surprise the &lt;code&gt;flash&lt;/code&gt; was always blank. Fortunately, I had an &amp;lsquo;aha!&amp;rsquo; moment when I realized that inside a partial there is a local variable named after the partial (without the underscore). It turned out that &lt;code&gt;flash&lt;/code&gt; was a local variable obscuring the &lt;code&gt;#flash&lt;/code&gt; method call that I wanted, since I named the partial &lt;code&gt;_flash.html.haml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A quick&lt;/p&gt;

&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;flash = flash()&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;at the top did the trick. Here&amp;rsquo;s the final version of the _flash partial:&lt;/p&gt;

&lt;p&gt;&lt;script src="https://gist.github.com/471083.js?file=_flash2.html.haml"&gt;&lt;/script&gt;&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://exviva.posterous.com/tricky-flash-partial-in-rails"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://exviva.posterous.com/tricky-flash-partial-in-rails#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/exviva/~4/ytimfjTvvPA" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://files.posterous.com/user_profile_pics/1344557/Ja_200x200.jpg</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5AkZcR93KE2B</posterous:profileUrl>
        <posterous:firstName>Olek</posterous:firstName>
        <posterous:lastName>Janiszewski</posterous:lastName>
        <posterous:nickName>Olek</posterous:nickName>
        <posterous:displayName>Olek Janiszewski</posterous:displayName>
      </posterous:author>
    </item>
    <item>
      <pubDate>Mon, 05 Jul 2010 23:37:00 -0700</pubDate>
      <title>Watermarking images with Rails 3 and Paperclip</title>
      <link>http://exviva.posterous.com/watermarking-images-with-rails-3-and-papercli</link>
      <guid>http://exviva.posterous.com/watermarking-images-with-rails-3-and-papercli</guid>
      <description>&lt;p&gt;
	&lt;p&gt;In one of the projects I&amp;rsquo;m working on, we needed a way to watermark images for public preview. We&amp;rsquo;re using Paperclip 2.3.3.&lt;/p&gt;

&lt;p&gt;Searching gave only one &lt;a href="http://github.com/ng/paperclip-watermarking-app/blob/master/lib/paperclip_processors/watermark.rb"&gt;result&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The included Paperclip processor had some issues, but a little debugging led to making it work properly. Of course, all the credits go to &lt;a href="http://github.com/ng"&gt;ng&lt;/a&gt; for sharing his code.&lt;/p&gt;

&lt;h2&gt;The model&lt;/h2&gt;

&lt;p&gt;Here&amp;rsquo;s how to set up the model to use the watermark processor:&lt;/p&gt;

&lt;p&gt;&lt;script src="https://gist.github.com/465088.js?file=photo.rb"&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Some comments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:processors =&amp;gt; [:watermark]&lt;/code&gt; enables the watermark processor&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:watermark_path =&amp;gt; "#{Rails.root}/public/images/watermark.png"&lt;/code&gt; declared the location of the watermark path&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:position =&amp;gt; 'Center'&lt;/code&gt; defines the position of the watermark on the image&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;I saved the found watermark processor in &lt;code&gt;lib/paperclip_processors&lt;/code&gt;, but&amp;hellip;&lt;/p&gt;

&lt;h2&gt;First obstacle&lt;/h2&gt;

&lt;p&gt;&amp;hellip;this gave me &lt;code&gt;uninitialized constant Paperclip::Watermark&lt;/code&gt;. That&amp;rsquo;s weird, since the &lt;a href="http://github.com/thoughtbot/paperclip/blob/v2.3.3/README.rdoc"&gt;Paperclip README&lt;/a&gt; says that all files in &lt;code&gt;lib/paperclip_processors&lt;/code&gt; should be loaded automatically. I decided to take the short way and just&lt;/p&gt;

&lt;p&gt;&lt;script src="https://gist.github.com/465088.js?file=photo_with_require.rb"&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;on top of &lt;code&gt;app/models/photo.rb&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Server restart, and&amp;hellip;&lt;/p&gt;

&lt;h2&gt;Second obstacle&lt;/h2&gt;

&lt;p&gt;now, when attempting to use the processor, &lt;code&gt;development.log&lt;/code&gt; shows:&lt;/p&gt;

&lt;p&gt;&lt;script src="https://gist.github.com/465088.js?file=development.log"&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Notice the weird single-quoting on the lines starting with &lt;code&gt;convert&lt;/code&gt; and &lt;code&gt;composite&lt;/code&gt;. It turned out that the watermark processor built the command params as a string, and when passed to &lt;a href="http://github.com/thoughtbot/paperclip/blob/v2.3.3/lib/paperclip.rb#L105"&gt;Paperclip.run&lt;/a&gt;, the whole string got quoted. The solution was to pass the params as consecutive arguments:&lt;/p&gt;

&lt;p&gt;&lt;script src="https://gist.github.com/465088.js?file=gistfile3.diff"&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;So, things started to look better after restarting the server. But then&amp;hellip;&lt;/p&gt;

&lt;h2&gt;Third obstacle&lt;/h2&gt;

&lt;p&gt;&lt;script src="https://gist.github.com/465088.js?file=development2.log"&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the single quotes are now as they should be. The issue is that the file names sometimes have this &lt;code&gt;[0]&lt;/code&gt; and double-quotes at the end. This was caused by buggy &lt;code&gt;#fromfile&lt;/code&gt; and &lt;code&gt;#tofile&lt;/code&gt;. Here&amp;rsquo;s how I fixed it:&lt;/p&gt;

&lt;p&gt;&lt;script src="https://gist.github.com/465088.js?file=gistfile4.diff"&gt;&lt;/script&gt;&lt;/p&gt;

&lt;p&gt;Now, after restarting the server, everything worked well.&lt;/p&gt;

&lt;p&gt;With some more formatting fixes, here&amp;rsquo;s the final version of the watermark processor:&lt;/p&gt;

&lt;p&gt;&lt;script src="https://gist.github.com/465088.js?file=watermark.rb"&gt;&lt;/script&gt;&lt;/p&gt;

&lt;h2&gt;Mission complete&lt;/h2&gt;

&lt;p&gt;Now I need to find a way to serve some styles directly from &lt;code&gt;public/&lt;/code&gt;, and to hide some of them behind a controller. Any ideas?&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://exviva.posterous.com/watermarking-images-with-rails-3-and-papercli"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://exviva.posterous.com/watermarking-images-with-rails-3-and-papercli#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/exviva/~4/McjRj-Ezc2I" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://files.posterous.com/user_profile_pics/1344557/Ja_200x200.jpg</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5AkZcR93KE2B</posterous:profileUrl>
        <posterous:firstName>Olek</posterous:firstName>
        <posterous:lastName>Janiszewski</posterous:lastName>
        <posterous:nickName>Olek</posterous:nickName>
        <posterous:displayName>Olek Janiszewski</posterous:displayName>
      </posterous:author>
    </item>
    <item>
      <pubDate>Thu, 24 Jun 2010 17:25:00 -0700</pubDate>
      <title>Welcome to my blog</title>
      <link>http://exviva.posterous.com/welcome-10692</link>
      <guid>http://exviva.posterous.com/welcome-10692</guid>
      <description>&lt;p&gt;
	&lt;p&gt;This blog is to allow me to take and share notes of my experiences on web development and related topics, experiments and findings that I will make during my day-to-day work as a web developer.&lt;/p&gt;

&lt;p&gt;These topics will mostly include (but not limit to):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ruby

&lt;ul&gt;
&lt;li&gt;Rails&lt;/li&gt;
&lt;li&gt;Gems&lt;/li&gt;
&lt;li&gt;Heroku&lt;/li&gt;
&lt;li&gt;RSpec&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;PHP

&lt;ul&gt;
&lt;li&gt;Trying to make it suck less (and doomed to fail)&lt;/li&gt;
&lt;li&gt;Zend Framework&lt;/li&gt;
&lt;li&gt;PHPUnit&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Web

&lt;ul&gt;
&lt;li&gt;HTTP/REST&lt;/li&gt;
&lt;li&gt;HTML5/CSS/JS (mostly jQuery)&lt;/li&gt;
&lt;li&gt;browsers&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Workflow tools

&lt;ul&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;li&gt;Trac&lt;/li&gt;
&lt;li&gt;Capistrano&lt;/li&gt;
&lt;li&gt;Cruisecontrol&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Sysadmining

&lt;ul&gt;
&lt;li&gt;Munin&lt;/li&gt;
&lt;li&gt;Apache&lt;/li&gt;
&lt;li&gt;MySQL&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/etc/*&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Ubuntu/Linux/GNU&lt;/li&gt;
&lt;li&gt;Netbeans/Vim/gedit&lt;/li&gt;
&lt;li&gt;professional development&lt;/li&gt;
&lt;li&gt;project/team management&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;This ad-hoc brainstorm list is definitely not carved in stone and will evolve together with my getting more comfortable with publishing.&lt;/p&gt;

&lt;h2&gt;Editor&amp;rsquo;s note&lt;/h2&gt;

&lt;p&gt;Yes, dear reader, this post &lt;em&gt;does&lt;/em&gt; feel a bit stiff and official. I hope with time my writing style gets more natural and witty (keep your fingers crossed).&lt;/p&gt;

&lt;p&gt;PS. Hey, Posterous, where&amp;rsquo;s my &lt;code&gt;"Preview before publishing to make sure it looks decent and at least try to find those typos"&lt;/code&gt; button?&lt;/p&gt;
	
&lt;/p&gt;

&lt;p&gt;&lt;a href="http://exviva.posterous.com/welcome-10692"&gt;Permalink&lt;/a&gt; 

	| &lt;a href="http://exviva.posterous.com/welcome-10692#comment"&gt;Leave a comment&amp;nbsp;&amp;nbsp;&amp;raquo;&lt;/a&gt;

&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/exviva/~4/3VBt_8PqS4w" height="1" width="1"/&gt;</description>
      <posterous:author>
        <posterous:userImage>http://files.posterous.com/user_profile_pics/1344557/Ja_200x200.jpg</posterous:userImage>
        <posterous:profileUrl>http://posterous.com/users/5AkZcR93KE2B</posterous:profileUrl>
        <posterous:firstName>Olek</posterous:firstName>
        <posterous:lastName>Janiszewski</posterous:lastName>
        <posterous:nickName>Olek</posterous:nickName>
        <posterous:displayName>Olek Janiszewski</posterous:displayName>
      </posterous:author>
    </item>
  </channel>
</rss>

