<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns: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/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Eric Wendelin's Blog</title>
	
	<link>http://eriwen.com</link>
	<description>Programming productively with open-source tools</description>
	<lastBuildDate>Thu, 26 Apr 2012 18:48:47 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/EricWendelin" /><feedburner:info uri="ericwendelin" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><geo:lat>39.929566</geo:lat><geo:long>-104.949317</geo:long><creativeCommons:license>http://creativecommons.org/licenses/by/2.0/</creativeCommons:license><feedburner:emailServiceId>EricWendelin</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item>
		<title>Notes from my pursuit of the perfect front-end build</title>
		<link>http://feedproxy.google.com/~r/EricWendelin/~3/jls9CbRHLcM/</link>
		<comments>http://eriwen.com/tools/perfect-front-end-build/#comments</comments>
		<pubDate>Thu, 01 Dec 2011 11:00:49 +0000</pubDate>
		<dc:creator>Eric Wendelin</dc:creator>
				<category><![CDATA[Tools]]></category>
		<category><![CDATA[CI]]></category>
		<category><![CDATA[Javascript]]></category>

		<guid isPermaLink="false">http://eriwen.com/tools/notes-from-my-pursuit-of-the-perfect-front-end-build/</guid>
		<description><![CDATA[I wrote previously about <a href="http://eriwen.com/tools/continuous-integration-for-javascript/">Continuous Integration for JavaScript</a> where I explained a build with <a href="http://jenkins-ci.org">Jenkins</a> and <a href="http://gradle.org">Gradle</a>. I've learned a lot since that article and thought it's now significant enough to write more on the topic.

<h2>Documentation</h2>
When you're writing code that other developers have to use or maintain, you ought to provide some amount of documentation. <strong>Your code is simply not self-documenting enough.</strong>

My favorite doc tool right now is <a href="https://github.com/senchalabs/jsduck">jsduck</a> developed by Sencha Labs for their Ext JS 4 docs. It basically consumes JSDoc-style comments (with some extras for namespaces, etc.) and generates beautiful documentation. Super easy to install and use:
 <a href="http://eriwen.com/tools/perfect-front-end-build/">Continue reading <span class="meta-nav">&#8594;</span></a>


Related posts:<ol><li><a href='http://eriwen.com/tools/wikify-yourself/' rel='bookmark' title='Why every programmer should have a Tiddlywiki'>Why every programmer should have a Tiddlywiki</a></li>
<li><a href='http://eriwen.com/tools/continuous-integration-for-javascript/' rel='bookmark' title='Continuous Integration for Javascript'>Continuous Integration for Javascript</a></li>
<li><a href='http://eriwen.com/javascript/text-size-prefs/' rel='bookmark' title='Guest Post: Save Text Size Preference Using MooTools and PHP'>Guest Post: Save Text Size Preference Using MooTools and PHP</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>I wrote previously about <a href="http://eriwen.com/tools/continuous-integration-for-javascript/">Continuous Integration for JavaScript</a> where I explained a build with <a href="http://jenkins-ci.org">Jenkins</a> and <a href="http://gradle.org">Gradle</a>. I&#8217;ve learned a lot since that article and thought it&#8217;s now significant enough to write more on the topic.</p>
<h2>Documentation</h2>
<p>When you&#8217;re writing code that other developers have to use or maintain, you ought to provide some amount of documentation. <strong>Your code is simply not self-documenting enough.</strong></p>
<p>My favorite doc tool right now is <a href="https://github.com/senchalabs/jsduck">jsduck</a> developed by Sencha Labs for their Ext JS 4 docs. It basically consumes JSDoc-style comments (with some extras for namespaces, etc.) and generates beautiful documentation. Super easy to install and use:</p>
<pre class="brush: bash; title: ; notranslate">
gem install jsduck
jsduck src/js --output target/docs
</pre>
<h2>Use the Gradle wrapper</h2>
<p>Using the <a href="http://gradle.org/current/docs/userguide/gradle_wrapper.html">Gradle wrapper</a> allows users to build your project <strong>without installing Gradle</strong>, which is beautiful because it removes a very significant dependency for building and running your project.</p>
<p>Here&#8217;s how to use it. Add this to your <code>build.gradle</code> file:</p>
<pre class="brush: groovy; title: ; notranslate">
task wrapper(type: Wrapper) {
    // version of Gradle you want
    gradleVersion = '1.0-milestone-6'
}
</pre>
<p>Then you just have to run in your shell:</p>
<pre class="brush: bash; light: true; title: ; notranslate">
gradle wrapper
</pre>
<p>and Gradle will add a few files to the project, most importantly <code>gradlew</code> and <code>gradlew.bat</code> (for Windows). These are binaries that your can run in lieu of <code>gradle</code>, and it wraps (obviously) the execution of Gradle such that it will download the correct version of Gradle and execute it locally. </p>
<p>I recommend that you switch to the Gradle wrapper when you have consumers of your project that may not have Gradle. I&#8217;m going to be doing this for all of my OSS projects from now on.</p>
<h2>Introducing the Gradle Web Suite</h2>
<p>Gradle really has building JVM-centric source down (for most languages), but I felt like it was cumbersome to operate on my web files with it. So I&#8217;ve written a collection of plugins that focus on making tasks with JavaScript, CSS, and other client-side tech dead simple.</p>
<pre class="brush: groovy; title: ; notranslate">
buildscript {
	repositories {
		mavenCentral()
	}
	dependencies {
		classpath 'com.eriwen:gradle-css-plugin:0.2'
		classpath 'com.eriwen:gradle-js-plugin:0.2'
	}
}

apply plugin: 'css'
apply plugin: 'js'
</pre>
<p>And now we can use the tasks provided by these plugins:</p>
<pre class="brush: groovy; title: ; notranslate">
// Combine, minify and GZip CSS to teenytiny.css
css {
    input = fileTree(dir: &quot;${projectDir}/css&quot;, include: [&quot;file1.css&quot;, &quot;file2.css&quot;])
    output = file(&quot;${buildDir}/teenytiny.css&quot;)
}

// Same thing here, and look, file-globs :)
js {
    input = fileTree(dir: &quot;${projectDir}/js&quot;, include: &quot;**/*.js&quot;)
    output = file(&quot;${buildDir}/combinedMinifiedAndGzipped.js&quot;)
}

// ... and there's support for other tools like CSS Lint!
csslint {
	inputs.files fileTree(dir: &quot;${projectDir}/css&quot;, include: &quot;**/*.css&quot;)
	outputs.file file(&quot;${buildDir}/csslint.xml&quot;)
	options = [&quot;--rules=adjoining-classes,box-model&quot;, '--format=lint-xml']
}
</pre>
<p><a href="http://git.io/gradlecss">Gradle CSS Plugin</a> <iframe src="http://markdotto.github.com/github-buttons/github-btn.html?user=eriwen&#038;repo=gradle-css-plugin&#038;type=watch&#038;count=true" allowtransparency="true" frameborder="0" scrolling="0" width="62px" height="20px"></iframe> | <a href="http://git.io/gradlejs">Gradle JS Plugin</a> <iframe src="http://markdotto.github.com/github-buttons/github-btn.html?user=eriwen&#038;repo=gradle-js-plugin&#038;type=watch&#038;count=true" allowtransparency="true" frameborder="0" scrolling="0" width="62px" height="20px"></iframe></p>
<h2>JsTestDriver</h2>
<p>One tool I hadn&#8217;t paid enough attention to until recently was <a href="http://code.google.com/p/js-test-driver/" title="js-test-driver">JsTestDriver</a>. The awesome thing about it is that <strong>it has adapters for other JS testing frameworks like Jasmine</strong>. This is great because I don&#8217;t have to convert my tests (mostly) to JsTestDriver&#8217;s test API and I get crazy speed and reporting I wouldn&#8217;t otherwise get. </p>
<p>In a nutshell, JSTD is a testing tool developed by Google whereby you start as server and then &#8220;capture&#8221; browsers so that JSTD uploads tests to them, the browser runs tests and then sends back test results. This is awesome because it&#8217;s super fast and you can have it run every major browser simultaneously!</p>
<p>Here&#8217;s how you can use it. First, we need to <a href="http://code.google.com/p/js-test-driver/downloads/list">download JsTestDriver and the coverage plugin JARs</a>. Then we need a configuration file for JsTestDriver:</p>
<pre class="brush: plain; title: jsTestDriver.conf; notranslate">
server: http://localhost:4224

load:
  - lib/jasmine.js
  - lib/sinon-1.2.0.js
  - lib/jasmine-sinon.js
  - lib/JasmineAdapter.js
  - ../js/main.js

test:
  - spec/*.js

plugin:
  - name: &quot;coverage&quot;
    jar: &quot;lib/plugins/coverage.jar&quot;
    module: &quot;com.google.jstestdriver.coverage.CoverageModule&quot;
    args: useCoberturaFormat

timeout: 30
</pre>
<p>then we need to start the JSTD server:</p>
<pre class="brush: bash; title: ; notranslate">
java -jar path/to/JsTestDriver.jar --port 4224
</pre>
<p>Now we want to capture a browser by navigating it to <code>http://localhost:4224/capture</code>. Finally, run our tests with all captured browsers:</p>
<pre class="brush: bash; title: ; notranslate">
java -jar path/to/JsTestDriver.jar --tests all
</pre>
<p>and you should see something like this:</p>
<pre class="brush: plain; title: ; notranslate">
Chrome: Reset
.................
Total 17 tests (Passed: 17; Fails: 0; Errors: 0) (13.00 ms)
  Chrome 17.0.942.0 Mac OS: Run 17 tests (Passed: 17; Fails: 0; Errors 0) (13.00 ms)
/Users/eric/src/eriwen.com/test/spec/PageSpec.js: 95.789474% covered
/Users/eric/src/eriwen.com/test/lib/jasmine.js: 51.640926% covered
/Users/eric/src/eriwen.com/test/lib/sinon-1.2.0.js: 22.916668% covered
/Users/eric/src/eriwen.com/test/lib/jasmine-sinon.js: 73.333336% covered
/Users/eric/src/eriwen.com/test/lib/JasmineAdapter.js: 64.83517% covered
/Users/eric/src/eriwen.com/js/main.js: 60.15037% covered
</pre>
<p>And here&#8217;s how you can run it with Gradle:</p>
<pre class="brush: groovy; title: ; notranslate">
task jstd(type: Exec, dependsOn: 'init', description: 'runs JS tests through JsTestDriver') {
    // Default to MacOS and check for other environments
    def firefoxPath = '/Applications/Firefox.app/Contents/MacOS/firefox'
    if (&quot;uname&quot;.execute().text.trim() != 'Darwin') {
        firefoxPath = &quot;which firefox&quot;.execute().text
    }

    commandLine = ['/usr/bin/env', 'DISPLAY=:1', 'java', '-jar', &quot;${projectDir}/path/to/JsTestDriver.jar&quot;, '--config', &quot;${projectDir}/path/to/jsTestDriver.conf&quot;, '--port', '4224', '--browser', firefoxPath, '--tests', 'all', '--testOutput', buildDir]
}
</pre>
<p>Notice the coverage numbers? JSTD has generated a report in <a href="http://ltp.sourceforge.net/coverage/lcov.php">lcov</a> format, but this isn&#8217;t very readable to humans. </p>
<h2>Code Coverage!</h2>
<p>I couldn&#8217;t find any working scripts on the interwebs to convert the coverage file to Cobertura XML for reporting, so I wrote an <a href="https://github.com/eriwen/lcov-to-cobertura-xml">lcov-to-cobertura-xml</a> converter so we can report code coverage with <a href="http://jenkins-ci.org">Jenkins</a>!</p>
<p><img src="http://static.eriwen.com/images/coverage.png"/></p>
<p>And again with Gradle:</p>
<pre class="brush: groovy; title: ; notranslate">
task jsCoverage(type: Exec, dependsOn: 'jstd', description: 'JS code coverage with cobertura') {
	commandLine = ['python', &quot;${projectDir}/path/to/lcov-to-cobertura-xml.py&quot;, '-b', &quot;${projectDir}/&quot;, '-e', 'test.spec', '-e', 'test.lib', '-o', &quot;${buildDir}/coverage.xml&quot;, &quot;${buildDir}/jsTestDriver.conf-coverage.dat&quot;]
}
</pre>
<p>I talked about all of this at the <a href="http://www.therichwebexperience.com">Rich Web Experience</a> and I have some <a href="http://www.slideshare.net/emwendelin/javascript-ci">slides from my talk</a> that might be helpful if you want more detail about this stuff. </p>
<p><iframe src="http://www.slideshare.net/slideshow/embed_code/8688458" width="550" height="460" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="margin: 0 auto;"></iframe></p>
<h2>What about PhantomJS?</h2>
<p><a href="http://www.phantomjs.org/">PhantomJS</a> is still very necessary because JsTestDriver does NOT allow page or DOM interaction like Phantom does. I&#8217;m really excited about <a href="https://github.com/n1k0/casperjs">CasperJS</a> as it looks like a really nice way to do more functional testing with Phantom. I recommend you check it out.</p>
<h2>Conclusion</h2>
<p>You can see all of this in action in the <a href="https://github.com/eriwen/eriwen.com/blob/master/build.gradle">build for this very site</a>. </p>
<p>So that&#8217;s all I have for now. Let me know your experiences with these things or if there is something I missed, comment it up! Cheers!</p>


<p>Related posts:<ol><li><a href='http://eriwen.com/tools/wikify-yourself/' rel='bookmark' title='Why every programmer should have a Tiddlywiki'>Why every programmer should have a Tiddlywiki</a></li>
<li><a href='http://eriwen.com/tools/continuous-integration-for-javascript/' rel='bookmark' title='Continuous Integration for Javascript'>Continuous Integration for Javascript</a></li>
<li><a href='http://eriwen.com/javascript/text-size-prefs/' rel='bookmark' title='Guest Post: Save Text Size Preference Using MooTools and PHP'>Guest Post: Save Text Size Preference Using MooTools and PHP</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/EricWendelin?a=jls9CbRHLcM:svZy5PdvOhQ:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=jls9CbRHLcM:svZy5PdvOhQ:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=jls9CbRHLcM:svZy5PdvOhQ:cGdyc7Q-1BI"><img src="http://feeds.feedburner.com/~ff/EricWendelin?d=cGdyc7Q-1BI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=jls9CbRHLcM:svZy5PdvOhQ:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=jls9CbRHLcM:svZy5PdvOhQ:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=jls9CbRHLcM:svZy5PdvOhQ:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/EricWendelin?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=jls9CbRHLcM:svZy5PdvOhQ:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=jls9CbRHLcM:svZy5PdvOhQ:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/EricWendelin/~4/jls9CbRHLcM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://eriwen.com/tools/perfect-front-end-build/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://eriwen.com/tools/perfect-front-end-build/</feedburner:origLink></item>
		<item>
		<title>Continuous Integration for Javascript</title>
		<link>http://feedproxy.google.com/~r/EricWendelin/~3/yHRvtVVpd6U/</link>
		<comments>http://eriwen.com/tools/continuous-integration-for-javascript/#comments</comments>
		<pubDate>Wed, 31 Aug 2011 11:45:52 +0000</pubDate>
		<dc:creator>Eric Wendelin</dc:creator>
				<category><![CDATA[Tools]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://eriwen.com/?p=1364</guid>
		<description><![CDATA[<a href="http://jenkins-ci.org" title="Jenkins CI">Jenkins</a> is a <abbr title="Continuous Integration">CI</abbr> tool that is often used for Running tests and code analysis for Java and .NET projects. There are a lot of benefits that we as a community are not taking advantage of for our web (CSS, JS, etc) code. In this article I'm going to walk you through setting up automated building and testing for a JavaScript project.

<p class="update">NOTE: The steps outlined are generally Linux/Mac centric, I don't go into depth on Windows setup, but it shouldn't be much different using <a href="http://cygwin.com">Cygwin</a>.</p>

<h2>Why use CI?</h2>
Aside from the traditional benefits you see from your compiled code, there are some very compelling reasons:
<ol><li>Automate versioning, combining, minifying, and gzipping files</li>
<li>Run automated tests and get reports, keeping the codebase <strong>maintainable</strong></li>
<li>Run static analysis tools like the closure compiler or jshint</li>
<li>Auto-deploy files (to S3, say) if our build passes</li>
<li>Tag and other special stuff for release builds</li>
<li>... that's just JavaScript, we can also hook in Selenium tests, <a href="http://csslint.net">CSS Lint</a>, and more</li></ol>

Not convinced? <a href="#comments">Tell me why in the comments</a>.
 <a href="http://eriwen.com/tools/continuous-integration-for-javascript/">Continue reading <span class="meta-nav">&#8594;</span></a>


Related posts:<ol><li><a href='http://eriwen.com/javascript/stacktrace-update/' rel='bookmark' title='Javascript Stacktrace update'>Javascript Stacktrace update</a></li>
<li><a href='http://eriwen.com/javascript/highlight-search-results-with-js/' rel='bookmark' title='How to highlight search results with JavaScript and CSS'>How to highlight search results with JavaScript and CSS</a></li>
<li><a href='http://eriwen.com/javascript/measure-ems-for-layout/' rel='bookmark' title='Javascript: Measure those &#8220;em&#8221;s for your layout'>Javascript: Measure those &#8220;em&#8221;s for your layout</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p class="update">I have posted more thoughts and tools on how to improve this <a href="http://eriwen.com/tools/perfect-front-end-build/" title="Notes from my pursuit of the perfect front-end build">here</a>.</p>
<p><a href="http://jenkins-ci.org" title="Jenkins CI">Jenkins</a> is a <abbr title="Continuous Integration">CI</abbr> tool that is often used for Running tests and code analysis for Java and .NET projects. There are a lot of benefits that we as a community are not taking advantage of for our web (CSS, JS, etc) code. In this article I&#8217;m going to walk you through setting up automated building and testing for a JavaScript project.</p>
<p class="update">NOTE: The steps outlined are generally Linux/Mac centric, I don&#8217;t go into depth on Windows setup, but it shouldn&#8217;t be much different using <a href="http://cygwin.com">Cygwin</a>.</p>
<h2>Why use CI?</h2>
<p>Aside from the traditional benefits you see from your compiled code, there are some very compelling reasons:</p>
<ol>
<li>Automate versioning, combining, minifying, and gzipping files</li>
<li>Run automated tests and get reports, keeping the codebase <strong>maintainable</strong></li>
<li>Run static analysis tools like the closure compiler or jshint</li>
<li>Auto-deploy files (to S3, say) if our build passes</li>
<li>Tag and other special stuff for release builds</li>
<li>And that&#8217;s not all!<sup>TM</sup> We can also hook in Selenium tests, <a href="http://csslint.net">CSS Lint</a>, and more</li>
</ol>
<p>Not convinced? <a href="#comments">Tell me why in the comments</a>.</p>
<h2>Jenkins setup</h2>
<p>Downloading and running Jenkins is incredibly easy. Just <a href="http://mirrors.jenkins-ci.org/war/latest/">download Jenkins</a> and run:</p>
<pre class="brush: bash; light: true; title: ; notranslate">
wget http://mirrors.jenkins-ci.org/war/latest/jenkins.war
java -jar jenkins.war
</pre>
<p>There are also native installers for most environments.</p>
<p>Now point your browser to <code>http://localhost:8080</code> to see it running.</p>
<p>Nailed it! Now we have a CI server!</p>
<h2>Prerequisites</h2>
<p>If we&#8217;re going to be using <a href="http://git-scm.org">git</a> and <a href="http://gradle.org">gradle</a>, we&#8217;ll need to install them (<a href="http://code.google.com/p/msysgit/downloads/list">Windows Git installer</a>). </p>
<pre class="brush: bash; title: Git language=installation; notranslate">
sudo yum install git-core  # CentOS/RedHat/etc
sudo apt-get install git   # Debian/Ubuntu/etc
sudo port install git-core # MacPorts
sudo brew install git      # Homebrew
</pre>
<pre class="brush: bash; title: Gradle language=installation; notranslate">
wget http://edub.me/ngMAeR # Gradle 1.0m3 ZIP
sudo mv gradle-1.0* /usr/local
sudo unzip /usr/local/gradle-1.0-milestone-3-bin.zip
sudo ln -s /usr/local/gradle-1.0-milestone-3 /usr/local/gradle
</pre>
<p>To tell Jenkins where to find Gradle, we go to <em>Manage Jenkins > Configure System</em> from the top page. Add a name and enter your GRADLE_HOME (/usr/local/gradle if you followed the instructions above). It should look like this:</p>
<p><img src="http://static.eriwen.com/images/jenkins-gradle-config-1.png" alt="Jenkins Gradle Setup"/></p>
<h2>Setup a CI job</h2>
<p>As an example, I&#8217;m going to use my <a href="https://github.com/eriwen/javascript-stacktrace" title="stacktrace.js project">stacktrace.js project on GitHub</a>. Even though it&#8217;s a small <abbr title="JavaScript">JS</abbr> library, almost all of the setup can be used for any type of project.</p>
<p>First, we want to install a few plugins that will help us out. We&#8217;ll need <a href="http://git-scm.org">Git</a> to pull down the code and <a href="http://www.gradle.org">Gradle</a> to build it. You&#8217;ll <strong>want the Git, Gradle, and Violations plugins installed</strong>. It&#8217;s pretty easy to figure out, but hit up the <a href="https://wiki.jenkins-ci.org/display/JENKINS/Use+Jenkins" title="Use Jenkins Wiki">Jenkins wiki</a> if you get stuck. </p>
<p>We want to create a new job that runs analysis on our JS and runs our tests. Click <em>New Job</em> on the Jenkins sidebar and you&#8217;ll see the setup form.</p>
<h2>Checking out and building a repo</h2>
<p>Under <em>Source Code Management</em> choose <em>Git</em> and enter <code>git://github.com/eriwen/javascript-stacktrace.git</code> for the repo location and <code>master</code> for the branch. It&#8217;ll look something like this:<br />
<img src="http://static.eriwen.com/images/jenkins-git-1.png" alt="Jenkins Git Setup"/></p>
<p>For the <em>Build</em> section of the setup, we want to run the <code>minify</code> build target from Gradle. You&#8217;ll also want to enter the location of the build file as <code>build/build.gradle</code>. Don&#8217;t worry about the contents of our build script right now, I have a slew of blog posts in-progress that explain it. <a href="http://eriwen.com/feed/">Stay tuned</a>.<br />
<img src="http://static.eriwen.com/images/jenkins-gradle-build.png" alt="Jenkins Gradle Minify"/></p>
<p>Now would be a good time to click <em>Save</em> at the bottom and then click <em>Build Now</em> on the sidebar for the job. You should see Jenkins checkout, pull down the latest Closure Compiler, and use it to minify stacktrace.js.</p>
<h2>Running JS unit tests with PhantomJS</h2>
<p>The days are past when you have to open a browser to see if your JS is generally working. <a href="http://www.phantomjs.org/" title="Headless Browser Testing">PhantomJS</a> is a headless WebKit browser that lets us interact with web pages (click links, pull from localStorage, etc.) without the browser window! This will let Jenkins run a browser with our tests and report the result. To follow along with the example, <a href="http://code.google.com/p/phantomjs/downloads/list">download</a> and install PhantomJS in <code>/usr/local/bin</code> (on Mac OS I just <code>sudo ln -s /Applications/phantomjs.app/Contents/MacOS/phantomjs /usr/local/bin/phantomjs</code>). Note that if you&#8217;re running Jenkins on a headless server, you&#8217;ll want to have <a href="http://en.wikipedia.org/wiki/Xvfb">xvfb</a>.</p>
<p>We also need to update the Build part of the configuration by telling gradle to run the <code>test</code> target.<br />
<img src="http://static.eriwen.com/images/jenkins-gradle-1.png" alt="Jenkins Gradle Setup"/></p>
<p>Gradle is now setup to run the <a href="http://docs.jquery.com/Qunit" title="QUnit Javascript Testing Framework">QUnit</a> tests in the project, but we need to tell Jenkins where to find the test reports. Easy! I encourage you to check out the <a href="https://github.com/eriwen/javascript-stacktrace/blob/master/build/build.gradle">source of build.gradle</a> if you want to know how this is setup. It&#8217;s really quite interesting.<br />
<img src="http://static.eriwen.com/images/jenkins-junit-1.png" alt="Jenkins JUnit Setup"/></p>
<p>Save and try that build again to bask in automated JavaScript testing awesomeness.</p>
<h2>Finding potential bugs with JSHint</h2>
<p>I&#8217;m a big fan of <a href="https://github.com/jshint/jshint/">JSHint</a> and I think it&#8217;s worthwhile to have it run on every <code>git push</code>. Here&#8217;s how to add that. To follow the example, you&#8217;ll have to install <a href="https://github.com/joyent/node/wiki/Installation">NodeJS</a> and the jshint module from <a href="http://npmjs.org" title="npm Is Not An Acronym">npm</a>:</p>
<pre class="brush: bash; light: true; title: Install 1=and 2=npm; notranslate">
sudo brew install node      # Homebrew
sudo port install node      # MacPorts
sudo apt-get install nodejs # Debian-based

curl http://npmjs.org/install.sh | sudo sh # Install NPM
sudo npm install -g jshint
</pre>
<p>Now we just need to tell Jenkins to run jshint as well as our tests and where to find the JSHint report. The gradle build puts it in <code>target/jshint.xml</code>. It should look like this:<br />
<img src="http://static.eriwen.com/images/jenkins-violations-1.png" alt="Jenkins Violations Setup"/><br />
<img src="http://static.eriwen.com/images/jenkins-jshint-1.png" alt="Jenkins JSHint Setup"/></p>
<p>One more <em>Build Now</em> and we have a fully functioning JavaScript build. You&#8217;ll also see graphs with test and jshint results on the job page and can drill down into details.</p>
<p>I have really loved my <abbr title="Continuous Integration">CI</abbr> setup for my web projects as well as my JVM-based ones. Now you have the power to go build a cool CI system for your projects. You can read more of my thoughts on this from my <a href="http://eriwen.com/tools/perfect-front-end-build/">notes from my pursuit of the perfect front-end build</a>. Enjoy!</p>


<p>Related posts:<ol><li><a href='http://eriwen.com/javascript/stacktrace-update/' rel='bookmark' title='Javascript Stacktrace update'>Javascript Stacktrace update</a></li>
<li><a href='http://eriwen.com/javascript/highlight-search-results-with-js/' rel='bookmark' title='How to highlight search results with JavaScript and CSS'>How to highlight search results with JavaScript and CSS</a></li>
<li><a href='http://eriwen.com/javascript/measure-ems-for-layout/' rel='bookmark' title='Javascript: Measure those &#8220;em&#8221;s for your layout'>Javascript: Measure those &#8220;em&#8221;s for your layout</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/EricWendelin?a=yHRvtVVpd6U:Hga-Y6wNF4c:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=yHRvtVVpd6U:Hga-Y6wNF4c:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=yHRvtVVpd6U:Hga-Y6wNF4c:cGdyc7Q-1BI"><img src="http://feeds.feedburner.com/~ff/EricWendelin?d=cGdyc7Q-1BI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=yHRvtVVpd6U:Hga-Y6wNF4c:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=yHRvtVVpd6U:Hga-Y6wNF4c:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=yHRvtVVpd6U:Hga-Y6wNF4c:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/EricWendelin?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=yHRvtVVpd6U:Hga-Y6wNF4c:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=yHRvtVVpd6U:Hga-Y6wNF4c:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/EricWendelin/~4/yHRvtVVpd6U" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://eriwen.com/tools/continuous-integration-for-javascript/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		<feedburner:origLink>http://eriwen.com/tools/continuous-integration-for-javascript/</feedburner:origLink></item>
		<item>
		<title>Best algorithms book I ever read</title>
		<link>http://feedproxy.google.com/~r/EricWendelin/~3/-aYIMnVhVXo/</link>
		<comments>http://eriwen.com/books/best-algorithms-book/#comments</comments>
		<pubDate>Wed, 23 Feb 2011 11:00:45 +0000</pubDate>
		<dc:creator>Eric Wendelin</dc:creator>
				<category><![CDATA[Books]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://eriwen.com/?p=1272</guid>
		<description><![CDATA[<img src="http://static.eriwen.com/images/algorithm_design_manual.jpeg" alt="The Algorithm Design Manual" class="img-left" width="160" height="214"/>I took a fair amount of time looking at data structures and algorithms while I was studying for my interviews with Google, and based on informed suggestions from <a href="http://steve-yegge.blogspot.com/2008/03/get-that-job-at-google.html" title="Get that job at Google">Steve Yegge's infamous post</a>, I decided to buy <a href="http://www.amazon.com/Algorithm-Design-Manual-Steven-Skiena/dp/1849967202/ref=sr_1_1?ie=UTF8&#038;qid=1297127794&#038;sr=8-1">The Algorithm Design Manual</a> by Steven S. Skiena.

If you don't care to read my ramblings about this book, here's a summary: Buy this book if you do ANY serious programming.

<h2>What makes The Algorithm Design Manual</h2>
2 main reasons I make this blatantly positive assessment: 
<ol><li>The first several chapters are dedicated to the basics of data structures and common problems involving algorithms. This is obviously not a unique feature, but what is unique are the "war stories" from actual field work. The stories include <strong>discussion about the failure cases</strong> and how Skiena went about solving problems he encountered. This alone is enough to make this book worthwhile.</li>
<li>Chapters 11-18 are a giant catalogue of algorithmic problems. Again, not a unique trait. However, not only does Skiena describe the basic approaches to solving each type of problem, he <strong>includes links to different implementations of in-the-field optimized solutions</strong>. He also brings up questions you should ask yourself when choosing an implementation.</li></ol>
 <a href="http://eriwen.com/books/best-algorithms-book/">Continue reading <span class="meta-nav">&#8594;</span></a>


Related posts:<ol><li><a href='http://eriwen.com/java/how-not-to-pass-the-scjp-exam/' rel='bookmark' title='How not to pass the SCJP exam'>How not to pass the SCJP exam</a></li>
<li><a href='http://eriwen.com/java/scwcd-lessons/' rel='bookmark' title='Lessons learned from the SCWCD'>Lessons learned from the SCWCD</a></li>
<li><a href='http://eriwen.com/microformats/add-hcard-to-blogroll/' rel='bookmark' title='Microformats: Add hCard to your blogroll in 2 minutes flat'>Microformats: Add hCard to your blogroll in 2 minutes flat</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p><img src="http://static.eriwen.com/images/algorithm_design_manual.jpeg" alt="The Algorithm Design Manual" class="img-left" width="160" height="214"/>I took a fair amount of time looking at data structures and algorithms while I was studying for my interviews with Google, and based on informed suggestions from <a href="http://steve-yegge.blogspot.com/2008/03/get-that-job-at-google.html" title="Get that job at Google">Steve Yegge&#8217;s infamous post</a>, I decided to buy <a href="http://www.amazon.com/Algorithm-Design-Manual-Steven-Skiena/dp/1849967202/ref=sr_1_1?ie=UTF8&#038;qid=1297127794&#038;sr=8-1">The Algorithm Design Manual</a> by Steven S. Skiena.</p>
<p>If you don&#8217;t care to read my ramblings about this book, here&#8217;s a summary: Buy this book if you do ANY serious programming.</p>
<h2>What makes The Algorithm Design Manual</h2>
<p>2 main reasons I make this blatantly positive assessment: </p>
<ol>
<li>The first several chapters are dedicated to the basics of data structures and common problems involving algorithms. This is obviously not a unique feature, but what is unique are the &#8220;war stories&#8221; from actual field work. The stories include <strong>discussion about the failure cases</strong> and how Skiena went about solving problems he encountered. This alone is enough to make this book worthwhile.</li>
<li>Chapters 11-18 are a giant catalogue of algorithmic problems. Again, not a unique trait. However, not only does Skiena describe the basic approaches to solving each type of problem, he <strong>includes links to different implementations of in-the-field optimized solutions</strong>. He also brings up questions you should ask yourself when choosing an implementation.</li>
</ol>
<p>The only caveat here is that most of the examples are written in C, which can be troublesome if you don&#8217;t know or have forgotten about pointers.</p>
<h2>You should buy this book if&#8230;</h2>
<p>You have at least <strong>1 year of computer science training</strong> under your belt. If you are just writing one website in PHP for your cousin&#8217;s lemonade stand; then I don&#8217;t know why have you read this far. In that case you won&#8217;t be interested in this book. </p>
<p>Students and professionals alike will find <a href="http://www.amazon.com/Algorithm-Design-Manual-Steven-Skiena/dp/1849967202/ref=sr_1_1?ie=UTF8&#038;qid=1297127794&#038;sr=8-1">The Algorithm Design Manual</a> useful. In addition to the standard problem sets, I&#8217;ve also found the accompanying interview questions to be very interesting. </p>
<p>The only programming book that tops this is <a href="http://www.amazon.com/Pragmatic-Programmer-Journeyman-Master/dp/020161622X/ref=sr_1_1?s=books&#038;ie=UTF8&#038;qid=1298329702&#038;sr=1-1" title="The Pragmatic Programmer: From Journeyman to Master book from Amazon">The Pragmatic Programmer</a> by Andy Hunt and Dave Thomas.</p>
<p>What are some of the best Data Structures/Algorithms books you&#8217;ve found?</p>


<p>Related posts:<ol><li><a href='http://eriwen.com/java/how-not-to-pass-the-scjp-exam/' rel='bookmark' title='How not to pass the SCJP exam'>How not to pass the SCJP exam</a></li>
<li><a href='http://eriwen.com/java/scwcd-lessons/' rel='bookmark' title='Lessons learned from the SCWCD'>Lessons learned from the SCWCD</a></li>
<li><a href='http://eriwen.com/microformats/add-hcard-to-blogroll/' rel='bookmark' title='Microformats: Add hCard to your blogroll in 2 minutes flat'>Microformats: Add hCard to your blogroll in 2 minutes flat</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/EricWendelin?a=-aYIMnVhVXo:j8U6XmYNzN8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=-aYIMnVhVXo:j8U6XmYNzN8:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=-aYIMnVhVXo:j8U6XmYNzN8:cGdyc7Q-1BI"><img src="http://feeds.feedburner.com/~ff/EricWendelin?d=cGdyc7Q-1BI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=-aYIMnVhVXo:j8U6XmYNzN8:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=-aYIMnVhVXo:j8U6XmYNzN8:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=-aYIMnVhVXo:j8U6XmYNzN8:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/EricWendelin?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=-aYIMnVhVXo:j8U6XmYNzN8:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=-aYIMnVhVXo:j8U6XmYNzN8:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/EricWendelin/~4/-aYIMnVhVXo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://eriwen.com/books/best-algorithms-book/feed/</wfw:commentRss>
		<slash:comments>27</slash:comments>
		<feedburner:origLink>http://eriwen.com/books/best-algorithms-book/</feedburner:origLink></item>
		<item>
		<title>Griffon, meet Jython</title>
		<link>http://feedproxy.google.com/~r/EricWendelin/~3/SFlwz-aIkvU/</link>
		<comments>http://eriwen.com/python/griffon-jython-plugin/#comments</comments>
		<pubDate>Thu, 03 Feb 2011 10:00:50 +0000</pubDate>
		<dc:creator>Eric Wendelin</dc:creator>
				<category><![CDATA[Griffon]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Project]]></category>

		<guid isPermaLink="false">http://eriwen.com/?p=1132</guid>
		<description><![CDATA[I've come to love the <a href="http://python.org/">Python</a> language for its elegant syntax combined with powerful constructs like comprehensions. <a href="http://jython.org/">Jython</a> allows me to take Python to the next level by allowing it to interact with my existing JVM-compatible code. Now I want to extend that even further and allow myself (and you, of course) to integrate Jython with <a href="http://griffon.codehaus.org/">Griffon</a>, a framework for building desktop applications in <a href="http://groovy.codehaus.org/">Groovy</a>.

<h2>Introducing the Jython plugin for Griffon</h2>
The Jython plugin enables compiling and running Jython code on your Griffon application. You don't even need to install Jython manually. A Jython REPL is available with access to your Groovy/Java classes
 <a href="http://eriwen.com/python/griffon-jython-plugin/">Continue reading <span class="meta-nav">&#8594;</span></a>


Related posts:<ol><li><a href='http://eriwen.com/interview/andres-almiray/' rel='bookmark' title='Interview with Andres Almiray'>Interview with Andres Almiray</a></li>
<li><a href='http://eriwen.com/python/first-impressions/' rel='bookmark' title='Python first impressions'>Python first impressions</a></li>
<li><a href='http://eriwen.com/python/update-feedburner-count/' rel='bookmark' title='Using Python to update your FeedBurner stats'>Using Python to update your FeedBurner stats</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve come to love the <a href="http://python.org/">Python</a> language for its elegant syntax combined with powerful constructs like comprehensions. <a href="http://jython.org/">Jython</a> allows me to take Python to the next level by allowing it to interact with my existing JVM-compatible code. Now I want to extend that even further and allow myself (and you, of course) to integrate Jython with <a href="http://griffon.codehaus.org/">Griffon</a>, a framework for building desktop applications in <a href="http://groovy.codehaus.org/">Groovy</a>.</p>
<h2>Introducing the Jython plugin for Griffon</h2>
<p>The Jython plugin enables compiling and running Jython code on your Griffon application. You don&#8217;t even need to install Jython manually. A Jython REPL is available with access to your Groovy/Java classes if you use:</p>
<pre class="brush: bash; light: true; title: ; notranslate">
griffon jython-repl
</pre>
<p>You can even load Jython scripts on-the-fly by putting them in <code>MyGriffonApp/griffon-app/resources/jython</code>!</p>
<p>In the rest of the article, we are going to create a simple application that mixes Griffon and Jython using the Griffon-Jython plugin.</p>
<p><img src="http://static.eriwen.com/images/jython-sample.png" alt="Jython Sample Application" /></p>
<h2>Getting started with griffon-jython</h2>
<p>It&#8217;s easy to setup Griffon, and you&#8217;ll find <a href="http://griffon.codehaus.org/Installing+Griffon" title="Installing Griffon">instructions here</a> and <a href="http://griffon.codehaus.org/Download" title="Griffon downloads">downloads here</a>. Once you&#8217;re done, you can create a Griffon app and install the jython plugin by typing:</p>
<pre class="brush: bash; light: true; title: ; notranslate">
griffon create-app MyGriffonApp
# Go into MyGriffonApp directory
cd !$
# Download and install the latest Jython plugin!
griffon install-plugin jython
</pre>
<p>Now that we&#8217;ve installed the Jython plugin, you can create a Jython class on your command-line:</p>
<pre class="brush: bash; light: true; title: ; notranslate">
griffon create-jython-class com.mypkg.MyJythonClass
</pre>
<p>Let&#8217;s create a Jython class that greets the user when a button is clicked.</p>
<pre class="brush: python; light: true; title: ; notranslate">
from com.mypkg import IGreeter

class MyJythonClass(IGreeter):
  def __init__(self):
    pass

  def greet(self, who, model):
    greeting = 'Hello %s from Jython!' % str(who)
    model.setOutput(greeting)
</pre>
<p>Jython classes are exposed to Griffon using an <a href="http://en.wikipedia.org/wiki/Factory_method_pattern">Object Factory Pattern</a> as suggested in the <a href="http://www.jython.org/jythonbook/en/1.0/JythonAndJavaIntegration.html#using-jython-within-java-applications" title="Using Jython Within Java Applications">Definitive Guide To Jython, Chapter 10</a>. Therefore, we create a Java (well, Groovy) interface that <code>MyJythonClass</code> will extend to allow Griffon to get at the proper method implementations. It sounds rather complicated, but it really is quite simple. Let&#8217;s create the <code>IGreeter</code> interface to show you what I&#8217;m talking about:</p>
<pre class="brush: groovy; light: true; title: ; notranslate">
package com.mypkg

public interface IGreeter {
  // Same signature as our Jython method
  public void greet(String greetee, def model)
}
</pre>
<p>Our <code>greet()</code> method accepts a <code>String</code> (the textField input) and a model of unspecified type.</p>
<p>Griffon auto-generates MVC classes for you, so we can use those. You&#8217;ll find them in the <code>MyGriffonApp/griffon-app/{models,views,controllers}</code> directories. We are going to change those for our app! Here is the aforementioned <code>Model</code>:</p>
<pre class="brush: groovy; light: true; title: ; notranslate">
package com.mypkg
import groovy.beans.Bindable

class MyGriffonAppModel {
    @Bindable String input = ''
    @Bindable String output = ''
}
</pre>
<p>Groovy implicitly creates <code>get/setInput()</code> methods and allows them to be bound (to the View textField value, e.g.). Here is that <code>MyGriffonAppView</code>:</p>
<pre class="brush: groovy; light: true; title: ; notranslate">
package com.mypkg

application(title:'Griffon Jython Sample', pack:true, locationByPlatform:true) {
  gridLayout(cols: 1, rows: 2)
  //Note the ID on this textField
  textField(id: &quot;input&quot;, columns: 20)
  button(&quot;Click me!&quot;, actionPerformed: controller.handleClick)
  bean(model, input: bind {input.text})
}
</pre>
<p>Finally, the most critical part of our application that will interact with our Jython class, the <code>MyGriffonAppController</code>:</p>
<pre class="brush: groovy; light: true; title: ; notranslate">
package com.mypkg

import java.beans.PropertyChangeListener
import griffon.jython.JythonObjectFactory
import javax.swing.JOptionPane

class MyGriffonAppController {
  // Values auto-injected
  def model
  def view
  def greeter

  def mvcGroupInit(Map args) {
     // When our model output has changed, show a dialog
     model.addPropertyChangeListener(&quot;output&quot;, { evt -&gt;
       if(!evt.newValue) return
       doLater {
         JOptionPane.showMessageDialog(app.windowManager.windows[0],
           evt.newValue, &quot;Message from Jython&quot;, JOptionPane.INFORMATION_MESSAGE)
       }
     } as PropertyChangeListener)

     // Instantiate MyJythonClass
     JythonObjectFactory factory =
         new JythonObjectFactory(IGreeter.class, 'MyJythonClass', 'MyJythonClass')
     greeter = (IGreeter) factory.createObject()
   }

  def handleClick = { evt = null -&gt;
    if(!model.input) return
    model.output = &quot;&quot;
    // invoke Jython class (outside EDT)
    doOutside {
      greeter.greet(model.input, model)
    }
  }
}
</pre>
<p>There you have it! Now we can utilize such Jython greatness as <a href="http://wiki.python.org/moin/Generators" title="Python generators">generators</a> and <a href="http://diveintopython.org/power_of_introspection/filtering_lists.html">list comprehensions</a>!</p>
<h2>Further reading</h2>
<p>The <a href="http://dist.codehaus.org/griffon/guide/index.html">Griffon Guide</a> is the best place to go for Griffon documentation. You can find more comprehensive documentation for the Jython plugin on the <a href="http://griffon.codehaus.org/Jython+Plugin" title="Griffon - Jython Plugin">official plugin page</a>. As always, this stuff is completely open-source, and you can find all of the code and submit suggestions and issues at the <a href="https://github.com/eriwen/griffon-jython" title="griffon-jython source code repo">GitHub repository</a>. </p>


<p>Related posts:<ol><li><a href='http://eriwen.com/interview/andres-almiray/' rel='bookmark' title='Interview with Andres Almiray'>Interview with Andres Almiray</a></li>
<li><a href='http://eriwen.com/python/first-impressions/' rel='bookmark' title='Python first impressions'>Python first impressions</a></li>
<li><a href='http://eriwen.com/python/update-feedburner-count/' rel='bookmark' title='Using Python to update your FeedBurner stats'>Using Python to update your FeedBurner stats</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/EricWendelin?a=SFlwz-aIkvU:LneIwvsIg08:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=SFlwz-aIkvU:LneIwvsIg08:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=SFlwz-aIkvU:LneIwvsIg08:cGdyc7Q-1BI"><img src="http://feeds.feedburner.com/~ff/EricWendelin?d=cGdyc7Q-1BI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=SFlwz-aIkvU:LneIwvsIg08:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=SFlwz-aIkvU:LneIwvsIg08:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=SFlwz-aIkvU:LneIwvsIg08:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/EricWendelin?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=SFlwz-aIkvU:LneIwvsIg08:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=SFlwz-aIkvU:LneIwvsIg08:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/EricWendelin/~4/SFlwz-aIkvU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://eriwen.com/python/griffon-jython-plugin/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://eriwen.com/python/griffon-jython-plugin/</feedburner:origLink></item>
		<item>
		<title>Continuation-passing and tail call elimination in Javascript</title>
		<link>http://feedproxy.google.com/~r/EricWendelin/~3/YD4xcqJ0ZB4/</link>
		<comments>http://eriwen.com/javascript/cps-tail-call-elimination/#comments</comments>
		<pubDate>Tue, 02 Nov 2010 08:00:44 +0000</pubDate>
		<dc:creator>Eric Wendelin</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://eriwen.com/?p=1199</guid>
		<description><![CDATA[I've been spending a lot of time recently tinkering with different constructs and methodologies in Javascript, and one of the most fascinating things I've come across is <a href="http://spencertipping.com/blog/" title="Spencer Tipping's Blog">Spencer Tipping</a>'s use of continuation-passing style. 

It's ok if you aren't familiar with <abbr title="Continuation-Passing Style">CPS</abbr>, but I think anyone hoping to make the cognitive leap to <a href="http://en.wikipedia.org/wiki/Functional_programming">functional programming</a> should study it. As a bare miniumum, you need to know that a continuation is:

<blockquote>[a reification of] an instance of a computational process at a given point in the process's execution</blockquote>
 <a href="http://eriwen.com/javascript/cps-tail-call-elimination/">Continue reading <span class="meta-nav">&#8594;</span></a>


Related posts:<ol><li><a href='http://eriwen.com/javascript/js-stack-trace/' rel='bookmark' title='A Javascript stacktrace in any browser'>A Javascript stacktrace in any browser</a></li>
<li><a href='http://eriwen.com/javascript/measure-ems-for-layout/' rel='bookmark' title='Javascript: Measure those &#8220;em&#8221;s for your layout'>Javascript: Measure those &#8220;em&#8221;s for your layout</a></li>
<li><a href='http://eriwen.com/javascript/highlight-search-results-with-js/' rel='bookmark' title='How to highlight search results with JavaScript and CSS'>How to highlight search results with JavaScript and CSS</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been spending a lot of time recently tinkering with different constructs and methodologies in Javascript, and one of the most fascinating things I&#8217;ve come across is <a href="http://spencertipping.com/blog/" title="Spencer Tipping's Blog">Spencer Tipping</a>&#8216;s use of continuation-passing style. </p>
<p>It&#8217;s ok if you aren&#8217;t familiar with <abbr title="Continuation-Passing Style">CPS</abbr>, but I think anyone hoping to make the cognitive leap to <a href="http://en.wikipedia.org/wiki/Functional_programming">functional programming</a> should study it. As a bare miniumum, you need to know that a continuation is:</p>
<blockquote><p>[a reification of] an instance of a computational process at a given point in the process&#8217;s execution</p></blockquote>
<p>Therefore, <a href="http://en.wikipedia.org/wiki/Continuation-passing_style">continuation-passing style</a> is just:</p>
<blockquote><p>a <strong>style of programming</strong> in which control is passed explicitly in the form of a continuation</p></blockquote>
<p class="update"><strong>NOTE:</strong> I have replaced my crappy examples just below with <a href="http://eriwen.com/javascript/cps-tail-call-elimination/#comment-7110">Outis&#8217;s much more reasonable (and correct) ones</a>. I take no credit for the simple CPS code below. Thank you Outis and David for the suggestions.</p>
<p>Consider the naive implementation of the recursive fibonacci function:</p>
<pre class="brush: jscript; title: Recursive fibonacci function; notranslate">
function fib(n) {
    if (n &lt; 1) {
        return 1;
    } else {
        return fib(n-2) + fib(n-1);
    }
}
</pre>
<p>Then, identify function calls and returns. For each such point, create a continuation and pass it to the function call or return it. For example, the continuation for <code>fibr(n-1) + fibr(n-2)</code> is:</p>
<pre class="brush: jscript; light: true; title: continuation for recursive fibonacci; notranslate">
function(x) {
    return x + fib(n-2);
}
</pre>
<p>and you get:</p>
<pre class="brush: jscript; title: Applying continuation passing to fibonacci; notranslate">
function cpsFib(n, _return) {
    if (n &lt;= 1) {
        return _return(1);
    } else {
        return cpsFib(n-2, function(a) {
            return cpsFib(n-1, function(b) {
                return _return(a+b);
            });
        });
    }
}
</pre>
<p>Apply this process to the linear recursive fibonacci function and you get:</p>
<pre class="brush: jscript; highlight: [9]; title: ; notranslate">
function cpsFib(n, prev, cur, _return) {
    // Key component: call escape function when done
    if (n &lt; 2) {
        return _return(cur);
    }
    return cpsFib(--n, cur, cur + prev, _return);
}
// Note the use of an identity function here
cpsFib(1000, 0, 1, function(x) {return x});
</pre>
<p>The only problem with this, however, is that <strong>Javascript engines to not optimize tail recursion</strong>, so calling: <em>fibonacci_cps(10000)</em> would cause a <em>StackOverflowError</em> in some browsers. </p>
<pre class="brush: jscript; light: true; title: StackOverflow!; notranslate">
function() {
	return [1000, 0, 1,
		function() { return [999, 1, 1,
			function() { return [998, 1, 2,
				... ]]
			}
		}
	];
}
</pre>
<p>However, by adding to Function.prototype and changing the way we pass continuations, <strong>we can fix this problem.</strong></p>
<pre class="brush: jscript; title: ; notranslate">
// Function prototypes heavily inspired by Spencer Tipping's js-in-ten-minutes:
//   http://github.com/spencertipping/js-in-ten-minutes
Function.prototype.tail = function() {
	return [this, arguments];
}
// Tail-call optimization
Function.prototype.tco = function() {
	var continuation = [this, arguments];
	var escapeFn = arguments[arguments.length - 1];
	while (continuation[0] !== escapeFn) {
		continuation = continuation[0].apply(this, continuation[1]);
	}
	return escapeFn.apply(this, continuation[1]);
}

// Note the use of &quot;Function.prototype.tail()&quot;
function cpsFib(n, prev, cur, escapeFn) {
	if (n &lt; 2) {
		return escapeFn.tail(cur);
	}
	return cpsFib.tail(--n, cur, cur + prev, escapeFn);
}

function identity(x) {return x}

// We pass the escape function instead of a reference to cpsFib
cpsFib.tco(1000, 0, 1, identity);
</pre>
<pre class="brush: jscript; light: true; title: Tail-call optimized; notranslate">
// within while (continuation[0] !== escapeFn) {
[cpsFib, [1000, 0, 1, identity]]
[cpsFib, [999, 1, 1, identity]]
[cpsFib, [998, 1, 2, identity]]
[cpsFib, [3, 2.686e+208, 4.3467e+208, identity]]

// return escapeFn.apply(this, continuation[1]);
[identity, 4.34673e+208]
</pre>
<h2>How CPS and TCO can be practical</h2>
<p>All this talk about styles and optimizations can sound rather like &#8220;over-engineering&#8221; to those of us who aren&#8217;t familiar with these concepts. While it&#8217;s a risk, good engineers will know when it is effective. Here&#8217;s how I would recommend you use these concepts:</p>
<ol>
<li>Processing large structures in a recursive way, perhaps recursing through an Object or HTML tree of indeterminate depth</li>
<li>You&#8217;re adding functional methods to iterable objects (adding Array.prototype.map())</li>
<li>Practicing uses of functional programming with Javascript</li>
</ol>
<h2>Conclusion</h2>
<p>Knowing how to use functional techniques in Javascript will be more valuable as it moves to the server-side (due to the rising popularity of <a href="http://nodejs.org/">node.js</a>) because doing more actual computation will be acceptable instead of blocking a <abbr title="User Interface">UI</abbr>. </p>
<p>I learned a lot from Spencer&#8217;s write-up <a href="http://github.com/spencertipping/js-in-ten-minutes">Javascript in Ten Minutes</a>, and would recommend you check it out. I&#8217;ve also found reading <a href="http://github.com/spencertipping">his other Javascript code</a> and comments very insightful.</p>
<p>Please share other uses of functional Javascript you&#8217;ve come across.</p>


<p>Related posts:<ol><li><a href='http://eriwen.com/javascript/js-stack-trace/' rel='bookmark' title='A Javascript stacktrace in any browser'>A Javascript stacktrace in any browser</a></li>
<li><a href='http://eriwen.com/javascript/measure-ems-for-layout/' rel='bookmark' title='Javascript: Measure those &#8220;em&#8221;s for your layout'>Javascript: Measure those &#8220;em&#8221;s for your layout</a></li>
<li><a href='http://eriwen.com/javascript/highlight-search-results-with-js/' rel='bookmark' title='How to highlight search results with JavaScript and CSS'>How to highlight search results with JavaScript and CSS</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/EricWendelin?a=YD4xcqJ0ZB4:71lSHGSKS9o:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=YD4xcqJ0ZB4:71lSHGSKS9o:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=YD4xcqJ0ZB4:71lSHGSKS9o:cGdyc7Q-1BI"><img src="http://feeds.feedburner.com/~ff/EricWendelin?d=cGdyc7Q-1BI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=YD4xcqJ0ZB4:71lSHGSKS9o:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=YD4xcqJ0ZB4:71lSHGSKS9o:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=YD4xcqJ0ZB4:71lSHGSKS9o:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/EricWendelin?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=YD4xcqJ0ZB4:71lSHGSKS9o:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=YD4xcqJ0ZB4:71lSHGSKS9o:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/EricWendelin/~4/YD4xcqJ0ZB4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://eriwen.com/javascript/cps-tail-call-elimination/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		<feedburner:origLink>http://eriwen.com/javascript/cps-tail-call-elimination/</feedburner:origLink></item>
		<item>
		<title>Testing your Hadoop jobs with MRUnit</title>
		<link>http://feedproxy.google.com/~r/EricWendelin/~3/bnqWQfUK4Zc/</link>
		<comments>http://eriwen.com/hadoop/testing-with-mrunit/#comments</comments>
		<pubDate>Thu, 20 May 2010 11:00:37 +0000</pubDate>
		<dc:creator>Eric Wendelin</dc:creator>
				<category><![CDATA[Hadoop]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://eriwen.com/?p=1137</guid>
		<description><![CDATA[Last Tuesday I gave a short presentation at the new <a href="http://www.meetup.com/Boulder-Denver-Hadoop/" title="Meetup.com Boulder Hadoop">Boulder Hadoopers Group</a> about testing Hadoop jobs with MRUnit. You will have to know what <a href="http://hadoop.apache.org/">Hadoop</a> is and how to read <a href="http://groovy.codehaus.org/" title="Groovy programming language">Groovy</a> code to fully understand it. I am including the important notes on the slides as well.
 <a href="http://eriwen.com/hadoop/testing-with-mrunit/">Continue reading <span class="meta-nav">&#8594;</span></a>


Related posts:<ol><li><a href='http://eriwen.com/tools/perfect-front-end-build/' rel='bookmark' title='Notes from my pursuit of the perfect front-end build'>Notes from my pursuit of the perfect front-end build</a></li>
<li><a href='http://eriwen.com/python/griffon-jython-plugin/' rel='bookmark' title='Griffon, meet Jython'>Griffon, meet Jython</a></li>
<li><a href='http://eriwen.com/javascript/stacktrace-update/' rel='bookmark' title='Javascript Stacktrace update'>Javascript Stacktrace update</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>Last Tuesday I gave a short presentation at the new <a href="http://www.meetup.com/Boulder-Denver-Hadoop/" title="Meetup.com Boulder Hadoop">Boulder Hadoopers Group</a> about testing Hadoop jobs with MRUnit. You will have to know what <a href="http://hadoop.apache.org/">Hadoop</a> is and how to read <a href="http://groovy.codehaus.org/" title="Groovy programming language">Groovy</a> code to fully understand it. I am including the important notes on the slides as well.<br />
<!--00ab2f96e6414b06a0abf5321e153198--></p>
<div style="width:580px" id="__ss_4073730"><strong>If your browser doesn&#8217;t support flash, check out the <a href="http://www.slideshare.net/emwendelin/testing-hadoop-jobs-with-mrunit">slides at slideshare</a></strong><object id="__sse4073730" width="580" height="420"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=hadoop-joins-100512163936-phpapp02&#038;stripped_title=testing-hadoop-jobs-with-mrunit" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse4073730" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=hadoop-joins-100512163936-phpapp02&#038;stripped_title=testing-hadoop-jobs-with-mrunit" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="580" height="420"></embed></object></div>
<h2>Why use MRUnit?</h2>
<p>Testing a Hadoop job requires a lot of effort not related to the job. You must configure it to run locally, create a sample input file, run the job on your sample input, and then compare to an expected output file. This not only takes time, but makes your tests run very slow due to all the file I/O.</p>
<p><a href="http://archive.cloudera.com/docs/mrunit/index.html">MRUnit</a> is:</p>
<blockquote><p>a unit test library designed to facilitate easy integration between your MapReduce development process and standard development and testing tools such as JUnit</p></blockquote>
<p>With MRUnit, there are no test files to create, no configuration parameters to change, and generally less test code. You can cut the clutter and focus on the meat of your tests.</p>
<h2>The Good</h2>
<p>Hadoop tests are much simpler to write using MRUnit. Here&#8217;s an example of entire test class:</p>
<pre class="brush: groovy; title: ; notranslate">
class ExampleTest() {
  private Example.MyMapper mapper
  private Example.MyReducer reducer
  private MapReduceDriver driver

  @Before void setUp() {
    mapper = new Example.MyMapper()
    reducer = new Example.MyReducer()
    driver = new MapReduceDriver(mapper, reducer)
  }

  @Test void testMapReduce() {
    driver.withInput(new Text('key'), new Text('val'))
        .withOutput(new Text('foo'), new Text('bar'))
        .runTest()
  }
}
</pre>
<p>You can test map and reduce separately, of course. You can also easily verify counters:</p>
<pre class="brush: groovy; light: true; title: ; notranslate">
driver.withInput(...)
driver.run()

def counters = driver.getCounters()

assertEquals(1, counters.findCounter('foo', 'bar').getValue())
</pre>
<p>There&#8217;s a mess of other cool stuff like <em>MockReporter</em> and <em>MockInputSplit</em>, but I mostly haven&#8217;t found a use for them or time to make a simple example.</p>
<h2>The Bad</h2>
<p>Before I tell you to go grab the latest distribution, I want you to know some of the problems we&#8217;ve encountered in the &#8220;real-world&#8221;.</p>
<ol>
<li>First and foremost, MRUnit is <strong>not useful for streaming jobs</strong>. If you only write streaming map-reduce jobs, you&#8217;ll have to do it the old fashioned way</li>
<li>Calling <em>driver.runTest()</em> doesn&#8217;t tell you what the failure was (it just throws an AssertionError). Instead, call <em>def output = driver.run()</em> and assert</li>
<li>The <strong>documentation sucks</strong>. There&#8217;s only one example and the rest you basically have to figure out from the API</li>
<li><em>setup()</em> is called for the new Hadoop API (mapreduce packages) but not the old API (mapred packages). You have to call it yourself if you need it</li>
<li>Finally, tests reuse the same JVM. So <strong>if you&#8217;re accidentally maintaining state in your job, you will be bitten!</strong></li>
</ol>
<h2>Conclusion</h2>
<p>MRUnit makes writing tests for Hadoop easier. It has drawbacks, but they are far outweighed by the benefits.</p>
<p><strong><a href="http://archive.cloudera.com/docs/mrunit/index.html">Grab the latest MRUnit JAR</a></strong></p>
<p>By the way, here&#8217;s how you test a streaming job:</p>
<pre class="brush: plain; light: true; title: ; notranslate">
./myMapper.py &lt; test.input | sort | ./myReducer.py &gt; actual.out
diff expected.out actual.out
</pre>


<p>Related posts:<ol><li><a href='http://eriwen.com/tools/perfect-front-end-build/' rel='bookmark' title='Notes from my pursuit of the perfect front-end build'>Notes from my pursuit of the perfect front-end build</a></li>
<li><a href='http://eriwen.com/python/griffon-jython-plugin/' rel='bookmark' title='Griffon, meet Jython'>Griffon, meet Jython</a></li>
<li><a href='http://eriwen.com/javascript/stacktrace-update/' rel='bookmark' title='Javascript Stacktrace update'>Javascript Stacktrace update</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/EricWendelin?a=bnqWQfUK4Zc:IexZSL6FWA4:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=bnqWQfUK4Zc:IexZSL6FWA4:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=bnqWQfUK4Zc:IexZSL6FWA4:cGdyc7Q-1BI"><img src="http://feeds.feedburner.com/~ff/EricWendelin?d=cGdyc7Q-1BI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=bnqWQfUK4Zc:IexZSL6FWA4:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=bnqWQfUK4Zc:IexZSL6FWA4:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=bnqWQfUK4Zc:IexZSL6FWA4:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/EricWendelin?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=bnqWQfUK4Zc:IexZSL6FWA4:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=bnqWQfUK4Zc:IexZSL6FWA4:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/EricWendelin/~4/bnqWQfUK4Zc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://eriwen.com/hadoop/testing-with-mrunit/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		<feedburner:origLink>http://eriwen.com/hadoop/testing-with-mrunit/</feedburner:origLink></item>
		<item>
		<title>Book Review: MooTools 1.2 Beginner’s Guide</title>
		<link>http://feedproxy.google.com/~r/EricWendelin/~3/Rlw6r5iIrvg/</link>
		<comments>http://eriwen.com/books/mootools-1-2-beginners-guide/#comments</comments>
		<pubDate>Thu, 11 Mar 2010 11:00:23 +0000</pubDate>
		<dc:creator>Eric Wendelin</dc:creator>
				<category><![CDATA[Books]]></category>

		<guid isPermaLink="false">http://eriwen.com/?p=1125</guid>
		<description><![CDATA[<img src="http://static.eriwen.com/images/mootools-beginners.png" alt="MooTools 1.2 Beginner's Guide cover" style="float: left; margin: 0 8px 8px 0; " width="100" height="123"/>I have liked the works of Jacob Gube of <a href="http://sixrevisions.com">Six Revisions</a> and <a href="http://www.garrickcheung.com">Garrick Cheung</a> of the MooTools Community Team, so when <a href="http://www.packtpub.com">Packt Publishing</a> wanted me to review their book, I accepted. 

I hope authors, as well as readers, will gain some insights. Here is my review of <a href="http://www.packtpub.com/mootools-1-2-beginners-guide/book">MooTools 1.2 Beginner's Guide</a>.
 <a href="http://eriwen.com/books/mootools-1-2-beginners-guide/">Continue reading <span class="meta-nav">&#8594;</span></a>


Related posts:<ol><li><a href='http://eriwen.com/javascript/text-size-prefs/' rel='bookmark' title='Guest Post: Save Text Size Preference Using MooTools and PHP'>Guest Post: Save Text Size Preference Using MooTools and PHP</a></li>
<li><a href='http://eriwen.com/css/color-palette-with-css-and-moo/' rel='bookmark' title='Create a Color Palette Using CSS and MooTools 1.2'>Create a Color Palette Using CSS and MooTools 1.2</a></li>
<li><a href='http://eriwen.com/java/scwcd-lessons/' rel='bookmark' title='Lessons learned from the SCWCD'>Lessons learned from the SCWCD</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p><img src="http://static.eriwen.com/images/mootools-beginners.png" alt="MooTools 1.2 Beginner's Guide cover" style="float: left; margin: 0 8px 8px 0; " width="100" height="123"/>I have liked the works of Jacob Gube of <a href="http://sixrevisions.com">Six Revisions</a> and <a href="http://www.garrickcheung.com">Garrick Cheung</a> of the MooTools Community Team, so when <a href="http://www.packtpub.com">Packt Publishing</a> wanted me to review their book, I accepted. </p>
<p>I hope authors, as well as readers, will gain some insights. Here is my review of <a href="http://www.packtpub.com/mootools-1-2-beginners-guide/book">MooTools 1.2 Beginner&#8217;s Guide</a>.</p>
<h2>Book Structure</h2>
<p>The book basically takes you, step-by-step, through downloading the <a href="http://mootools.net">MooTools library</a> parts and building simple examples with HTML, CSS, and, of course, MooTools. It seems to touch on many of major parts of MooTools: Core, DOM selection, Events, Ajax, and Fx. Finally, it introduces you to MooTools More and how to write your own MooTools plugins. it approaches everything with <strong>very simple, very &#8220;hands-on&#8221; examples</strong>. There are some deviations (like pop quizzes), but they are few.</p>
<p>The examples themselves generally introduce a topic, give an HTML/CSS template and then progressively fill in the MooTools bits.</p>
<h2>The Good</h2>
<p>You can tell that the authors are bloggers by their very informal writing style. They know how to use simple language so that their writing does not impede the learning ability of the reader. I was able to read the entire book in about <strong>3 hours cover-to-cover, a testament to how easy-to-read it is</strong>. </p>
<p>This is a book that a real, never-coded-a-web-page-before dude(tte) could pick up and do something with immediately. </p>
<h2>The Bad</h2>
<p>It truly is a <strong>beginner&#8217;s</strong> guide, and having some sort of MooTools knowledge myself I was annoyed by the verboseness of the examples. There seemed to be a lot of times I was seeing a small code example stretched out to several pages of text. </p>
<p>I was slightly disappointed by the number of linguistic (spelling and grammar) mistakes throughout the book. These were obviously not cultural differences between the UK-based Packt and the US. I was always able to understand what the writer meant, but I kept getting hung up on the mistakes because that&#8217;s the kind of asshole I am ;)</p>
<p>I really <strong>missed a good reference or appendix section</strong> at the end where I could find links to more information about the parts of MooTools I was learning about. There was some stuff within the chapter texts, but not enough.</p>
<h2>You should buy this book if&#8230;</h2>
<p>&#8230; you are truly a beginning web developer. This book is a great introduction to web development with a core focus on MooTools. It seems to generally promote good web development practices in my opinion. </p>
<p>Conversely, this book is not great to use just for reference. If you want to lookup anything advanced, it&#8217;s not going to be your best bet. </p>
<p><a href="http://www.packtpub.com/mootools-1-2-beginners-guide/book">MooTools 1.2 Beginner&#8217;s Guide &raquo;</a></p>


<p>Related posts:<ol><li><a href='http://eriwen.com/javascript/text-size-prefs/' rel='bookmark' title='Guest Post: Save Text Size Preference Using MooTools and PHP'>Guest Post: Save Text Size Preference Using MooTools and PHP</a></li>
<li><a href='http://eriwen.com/css/color-palette-with-css-and-moo/' rel='bookmark' title='Create a Color Palette Using CSS and MooTools 1.2'>Create a Color Palette Using CSS and MooTools 1.2</a></li>
<li><a href='http://eriwen.com/java/scwcd-lessons/' rel='bookmark' title='Lessons learned from the SCWCD'>Lessons learned from the SCWCD</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/EricWendelin?a=Rlw6r5iIrvg:Ekgn-XaslK0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=Rlw6r5iIrvg:Ekgn-XaslK0:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=Rlw6r5iIrvg:Ekgn-XaslK0:cGdyc7Q-1BI"><img src="http://feeds.feedburner.com/~ff/EricWendelin?d=cGdyc7Q-1BI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=Rlw6r5iIrvg:Ekgn-XaslK0:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=Rlw6r5iIrvg:Ekgn-XaslK0:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=Rlw6r5iIrvg:Ekgn-XaslK0:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/EricWendelin?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=Rlw6r5iIrvg:Ekgn-XaslK0:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=Rlw6r5iIrvg:Ekgn-XaslK0:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/EricWendelin/~4/Rlw6r5iIrvg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://eriwen.com/books/mootools-1-2-beginners-guide/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://eriwen.com/books/mootools-1-2-beginners-guide/</feedburner:origLink></item>
		<item>
		<title>Leaving Sun/Oracle</title>
		<link>http://feedproxy.google.com/~r/EricWendelin/~3/CvfK7M2z_aI/</link>
		<comments>http://eriwen.com/updates/leaving-sun-oracle/#comments</comments>
		<pubDate>Thu, 25 Feb 2010 11:00:43 +0000</pubDate>
		<dc:creator>Eric Wendelin</dc:creator>
				<category><![CDATA[Updates]]></category>

		<guid isPermaLink="false">http://eriwen.com/?p=1114</guid>
		<description><![CDATA[I had a great 2-and-a-half year journey with Sun, but my time there is sadly at an end. I was very fortunate to have worked with some <a href="http://blogs.sun.com/eric" title="Eric Arseneau">very</a>, <a href="http://fredjean.net" title="Fred Jean">very smart</a> people. We'll certainly keep in touch.

I worked on some really cool internal (and therefore not shareable) projects in Java, Jython, and Web languages and platforms. They were generally fun, diverse and challenging.

<h2>On to Return Path!</h2>
<a href="http://returnpath.net"><img src="http://static.eriwen.com/images/rp-logo.png" alt="Return Path logo" style="margin: 0 8px 8px 0; float: left;"  width="120" height="58"/></a>I'll now be joining a small, agile team at <a href="http://returnpath.net" title="Improve Email Deliverability">Return Path</a>. <strong>We will make email safer, and (I hope) win the war over spam.</strong> Audacious yes. Impossible... I think not.

I wish all my Sun/Oracle counterparts well. Good luck!
 <a href="http://eriwen.com/updates/leaving-sun-oracle/">Continue reading <span class="meta-nav">&#8594;</span></a>


Related posts:<ol><li><a href='http://eriwen.com/python/site-monitor/' rel='bookmark' title='Site monitoring with Python and cron'>Site monitoring with Python and cron</a></li>
<li><a href='http://eriwen.com/javascript/cps-tail-call-elimination/' rel='bookmark' title='Continuation-passing and tail call elimination in Javascript'>Continuation-passing and tail call elimination in Javascript</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<p>I had a great 2-and-a-half year journey with Sun, but my time there is sadly at an end. I was very fortunate to have worked with some <a href="http://blogs.sun.com/eric" title="Eric Arseneau">very</a>, <a href="http://fredjean.net" title="Fred Jean">very smart</a> people. We&#8217;ll certainly keep in touch.</p>
<p>I worked on some really cool internal (and therefore not shareable) projects in Java, Jython, and Web languages and platforms. They were generally fun, diverse and challenging.</p>
<h2>On to Return Path!</h2>
<p><a href="http://returnpath.net"><img src="http://static.eriwen.com/images/rp-logo.png" alt="Return Path logo" style="margin: 0 8px 8px 0; float: left;" width="120" height="58"/></a>I&#8217;ll now be joining a small, agile team at <a href="http://returnpath.net" title="Improve Email Deliverability">Return Path</a>. <strong>We will make email safer, and (I hope) win the war over spam.</strong> Audacious yes. Impossible&#8230; I think not.</p>
<p>I wish all my Sun/Oracle counterparts well. Good luck!</p>


<p>Related posts:<ol><li><a href='http://eriwen.com/python/site-monitor/' rel='bookmark' title='Site monitoring with Python and cron'>Site monitoring with Python and cron</a></li>
<li><a href='http://eriwen.com/javascript/cps-tail-call-elimination/' rel='bookmark' title='Continuation-passing and tail call elimination in Javascript'>Continuation-passing and tail call elimination in Javascript</a></li>
</ol></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/EricWendelin?a=CvfK7M2z_aI:9jboX01JpeY:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=CvfK7M2z_aI:9jboX01JpeY:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=CvfK7M2z_aI:9jboX01JpeY:cGdyc7Q-1BI"><img src="http://feeds.feedburner.com/~ff/EricWendelin?d=cGdyc7Q-1BI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=CvfK7M2z_aI:9jboX01JpeY:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=CvfK7M2z_aI:9jboX01JpeY:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=CvfK7M2z_aI:9jboX01JpeY:I9og5sOYxJI"><img src="http://feeds.feedburner.com/~ff/EricWendelin?d=I9og5sOYxJI" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/EricWendelin?a=CvfK7M2z_aI:9jboX01JpeY:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/EricWendelin?i=CvfK7M2z_aI:9jboX01JpeY:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/EricWendelin/~4/CvfK7M2z_aI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://eriwen.com/updates/leaving-sun-oracle/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		<feedburner:origLink>http://eriwen.com/updates/leaving-sun-oracle/</feedburner:origLink></item>
	</channel>
</rss>

