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

<channel>
	<title>Saturnboy &#187; Work</title>
	<atom:link href="http://saturnboy.com/category/work/feed/" rel="self" type="application/rss+xml" />
	<link>http://saturnboy.com</link>
	<description>Code, Work, and Life</description>
	<lastBuildDate>Thu, 01 Mar 2012 22:35:28 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Intro to OCHamcrest</title>
		<link>http://saturnboy.com/2011/08/intro-to-ochamcrest/</link>
		<comments>http://saturnboy.com/2011/08/intro-to-ochamcrest/#comments</comments>
		<pubDate>Wed, 17 Aug 2011 05:04:09 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=1862</guid>
		<description><![CDATA[Sometimes I feel like I write more test code than real code. For unit tests on iOS our stack is OCHamcrest, OCMock, and GHUnit. For functional tests, there&#8217;s nothing better than FoneMonkey. For this post, I&#8217;m going to focus on OCHamcrest. Hamcrest was born in the Java world as the matcher framework in jMock. It [...]]]></description>
			<content:encoded><![CDATA[<p>Sometimes I feel like I write more test code than real code. For unit tests on iOS our stack is <a href="https://github.com/jonreid/OCHamcrest">OCHamcrest</a>, <a href="http://www.mulle-kybernetik.com/software/OCMock/">OCMock</a>, and <a href="https://github.com/gabriel/gh-unit">GHUnit</a>. For functional tests, there&#8217;s nothing better than <a href="http://www.gorillalogic.com/fonemonkey">FoneMonkey</a>. For this post, I&#8217;m going to focus on OCHamcrest.</p>
<p><a href="http://code.google.com/p/hamcrest/">Hamcrest</a> was born in the Java world as the matcher framework in <a href="http://www.jmock.org/">jMock</a>. It was quickly extracted into its own framework  and has become somewhat of a monster in the testing world. It&#8217;s now included directly in <a href="http://www.junit.org/">JUnit</a> (since v4.4), and has been ported to many languages (OCHamcrest in Objective-C, <a href="https://github.com/drewbourne/hamcrest-as3">Hamcrest-AS3</a> in Actionscript, <a href="https://github.com/jonreid/PyHamcrest">PyHamcrest</a> in Python, etc.).  Additionally, the matcher concept is generally useful, and Hamcrest is <a href="http://code.google.com/p/hamcrest/wiki/UsesOfHamcrest">used is lots of different places</a> (my favorite is collection filtering with Hamcrest in <a href="http://code.google.com/p/lambdaj/">LambdaJ</a>).</p>
<p>When writing unit tests, OCHamcrest offers lots of advantages over the vanilla SenTest assertions.  First, there&#8217;s a ton of matchers that really make life easy, especially when testing collections like <code>NSArray</code>.  Second, OCHamcrest matchers are very readable in code, almost self-documenting.  Lastly, OCHamcrest automatically provides excellent failure messages when actual is not equal to expected.</p>
<h3>Matching Strings</h3>
<p class="bottom">Some string matching examples:</p>
<ul>
<li><b>is</b> &#8211; match the complete string</li>
<li><b>startsWith</b> &#8211; match the beginning of a string</li>
<li><b>endsWith</b> &#8211; match the end of a string</li>
<li><b>containsString</b> &#8211; match part of the string</li>
<li><b>equalTo</b> &#8211; match the complete string</li>
<li><b>equalToIgnoringCase</b> &#8211; match the complete string but ignore case</li>
<li><b>equalToIgnoringWhiteSpace</b> &#8211; match the complete string but ignore <i>extra</i> whitespace (new line, tab, or double spaces)</li>
</ul>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>s <span style="color: #002200;">=</span> <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;FooBar&quot;</span>;
&nbsp;
assertThat<span style="color: #002200;">&#40;</span>s, is<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;FooBar&quot;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
&nbsp;
assertThat<span style="color: #002200;">&#40;</span>s, startsWith<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Foo&quot;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
assertThat<span style="color: #002200;">&#40;</span>s, endsWith<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Bar&quot;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
assertThat<span style="color: #002200;">&#40;</span>s, containsString<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;oo&quot;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
assertThat<span style="color: #002200;">&#40;</span>s, equalToIgnoringCase<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;foobar&quot;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
&nbsp;
assertThat<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot; X <span style="color: #2400d9;">\n</span>  Y <span style="color: #2400d9;">\t</span><span style="color: #2400d9;">\t</span>  Z <span style="color: #2400d9;">\n</span>&quot;</span>, equalToIgnoringWhiteSpace<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;X Y Z&quot;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;</pre></div></div>

<blockquote class="deeper"><p><b>NOTE:</b> Technically, <code>is</code> isn&#8217;t really a matcher, it&#8217;s a <i>matcher decorator</i> that implicity converts to the <code>equalTo</code> matcher. [thanks Jon!]</p></blockquote>
<h3>Combining Matchers</h3>
<p class="bottom">You can combine multiple matchers with:</p>
<ul>
<li><b>allOf</b> &#8211; AND together all matchers</li>
<li><b>anyOf</b> &#8211; OR togehter all matches</li>
</ul>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>s <span style="color: #002200;">=</span> <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;FooBar&quot;</span>;
&nbsp;
assertThat<span style="color: #002200;">&#40;</span>s, allOf<span style="color: #002200;">&#40;</span>startsWith<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Foo&quot;</span><span style="color: #002200;">&#41;</span>, endsWith<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Bar&quot;</span><span style="color: #002200;">&#41;</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
assertThat<span style="color: #002200;">&#40;</span>s, anyOf<span style="color: #002200;">&#40;</span>startsWith<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Foo&quot;</span><span style="color: #002200;">&#41;</span>, startsWith<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Bar&quot;</span><span style="color: #002200;">&#41;</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
assertThat<span style="color: #002200;">&#40;</span>s, anyOf<span style="color: #002200;">&#40;</span>endsWith<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Foo&quot;</span><span style="color: #002200;">&#41;</span>, endsWith<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Bar&quot;</span><span style="color: #002200;">&#41;</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;</pre></div></div>

<blockquote class="deeper"><p><b>NOTE:</b> The list of matchers must be <code>nil</code> terminated.</p></blockquote>
<p class="bottom">You can invert a matcher, or multiple matchers, with:</p>
<ul>
<li><b>isNot</b> &#8211; negate the matcher</li>
</ul>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>s <span style="color: #002200;">=</span> <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;FooBar&quot;</span>;
&nbsp;
assertThat<span style="color: #002200;">&#40;</span>s, isNot<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;foo&quot;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
assertThat<span style="color: #002200;">&#40;</span>s, isNot<span style="color: #002200;">&#40;</span>endsWith<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Baz&quot;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
assertThat<span style="color: #002200;">&#40;</span>s, isNot<span style="color: #002200;">&#40;</span>allOf<span style="color: #002200;">&#40;</span>startsWith<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Baz&quot;</span><span style="color: #002200;">&#41;</span>, endsWith<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Baz&quot;</span><span style="color: #002200;">&#41;</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
assertThat<span style="color: #002200;">&#40;</span>s, isNot<span style="color: #002200;">&#40;</span>anyOf<span style="color: #002200;">&#40;</span>startsWith<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Baz&quot;</span><span style="color: #002200;">&#41;</span>, startsWith<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Baz&quot;</span><span style="color: #002200;">&#41;</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;</pre></div></div>

<h3>Matching <code>nil</code></h3>
<p class="bottom">You can match <code>nil</code> with:</p>
<ul>
<li><b>nilValue()</b> &#8211; stands in for <code>nil</code></li>
<li><b>notNilValue()</b> &#8211; stands in for <code>!nil</code></li>
</ul>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #400080;">NSObject</span> <span style="color: #002200;">*</span>o <span style="color: #002200;">=</span> <span style="color: #a61390;">nil</span>;
assertThat<span style="color: #002200;">&#40;</span>o, nilValue<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
&nbsp;
<span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>s <span style="color: #002200;">=</span> <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;FooBar&quot;</span>;
assertThat<span style="color: #002200;">&#40;</span>s, notNilValue<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;</pre></div></div>

<h3>Matching Classes</h3>
<p class="bottom">You can match an instance&#8217;s class with:</p>
<ul>
<li><b>instanceOf</b> &#8211; match the class</li>
</ul>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>s <span style="color: #002200;">=</span> <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;FooBar&quot;</span>;
assertThat<span style="color: #002200;">&#40;</span>s, instanceOf<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSString</span> class<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;</pre></div></div>

<h3>Matching Numbers</h3>
<p class="bottom">One of the great pains of Objective-C is typing numbers from primitive types to objects and back again.  OCHamcrest has a variety of matchers the help make life easy.</p>
<ul>
<li><b>assertThatInt</b> &#8211; typed assert that expects an <code>int</code> (other types too: <code>assertThatFloat</code>, <code>assertThatDouble</code>, etc.)</li>
<li><b>equalToInt</b> &#8211; typed equals that takes an <code>int</code> (other types too: <code>equalToFloat</code>, <code>equalToDouble</code>, <code>equalToBool</code>, etc.)</li>
<li><b>closeTo</b> &#8211; match a number with a target number plus or minus a delta (both params are <code>double</code>)</li>
<li><b>lessThan</b> &#8211; match a number less than the given number (param is <code>NSNumber</code>), also <code>lessThanOrEqualTo</code></li>
<li><b>greaterThan</b> &#8211; match a number greater than the given number (param is <code>NSNumber</code>), also <code>greaterThanOrEqualTo</code></li>
</ul>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;">assertThatInt<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">5</span>, equalToInt<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">5</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
assertThatFloat<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">3.14</span>, equalToFloat<span style="color: #002200;">&#40;</span>3.14f<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
assertThatBool<span style="color: #002200;">&#40;</span> <span style="color: #a61390;">false</span>, equalToBool<span style="color: #002200;">&#40;</span><span style="color: #a61390;">NO</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#41;</span>;
&nbsp;
<span style="color: #400080;">NSNumber</span> <span style="color: #002200;">*</span>i <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithInt<span style="color: #002200;">:</span><span style="color: #2400d9;">5</span><span style="color: #002200;">&#93;</span>;
assertThat<span style="color: #002200;">&#40;</span>i, equalToInt<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">5</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
assertThat<span style="color: #002200;">&#40;</span>i, is<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithInt<span style="color: #002200;">:</span><span style="color: #2400d9;">5</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
&nbsp;
<span style="color: #400080;">NSNumber</span> <span style="color: #002200;">*</span>f <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithFloat<span style="color: #002200;">:</span>3.14f<span style="color: #002200;">&#93;</span>;
assertThat<span style="color: #002200;">&#40;</span>f, equalToFloat<span style="color: #002200;">&#40;</span>3.14f<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
assertThat<span style="color: #002200;">&#40;</span>f, is<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithFloat<span style="color: #002200;">:</span>3.14f<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;</pre></div></div>

<p>The easiest cleanest approach is to use <code>assertThatInt</code> with <code>equalToInt</code>, the next best option is to use the vanilla <code>assertThat</code> with <code>equalToInt</code>, the most verbose option is to use <code>NSNumber</code> everywhere.</p>
<p class="bottom">It&#8217;s easy to make rough number comparisons too:</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #400080;">NSNumber</span> <span style="color: #002200;">*</span>f <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithFloat<span style="color: #002200;">:</span>3.14f<span style="color: #002200;">&#93;</span>;
assertThat<span style="color: #002200;">&#40;</span>f, closeTo<span style="color: #002200;">&#40;</span>3.0f, 0.25f<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
&nbsp;
assertThat<span style="color: #002200;">&#40;</span>f, lessThan<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithInt<span style="color: #002200;">:</span><span style="color: #2400d9;">4</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
assertThat<span style="color: #002200;">&#40;</span>f, greaterThan<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithInt<span style="color: #002200;">:</span><span style="color: #2400d9;">3</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;</pre></div></div>

<blockquote class="deeper"><p><b>NOTE:</b> It is a little weird, but <code>closeTo</code> takes <code>double</code> params, but everything else expects <code>NSNumber</code> params.</p></blockquote>
<p class="bottom">Numeric comparisons also work great on dates too:</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #400080;">NSDate</span> <span style="color: #002200;">*</span>now <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDate</span> date<span style="color: #002200;">&#93;</span>;
&nbsp;
<span style="color: #11740a; font-style: italic;">//now minus 1000 seconds</span>
<span style="color: #400080;">NSDate</span> <span style="color: #002200;">*</span>beforeNow <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDate</span> dateWithTimeIntervalSinceNow<span style="color: #002200;">:-</span><span style="color: #2400d9;">1000</span><span style="color: #002200;">&#93;</span>; 
&nbsp;
assertThat<span style="color: #002200;">&#40;</span>now, greaterThan<span style="color: #002200;">&#40;</span>beforeNow<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;</pre></div></div>

<h3>Matching Arrays</h3>
<p class="bottom">Easily the best part of OCHamcrest is its ability to match lists of objects.  Array matchers are every powerful, but don&#8217;t forget to add the terminating <code>nil</code> to all lists.</p>
<ul>
<li><b>hasItem</b> &#8211; match if given item appears in the list</li>
<li><b>hasItems</b> &#8211; match if all given items appear in the list (in any order)</li>
<li><b>contains</b> &#8211; match exactly the entire array</li>
<li><b>containsInAnyOrder</b> &#8211; match entire array, but in any order</li>
<li><b>hasCountOf</b> &#8211; match the size of the array</li>
<li><b>empty</b> &#8211; match an empty array</li>
</ul>
<p class="bottom">Here some basic array examples:</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #400080;">NSArray</span> <span style="color: #002200;">*</span>a <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSArray</span> array<span style="color: #002200;">&#93;</span>;
&nbsp;
assertThat<span style="color: #002200;">&#40;</span>a, is<span style="color: #002200;">&#40;</span>empty<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
assertThat<span style="color: #002200;">&#40;</span>a, hasCountOf<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">0</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;</pre></div></div>

<p class="bottom">Here some <code>hasItem</code> examples:</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #400080;">NSArray</span> <span style="color: #002200;">*</span>a <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSArray</span> arrayWithObjects<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;a&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;b&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;c&quot;</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;
&nbsp;
assertThat<span style="color: #002200;">&#40;</span>a, hasItem<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;a&quot;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
assertThat<span style="color: #002200;">&#40;</span>a, isNot<span style="color: #002200;">&#40;</span>hasItem<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;X&quot;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
assertThat<span style="color: #002200;">&#40;</span>a, hasItem<span style="color: #002200;">&#40;</span>equalToIgnoringCase<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;A&quot;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;</pre></div></div>

<p>The last matcher may look a little weird, but remember matchers expect a matcher as their input param, and only default to <code>equalTo</code> if none is given.  Thus, the first matcher <code>hasItem(@"a")</code> can be rewritten as <code>hasItem(equalTo(@"a"))</code>.</p>
<p class="bottom">We repeat the above example, but this time using numbers in our <code>NSArray</code>.  As you can see below, all the number matchers require us to explicitly use <code>equalToInt</code> everywhere:</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #400080;">NSArray</span> <span style="color: #002200;">*</span>a <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSArray</span> arrayWithObjects<span style="color: #002200;">:</span>
    <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithInt<span style="color: #002200;">:</span><span style="color: #2400d9;">2</span><span style="color: #002200;">&#93;</span>,
    <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithInt<span style="color: #002200;">:</span><span style="color: #2400d9;">3</span><span style="color: #002200;">&#93;</span>,
    <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithInt<span style="color: #002200;">:</span><span style="color: #2400d9;">5</span><span style="color: #002200;">&#93;</span>,
    <span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;
&nbsp;
assertThat<span style="color: #002200;">&#40;</span>a, hasItem<span style="color: #002200;">&#40;</span>equalToInt<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">2</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
assertThat<span style="color: #002200;">&#40;</span>a, isNot<span style="color: #002200;">&#40;</span>hasItem<span style="color: #002200;">&#40;</span>equalToInt<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">13</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
&nbsp;
assertThat<span style="color: #002200;">&#40;</span>a, contains<span style="color: #002200;">&#40;</span>equalToInt<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">2</span><span style="color: #002200;">&#41;</span>, equalToInt<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">3</span><span style="color: #002200;">&#41;</span>, equalToInt<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">5</span><span style="color: #002200;">&#41;</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;</pre></div></div>

<p class="bottom">Here are some more complex array matchers:</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #400080;">NSArray</span> <span style="color: #002200;">*</span>a <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSArray</span> arrayWithObjects<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;a&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;b&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;c&quot;</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;
&nbsp;
assertThat<span style="color: #002200;">&#40;</span>a, hasItems<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;b&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;a&quot;</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
&nbsp;
assertThat<span style="color: #002200;">&#40;</span>a, contains<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;a&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;b&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;c&quot;</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
assertThat<span style="color: #002200;">&#40;</span>a, containsInAnyOrder<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;c&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;b&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;a&quot;</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
&nbsp;
assertThat<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>a componentsJoinedByString<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;,&quot;</span><span style="color: #002200;">&#93;</span>, is<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;a,b,c&quot;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;</pre></div></div>

<p>And as I show in the last matcher, you can always dump to a string, and just match strings.</p>
<h3>Matching Dictionaries</h3>
<p class="bottom">The dictionary matchers build on the array matchers:</p>
<ul>
<li><b>hasKey</b> &#8211; match a key</li>
<li><b>hasValue</b> &#8211; match a value</li>
<li><b>hasEntry</b> &#8211; match a key-value pair</li>
<li><b>hasEntries</b> &#8211; match a list of k-v pairs</li>
</ul>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #400080;">NSDictionary</span> <span style="color: #002200;">*</span>d <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDictionary</span> dictionaryWithObjectsAndKeys<span style="color: #002200;">:</span>
    <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;valA&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;keyA&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;valB&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;keyB&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;valC&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;keyC&quot;</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;
&nbsp;
assertThat<span style="color: #002200;">&#40;</span>d, hasCountOf<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">3</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
assertThat<span style="color: #002200;">&#40;</span>d, isNot<span style="color: #002200;">&#40;</span>empty<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
&nbsp;
assertThat<span style="color: #002200;">&#40;</span>d, hasKey<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;keyA&quot;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
assertThat<span style="color: #002200;">&#40;</span>d, isNot<span style="color: #002200;">&#40;</span>hasKey<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;keyX&quot;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
&nbsp;
assertThat<span style="color: #002200;">&#40;</span>d, hasValue<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;valA&quot;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
&nbsp;
assertThat<span style="color: #002200;">&#40;</span>d, hasEntry<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;keyA&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;valA&quot;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
&nbsp;
assertThat<span style="color: #002200;">&#40;</span>d, hasEntries<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;keyA&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;valA&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;keyC&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;valC&quot;</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;</pre></div></div>

<h3>Matcher Error Messages</h3>
<p class="bottom">When a matcher fails, you get a standardize error message of: <code>Expected "foo", but was "bar"</code>.  This default message is easy to modify by using the <code>describedAs()</code> matcher in place of the typical <code>is()</code> matcher.</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>s <span style="color: #002200;">=</span> <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;bar&quot;</span>;
&nbsp;
assertThat<span style="color: #002200;">&#40;</span>s, is<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;foo&quot;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
<span style="color: #11740a; font-style: italic;">//Expected &quot;foo&quot;, but was &quot;bar&quot;</span>
&nbsp;
assertThat<span style="color: #002200;">&#40;</span>s, describedAs<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;doh! this should be 'foo'&quot;</span>, equalTo<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;foo&quot;</span><span style="color: #002200;">&#41;</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
<span style="color: #11740a; font-style: italic;">//Expected doh! this should be 'foo', but was &quot;bar&quot;</span>
&nbsp;
assertThat<span style="color: #002200;">&#40;</span>s, describedAs<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;doh! this should be foo, %0, %1&quot;</span>, equalTo<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;foo&quot;</span><span style="color: #002200;">&#41;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;baz&quot;</span>, <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithInt<span style="color: #002200;">:</span><span style="color: #2400d9;">42</span><span style="color: #002200;">&#93;</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
<span style="color: #11740a; font-style: italic;">//Expected doh! this should be foo, &quot;baz&quot;, &lt;42&gt;, but was &quot;bar&quot;</span></pre></div></div>

<blockquote class="deeper"><p><b>NOTE:</b> The argument list for <code>describedAs()</code> <b>MUST</b> end with <code>nil</code> or your tests will crash instantly with no useful error message.</p></blockquote>
<h3>Building a Custom Matcher</h3>
<p class="bottom">Writing your own custom matchers is relatively easy.  Here&#8217;s an example of a matcher that matches the value of some property on an object:</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #6e371a;">#import &lt;OCHamcrestIOS/OCHamcrestIOS.h&gt;</span>
<span style="color: #6e371a;">#import &lt;objc/objc-api.h&gt;</span>
&nbsp;
<span style="color: #a61390;">@interface</span> HasProperty <span style="color: #002200;">:</span> HCBaseMatcher <span style="color: #002200;">&#123;</span>
    <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>property;
    id&lt;HCMatcher&gt; valueMatcher;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">+</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span> hasProperty<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aProperty value<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>id&lt;HCMatcher&gt;<span style="color: #002200;">&#41;</span>aValueMatcher;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span> initWithProperty<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aProperty value<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>id&lt;HCMatcher&gt;<span style="color: #002200;">&#41;</span>aValueMatcher;
&nbsp;
<span style="color: #a61390;">@end</span>
&nbsp;
OBJC_EXPORT id&lt;HCMatcher&gt; hasProperty<span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>property, <span style="color: #a61390;">id</span> valueMatcher<span style="color: #002200;">&#41;</span>;</pre></div></div>

<p>We extends <code>HCBaseMatcher</code> with our custom <code>HasProperty</code> class.  We store the name of the property and a value matcher.</p>
<p class="bottom">And the implementation:</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #6e371a;">#import &quot;HasProperty.h&quot;</span>
<span style="color: #6e371a;">#import &lt;OCHamcrestIOS/HCDescription.h&gt;</span>
<span style="color: #6e371a;">#import &lt;OCHamcrestIOS/HCWrapInMatcher.h&gt;</span>
&nbsp;
<span style="color: #a61390;">@implementation</span> HasProperty
&nbsp;
<span style="color: #002200;">+</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span> hasProperty<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aProperty value<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>id&lt;HCMatcher&gt;<span style="color: #002200;">&#41;</span>aValueMatcher <span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self alloc<span style="color: #002200;">&#93;</span> initWithProperty<span style="color: #002200;">:</span>aProperty value<span style="color: #002200;">:</span>aValueMatcher<span style="color: #002200;">&#93;</span> autorelease<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span> initWithProperty<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aProperty value<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>id&lt;HCMatcher&gt;<span style="color: #002200;">&#41;</span>aValueMatcher <span style="color: #002200;">&#123;</span>
    self <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>super init<span style="color: #002200;">&#93;</span>;
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>self <span style="color: #002200;">!=</span> <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
        property <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>aProperty copy<span style="color: #002200;">&#93;</span>;
        valueMatcher <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>aValueMatcher retain<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#125;</span>
    <span style="color: #a61390;">return</span> self;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span> dealloc <span style="color: #002200;">&#123;</span>
    <span style="color: #002200;">&#91;</span>property release<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>valueMatcher release<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#91;</span>super dealloc<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>matches<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>item <span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">SEL</span> propertyGetter <span style="color: #002200;">=</span> NSSelectorFromString<span style="color: #002200;">&#40;</span>property<span style="color: #002200;">&#41;</span>;
&nbsp;
    <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>item respondsToSelector<span style="color: #002200;">:</span>propertyGetter<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
        <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>valueMatcher matches<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>item performSelector<span style="color: #002200;">:</span>propertyGetter<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span>
            <span style="color: #a61390;">return</span> <span style="color: #a61390;">YES</span>;
    <span style="color: #002200;">&#125;</span>
    <span style="color: #a61390;">return</span> <span style="color: #a61390;">NO</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span> describeTo<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>id&lt;HCDescription&gt;<span style="color: #002200;">&#41;</span>description <span style="color: #002200;">&#123;</span>
    <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>description appendText<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSString</span> stringWithFormat<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;an object with a property named '%@' with a value of {&quot;</span>, property<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>
        appendDescriptionOf<span style="color: #002200;">:</span>valueMatcher<span style="color: #002200;">&#93;</span>
        appendText<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;}&quot;</span><span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
<span style="color: #a61390;">@end</span>
&nbsp;
OBJC_EXPORT id&lt;HCMatcher&gt; hasProperty<span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>property, <span style="color: #a61390;">id</span> valueMatcher<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span>HasProperty hasProperty<span style="color: #002200;">:</span>property value<span style="color: #002200;">:</span>HCWrapInMatcher<span style="color: #002200;">&#40;</span>valueMatcher<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></div></div>

<p>When we write a custom matcher, we must implement two methods, <code>matches:</code> to do the matching and <code>describeTo:</code> to provide feedback in case of match failure.  In the above code, we first construct a selector from the given property name, then call the selector to get the actual property value, and finally check if actual matches the expected value (given by the <code>valueMatcher</code>).</p>
<p class="bottom">Usage looks like this:</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;">Person <span style="color: #002200;">*</span>p <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>Person personWithFirstName<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Joe&quot;</span> andLastname<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Doe&quot;</span><span style="color: #002200;">&#93;</span>;
&nbsp;
assertThat<span style="color: #002200;">&#40;</span>p, hasProperty<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;firstName&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Joe&quot;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;</pre></div></div>

<p class="bottom">Or more importantly, we can now use our custom <code>hasProperty</code> matcher to match an arrays of objects:</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #400080;">NSArray</span> <span style="color: #002200;">*</span>a <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSArray</span> arrayWithObjects<span style="color: #002200;">:</span>
    <span style="color: #002200;">&#91;</span>Person personWithFirstName<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Joe&quot;</span> andLastname<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Doe&quot;</span><span style="color: #002200;">&#93;</span>,
    <span style="color: #002200;">&#91;</span>Person personWithFirstName<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Joe&quot;</span> andLastname<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Smith&quot;</span><span style="color: #002200;">&#93;</span>,
    <span style="color: #002200;">&#91;</span>Person personWithFirstName<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Jane&quot;</span> andLastname<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Allen&quot;</span><span style="color: #002200;">&#93;</span>,
    <span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;
&nbsp;
assertThat<span style="color: #002200;">&#40;</span>a, contains<span style="color: #002200;">&#40;</span>
    hasProperty<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;firstName&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Joe&quot;</span><span style="color: #002200;">&#41;</span>,
    hasProperty<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;firstName&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Joe&quot;</span><span style="color: #002200;">&#41;</span>,
    hasProperty<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;firstName&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Jane&quot;</span><span style="color: #002200;">&#41;</span>,
    <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;</pre></div></div>

<p>That&#8217;s it.  Go forth and match.</p>
<p><b>UPDATE:</b> I put the above <code>hasProperty</code> matcher into <a href="https://github.com/jonreid/OCHamcrest/pull/2">a pull request</a>, and Jon Reid accepted it into OCHamcrest v1.6. He even wrote a <a href="http://jonreid.blogs.com/qualitycoding/2011/10/simplify-your-tests-with-ochamcrests-hasproperty.html">nice post</a> about it.  Get the lastest OCHamcrest from <a href="https://github.com/jonreid/OCHamcrest/">github</a>.</p>
<h3>Links</h3>
<ul>
<li><a href="https://github.com/jonreid/OCHamcrest">OCHamcrest</a> &#8211; github repo</li>
<li><a href="http://jonreid.github.com/OCHamcrest/">OCHamcrest Docs</a> &#8211; docs</li>
<li><a href="http://code.google.com/p/hamcrest/">Hamcrest</a> &#8211; on Java</a>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2011/08/intro-to-ochamcrest/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>To the Mountaintop</title>
		<link>http://saturnboy.com/2010/11/to-the-mountaintop/</link>
		<comments>http://saturnboy.com/2010/11/to-the-mountaintop/#comments</comments>
		<pubDate>Thu, 11 Nov 2010 03:00:50 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[goals]]></category>
		<category><![CDATA[teaching]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=1604</guid>
		<description><![CDATA[Back in December 2009, I had the amazing opportunity to teach for a whole week at Boulder Digital Works. BDW had just started that fall and the first class of 12 students1 was just getting started on a 60-week program. Teaching was a ton of fun! We wrote some PHP code together and everyone was [...]]]></description>
			<content:encoded><![CDATA[<p>Back in December 2009, I had the amazing opportunity to teach for a whole week at <a href="http://bdw.colorado.edu/">Boulder Digital Works</a>.  BDW had just started that fall and the first class of 12 students<sup><a href="#footnote-first12">1</a></sup> was just getting started on a 60-week program.</p>
<p>Teaching was a ton of fun!  We wrote some PHP code together and everyone was able to experience a little slice of the joy/hell that is development.  We also did a <i>lot</i> of talking, which was fun, too.  Since most of the class was non-technical, we didn&#8217;t geek out technology stuff, instead we spent a lot of time talking about meta-development.  We talked about process, how developers think, how development fits into digital, what it means to actually build something real, etc.  I found the whole thing to be very cathartic, having 12 smart people listening to me and participating in a fun discussion was just awesome.</p>
<h3>To Be Great</h3>
<p>One of the more interesting topics I discussed during class was how to be a <i>great</i> developer.  I spend a lot of my time and brainpower thinking about what I can do to be better.  That&#8217;s the mountaintop, but it&#8217;s always a long way away.</p>
<p>Some options for improvement are external but many are internal.  For example, I&#8217;m always asking myself: Who knows something that I want to know?  Who can I model?  What can I borrow from those around me? Who can I mentor?  Who should I ask to mentor me? What should I learn next? What should I forget?  What can I read?  Do I need to change my approach?  What is today&#8217;s definition of value?</p>
<p>I always think my kung-fu is strong, but I&#8217;m not a master.  So here&#8217;s a quick summary of the components of greatness as I see them today.  Please feel free to ignore everything as you see fit.</p>
<h3>Undying Hunger</h3>
<p>If you have the hunger to be better then you&#8217;re always on the upslope.  And this isn&#8217;t the vanilla-level hunger of &#8220;Hey, there&#8217;s more I could learn.&#8221;  This is the full on, I&#8217;m-starving-more-is-never-enough hunger.</p>
<p>Once upon a time, back when I was a young lad of 10 or so, there was a series of TV commercials asking &#8220;Do you see the glass half full or half empty? Blah blah blah&#8221;  After the hundredth viewing, I turned to my dad and said, &#8220;Dad, I see it as not enough! What does that make me?&#8221;  And in his infinite wisdom, my dad replied, &#8220;That makes you a hog!&#8221;  &#8211; which is an apt description without a doubt.</p>
<p>To be great, you need to be a hog.</p>
<h3>Effort</h3>
<p>Where hunger is internal, effort is external.  Where hunger is mostly mental, effort is mostly physical.  Effort is all about doing the work, expending the energy, getting really tired, waking up the next day, and doing it all over again.  There is an obvious correlation between hunger and effort, but it&#8217;s definitely not one of causation.  I fully control my decision to turn off the TV and pick up a book or sling some code.</p>
<p>The best thing about effort is that it&#8217;s just a switch, and I truly believe that.  You can decide for yourself to turn it on any time you want. And with the right carrot, you can even flip the switch on for someone else.  In my many years of coaching frisbee, I have repeatedly witnessed the switch being flipped.  People can be taught to work hard, but it&#8217;s a heck of a lot easier when they are on a team of hard workers.</p>
<p>Unfortunately for me, the effort switch is more of a dimmer switch then an on-off switch.  Burning bright and bringing a high level of effort for an extended period of time is hard.  Motivation naturally ebbs and flows, and it&#8217;s challenging to maintain it.  The best solution I&#8217;ve found to keep motivation high is to find a partner in crime.  When there&#8217;s someone else to work with and compete against, it&#8217;s much easier to work hard.  When I&#8217;m on my own, the only trick I have is to maximize variety, some days I work hard by doing some extra reading, some days it&#8217;s writing, some days it&#8217;s hacking, etc.</p>
<p>Effort in athletics is pretty easy to recognize.  It&#8217;s spending time in the weight room during the off-season and out-hustling the other guy during the game.  Effort in development is a little harder to figure out.  Some of my typical outside-of-work adventures include reading (books, blogs), writing (this blog, the occasional article), speaking (local user group), teaching (BDW), and lots of side projects (<a href="http://flexlayouts.org/">contribute to open source</a>, <a href="http://saturnboy.com/states-n-capitals/">silly iPhone apps</a>).  There are also quite a few at-work hustle opportunities: you can give a brown bag talk, you can mentor others, and you can be a good mentee (basically you need find someone who knows something you want to know and beg them to teach you).  But my favorite thing to do at work is find a like-minded peer and inspire them to work hard.  You can do this by co-reading, co-writing, co-speaking, pair programming, etc.</p>
<p>To be great, you must work hard, constantly.</p>
<h3>Creative &amp; Pedantic</h3>
<p>Unfortunately, no matter how hungry you are or how hard you work, you must also be creative to be a great programmer.  Without creativity, you will forever be a cog in the machine.  You might be the best cog ever, but you are a cog none the less. In <u>Hackers &amp; Painters</u><sup><a href="#footnote-hackers-n-painters">2</a></sup>, Paul Graham talks a lot about the creative nature of software construction.  Hackers, painters, architects, and writers are all <i>makers</i> in Paul&#8217;s world, and he spends quite a bit of prose comparing them.</p>
<p>I really like Paul&#8217;s take on the process of construction, and the different disciplines that practice it, but I try to take a more practical view.  To me, creativity is nothing more than a measure of one&#8217;s ability to escape <b>the box</b>.  I see it as just another skill that can be learned, practiced, and improved.  Over time, you can learn to recognize the box faster and more fully.  The more boxes you see, and solve, the more solution patterns you will remember.  Eventually, you will develop a toolbox of escape tactics.</p>
<p>Again, it&#8217;s still not enough.  No amount of creativity will help you actually implement a solution to any given box.  There are a lot of details that are critically important to the construction process.  Paul Graham writes, &#8220;In both painting and hacking there are some tasks that are terrifyingly ambitious, and others that are comfortingly routine.&#8221;  Much like Superman has Bizarro, the creativity has pedanticalness (yes that&#8217;s a word).  Many of the routine tasks in programming are routine to the point of being tedious.</p>
<p>I often liken the pedantic aspect of development to licking envelopes.  It&#8217;s easy, but yuck!  Who actually likes the taste of envelopes?  If you don&#8217;t do it right, then don&#8217;t be surprised if you mail explodes while in transit.  In my experience, there are a multitude of development tasks that taste a heck of a lot like envelope glue, but you don&#8217;t really have much choice.  You can either do them the right way, or watch them explode.</p>
<p>To be great, you must embrace both the creative side of development and the pedantic side.</p>
<h3>Ego</h3>
<p>The number one, most important, aspect of greatness is ego.  The truth of development is that not everything goes your way.  And even when it does, it can be exceedingly difficult.  For all those times when you are tumbling down the mountain, you need a certain amount of ego to arrest your fall and start upwards again.  I&#8217;ve actually spent time and effort into stroking my own ego for this simple reason: you learn more when you lose than when you win.</p>
<p>I heard a pretty amazing football stat the other day.  In 9 of the last 10 seasons in the NFL, at least one last place division team fought their way to first place in their division the following year.  Most recently, the Saints finished 8-8 in 2008 and were in last place in the NFC South.  In 2009, they won their division at 13-3 and went on to win the Superbowl.  Why?  Because you learn more when you lose than when you win.  Fact.</p>
<p>The mud is a great teacher.  But you must have a certain level of mental fortitude to climb out and get clean again.  To me ego is just that &#8211; confidence in yourself and your ability, lack of fear, and a basic mental toughness.  I&#8217;ll go willingly into the mud to take on a difficult problem or learn a new language (<a href="http://saturnboy.com/2010/04/the-schizophrenic-programmer/">or maybe a new API instead of another language</a>).  And if I get thrown into the mud unexpectedly, which happens all the time in consulting, there won&#8217;t be any fear or panic.</p>
<p>Do I get dirty? Hell yes.  Does it stink?  Of course.  Having confidence in yourself and believing in your abilities doesn&#8217;t magically transform the metaphoric mud into flowers, it&#8217;s still mud.</p>
<p>To be great, you must be confident and fearless.</p>
<h3>Conclusion</h3>
<p>It&#8217;s hard to know what you don&#8217;t know.  In fact, it&#8217;s really damn hard.  But I don&#8217;t find it discouraging in the least to know the code I write today is going to suck compared to the code I write tomorrow.  That&#8217;s called progress.</p>
<p class="bottom">I feel good when I focus on what I do know.  I know I want to be the best dad I can be, the best husband I can be, and the best developer I can be.  And today, that means this:</p>
<ul>
<li><b>undying hunger</b> &mdash; more is never enough</li>
<li><b>effort</b> &mdash; constantly work hard</li>
<li><b>creative &amp; pedantic</b> &mdash; embrace both sides, writing elegant algorithms and head-pounding debugging</li>
<li><b>ego</b> &mdash; be confident in yourself</li>
</ul>
<p>So stay hungry, work your ass off, lick your envelopes, and welcome the mud at every opportunity.  Good luck.</p>
<blockquote><p>&ldquo;And whenever men and women straighten their backs up, they are going somewhere, because a man can&#8217;t ride your back unless it is bent.&rdquo; &mdash; Martin Luther King, Jr<sup style="font-style:normal;">&nbsp;<a href="#footnote-mlk">3</a></sup></p></blockquote>
<h5>Footnotes</h5>
<ol>
<li><a name="footnote-first12"></a>I&#8217;d like to thank BDW&#8217;s First 12 for listening to a crazy opinionated developer. <a href="http://twitter.com/botvinick">@botvinick</a>, <a href="http://twitter.com/kygalle">@kygalle</a>, <a href="http://twitter.com/dasn101">@dasn101</a>, <a href="http://twitter.com/tetonmarketing">@tetonmarketing</a>, <a href="http://twitter.com/jefferyjake">@jefferyjake</a>, <a href="http://twitter.com/justinmccammon">@justinmccammon</a>, <a href="http://twitter.com/rosErin">@rosErin</a>, <a href="http://twitter.com/JadedSkipping">@JadedSkipping</a>, <a href="http://twitter.com/hseal">@hseal</a>, <a href="http://twitter.com/tegoenfuego">@tegoenfuego</a>, <a href="http://twitter.com/dviens">@dviens</a>, <a href="http://twitter.com/ndubsglobal">@ndubsglobal</a></li>
<li><a name="footnote-hackers-n-painters"></a><a href="http://oreilly.com/catalog/9780596006624">Hackers &amp; Painters</a> by Paul Graham</li>
<li><a name="footnote-mlk"></a><a href="http://www.americanrhetoric.com/speeches/mlkivebeentothemountaintop.htm">I&#8217;ve Been to the Mountaintop</a> by Martin Luther King, Jr.  This speech was given on April 3, 1968.</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2010/11/to-the-mountaintop/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Metrics and the AIR Install Badge</title>
		<link>http://saturnboy.com/2010/05/metrics-air-install-badge/</link>
		<comments>http://saturnboy.com/2010/05/metrics-air-install-badge/#comments</comments>
		<pubDate>Wed, 19 May 2010 15:21:01 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[AIR]]></category>
		<category><![CDATA[flash]]></category>
		<category><![CDATA[flexmonkey]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=1405</guid>
		<description><![CDATA[The AIR Install Badge is a very handy little flash application for delivering AIR applications to your users via the web. The badge allows your users to download and install both your application and the Adobe AIR runtime. Additionally, the install badge will automatically prompt users to upgrade if a previously installed version is detected. [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://www.adobe.com/devnet/air/articles/badge_for_air.html">AIR Install Badge</a> is a very handy little flash application for delivering AIR applications to your users via the web.  The badge allows your users to download and install both your application and the Adobe AIR runtime.  Additionally, the install badge will automatically prompt users to upgrade if a previously installed version is detected.  At <a href="http://www.gorillalogic.com/">Gorilla Logic</a>, we use the AIR Install Badge on the <a href="http://www.gorillalogic.com/flexmonkey/download">FlexMonkey download page</a> (free registration required).</p>
<p>Alas, flash is opaque to analytics.  We have no idea what our users are doing inside the AIR Install Badge application.  Are they installing? Or upgrading?  No problem, we just need to write some code&#8230;</p>
<h3>The Code</h3>
<p>Using flash&#8217;s <a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/external/ExternalInterface.html">ExternalInterface</a>, we can manually push the data out of flash and into javascript.  Once we have the data in javascript, we have total control.  One option is to <a href="http://blog.creoff.net/using-google-analytics-with-adobe-air-install-badge/">use google analytics to store our badge data</a>.  In the case of FlexMonkey, we send the badge data along with the user&#8217;s credentials to our CRM platform, <a href="http://www.salesforce.com/">SalesForce.com</a>.</p>
<p class="bottom"><b>Step 1:</b> First, open <code>AIRInstallBadge.as</code> and add this to the top:</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;"><span style="color: #0066CC;">import</span> flash.<span style="color: #006600;">external</span>.<span style="color: #006600;">ExternalInterface</span>;</pre></div></div>

<p class="bottom"><b>Step 2:</b> Next, add the <code>ExternalInterface</code> call to the top of the <code>handleActinClick()</code> function in <code>AIRInstallBadge.as</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;">protected <span style="color: #000000; font-weight: bold;">function</span> handleActionClick<span style="color: #66cc66;">&#40;</span>evt:MouseEvent<span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>action == <span style="color: #ff0000;">'install'</span> <span style="color: #66cc66;">||</span> action == <span style="color: #ff0000;">'upgrade'</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #808080; font-style: italic;">//send data to js</span>
        ExternalInterface.<span style="color: #0066CC;">call</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'badgeJS'</span>,action<span style="color: #66cc66;">&#41;</span>;
    <span style="color: #66cc66;">&#125;</span>
    ...
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>Since I only care about the <code>install</code> or <code>upgrade</code> actions, I&#8217;ll only send those out to javascript.  Re-compile the badge and deploy.</p>
<p class="bottom"><b>Step 3:</b> Last, add the <code>badgeJS()</code> javascript callback to the page containing the badge and do whatever you want with the incoming badge data:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> badgeJS<span style="color: #009900;">&#40;</span>action<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #006600; font-style: italic;">//do metrics here...</span>
    <span style="color: #000066;">alert</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'badge action='</span> <span style="color: #339933;">+</span> action<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<h3>Conclusion</h3>
<p>With an hour of effort, and a very small amount of code, we&#8217;ve managed to get the useful metrics of installs and upgrades out of the AIR Install Badge and into our analytics engine of choice.  A job well done.</p>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2010/05/metrics-air-install-badge/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Schizophrenic Following</title>
		<link>http://saturnboy.com/2010/05/schizophrenic-following/</link>
		<comments>http://saturnboy.com/2010/05/schizophrenic-following/#comments</comments>
		<pubDate>Thu, 06 May 2010 04:01:24 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[crazy]]></category>
		<category><![CDATA[goals]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=1311</guid>
		<description><![CDATA[This post is a follow-up to my previous post, The Schizophrenic Programmer. I must have struck a chord, because I got a ton of fantastic feedback not just on this blog, but also on Reddit and DZone. After further reflection, I still agree with what I said and my conclusions. Moving forward, I plan to [...]]]></description>
			<content:encoded><![CDATA[<p>This post is a follow-up to my previous post, <a href="http://saturnboy.com/2010/04/the-schizophrenic-programmer/">The Schizophrenic Programmer</a>.  I must have struck a chord, because I got a ton of fantastic feedback not just on this blog, but also on <a href="http://www.reddit.com/r/programming/comments/bvrvy/the_schizophrenic_programmer/">Reddit</a> and <a href="http://dzone.com/links/the_schizophrenic_programmer.html">DZone</a>.</p>
<p>After further reflection, I still agree with what I said and my conclusions.  Moving forward, I plan to learn fewer languages and less syntax.  My daily pain is that too much of my knowledge is too tightly bound to the implementation details, and when I switch languages I can&#8217;t bring my solutions to bear.  It sucks, and it makes me feel stupid.  So the simple fix is to put my energy into learning more unbound concepts (like my soft skills of speaking and writing) and more easily transferable concepts (like APIs).</p>
<h3>Analytics</h3>
<div class="span-14 last" style="min-height:137px;">
<img src="http://saturnboy.com/wp-content/uploads/2010/05/schizophrenic-analytics.png" alt="google-analytics" title="google-analytics" width="530" height="127" /></div>
<p>I had a huge bump in traffic mostly due to Reddit and DZone that basically crushed my regular traffic down into the noise.  My poor slice at <a href="http://www.slicehost.com/">Slicehost</a> was taking a beating, so I quickly installed the <a href="http://www.satollo.net/plugins/hyper-cache">Hyper Cache</a> plugin.  It&#8217;s dead simple and it really works.  On Sunday morning, my load went from 0.2 to 0.02 instantly.</p>
<p>I also tracked my <a href="http://bit.ly/cR6cnY+">twitter analytics</a> via <a href="http://bit.ly/">bit.ly</a>.  As a side note, you can just put a plus &#8220;+&#8221; at the end of any bit.ly url to see it&#8217;s analytics.  So, since the original post was shortened to <a href="http://bit.ly/cR6cnY">http://bit.ly/cR6cnY</a>, the analytics are available here: <a href="http://bit.ly/cR6cnY+">http://bit.ly/cR6cnY+</a>.</p>
<h3>Commentary</h3>
<p class="bottom">Lots of stuff was said, but I just wanted to touch on some of the key points.</p>
<ol>
<li><b>I feel your pain</b> &ndash; thanks.  I find it comforting to know I&#8217;m not alone.</li>
<li><b>definition of schizophrenia</b> &ndash; a couple of comments mentioned that my post had nothing to do with schizophrenia. First, I suggest you <a href="http://www.merriam-webster.com/dictionary/schizophrenic">look it up</a>: &ldquo;contradictory or antagonistic qualities or attitudes&rdquo;.  My Erland knowledge is definitely in opposition with my Java, which is in opposition with my Actionscript, etc.  If you don&#8217;t have this problem, good on you.  Second, there&#8217;s thing called artistic license and if you are a writer you get to use it.  I picked a sensational word for a reason.  I welcome criticism of the choice, but it&#8217;s silly to take umbrage with its validity.</li>
<li><b>short sighted</b> &ndash; my plan was called out as short sighted a couple of times.  I tend to think of life and plans like this&#8230; There are three choices when it comes to plans.  First, you can have no plan, and just drift along.  Sometimes you get smashed into the rocks, and other times you wash up on a tropical paradise with beer, virgins, and fiber broadband.  Second, you can have a short term plan that gets revisited and revised as things change.  Third, you can have a short term plan, but be so unbelievably naive that you think it is actually some awesome long term plan.  Life is agile. All plans are short term.</li>
<li><b>embrace and extend</b> &ndash; a few people said don&#8217;t fight it and embrace the insanity. I really lust after new stuff, so it was easy to try to the embrace-the-insanity method first.  Alas, it didn&#8217;t work out and I think it actually made matters worse.  Thus, I decided to go with a new plan to fight against the insanity.</li>
<li><b>python</b> &ndash; a couple people mentioned I should switch to python.  Yes I&#8217;ve written many thousands of lines of python, but none in 2010 so far.</li>
</ol>
<p>Thanks for reading.  As always, I love feedback.</p>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2010/05/schizophrenic-following/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Schizophrenic Programmer</title>
		<link>http://saturnboy.com/2010/04/the-schizophrenic-programmer/</link>
		<comments>http://saturnboy.com/2010/04/the-schizophrenic-programmer/#comments</comments>
		<pubDate>Thu, 22 Apr 2010 01:06:44 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[crazy]]></category>
		<category><![CDATA[goals]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=1241</guid>
		<description><![CDATA[Hi, my name is Justin and I have a problem. I&#8217;m insane!1 Being insane really sucks. But I&#8217;ve got a plan to get back on track. First, I&#8217;ll dole out some blame. Then, I&#8217;ll give a little background. Next, I&#8217;ll really dig into my current insanity. And finally, I&#8217;ll layout my plan for the future. [...]]]></description>
			<content:encoded><![CDATA[<p>Hi, my name is Justin and I have a problem.  I&#8217;m <b>insane</b>!<sup><a href="#footnote-insane">1</a></sup></p>
<p>Being insane really sucks.  But I&#8217;ve got a plan to get back on track.  First, I&#8217;ll dole out some blame.  Then, I&#8217;ll give a little background. Next, I&#8217;ll really dig into my current insanity.  And finally, I&#8217;ll layout my plan for the future.</p>
<h3>The Blame</h3>
<p>I like to curse.  And when I&#8217;m mad, I find it definitely helps to calm the rage.  So to begin, I&#8217;d like to give a big fuck you to Andy Hunt and Dave Thomas, the <a href="http://www.pragprog.com/">pragmatic programmers</a>.  I love you guys but you get at least some of the blame for making me insane.  Next, I&#8217;d like to give some blame to my wonderful employer, <a href="http://www.gorillalogic.com/">Gorilla Logic</a>, and their penchant for landing such a diverse set of inspiring projects.  You suck for building a candy store and filling it with the sweetest treats.</p>
<p>Unfortunately for me, the lion&#8217;s share of the blame is mine and mine alone.  I&#8217;m insane today because of my lust for the new coupled with my desire to be great.  I want to be a great dad, a great husband, and a great employee.  Who wants to be average?</p>
<p>It&#8217;s just not possible that I&#8217;m alone.  Who doesn&#8217;t like cool new stuff?  Who doesn&#8217;t want to be great?  There must be thousands, if not tens of thousands, of fellow developers suffering from insanity that goes undiagnosed.  So this tale goes out to you, my functionally insane brethren.  Together we can heal ourselves.</p>
<h3>Who Am I?</h3>
<p>I&#8217;d like to give a little background before I get in too deep with my current insanity.  I&#8217;m a developer.  I get paid to write code (woo hoo!) to solve problems.  Blah, blah, blah, if you just fill in the rest with a bunch of geek stereotypes you won&#8217;t be far off.  Yes, I like to IM my coworkers instead of just walking over and talking with them.  Yes, I read <a href="http://slashdot.org/">slashdot</a>.  Yes, I read sci-fi.  Yes, I played lots of Dungeons &amp; Dragons.<sup><a href="#footnote-dnd">2</a></sup> Et cetera&#8230;</p>
<p>I consider myself a smart guy, just like every single developer I&#8217;ve ever met.  I stay hungry and motivated to learn something new every day, every week, every year.  Thanks to Andy and Dave, I learn one new language every year.  And most importantly, I try very hard to listen or at least listen more than I argue.  Sometimes it doesn&#8217;t work out so well, but that&#8217;s another tale&#8230;</p>
<h3>How I Became Insane</h3>
<p>I&#8217;m a big fan of &ldquo;right tool for the job&rdquo; in both life and development.  In the realm of development, the concept of right tool for the job has metamorphosized into <b>right language for the job</b>, aka polyglot programming.  On the face of it, polyglot programming has a lot of advantages (here&#8217;s a <a href="http://www.infoq.com/presentations/polyglot-polyparadigm-programming">good talk</a> by Dean Wampler), but it is one of the root causes of my insanity.</p>
<p>At Gorilla Logic, we are regular practitioners of polyglot programming.  Our typical enterprise RIA project uses Java on the backend and Flex on the frontend.  Of course, the mix of languages doesn&#8217;t stop there.  I develop for the web, so when you talk about websites, <a href="http://wordpress.org/">WordPress</a> and <a href="http://drupal.org/">Drupal</a> are immediately in the conversation, and thus PHP.  And since a rich client-side experience is critically important, HTML, CSS, and Javascript are drawn into the mix.  In the mobile world, <a href="http://blackberry.com/eng/developers/">Blackberry</a> and <a href="http://developer.android.com/">Android</a> are thankfully mostly Java, but anything Apple takes me into the non-GC&#8217;d world of Objective-C.</p>
<p>I&#8217;ve also been diligently learning my one language a year for a while now.  And when you combine that with work, it has simply become too much.  I&#8217;ve become scattered, my mind has become messy.  Looking at the syntax level, the symptoms are acute.  I can&#8217;t write a loop. I can&#8217;t match a pattern.  I can&#8217;t build array operations.  My context switching pain is severe, it can literally take hours before I get back up to speed with the language at hand.</p>
<p>But it&#8217;s not just the low-level stuff anymore.  I&#8217;m finding that even at the highest levels of architecture, clean thought is hard to achieve.  Different languages tend to espouse different patterns and paradigms that directly impact architecture level decisions.  For example, if I wanted to write a server in PHP I might consider using OS support like fork and cron.  In Java, I&#8217;m off in thread land.  Erlang it&#8217;s processing and messaging.  Scala is all about actors.</p>
<p>I find myself mixing paradigms and doing stupid stuff, like trying to fake Erlang&#8217;s message passing in PHP by multiple scripts communicating by repeatedly touching rows in a database.  Dumb, but becoming harder to avoid as everything slowly bleeds together in my mind.  I&#8217;m in the mud and I desperately what to be clean again.</p>
<h3>My Current Insanity</h3>
<p class="bottom">Here&#8217;s a broad sample of what I&#8217;ve done lately (as in the last month or so) for work and personal projects:</p>
<dl>
<dt>Erlang <span class="quiet">&ndash; Work</span></dt>
<dd>Freshened my Erlang, wrote a sample custom module for <a href="http://www.ejabberd.im/">ejabberd</a>, played with <a href="http://nitrogenproject.com/">Nitrogen</a>.</dd>
<dt>Flex/AS3 <span class="quiet">&ndash; Work</span></dt>
<dd>I helped out a little bit with <a href="http://www.gorillalogic.com/flexmonkey/">FlexMonkey 1.0</a>, including the fuzzy pixel bitmap comparison support.</dd>
<dt>Flex/AS3 <span class="quiet">&ndash; Work</span></dt>
<dd>ScrumMonkey is another Gorilla Logic open-source project.  I upgraded everything to work with Flex 4 and LCDS 3.0.</dd>
<dt>Java <span class="quiet">&ndash; Work</span></dt>
<dd>Fun with Spring, Hibernate, and <a href="http://www.springactionscript.org/">Spring Actionscript</a>.  Can&#8217;t say any more about the project.</dd>
<dt>Javascript <span class="quiet">&ndash; Work</span></dt>
<dd>I helped develop <a href="http://stu-stern.blogspot.com/2010/02/flexmonkium-movie.html">FlexMonkium</a>, a Selenium-to-FlexMonkey testing tool that enabled automated functional testing of hybrid web apps.  I used Javascript and XUL.</dd>
<dt>Objective-C <span class="quiet">&ndash; Justin</span></dt>
<dd>Wrote and published a US states and capitals memorization helper app.  <a href="http://saturnboy.com/states-n-capitals/">Read more</a> or <a href="http://www.itunes.com/app/statesncapitals">get it</a> from the app store.</dd>
<dt>Objective-C <span class="quiet">&ndash; Work</span></dt>
<dd>iPhone and iPad.  Cool stuff.  Can&#8217;t talk about it yet.</dd>
<dt>PHP <span class="quiet">&ndash; Justin</span></dt>
<dd>Released <a href="http://saturnboy.com/viceroy/">Viceroy</a>, a one-column WordPress theme with a dash of pink.</dd>
<dt>PHP <span class="quiet">&ndash; Work</span></dt>
<dd>We needed to get our community feedback out of Google Groups and into our <a href="http://www.gorillalogic.com/forum/7">FlexMonkey Forum</a>.  I wrote a simple scrapper in PHP and <a href="http://saturnboy.com/2010/03/scraping-google-groups/">blogged about it</a>.</dd>
<dt>PHP <span class="quiet">&ndash; Justin</span></dt>
<dd>Various WordPress and Drupal side projects just for fun.</dd>
<dt>Ant, Maven, Bash, Rake <span class="quiet">&ndash; Work &amp; Justin</span></dt>
<dd>Scripted a bunch of stuff&#8230;</dd>
</dl>
<p>And that&#8217;s just my current insanity: the languages that I&#8217;ve touched lately.  But I&#8217;m <b>not</b> special!  At least, not in this case.  The list is similar for many co-workers, and many of my friends that are web developers.</p>
<h3>The Sensible Plan</h3>
<p>If I&#8217;m to blame, then I&#8217;ve got to be the one to fix it.  So here&#8217;s my plan:</p>
<ul>
<li><b>Forget one language every year</b> &ndash; Forget the syntax, forget the weirdness, and forget the whole ecosystem (frameworks, tools, community).  Say goodbye and don&#8217;t look back.  But before you leave a language behind, pick one core concept, one of the things the language does right, and take that with you. For example, when I forget Erlang, I&#8217;ll take the concept of concurrent programming with me.  So I&#8217;ll remember stuff like immutability, message passing, and processes.  When I forget Ruby, I&#8217;ll take DSLs with me.  Ruby does lots of stuff well, like blocks, mixins, terse syntax, and meta-programming, but I always enjoyed using all the great DSLs the best, so that&#8217;s what I&#8217;ll remember.</li>
<li><b>Don&#8217;t learn one programming language every year</b> &ndash; Yep, I&#8217;m going against Andy &#038; Dave.  So no Haskel, Clojure, Duby, Go, or <a href="http://reia-lang.org/">Reia</a> for me this year.  I&#8217;m obviously feeling a little full on languages right now, so I&#8217;ll take a break for a few years.</li>
<li><b>Learn one or more APIs every year</b> &ndash; Since Web 3.0 is all about APIs, I might as well spend some time learning more of them.  The big boys are obvious: Twitter, Facebook, Flickr, Google Maps, but there are plenty more that are really interesting.  From the practical side, every single web project either integrates with other APIs, wants their own API, or has some set of requirements that force a good SOA architecture (aka some internal set of APIs).</li>
<li><b>Upgrade my soft skills</b> &ndash; Slinging code is fun, but it can&#8217;t be the only thing I do if I want to be a great employee.  So instead of picking up all these little bits of shiny tech, I&#8217;m going to going to focus my lust for the new on upgrading my soft skills.  I write this blog to improve my writing, but I haven&#8217;t spoken at a big conference since CLEO/QELS in 1999 and I was really bad.  So I hope to do some public speaking in 2010.</li>
</ul>
<p>Basically, I&#8217;m hoping to elevate my kung-fu by going for more depth of knowledge.  Then, I&#8217;ll do my best to control the relentless expansion of breadth.  New and shiny is no longer sufficient.  Talking things through with co-workers and writing this post is a great first step into the future.  I&#8217;m already feeling optimistic about my path.</p>
<h5>Footnotes</h5>
<ol>
<li><a name="footnote-insane"></a>I&#8217;m not really insane, at least I don&#8217;t think so.  I&#8217;m just functionally insane.  For a glimpse into the mind of a real schizophrenic, I highly recommend <i>Is There No Place On Earth For Me?</i> by Susan Sheehan.  It won the non-fiction pulitzer prize in 1983, so it&#8217;s a little bit dated now, but an unimaginable story.</li>
<li><a name="footnote-dnd"></a>Actually, my friends and I played a lot of Rolemaster (<a href="http://en.wikipedia.org/wiki/Rolemaster">wikipedia</a>) and Champions (<a href="http://en.wikipedia.org/wiki/Champions_(role-playing_game)">wikipedia</a>) which are superior role playing games.  If you are a true fan, you&#8217;ll understand. If not, the image of boys with dice conjured by Dungeons &amp; Dragons is a good takeaway.</li>
</ol>
<p><span style="font-weight:bold;font-size:125%;">UPDATE:</span> I wrote a follow-up post to address all the great feedback: <a href="http://saturnboy.com/2010/05/schizophrenic-following/">Schizophrenic Following</a></p>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2010/04/the-schizophrenic-programmer/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Scraping Google Groups</title>
		<link>http://saturnboy.com/2010/03/scraping-google-groups/</link>
		<comments>http://saturnboy.com/2010/03/scraping-google-groups/#comments</comments>
		<pubDate>Mon, 29 Mar 2010 03:31:31 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[flexmonkey]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=1105</guid>
		<description><![CDATA[When we launched the new and improved Gorilla Logic website, we decided to bring all our open source projects together under one roof. In order to migrate all things FlexMonkey back to our website, we need to get our forum data migrated out of Google Groups. Alas, Google doesn&#8217;t provide any way to export data [...]]]></description>
			<content:encoded><![CDATA[<p>When we launched the new and improved <a href="http://www.gorillalogic.com/">Gorilla Logic</a> website, we decided to bring all our open source projects together under one roof.  In order to migrate all things <a href="http://www.gorillalogic.com/flexmonkey">FlexMonkey</a> back to our website, we need to get our forum data migrated out of Google Groups.  Alas, Google doesn&#8217;t provide any way to export data from Google Groups.  The only way to preserve the amazing contributions from the FlexMonkey community was to scrape Google Groups.  So that&#8217;s just what we did.</p>
<p>With a very minimal amount of PHP, I was able to walk the entire FlexMonkey Google Group, scrap all the topics (aka threads) and all the posts inside each thread.  The first step was to build a generic scraper class that grabs an html page (using <a href="http://curl.haxx.se/">cURL</a>) and parses out all unique outbound links.</p>
<p class="bottom">Here&#8217;s the code for the <code>Scraper</code> class:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Scraper <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$html</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$links</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #009900;">&#40;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">url</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$url</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> run<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">html</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">links</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">//scrape url &amp; store html</span>
        <span style="color: #000088;">$ch</span> <span style="color: #339933;">=</span> <span style="color: #990000;">curl_init</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #990000;">curl_setopt</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_URL<span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">url</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #990000;">curl_setopt</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_HEADER<span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #990000;">curl_setopt</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #339933;">,</span> CURLOPT_RETURNTRANSFER<span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">html</span> <span style="color: #339933;">=</span> <span style="color: #990000;">curl_exec</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #990000;">curl_close</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$ch</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
         <span style="color: #666666; font-style: italic;">//parse html for all links</span>
        <span style="color: #000088;">$matches</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #990000;">preg_match_all</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'#&lt;a.*?href\s*=\s*&quot;(.*?)&quot;.*?&gt;(.*?)&lt;/a&gt;#i'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">html</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$matches</span> <span style="color: #339933;">!==</span> <span style="color: #009900; font-weight: bold;">false</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$matches</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> <span style="color: #cc66cc;">3</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$i</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">;</span> <span style="color: #000088;">$i</span> <span style="color: #339933;">&lt;</span> <span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000088;">$i</span><span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                <span style="color: #000088;">$href</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
                <span style="color: #000088;">$val</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
                <span style="color: #666666; font-style: italic;">//unique links</span>
                <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">array_key_exists</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$href</span><span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">links</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">links</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$href</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$val</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>In the <code>run()</code> method, cURL is used to grab the html.  Next, a regular expression is used to match all outbound links.  The links are are stored in a hash, while making sure they point to unique urls.</p>
<p class="bottom">Built on top of the generic <code>Scraper</code> class is a specialized Google Groups scraper class, aptly named <code>GoogleGroupsScraper</code>.  For a given Google Group, the url of the main page (containing a list of most recent topics) is:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">http://groups.google.com/group/[GROUP]/topics</pre></div></div>

<p class="bottom">And the url of a single topic (aka thread) is:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">http://groups.google.com/group/[GROUP]/browse_thread/thread/[THEAD_ID]#</pre></div></div>

<p>Where <code>[GROUP]</code> is the name of the Google Group, and <code>[THREAD_ID]</code> is some alphanumeric id.  Most importantly, at the bottom of the main page is an <u>Older &raquo;</u> link that points to the next page of topics.  The <code>GoogleGroupsScraper</code> exploits this to spider the entire group, recording topic title and topic url as it walks each page.</p>
<p>Next, each individual topic page is scraped by the <code>GoogleGroupsTopicScraper</code> class and parsed into a list of posts with author name, date, timestamp, etc.  The topic scraper uses various regular expressions to extract and massage the html to extract the different parts of each post.  In particular, the post body needs a lots of work to strip out any Google Groups specific links and code.</p>
<p>Lastly, the topics and their posts are assembled into an XML document with a nice big CDATA block around the post body to preserve the html content.</p>
<p class="bottom">Here&#8217;s some sample output from the scraper:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;scrape</span> <span style="color: #000066;">group</span>=<span style="color: #ff0000;">&quot;flexmonkey&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;topic<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>FlexMonkey User Group is now located at www.gorillalogic.com/flexmonkey!<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;link<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>http://groups.google.com/group/flexmonkey/browse_thread/thread/fe9ed66bf56db88e#<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/link<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;posts<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;post</span> <span style="color: #000066;">idx</span>=<span style="color: #ff0000;">&quot;0&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;author<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Stu<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/author<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;email<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>stu.st...@gorillalogic.com<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/email<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;date<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>February 10, 2010 21:17:52 UTC<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/date<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;timestamp<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>1265836672<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/timestamp<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #339933;">&lt;![CDATA[</span>
<span style="color: #339933;">&lt;p&gt;People of FlexMonkey, &lt;p&gt;We have migrated the FlexMonkey discussion forum to &lt;a href=&quot;http://www.gorillalogic.com/flexmonkey&quot;&gt;http://www.gorillalogic.com/flexmonkey&lt;/a&gt;. Please note that you will need to re-subscribe to the new forum to continue receiving FlexMonkey discussion messages. &lt;p&gt;-Stu &lt;br&gt;</span>
<span style="color: #339933;">]]&gt;</span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/post<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/posts<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/topic<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;topic<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Record button clicks based on Ids instead of names?<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;link<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>http://groups.google.com/group/flexmonkey/browse_thread/thread/4f079b1959374f53#<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/link<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;posts<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;post</span> <span style="color: #000066;">idx</span>=<span style="color: #ff0000;">&quot;0&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;author<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Shilpa<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/author<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;email<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>shilpa.g...@gmail.com<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/email<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;date<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>February 9, 2010 23:44:44 UTC<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/date<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;timestamp<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>1265759084<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/timestamp<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/post<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;post</span> <span style="color: #000066;">idx</span>=<span style="color: #ff0000;">&quot;1&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;author<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Shilpa<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/author<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;email<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>shilpa.g...@gmail.com<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/email<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;date<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>February 10, 2010 00:05:44 UTC<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/date<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;timestamp<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>1265760344<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/timestamp<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/post<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;post</span> <span style="color: #000066;">idx</span>=<span style="color: #ff0000;">&quot;2&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;author<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Gokuldas K Pillai<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/author<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;email<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>gokul...@gmail.com<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/email<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;date<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>February 10, 2010 00:16:34 UTC<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/date<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;timestamp<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>1265760994<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/timestamp<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/post<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;post</span> <span style="color: #000066;">idx</span>=<span style="color: #ff0000;">&quot;3&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;author<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Shilpa<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/author<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;email<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>shilpa.g...@gmail.com<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/email<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;date<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>February 10, 2010 01:18:42 UTC<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/date<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;timestamp<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>1265764722<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/timestamp<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
      <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/post<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
...</pre></div></div>

<p class="bottom">Finally, there is a very simple PHP driver for the scraper that runs the scraping process:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #b1b100;">require_once</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'GoogleGroupsScraper.class.php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$scraper</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> GoogleGroupsScraper<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'[GROUP]'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$scraper</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">run</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #b1b100;">print</span> <span style="color: #000088;">$scraper</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getXML</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p class="bottom">And you run it as usual:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">php scrape.php &gt; output.xml</pre></div></div>

<p>Just enter the name of the Google Group you wish to scrap, and away you go.  Here are a couple of notes to help you along:</p>
<ol>
<li><code>[GROUP]</code> is the group name as it appears in the url, so no spaces, etc.</li>
<li>It&#8217;s not fast, so be patient, or modify the scraper code to generate some intermediate output.</li>
<li>Via a browser, Google Group displays 30 topics per page, but via PHP &amp; cURL you only get 10.  Probably some Cookie or User Agent magic going on.</li>
<li>Not much error handling.   The error handling that exists isn&#8217;t very good. It will break.</li>
<li>Good luck!</li>
</ol>
<p>Please download the code and use it however you wish.  Hopefully, putting the code online and writing this post will save someone else some time when migrating data off Google Groups.</p>
<h5>Files</h5>
<ul>
<li><a href="http://saturnboy.com/proj/gorilla/scraper/GoogleGroupsScraper.tgz">GoogleGroupsScraper.tgz</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2010/03/scraping-google-groups/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Getting started with LCDS 3 Beta and MySQL, Part 2</title>
		<link>http://saturnboy.com/2009/07/get-started-lcds-mysql-2/</link>
		<comments>http://saturnboy.com/2009/07/get-started-lcds-mysql-2/#comments</comments>
		<pubDate>Wed, 15 Jul 2009 21:40:40 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[flex4]]></category>
		<category><![CDATA[LCDS]]></category>
		<category><![CDATA[mysql]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=645</guid>
		<description><![CDATA[In Part 1, I covered the basic setup of LiveCycle Data Services 3 Beta sitting on a MySQL database. Now, I&#8217;ll get into the Flash Builder side of things, and talk about the Modeler plugin and model driven development. Setup Modeler Plugin Get Flash Builder 4 Beta (download) Get the LCDS Modeler plugin (download) Install [...]]]></description>
			<content:encoded><![CDATA[<p>In <a href="http://saturnboy.com/2009/07/get-started-lcds-mysql-1/">Part 1</a>, I covered the basic setup of <a href="http://labs.adobe.com/technologies/livecycle_dataservices3/">LiveCycle Data Services 3 Beta</a> sitting on a <a href="http://www.mysql.com/">MySQL</a> database.  Now, I&#8217;ll get into the <a href="http://labs.adobe.com/technologies/flashbuilder4/">Flash Builder</a> side of things, and talk about the Modeler plugin and model driven development.</p>
<h5>Setup Modeler Plugin</h5>
<ol>
<li>Get Flash Builder 4 Beta (<a href="http://www.adobe.com/cfusion/entitlement/index.cfm?e=labs_flashbuilder4">download</a>)</li>
<li>Get the LCDS Modeler plugin (<a href="http://www.adobe.com/cfusion/entitlement/index.cfm?e=labs_livecycle_dataservices3">download</a>)</li>
<li>Install the Modeler plugin:
<ul>
<li>Unzip to a temp folder, which will create a <code>plugins</code> folder</li>
<li>Copy the <code>plugins</code> folder&#8217;s contents directly into Flash Builder&#8217;s <code>plugins</code> folder (typically located in <code>/Applications/Adobe Flash Builder Beta/plugins</code> if you are on a Mac)</li>
<li>Restart Flash Builder</li>
</ul>
</li>
</ol>
<h5>Model Driven Development</h5>
<ol>
<li>Create a new Flex project
<ul>
<li>In Flash Builder, right-click and say <i>New &gt; Flex Project</i><br />
<img src="http://saturnboy.com/wp-content/uploads/2009/07/lcds_1_new_project_thumb.png" alt="new flex project" title="new flex project" width="500" height="250" /><br />
<a href="http://saturnboy.com/wp-content/uploads/2009/07/lcds_1_new_project.png">enlarge</a></li>
<li>Choose <i>J2EE</i> for Application Server Type, and select LCDS</li>
<li>Click Next to configure your server<br />
<img src="http://saturnboy.com/wp-content/uploads/2009/07/lcds_2_server_config_thumb.png" alt="j2ee server config" title="j2ee server config" width="500" height="250" /><br />
<a href="http://saturnboy.com/wp-content/uploads/2009/07/lcds_2_server_config.png">enlarge</a></li>
<li>Uncheck <i>Use Default Location</i>, and fill in your root folder, url, and context (see <a href="http://saturnboy.com/wp-content/uploads/2009/07/lcds_2_server_config.png">screenshot</a>)</li>
<li>Click <i>Validate Configuration</i> (this will fail if LCDS is not running), and then Finish</li>
</ul>
</li>
<li>Create a new data model
<ul>
<li>Select the <i>Data/Services</i> tab in the bottom window</li>
<li>Click the <i>Edit Active Data Model</i> icon in the tab&#8217;s menubar (see <a href="http://saturnboy.com/wp-content/uploads/2009/07/lcds_3_new_model.png">screenshot</a>)<br />
<img src="http://saturnboy.com/wp-content/uploads/2009/07/lcds_3_new_model_thumb.png" alt="new model" title="new model" width="500" height="250" /><br />
<a href="http://saturnboy.com/wp-content/uploads/2009/07/lcds_3_new_model.png">enlarge</a></li>
<li>This will create a new data model for your project, and bring up <code>MyApp.fml</code> in the Modeler&#8217;s design view (see <a href="http://saturnboy.com/wp-content/uploads/2009/07/lcds_3_new_model.png">screenshot</a>)</li>
<li>To see the file in the Package Explorer, click the <i>Filters</i> icon (see <a href="http://saturnboy.com/wp-content/uploads/2009/07/lcds_3_new_model.png">screenshot</a>), then uncheck <code>.*</code> and <code>.model</code></li>
</ul>
</li>
<li>Connect to the server
<ul>
<li>Switch to the <i>Adobe Data Model</i> perspective</li>
<li>In the <i>RDS Dataview</i> window, click the <i>RDS Configuration</i> icon<br />
<img src="http://saturnboy.com/wp-content/uploads/2009/07/lcds_4_rds_config_thumb.png" alt="rds config" title="rds config" width="500" height="250" /><br />
<a href="http://saturnboy.com/wp-content/uploads/2009/07/lcds_4_rds_config.png">enlarge</a></li>
<li>Set the <i>Context Root</i> to <code>myapp</code> (because our server is running at <code>http://localhost:8080/myapp/</code>)</li>
<li>Click <i>Test Connection</i>, and then OK</li>
</ul>
</li>
<li>Verify the server&#8217;s connection to MySQL
<ul>
<li>In the <i>RDS Dataview</i> window, expand until we can see our tables<br />
<img src="http://saturnboy.com/wp-content/uploads/2009/07/lcds_5_rds_dataview_thumb.png" alt="rds dataview" title="rds dataview" width="344" height="244" /><br />
<a href="http://saturnboy.com/wp-content/uploads/2009/07/lcds_5_rds_dataview.png">enlarge</a></li>
<li>Right-click on a table, and select <i>Show Table Contents</i><br />
<img src="http://saturnboy.com/wp-content/uploads/2009/07/lcds_6_rds_show_table_thumb.png" alt="rds show table" title="rds show table" width="494" height="156" /><br />
<a href="http://saturnboy.com/wp-content/uploads/2009/07/lcds_6_rds_show_table.png">enlarge</a></li>
</ul>
</li>
<li>Edit the model
<ul>
<li>Just drag tables from the <i>RDS Dataview</i> to add them to the model<br />
<img src="http://saturnboy.com/wp-content/uploads/2009/07/lcds_7_edit_model_thumb.png" alt="edit model" title="edit model" width="364" height="187" /><br />
<a href="http://saturnboy.com/wp-content/uploads/2009/07/lcds_7_edit_model.png">enlarge</a></li>
</ul>
</li>
<li>Browse the generated services and code
<ul>
<li>Once the model is updated, the builder automatically generates standard CRUD services.  Switch back to the <i>Flash Builder</i> perspective, and you can view them in the <i>Data/Services</i> tab<br />
<img src="http://saturnboy.com/wp-content/uploads/2009/07/lcds_8_services_browser_thumb.png" alt="services browser" title="services browser" width="295" height="249" /><br />
<a href="http://saturnboy.com/wp-content/uploads/2009/07/lcds_8_services_browser.png">enlarge</a></li>
<li>The generated code is available in the <i>Package Explorer</i>.  Files you don&#8217;t want to touch are prefixed with an underscore.  The other files, like <code>Player.as</code> and <code>PlayerService.as</code> are available for you to customize.<br />
<img src="http://saturnboy.com/wp-content/uploads/2009/07/lcds_9_generated_code_thumb.png" alt="generated code" title="generated code" width="301" height="292" /><br />
<a href="http://saturnboy.com/wp-content/uploads/2009/07/lcds_9_generated_code.png">enlarge</a></li>
</ul>
</li>
</ol>
<h5>More Docs</h5>
<ol>
<li>LCDS Modeler Guide (<a href="http://download.macromedia.com/pub/labs/livecycle_dataservices3/livecycle_dataservices3_modelerguide_061509.zip">zip</a>)</li>
</ol>
<h5>Conclusion</h5>
<p>Once again, that&#8217;s it.  I&#8217;ll have to learn something new about LCDS before I write more.</p>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2009/07/get-started-lcds-mysql-2/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>Getting started with LCDS 3 Beta and MySQL, Part 1</title>
		<link>http://saturnboy.com/2009/07/get-started-lcds-mysql-1/</link>
		<comments>http://saturnboy.com/2009/07/get-started-lcds-mysql-1/#comments</comments>
		<pubDate>Wed, 01 Jul 2009 20:19:17 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[flex4]]></category>
		<category><![CDATA[LCDS]]></category>
		<category><![CDATA[mysql]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=614</guid>
		<description><![CDATA[With the beta release of LiveCycle Data Services 3, Adobe has changed the game by bringing model driven development to the forefront. The geniuses from the entity formerly known as Macromedia have put together a compelling product if you are in the business of enterprise RIAs like us. Here are a few choice words from [...]]]></description>
			<content:encoded><![CDATA[<p>With the beta release of <a href="http://labs.adobe.com/technologies/livecycle_dataservices3/">LiveCycle Data Services 3</a>, Adobe has changed the game by bringing model driven development to the forefront.  The geniuses from the entity formerly known as Macromedia have put together a compelling product if you are in the business of enterprise RIAs like <a href="http://www.gorillalogic.com/">us</a>.  Here are a <a href="http://www.infoq.com/news/2009/06/model-driven-dev-with-flex">few choice words</a> from Adobe about the beta release.</p>
<p>Now on to the fun part: playing with our new toy.  Vroom, vroom!  In Part 1, I&#8217;ll walk through getting started with LCDS sitting on top of <a href="http://www.mysql.com/">MySQL</a>.  <a href="http://saturnboy.com/2009/07/get-started-lcds-mysql-2/">Part 2</a> covers using the Modeler plugin in Flash Builder 4 to bring the dream of model driven development to reality.</p>
<blockquote><p><b>NOTE:</b> This article was written for LCDS 3 Beta 1, but I assume it&#8217;s mostly relevant for Beta 3 (released at AdobeMAX) and all future versions of LCDS 3.</p></blockquote>
<blockquote><p><b>NOTE 2:</b> The Mac installer for Beta 3 (released at AdobeMAX) does <b>not</b> included the integrated Tomcat which is a huge pain in the ass for all Mac developers.  I recommend you grab the integrated Tomcat out of the Windows installer.</p></blockquote>
<h5>Setup MySQL</h5>
<ol>
<li>Install &amp; start MySQL (this is an exercise for the reader, I remember it being a little painful on my Mac)</li>
<li>Create a new db &amp; user:
<ul>
<li><code>mysql -uroot -p</code>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">DATABASE</span> mydb;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">USER</span> <span style="color: #ff0000;">'myusr'</span>@<span style="color: #ff0000;">'localhost'</span> <span style="color: #993333; font-weight: bold;">IDENTIFIED</span> <span style="color: #993333; font-weight: bold;">BY</span> <span style="color: #ff0000;">'mypassword'</span>;
<span style="color: #993333; font-weight: bold;">GRANT</span> <span style="color: #993333; font-weight: bold;">ALL</span> PRIVILEGES <span style="color: #993333; font-weight: bold;">ON</span> mydb<span style="color: #66cc66;">.*</span> <span style="color: #993333; font-weight: bold;">TO</span> myusr@localhost;</pre></div></div>

<p>NOTE: Don&#8217;t use <code>user</code> in any part of a username (ex: <code>myuser</code> doesn&#8217;t work) because it is a reserved word in MySQL.</li>
</ul>
</li>
<li>Create some sample tables:
<ul>
<li><code>mysql -umyusr -pmypassword mydb</code>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">DROP</span> <span style="color: #993333; font-weight: bold;">TABLE</span> <span style="color: #993333; font-weight: bold;">IF</span> <span style="color: #993333; font-weight: bold;">EXISTS</span> team;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> team <span style="color: #66cc66;">&#40;</span>
  id <span style="color: #993333; font-weight: bold;">INT</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">AUTO_INCREMENT</span><span style="color: #66cc66;">,</span>
  name <span style="color: #993333; font-weight: bold;">VARCHAR</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">150</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>
  <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #66cc66;">&#40;</span>id<span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #993333; font-weight: bold;">DROP</span> <span style="color: #993333; font-weight: bold;">TABLE</span> <span style="color: #993333; font-weight: bold;">IF</span> <span style="color: #993333; font-weight: bold;">EXISTS</span> player;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> player <span style="color: #66cc66;">&#40;</span>
  id <span style="color: #993333; font-weight: bold;">INT</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">AUTO_INCREMENT</span><span style="color: #66cc66;">,</span>
  name <span style="color: #993333; font-weight: bold;">VARCHAR</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">150</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>
  <span style="color: #993333; font-weight: bold;">NUMBER</span> <span style="color: #993333; font-weight: bold;">INT</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
  salary <span style="color: #993333; font-weight: bold;">INT</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
  team_id <span style="color: #993333; font-weight: bold;">INT</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
  <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #66cc66;">&#40;</span>id<span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span>;</pre></div></div>

</li>
</ul>
</li>
<li>Insert data:
<ul>
<li>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> team <span style="color: #66cc66;">&#40;</span>name<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;Denver Broncos&quot;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> team <span style="color: #66cc66;">&#40;</span>name<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;Oakland Raiders&quot;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> player <span style="color: #66cc66;">&#40;</span>name<span style="color: #66cc66;">,</span><span style="color: #993333; font-weight: bold;">NUMBER</span><span style="color: #66cc66;">,</span>salary<span style="color: #66cc66;">,</span>team_id<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;Jay Cutler&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">6</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">6497500</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> player <span style="color: #66cc66;">&#40;</span>name<span style="color: #66cc66;">,</span><span style="color: #993333; font-weight: bold;">NUMBER</span><span style="color: #66cc66;">,</span>salary<span style="color: #66cc66;">,</span>team_id<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;Champ Bailey&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">24</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">8003050</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> player <span style="color: #66cc66;">&#40;</span>name<span style="color: #66cc66;">,</span><span style="color: #993333; font-weight: bold;">NUMBER</span><span style="color: #66cc66;">,</span>salary<span style="color: #66cc66;">,</span>team_id<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;Eddie Royal&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">19</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">2539830</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> player <span style="color: #66cc66;">&#40;</span>name<span style="color: #66cc66;">,</span><span style="color: #993333; font-weight: bold;">NUMBER</span><span style="color: #66cc66;">,</span>salary<span style="color: #66cc66;">,</span>team_id<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;Tony Scheffler&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">88</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">612480</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> player <span style="color: #66cc66;">&#40;</span>name<span style="color: #66cc66;">,</span><span style="color: #993333; font-weight: bold;">NUMBER</span><span style="color: #66cc66;">,</span>salary<span style="color: #66cc66;">,</span>team_id<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;JaMarcus Russell&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">2</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">16872400</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">2</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> player <span style="color: #66cc66;">&#40;</span>name<span style="color: #66cc66;">,</span><span style="color: #993333; font-weight: bold;">NUMBER</span><span style="color: #66cc66;">,</span>salary<span style="color: #66cc66;">,</span>team_id<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;Darren McFadden&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">20</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">4375000</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">2</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> player <span style="color: #66cc66;">&#40;</span>name<span style="color: #66cc66;">,</span><span style="color: #993333; font-weight: bold;">NUMBER</span><span style="color: #66cc66;">,</span>salary<span style="color: #66cc66;">,</span>team_id<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;Sebastian Janikowski&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">11</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">2625000</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">2</span><span style="color: #66cc66;">&#41;</span>;</pre></div></div>

<p>NOTE: Ignore the fact that Jay Cutler now plays for Da Bears.</li>
</ul>
</li>
</ol>
<blockquote class="deeper"><p><b>Digging Deeper:</b> Setting up a database is required, but setting up tables or inserting data is not.  You can use the model driven development features of LCDS (and the Modeler plugin) to create <b>all</b> of your tables and data.</p></blockquote>
<h5>Setup LCDS</h5>
<ol>
<li>Grab LCDS 3 Beta from Adobe Labs (<a href="http://labs.adobe.com/technologies/livecycle_dataservices3/">download</a>)</li>
<li>Run installer &amp; choose to install with bundled Tomcat (on Mac this installs to <code>/Applications/lcds</code> and the bundled Tomcat to <code>/Applications/lcds/tomcat</code>)</li>
<li>Create a new LCDS app, by copying the template app (in <code>lcds/tomcat/webapps/lcds</code>) to a new folder:
<ul>
<li><code>cd /Applications/lcds/tomcat/webapps</code></li>
<li><code>cp -R lcds myapp</code></li>
</ul>
</li>
<li>Enable RDS (Remove Dev Services) &#8211; This enables some dev only stuff like updating the database tables on the server directly from Flash Builder.  For obvious security reasons, RDS would never be running in a production environment.
<ul>
<li>Edit <code>/Applications/lcds/tomcat/webapps/myapp/WEB-INF/web.xml</code></li>
<li>Uncomment the entire RDS section</li>
<li>Set <code>userAppserverSecurity = false</code> (in the newly uncommented RDS section)</li>
</ul>
</li>
<li>Update <code>services-config.xml</code> to avoid collisions with template <code>lcds</code> app:
<ul>
<li><code>cd /Applications/lcds/tomcat/webapps/myapp/WEB-INF/flex</code></li>
<li>Edit <code>services-config.xml</code>:
<ul>
<li>In the <code>&lt;channel-definition id="my-rtmp"&gt;</code> section, change port 2038 to port 2039</li>
<li>In the <code>&lt;channel-definition id="my-nio-amf"&gt;</code> section, change port 2880 to port 2881</li>
<li>In the <code>&lt;channel-definition id="my-nio-amf-poll"&gt;</code> section, change port 2880 to port 2881</li>
<li>In the <code>&lt;channel-definition id="my-nio-http"&gt;</code> section, change port 2880 to port 2881</li>
</ul>
</li>
</ul>
<p>NOTE: As an alternative, you can just remove the template <code>lcds</code> app and skip the collision avoidance stuff above.</li>
</ol>
<h5>Setup LCDS to talk to MySQL</h5>
<ol>
<li>Get MySQL Connector/J, and be sure to match the version to your MySQL version (<a href="http://dev.mysql.com/downloads/connector/j/5.1.html">download</a>)</li>
<li>Put <code>mysql-connector-java-5.1.7-bin.jar</code> into Tomcat&#8217;s <code>lib</code> folder:
<ul>
<li><code>cp mysql-connector-java-5.1.7-bin.jar /Applications/lcds/tomcat/lib/</code></li>
</ul>
</li>
<li>Config Tomcat to recognize your MySQL db by creating a new Context for your app:
<ul>
<li><code>cd /Applications/lcds/tomcat/conf/Catalina/localhost</code></li>
<li><code>cp lcds.xml myapp.xml</code></li>
<li>Add a JDBC Resource block to <code>myapp.xml</code>, so it looks like this:

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Context</span> <span style="color: #000066;">privileged</span>=<span style="color: #ff0000;">&quot;true&quot;</span> <span style="color: #000066;">antiResourceLocking</span>=<span style="color: #ff0000;">&quot;false&quot;</span> <span style="color: #000066;">antiJARLocking</span>=<span style="color: #ff0000;">&quot;false&quot;</span> <span style="color: #000066;">reloadable</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #808080; font-style: italic;">&lt;!-- JOTM --&gt;</span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Transaction</span> <span style="color: #000066;">factory</span>=<span style="color: #ff0000;">&quot;org.objectweb.jotm.UserTransactionFactory&quot;</span> <span style="color: #000066;">jotm.timeout</span>=<span style="color: #ff0000;">&quot;60&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
&nbsp;
    <span style="color: #808080; font-style: italic;">&lt;!-- MySQL --&gt;</span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Resource</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;jdbc/MyDB&quot;</span> <span style="color: #000066;">auth</span>=<span style="color: #ff0000;">&quot;Container&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;javax.sql.DataSource&quot;</span></span>
<span style="color: #009900;">        <span style="color: #000066;">maxActive</span>=<span style="color: #ff0000;">&quot;100&quot;</span> <span style="color: #000066;">maxIdle</span>=<span style="color: #ff0000;">&quot;30&quot;</span> <span style="color: #000066;">maxWait</span>=<span style="color: #ff0000;">&quot;10000&quot;</span></span>
<span style="color: #009900;">        <span style="color: #000066;">username</span>=<span style="color: #ff0000;">&quot;myusr&quot;</span> <span style="color: #000066;">password</span>=<span style="color: #ff0000;">&quot;mypassword&quot;</span></span>
<span style="color: #009900;">        <span style="color: #000066;">driverClassName</span>=<span style="color: #ff0000;">&quot;com.mysql.jdbc.Driver&quot;</span></span>
<span style="color: #009900;">        <span style="color: #000066;">url</span>=<span style="color: #ff0000;">&quot;jdbc:mysql://localhost:3306/mydb?autoReconnect=true&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
&nbsp;
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Context<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

</li>
</ul>
</li>
</ol>
<h5>Start LCDS</h5>
<ol>
<li>Point Tomcat to the bundled Tomcat installed with LCDS:
<ul>
<li><code>export CATALINA_HOME=/Applications/lcds/tomcat</code></li>
<li>Windows: <code>set CATALINA_HOME=C:\lcds\tomcat</code></li>
</ul>
</li>
<li>Set Java to Java 6:
<ul>
<li><code>export JRE_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home</code></li>
<li>Windows: <code>set JRE_HOME=C:\Program Files\Java\jdk1.6.0_14\jre</code></li>
</ul>
</li>
<li>Run it:
<ul>
<li><code>/Applications/lcds/tomcat/bin/catalina.sh run</code></li>
<li>Windows: <code>C:\lcds\tomcat\bin\catalina.bat run</code></li>
</ul>
</li>
<li>Sometimes Tomcat does not get the value of <code>JRE_HOME</code> (usually on Windows).  The caused by a hard-coded value inside <code>catalina.sh</code>, you&#8217;ll need to edit this file and comment out that line.</li>
<li>Verify it all worked by browsing to:
<ul>
<li><code>http://localhost:8400/myapp/</code></li>
</ul>
</li>
<li>A helpful bash script that does #1 &#8211; #3 all in one shot:
<ul>
<li>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/bash</span>
<span style="color: #7a0874; font-weight: bold;">export</span> <span style="color: #007800;">CATALINA_HOME</span>=<span style="color: #000000; font-weight: bold;">/</span>Applications<span style="color: #000000; font-weight: bold;">/</span>lcds<span style="color: #000000; font-weight: bold;">/</span>tomcat
<span style="color: #7a0874; font-weight: bold;">export</span> <span style="color: #007800;">JRE_HOME</span>=<span style="color: #000000; font-weight: bold;">/</span>System<span style="color: #000000; font-weight: bold;">/</span>Library<span style="color: #000000; font-weight: bold;">/</span>Frameworks<span style="color: #000000; font-weight: bold;">/</span>JavaVM.framework<span style="color: #000000; font-weight: bold;">/</span>Versions<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">1.6</span><span style="color: #000000; font-weight: bold;">/</span>Home
<span style="color: #000000; font-weight: bold;">/</span>Applications<span style="color: #000000; font-weight: bold;">/</span>lcds<span style="color: #000000; font-weight: bold;">/</span>tomcat<span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span>catalina.sh run</pre></div></div>

</li>
<li>Windows:

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">set</span> <span style="color: #007800;">CATALINA_HOME</span>=C:\lcds\tomcat
<span style="color: #000000; font-weight: bold;">set</span> <span style="color: #007800;">JRE_HOME</span>=C:\Program Files\Java\jdk1.6.0_14\jre
C:\lcds\tomcat\bin\catalina.bat run</pre></div></div>

</li>
</ul>
</li>
</ol>
<h5>More Docs</h5>
<ol>
<li><a href="http://www.adobe.com/devnet/livecycle/articles/lcdses3_whatsnew.html">What&#8217;s new in LCDS 3</a></li>
<li>LCDS Dev Guide (<a href="http://download.macromedia.com/pub/labs/livecycle_dataservices3/livecycle_dataservices3_devguide_061509.zip">zip</a>)</li>
<li><a href="http://labs.adobe.com/technologies/livecycle_dataservices3/videos/lcds3_demo/">Tutorial Video</a> &#8211; awesome, 20 min long, and <b>very</b> worthwhile</li>
</ol>
<h5>To Be Continued&#8230;</h5>
<p>That&#8217;s it for Part 1.  LCDS should be up and running on top of MySQL.  Next up, <a href="http://saturnboy.com/2009/07/get-started-lcds-mysql-2/">Part 2</a> covers the Modeler plugin and model driven development.</p>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2009/07/get-started-lcds-mysql-1/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Degrafa Button Explorer</title>
		<link>http://saturnboy.com/2009/03/degrafa-button-explorer/</link>
		<comments>http://saturnboy.com/2009/03/degrafa-button-explorer/#comments</comments>
		<pubDate>Fri, 27 Mar 2009 22:50:58 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[degrafa]]></category>
		<category><![CDATA[flex]]></category>
		<category><![CDATA[skinning]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=332</guid>
		<description><![CDATA[Recently, I&#8217;ve been playing around with Degrafa in preparation for actually using it on an upcoming project at work. For those that aren&#8217;t in the know, Degrafa is a badass graphics framework for Flex. One of my favorite parts so far is the amazing leverage it brings to building custom-styled components. It&#8217;s terse and powerful, [...]]]></description>
			<content:encoded><![CDATA[<p>Recently, I&#8217;ve been playing around with <a href="http://www.degrafa.org/">Degrafa</a> in preparation for actually using it on an upcoming project at <a href="http://www.gorillalogic.com/">work</a>.  For those that aren&#8217;t in the know, Degrafa is a badass graphics framework for Flex.  One of my favorite parts so far is the amazing leverage it brings to building custom-styled components.  It&#8217;s terse and powerful, just the way I like it.</p>
<h5>Building Buttons</h5>
<p class="bottom">With a very minimal amount of effort, I was able to create a few &#8220;web 2.0&#8243; button skins.  I just followed one of the millions of glass button photoshop tutorials, but did the work in mxml code using Degrafa&#8217;s declarative syntax.  Here are my results (view source enabled):</p>
<div class="span-14 top bottom" style="text-align:center;">
<div id="flashcontent-degrafa-buttons">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
</div>
<h5>Button Explorer</h5>
<p>But then I decided to take it a step further and build out a Degrafa Button Explorer (with a small tip of the hat to the original <a href="http://examples.adobe.com/flex3/consulting/styleexplorer/Flex3StyleExplorer.html">Flex Style Explorer</a>).  The Degrafa Button Explorer allows you to adjust a bunch of properties and colors for all three buttons styles.  It goes a step further than the original and provides not only the CSS, but also the full code of the stateful Degrafa-powered button components.</p>
<p class="large">&nbsp;&raquo;&nbsp;&nbsp;<a href="http://saturnboy.com/proj/degrafa_button_explorer/" target="_blank">Degrafa Button Explorer</a></p>
<blockquote class="deeper"><p><b>Digging Deeper:</b> I&#8217;ve been following the skinning performance issues discovered by the <a href="http://behindtheui.blogspot.com/2009/03/flex-component-kit-cpu-black-hole.html">guys</a> at <a href="http://www.effectiveui.com/">EffectiveUI</a>.  <a href="http://patrickhansen.com/blog/index.php/2009/03/25/stateful-vs-stateless-now-vs-degrafa/">The most recent benchmarks</a> appear to show that stateful Degrafa skins (like those produced by the Degrafa Button Explorer) are safe to use.</p>
</blockquote>
<div>
<script type="text/javascript">
swfobject.embedSWF('http://saturnboy.com/proj/degrafa_skins/degrafa_buttons/degrafa_buttons.swf', 'flashcontent-degrafa-buttons', '300', '90', '9.0.28', 'expressInstall.swf', false, { 'bgColor':'#ffffff', 'base':'.' });
</script>
</div>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2009/03/degrafa-button-explorer/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Testing async services with Fluint</title>
		<link>http://saturnboy.com/2009/03/fluint-async-testing/</link>
		<comments>http://saturnboy.com/2009/03/fluint-async-testing/#comments</comments>
		<pubDate>Mon, 23 Mar 2009 04:58:45 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[async]]></category>
		<category><![CDATA[flex]]></category>
		<category><![CDATA[flexmonkey]]></category>
		<category><![CDATA[fluint]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=307</guid>
		<description><![CDATA[We&#8217;re pretty big on testing at Gorilla Logic, and in the world of Flex that usually means using FlexMonkey to test the UI and using FlexUnit to test the code. Alas, it is a huge pain in the ass to correctly test the many async objects and services inherent in any Flex app with FlexUnit. [...]]]></description>
			<content:encoded><![CDATA[<p>We&#8217;re pretty big on testing at <a href="http://www.gorillalogic.com/">Gorilla Logic</a>, and in the world of Flex that usually means using <a href="http://code.google.com/p/flexmonkey/">FlexMonkey</a> to test the UI and using <a href="http://opensource.adobe.com/wiki/display/flexunit/Flexunit">FlexUnit</a> to test the code.  Alas, it is a huge pain in the ass to correctly test the many async objects and services inherent in any Flex app with FlexUnit.  Enter <a href="http://code.google.com/p/fluint/">Fluint</a>, an superior Flex unit tesing framework by the cool guys at <a href="http://www.digitalprimates.net/">digital primates</a> (no relation).  Fluint is the heir apparent to take over the unit testing crown from the venerable FlexUnit.  So let&#8217;s take Fluint and its enhanced async testing support for a spin.</p>
<h5>Service Layer</h5>
<p class="bottom">First, assume we have a nice service layer in Flex that talks asynchronously to our backend.  Just something simple to start:</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript3" style="font-family:monospace;"><span style="color: #0033ff; font-weight: bold;">public</span> <span style="color: #9900cc; font-weight: bold;">class</span> MyService <span style="color: #000000;">&#123;</span>
    <span style="color: #0033ff; font-weight: bold;">public</span> <span style="color: #339966; font-weight: bold;">function</span> getSomething<span style="color: #000000;">&#40;</span>result<span style="color: #000066; font-weight: bold;">:</span><span style="color: #004993;">Function</span><span style="color: #000066; font-weight: bold;">,</span> fault<span style="color: #000066; font-weight: bold;">:</span><span style="color: #004993;">Function</span><span style="color: #000000;">&#41;</span><span style="color: #000066; font-weight: bold;">:</span>AsyncToken <span style="color: #000000;">&#123;</span>
        <span style="color: #009900; font-style: italic;">//call the backend</span>
        <span style="color: #6699cc; font-weight: bold;">var</span> token<span style="color: #000066; font-weight: bold;">:</span>AsyncToken = backend<span style="color: #000066; font-weight: bold;">.</span>getSomething<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000066; font-weight: bold;">;</span>
&nbsp;
        <span style="color: #009900; font-style: italic;">//wire the callbacks to the result</span>
        token<span style="color: #000066; font-weight: bold;">.</span>addResponder<span style="color: #000000;">&#40;</span><span style="color: #0033ff; font-weight: bold;">new</span> AsyncResponder<span style="color: #000000;">&#40;</span>result<span style="color: #000066; font-weight: bold;">,</span> fault<span style="color: #000066; font-weight: bold;">,</span> token<span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><span style="color: #000066; font-weight: bold;">;</span>
&nbsp;
        <span style="color: #0033ff; font-weight: bold;">return</span> token<span style="color: #000066; font-weight: bold;">;</span>
    <span style="color: #000000;">&#125;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>

<p>In this example, our service only has one method, <code>getSomething()</code> that takes two callback functions.  It simply calls the backend method, wires up the callbacks (which get called when the backend method returns a result), and returns the token.  It is <b>absolutely critical</b> that our callback-powered service method return the <code>AsyncToken</code>.  The reason for this will become apparent.</p>
<p class="bottom">We might use our service like this:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Application</span></span>
<span style="color: #000000;">        xmlns:mx=<span style="color: #ff0000;">&quot;http://www.adobe.com/2006/mxml&quot;</span></span>
<span style="color: #000000;">        creationComplete=<span style="color: #ff0000;">&quot;complete()&quot;</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #339933;">&lt;mx:Script&gt;</span>
<span style="color: #339933;">    &lt;![CDATA[</span>
<span style="color: #339933;">        import com.saturnboy.services.MyService;</span>
<span style="color: #339933;">        private var service:MyService;</span>
&nbsp;
<span style="color: #339933;">        private function complete():void {</span>
<span style="color: #339933;">            service = new MyService();</span>
<span style="color: #339933;">            service.getSomething(resultHandler, faultHandler);</span>
<span style="color: #339933;">        }</span>
&nbsp;
<span style="color: #339933;">        private function resultHandler(result:Object, token:Object=null):void {</span>
<span style="color: #339933;">            lbl.text = result.result.name;</span>
<span style="color: #339933;">        }</span>
&nbsp;
<span style="color: #339933;">        public function faultHandler(error:Object, token:Object=null):void {</span>
<span style="color: #339933;">            lbl.text = 'fault';</span>
<span style="color: #339933;">        }</span>
<span style="color: #339933;">    ]]&gt;</span>
<span style="color: #339933;">    &lt;/mx:Script&gt;</span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Label</span> id=<span style="color: #ff0000;">&quot;lbl&quot;</span> text=<span style="color: #ff0000;">&quot;initial&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:Application</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>We make a call our service, and then use the callbacks to alter the UI however we want depending on the result.  In common usage, the fact that our service returns an <code>AsyncToken</code> is worthless, it might as well return <code>void</code>.  So, why did I say this is critical?  Throw Fluint testing into the mix and it&#8217;s &#8220;Show em what&#8217;s behind door number 2, Johnny!&#8221;</p>
<h5>Fluint Testing</h5>
<p class="bottom">Fluint provides two different async wrapper methods: <code>asyncHandler</code> and <code>asyncResponder</code>.  The first allows a test to be wired to an async method by events, the second allows a test to be wired to an async method by a responder.  Since the service method we&#8217;re trying to test doesn&#8217;t throw any events, we&#8217;ll need to use the latter.  So inside a Fluint test case, we have our test method:</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript3" style="font-family:monospace;"><span style="color: #0033ff; font-weight: bold;">public</span> <span style="color: #339966; font-weight: bold;">function</span> testGetSomething<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000066; font-weight: bold;">:</span><span style="color: #0033ff; font-weight: bold;">void</span> <span style="color: #000000;">&#123;</span>
    <span style="color: #009900; font-style: italic;">//call service with dummy callback</span>
    <span style="color: #6699cc; font-weight: bold;">var</span> token<span style="color: #000066; font-weight: bold;">:</span>AsyncToken = service<span style="color: #000066; font-weight: bold;">.</span>getSomething<span style="color: #000000;">&#40;</span>dummyResult<span style="color: #000066; font-weight: bold;">,</span> dummyFault<span style="color: #000000;">&#41;</span><span style="color: #000066; font-weight: bold;">;</span>
&nbsp;
    <span style="color: #009900; font-style: italic;">//create async test responder</span>
    <span style="color: #6699cc; font-weight: bold;">var</span> responder<span style="color: #000066; font-weight: bold;">:</span>IResponder = asyncResponder<span style="color: #000000;">&#40;</span>
            <span style="color: #0033ff; font-weight: bold;">new</span> TestResponder<span style="color: #000000;">&#40;</span>testHandler<span style="color: #000066; font-weight: bold;">,</span> faultHandler<span style="color: #000000;">&#41;</span><span style="color: #000066; font-weight: bold;">,</span> <span style="color: #000000; font-weight:bold;">1000</span><span style="color: #000066; font-weight: bold;">,</span> token<span style="color: #000000;">&#41;</span><span style="color: #000066; font-weight: bold;">;</span>
&nbsp;
    <span style="color: #009900; font-style: italic;">//wire test responder as 2nd callback</span>
    token<span style="color: #000066; font-weight: bold;">.</span>addResponder<span style="color: #000000;">&#40;</span>responder<span style="color: #000000;">&#41;</span><span style="color: #000066; font-weight: bold;">;</span>
<span style="color: #000000;">&#125;</span>
<span style="color: #0033ff; font-weight: bold;">private</span> <span style="color: #339966; font-weight: bold;">function</span> testHandler<span style="color: #000000;">&#40;</span>result<span style="color: #000066; font-weight: bold;">:</span><span style="color: #004993;">Object</span><span style="color: #000066; font-weight: bold;">,</span> passThroughData<span style="color: #000066; font-weight: bold;">:</span><span style="color: #004993;">Object</span><span style="color: #000000;">&#41;</span><span style="color: #000066; font-weight: bold;">:</span><span style="color: #0033ff; font-weight: bold;">void</span> <span style="color: #000000;">&#123;</span>
    assertEquals<span style="color: #000000;">&#40;</span><span style="color: #990000;">'something'</span><span style="color: #000066; font-weight: bold;">,</span> result<span style="color: #000066; font-weight: bold;">.</span>result<span style="color: #000066; font-weight: bold;">.</span><span style="color: #004993;">name</span><span style="color: #000000;">&#41;</span><span style="color: #000066; font-weight: bold;">;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>

<p>The trick is to wire a second callback via Fluint&#8217;s <code>asyncResponder</code> helper that actually does the testing, and just give the original service call some dummy callbacks.  Note that if the service method didn&#8217;t return its <code>AsyncToken</code> there would be no way to wire a second callback.  The Fluint async helper do two import operations: they handle the event or call the callback AND they mark the test method as an async method so the result is correctly reported by the test harness.  You can read more about <a href="http://code.google.com/p/fluint/wiki/AsyncTest">Async Testing</a> in Fluint&#8217;s wiki.  The rest of Fluint is your standard chain of crap borrowed from JUnit: test runner, test suites, and test cases.</p>
<blockquote class="deeper"><p><b>Digging Deeper:</b> It is equally critical to use dummy callbacks in the original service method call because in a failure situation they will cause Flash Player to error out instead of being caught by Fluint and reported as a test failure.</p></blockquote>
<h5>Files</h5>
<p>The complete code is up on <a href="http://www.github.com/">GitHub</a> here: <a href="http://github.com/saturnboy/test_fluint_async/tree/master">test_fluint_async</a>.  The code is MIT licensed and includes a working fluint.swc (see below) plus a mock async backend (so timeouts and faults are easily testable).</p>
<p>Alas, Fluint v1.1.0 was built incorrectly and is missing the <code>TestResponder</code> class (see <a href="http://code.google.com/p/fluint/issues/detail?id=35&#038;can=1">issue 35</a>).  So if you want to try out Fluint in your project, I recommend you grab it from svn and build the swc yourself.  Hopefully, this will all be fixed in the next release.</p>
<p><strong>UPDATE:</strong> Fluint v1.1.1 was release on May 1, 2009 and fixes this issues and a few others.  Download it <a href="http://code.google.com/p/fluint/downloads/list">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2009/03/fluint-async-testing/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

