<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3376508392331888241</id><updated>2012-01-23T10:03:00.615-08:00</updated><category term='ruby'/><category term='couchdb'/><category term='processing'/><category term='groovycasts'/><category term='tools'/><category term='javascript'/><category term='ai'/><category term='clojure'/><category term='erlang'/><category term='dd'/><category term='cappuccino'/><category term='vm'/><category term='junit'/><category term='community'/><category term='gwt'/><category term='maven'/><category term='github'/><category term='environment'/><category term='lua'/><category term='time machine'/><category term='telnetd'/><category term='hadoop'/><category term='geb'/><category term='starcraft'/><category term='firefox'/><category term='grails'/><category term='gradle'/><category term='p2v'/><category term='agile'/><category term='git'/><category term='screencasts'/><category term='jetty'/><category term='haskell'/><category term='nodejs'/><category term='windows'/><category term='app'/><category term='ast'/><category term='dht'/><category term='tdd'/><category term='imagemagick'/><category term='testings'/><category term='cometd'/><category term='training'/><category term='get your groovy on'/><category term='backup'/><category term='tapestry'/><category term='gaelyk'/><category term='anomaly detection'/><category term='arduino'/><category term='linux'/><category term='bittorrent'/><category term='xml'/><category term='lean'/><category term='saaraa'/><category term='reading'/><category term='virtualbox'/><category term='grease monkey'/><category term='java'/><category term='octave'/><category term='process'/><category term='grouch'/><category term='jai'/><category term='webcam'/><category term='mac os x'/><category term='graffiti'/><category term='textmate'/><category term='communication'/><category term='aspectj'/><category term='game'/><category term='test first challenge'/><category term='ideas'/><category term='nas'/><category term='express'/><category term='android'/><category term='groovy app engine'/><category term='groovy'/><category term='mac'/><category term='dominion'/><category term='team'/><category term='fun'/><category term='heroku'/><category term='ubuntu'/><category term='maps'/><category term='jade'/><category term='testing'/><category term='starcraft2'/><category term='coffeescript'/><category term='subversion'/><title type='text'>curious-attempt-bunny</title><subtitle type='html'>Inquisitive guinea pig =&gt;
neugieriges Versuchskaninschen =&gt; curious attemptbunny</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default?start-index=101&amp;max-results=100'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>464</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-7611714759388972102</id><published>2012-01-20T09:02:00.001-08:00</published><updated>2012-01-20T09:09:45.594-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gradle'/><title type='text'>Gradle Goodness</title><content type='html'>This is my final installment, and it's a biggie! This post includes:&lt;br /&gt;* automatically opening test reports on test failure&lt;br /&gt;* grouping tasks for the gradle task list&lt;br /&gt;* renaming all your build.gradle files to match the names of the subprojects&lt;br /&gt;* plugin extensions as the replacement for plugin conventions&lt;br /&gt;* changing the project's artifactId (useful for non-uploadArchive tasks consuming the pom)&lt;br /&gt;* dependency specifications for easy reuse of customizations such as exclusions in multi-project builds&lt;br /&gt;&lt;br /&gt;Automatically opening test reports on test failure. As an added bonus, your headless CI server will return false for Desktop.isDesktopSupported(). Note that this requires JDK 1.6:&lt;pre&gt;&lt;code&gt;test {&lt;br /&gt;    successful = true&lt;br /&gt;&lt;br /&gt;    afterTest { desc, result -&gt;&lt;br /&gt;        if (result.toString() == 'FAILURE') {&lt;br /&gt;         successful = false&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;import java.awt.Desktop&lt;br /&gt;&lt;br /&gt;gradle.taskGraph.afterTask { task, taskState -&gt;&lt;br /&gt;    if (task instanceof Test &amp;&amp; !task.successful) {&lt;br /&gt;        if (Desktop.isDesktopSupported()) {&lt;br /&gt;            Desktop.desktop.browse( new File(task.testReportDir, 'index.html').toURI() )&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;Grouping tasks for the gradle task list. Make use of the Task.group property:&lt;pre&gt;&lt;code&gt;task build(dependsOn: [test, assemble]) {&lt;br /&gt;    group = 'build'&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;Renaming all your build.gradle files to match the names of the subprojects. Place this in your settings.gradle:&lt;pre&gt;&lt;code&gt;rootProject.children.each { project -&gt;&lt;br /&gt;    String fileBaseName = project.name.replaceAll("\\p{Upper}") { "-${it.toLowerCase()}" }&lt;br /&gt;    project.buildFileName = "${fileBaseName}.gradle"&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;Plugin extensions as the replacement for plugin conventions:&lt;pre&gt;&lt;code&gt;project.extensions.myextension = [name: "default"]&lt;br /&gt;&lt;br /&gt;myextension.name = "some other value"&lt;br /&gt;&lt;br /&gt;myextension {&lt;br /&gt;    name = "a different value"&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;Changing the project's artifactId (useful for non-uploadArchive tasks consuming the pom):&lt;pre&gt;&lt;code&gt;project.archivesBaseName = "my-preferred-artifactId"&lt;/code&gt;&lt;/pre&gt;Dependency specifications for easy reuse of customizations such as exclusions in multi-project builds. Use: &lt;code&gt;dependencies.create(notation, closure)&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-7611714759388972102?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/7611714759388972102/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=7611714759388972102' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/7611714759388972102'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/7611714759388972102'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2012/01/gradle-goodness_20.html' title='Gradle Goodness'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-1211898891292888268</id><published>2012-01-18T18:13:00.000-08:00</published><updated>2012-01-18T18:36:24.220-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gradle'/><title type='text'>Gradle Goodness</title><content type='html'>A few more of today's learnings in Gradle:&lt;br /&gt;&lt;br /&gt;When migrating build script code to a plugin you will typically need to add &lt;code&gt;project.&lt;/code&gt; in places (because the delegate of a Gradle build script is the project). You can use &lt;a href="http://gradle.org/docs/current/javadoc/org/gradle/api/Project.html#configure(java.lang.Object, groovy.lang.Closure)"&gt;Project.configure&lt;/a&gt; to make the migration smoother, e.g.:&lt;pre&gt;&lt;code&gt;apply plugin: MyPlugin&lt;br /&gt;&lt;br /&gt;class MyPlugin implements Plugin&lt;Project&gt; {&lt;br /&gt;  void apply(Project project) {&lt;br /&gt;    project.configure(project) {&lt;br /&gt;       version '1.0' // instead of project.version '1.0'&lt;br /&gt;    }&lt;br /&gt;  } &lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;For testing your Gradle plugins you can use &lt;code&gt;ProjectBuilder.builder().build()&lt;/code&gt; to &lt;a href="http://gradle.org/docs/current/userguide/userguide_single.html#N14BFA"&gt;test the wiring of your plugin&lt;/a&gt;. For integration testing there's GradleDistributionExecutor, BUT it's not publically exposed - so please &lt;a href="http://forums.gradle.org/gradle/topics/testing_toolkit_for_custom_build_logic"&gt;vote for the testing toolkit roadmap item&lt;/a&gt; to see this feature sooner.&lt;br /&gt;&lt;br /&gt;So you know about the Copy task. Ever find yourself wanting to be certain that the destination folder is clean of other output? use the &lt;a href="http://gradle.org/docs/current/dsl/org.gradle.api.tasks.Sync.html"&gt;Sync&lt;/a&gt; task. Very nice.&lt;br /&gt;&lt;br /&gt;Find yourself wanting to configure all current and future tasks matching a certain criteria? Take a look at the &lt;a href="http://gradle.org/docs/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:tasks"&gt;project.tasks&lt;/a&gt;. E.g.:&lt;pre&gt;&lt;code&gt;tasks.withType(Jar) {&lt;br /&gt;    aProperty = 'value'&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-1211898891292888268?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/1211898891292888268/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=1211898891292888268' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/1211898891292888268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/1211898891292888268'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2012/01/gradle-goodness_18.html' title='Gradle Goodness'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-8605720678409216813</id><published>2012-01-17T20:12:00.001-08:00</published><updated>2012-01-17T20:28:15.565-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gradle'/><title type='text'>Gradle Goodness</title><content type='html'>A little known fact is that in Gradle you can now change property assignments into method calls in your build scripts (essentially by omitting the equals sign). Here's the good part: if the property does not exist the build script will fail. Yay! No more silent typo bugs! To illustrate, this works:&lt;pre&gt;&lt;code&gt;version = '1.0'&lt;/code&gt;&lt;/pre&gt;As does this:&lt;pre&gt;&lt;code&gt;version '1.0'&lt;/code&gt;&lt;/pre&gt;But this build script will fail:&lt;pre&gt;&lt;code&gt;versionxxx '1.0'&lt;/code&gt;&lt;/pre&gt;Nice!&lt;br /&gt;&lt;br /&gt;Another tip:&lt;br /&gt;&lt;br /&gt;Rather than make use of &lt;code&gt;afterEvaluate&lt;/code&gt; you may be able to make good use of lazy GStrings. For example you could define your project version as &lt;code&gt;"version-${-&gt; buildNumber}"&lt;/code&gt;! See the &lt;a href="http://groovy.codehaus.org/Strings+and+GString"&gt;explanation of Groovy lazy GString syntax&lt;/a&gt; for more information.&lt;br /&gt;&lt;br /&gt;Did you know that the --exclude-task (-x) command-line switch differs from skipping tasks in that it prunes away the whole task graph associated with the excluded task? I didn't!&lt;br /&gt;&lt;br /&gt;Finally, if your company is putting a lot of effort into customizing the Gradle experience, did you know that you could take advantage of Gradle init scripts in the Gradle init.d folder? Yes? Fiddly though, isn't it? Did you know that you can bundle your custom init scripts inside a Gradle distribution?!&lt;br /&gt;&lt;br /&gt;To use this you need to assemble a Gradle distribution zip (basically by adding your init.d scripts to it), make it available internally (say, in your Artifactory repository), and then simply edit your &lt;code&gt;gradle/wrapper/gradle-wrapper.properties&lt;/code&gt;. In there is the URL to download the Gradle distribution (distributionUrl).&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-8605720678409216813?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/8605720678409216813/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=8605720678409216813' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/8605720678409216813'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/8605720678409216813'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2012/01/gradle-goodness.html' title='Gradle Goodness'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-3055515623557161117</id><published>2012-01-12T19:52:00.000-08:00</published><updated>2012-01-12T20:03:09.047-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tapestry'/><category scheme='http://www.blogger.com/atom/ns#' term='gradle'/><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><category scheme='http://www.blogger.com/atom/ns#' term='community'/><category scheme='http://www.blogger.com/atom/ns#' term='geb'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Hackergarten in PDX - Friday January 20th</title><content type='html'>&lt;a href="http://hackergarten.net"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 196px; background-color: #AAAAAA;" src="http://hackergarten.net/hackergarten_b_and_w_small.png" border="0" alt="" /&gt;&lt;/a&gt;I'm taking advantage of Luke Daley coming to town next week, and organizing the first US &lt;a href="http://hackergarten.net"&gt;Hackergarten&lt;/a&gt; here in Portland. The idea is to come up with an improvement to an open source project in a short period of time. I plan to work on &lt;a href="http://issues.gradle.org/browse/GRADLE-1677"&gt;GRADLE-1677&lt;/a&gt;. So far participants include:&lt;br /&gt;* &lt;a href="http://ldaley.com/"&gt;Luke Daley&lt;/a&gt; (of Geb, and Gradle)&lt;br /&gt;* &lt;a href="http://tapestryjava.blogspot.com/"&gt;Howard Lewis Ship&lt;/a&gt; (of Tapestry)&lt;br /&gt;&lt;br /&gt;YesMail is hosting, and we kick off at 6pm on Friday January the 20th. Are you interested? RSVP and I'll send you all the details.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-3055515623557161117?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/3055515623557161117/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=3055515623557161117' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3055515623557161117'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3055515623557161117'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2012/01/hackergarten-in-pdx-friday-january-20th.html' title='Hackergarten in PDX - Friday January 20th'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-46345276428782227</id><published>2012-01-09T17:37:00.000-08:00</published><updated>2012-01-09T18:02:39.054-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ai'/><category scheme='http://www.blogger.com/atom/ns#' term='anomaly detection'/><title type='text'>Machine Learning: Applying Anomaly Detection to Real World Problems</title><content type='html'>I've had a lot of success applying an &lt;a href="http://en.wikipedia.org/wiki/Anomaly_detection"&gt;Anomaly Detection&lt;/a&gt; algorithm to a problem at work. Without revealing anything sensitive, essentially the idea is be able to flag actions taken by the user of the system as "anomalies" and take preventative action.&lt;br /&gt;&lt;br /&gt;There are many ways to do anomaly detection. My data has some characteristics that made the &lt;a href="http://en.wikipedia.org/wiki/Multivariate_Gaussian"&gt;Multivariate Gaussian&lt;/a&gt; approach a good fit, namely:&lt;br /&gt;&lt;br /&gt;* most features follow a normal distribution&lt;br /&gt;* anomalies have features with values on extreme ends of the scale (i.e a number of standard deviations away from the mean)&lt;br /&gt;* feature values are interrelated (i.e. a large value in feature A tends to correspond to a large value in feature B)&lt;br /&gt;&lt;br /&gt;I didn't apply &lt;a href="http://en.wikipedia.org/wiki/Principle_Component_Analysis"&gt;Principle Component Analysis&lt;/a&gt;. I wanted to see how good the results were before complicating the solution. As it turns out, it does pretty well. I had 4271 examples - of which only 3 were labelled as known anomalies. Only 0.5% (24) examples were predicted to be anomalies. All three known anomalies were found, and a further four were uncovered after hand labeling the remaining 21. Very nice indeed!&lt;br /&gt;&lt;br /&gt;This results in a fantastic seeming F1 score (0.998). The fallacy in the calculation is that I haven't hand labeled a representative set of the unlabeled data - i.e. I've made the dangerous assumption that all examples predicted to be normal are indeed normal, and that there were no anomalies in fact predicted to be normal.&lt;br /&gt;&lt;br /&gt;Very rewarding, none the less. All of this enabled by Octave of course. Ahh: &lt;code&gt;hist(X(:,2))&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-46345276428782227?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/46345276428782227/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=46345276428782227' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/46345276428782227'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/46345276428782227'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2012/01/machine-learning-applying-anomaly.html' title='Machine Learning: Applying Anomaly Detection to Real World Problems'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-3631510805915640879</id><published>2012-01-09T12:18:00.000-08:00</published><updated>2012-01-09T12:25:09.514-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='nodejs'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Node: Reading Every Line in a File</title><content type='html'>In Groovy this would be concise: &lt;code&gt;new File(filename).eachLine { ... }&lt;/code&gt;. Here's what it looks like in Node using CoffeeScript:&lt;pre&gt;&lt;code&gt;fs = require('fs')&lt;br /&gt;EM = require('events').EventEmitter&lt;br /&gt;ev = new EM()&lt;br /&gt;stream = fs.createReadStream(filename)&lt;br /&gt;buffer = new Buffer(0)&lt;br /&gt;stream.on 'data', (data) -&gt;&lt;br /&gt;    nextBuffer = new Buffer(buffer.length+data.length)&lt;br /&gt;    buffer.copy(nextBuffer)&lt;br /&gt;    data.copy(nextBuffer, buffer.length)&lt;br /&gt;    start = 0&lt;br /&gt;    offset = buffer.length&lt;br /&gt;    buffer = nextBuffer&lt;br /&gt;&lt;br /&gt;    for i in [1..data.length]&lt;br /&gt;        if data[i] == 10&lt;br /&gt;            end = i+offset+1&lt;br /&gt;            line = buffer.slice start, end&lt;br /&gt;            start = end&lt;br /&gt;            ev.emit "line", line.toString()&lt;br /&gt;&lt;br /&gt;    buffer = buffer.slice start&lt;br /&gt;            &lt;br /&gt;stream.on 'end', () -&gt;&lt;br /&gt;    ev.emit 'line', buffer.toString() unless buffer.length == 0&lt;br /&gt;    &lt;br /&gt;ev.on 'line', (line) -&gt;&lt;br /&gt;    ...&lt;/code&gt;&lt;/pre&gt;Do you have a smarter way of doing this?&lt;br /&gt;&lt;br /&gt;Edit: I'm reading a very large file with this code. That's why this isn't synchronous.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-3631510805915640879?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/3631510805915640879/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=3631510805915640879' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3631510805915640879'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3631510805915640879'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2012/01/node-reading-every-line-in-file.html' title='Node: Reading Every Line in a File'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-8884144239300852586</id><published>2012-01-03T12:38:00.000-08:00</published><updated>2012-01-03T12:43:05.055-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jade'/><category scheme='http://www.blogger.com/atom/ns#' term='nodejs'/><category scheme='http://www.blogger.com/atom/ns#' term='express'/><title type='text'>Escaped HTML in Jade Layout Body</title><content type='html'>&lt;a href="http://jade-lang.com/public/images/logo.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 217px; height: 120px;" src="http://jade-lang.com/public/images/logo.png" border="0" alt="" /&gt;&lt;/a&gt;Jade makes for very readable HTML. The one hurdle that got me was how to reference the body of your view without escaping the HTML. I had been using &lt;code&gt;#{body}&lt;/code&gt;, whereas this does the right thing: &lt;code&gt;div.postings!= body&lt;/code&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-8884144239300852586?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/8884144239300852586/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=8884144239300852586' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/8884144239300852586'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/8884144239300852586'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2012/01/escaped-html-in-jade-layout-body.html' title='Escaped HTML in Jade Layout Body'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-4230862609200275390</id><published>2012-01-03T11:57:00.000-08:00</published><updated>2012-01-03T12:01:53.721-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='coffeescript'/><category scheme='http://www.blogger.com/atom/ns#' term='textmate'/><title type='text'>CoffeeScript Frustrations (in TextMate)</title><content type='html'>&lt;a href="http://2.bp.blogspot.com/-kjhzU0Rth0I/TwNehEFgOfI/AAAAAAAAAa0/c3seOFifVWc/s1600/text%2Bmate%2Bsoft%2Btabs.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 200px; height: 125px;" src="http://2.bp.blogspot.com/-kjhzU0Rth0I/TwNehEFgOfI/AAAAAAAAAa0/c3seOFifVWc/s200/text%2Bmate%2Bsoft%2Btabs.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5693498276051958258" /&gt;&lt;/a&gt;If you're using CoffeeScript in TextMate and you're getting some wierd behaviour (for me are variables being undefined), then TextMate's tabbing may be the problem. First, verify that this is your problem by inspecting the generated JavaScript. If it's the tabbing, switch TextMate to soft tabs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-4230862609200275390?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/4230862609200275390/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=4230862609200275390' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4230862609200275390'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4230862609200275390'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2012/01/coffeescript-frustrations-in-textmate.html' title='CoffeeScript Frustrations (in TextMate)'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-kjhzU0Rth0I/TwNehEFgOfI/AAAAAAAAAa0/c3seOFifVWc/s72-c/text%2Bmate%2Bsoft%2Btabs.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-2168584381675032842</id><published>2011-12-26T14:34:00.000-08:00</published><updated>2011-12-26T14:41:54.793-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xml'/><category scheme='http://www.blogger.com/atom/ns#' term='heroku'/><category scheme='http://www.blogger.com/atom/ns#' term='nodejs'/><title type='text'>Heroku: Parsing RSS Feed XML</title><content type='html'>I want a scheduled job to run on heroku that pulls in data from an external RSS feed. I started out with &lt;a href="https://github.com/polotek/libxmljs"&gt;libxmljs&lt;/a&gt;. Things looked promising until I deployed to heroku. In order to build my slug file libxmljs needs to have access to SCons:&lt;pre&gt;-----&gt; Installing dependencies with npm 1.0.94&lt;br /&gt;       &lt;br /&gt;       &gt; libxmljs@0.4.3 preinstall /tmp/build_16f6d4f95rt18/node_modules/easyrss/node_modules/libxmljs&lt;br /&gt;       &gt; make node&lt;br /&gt;       &lt;br /&gt;       make: scons: Command not found&lt;br /&gt;       make: *** [node] Error 127&lt;br /&gt;       npm ERR! error installing libxmljs@0.4.3 Error: libxmljs@0.4.3 preinstall: `make node`&lt;br /&gt;       npm ERR! error installing libxmljs@0.4.3 `sh "-c" "make node"` failed with 2&lt;/pre&gt;Shame!&lt;br /&gt;&lt;br /&gt;&lt;a href="https://github.com/drudge/node-easyrss"&gt;Easyrss&lt;/a&gt; looked good too but also had the same libxmljs dependency.&lt;br /&gt;&lt;br /&gt;In the end I settled on &lt;a href="https://github.com/Leonidas-from-XIV/node-xml2js"&gt;xml2js&lt;/a&gt; which works just fine. Here's my code snippet:&lt;code&gt;&lt;pre&gt;var request = require('request'),&lt;br /&gt;    xml2js = require('xml2js'),&lt;br /&gt;    _ = require('underscore');&lt;br /&gt;&lt;br /&gt;var parser = new xml2js.Parser();&lt;br /&gt;request('http://url.to.my.rss.feed', function(error, response, body) {&lt;br /&gt;    if (!error &amp;&amp; response.statusCode == 200) {&lt;br /&gt;        parser.parseString(body, function (err, result) {&lt;br /&gt;            _(result.item).each( function(item) {&lt;br /&gt;                console.log(item.title);&lt;br /&gt;            });&lt;br /&gt;        });&lt;br /&gt;    }&lt;br /&gt;});&lt;/pre&gt;&lt;/code&gt;I can exercise the script successfully via &lt;em&gt;heroku run bash&lt;/em&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-2168584381675032842?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/2168584381675032842/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=2168584381675032842' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/2168584381675032842'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/2168584381675032842'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/12/heroku-parsing-rss-feed-xml.html' title='Heroku: Parsing RSS Feed XML'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-9110273888946754093</id><published>2011-12-21T08:52:00.000-08:00</published><updated>2011-12-21T09:01:11.262-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gradle'/><category scheme='http://www.blogger.com/atom/ns#' term='community'/><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><title type='text'>Learn You a Gradle Fu For Great Good</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://gradleware.com/training"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 280px; height: 77px;" src="http://gradle.org/img/gradle_logo.gif" border="0" alt="" /&gt;&lt;/a&gt;It's not too late to sign up for the &lt;a href="http://gradleware.com/training"&gt;Gradle training course&lt;/a&gt; that's coming to PDX in January*! The training came up at last night's PJUG (although Gradle builds for JVM languages in general). Here is my on-list response:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"That [500 line] pom.xml from last night is a great reminder of what is was like to use Maven. Maven is great at dependency management, but terrible at everything else. Gradle build scripts are readable, concise, only go into detail where it matters, and are configurable at a higher level of abstraction than Ant. Perhaps most importantly, Gradle is well documented.&lt;br /&gt;&lt;br /&gt;All that said, there are conventions, idioms, and a certain way of thinking that will heighten your Gradle-fu. You will learn these on your own over time. However, attending the training course is going to be much more time efficient."&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;If you don't know what this is all about, then you should definitely be taking a look at &lt;a href="http://gradle.org/"&gt;Gradle&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;*  Howard Lewis Ship &lt;a href="http://tapestryjava.blogspot.com/2011/11/gradle-training-in-portland.html"&gt;recommends Gradle&lt;/a&gt; too.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-9110273888946754093?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/9110273888946754093/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=9110273888946754093' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/9110273888946754093'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/9110273888946754093'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/12/learn-you-gradle-fu-for-great-good.html' title='Learn You a Gradle Fu For Great Good'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-5915849340930691576</id><published>2011-12-20T21:51:00.000-08:00</published><updated>2011-12-21T20:46:42.474-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ai'/><category scheme='http://www.blogger.com/atom/ns#' term='gradle'/><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><category scheme='http://www.blogger.com/atom/ns#' term='heroku'/><category scheme='http://www.blogger.com/atom/ns#' term='graffiti'/><title type='text'>1. Heroku + Gradle + Graffiti + AI 2. ? 3. Profit!</title><content type='html'>&lt;a href="http://www.heroku.com"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 100px;" src="http://4.bp.blogspot.com/-9qi8NBSLXak/TvF4G_ep9jI/AAAAAAAAAao/5v1Y_SeEOZo/s200/heroku.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5688459865860208178" /&gt;&lt;/a&gt;Very nice. &lt;a href="http://www.jamesward.com/"&gt;James Ward&lt;/a&gt; came to evangelize Heroku at our local usergroup. Thanks, James! Armed with a better understanding of Heroku, I set out to provide a simple web-service on heroku while at the usergroup post-talk bar visit. So, here it is:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://genderservice.heroku.com"&gt;GenderService&lt;/a&gt;! Okay. It's a dubious name, but it does something useful. You can hit the webservice and provide a name and it will infer the gender for you. You can make up a name that doesn't even exist and it will do a reasonable job of determining the gender. Give it a shot!&lt;br /&gt;&lt;br /&gt;Here are some that I tried: (if you browser behaves strangely, it may be detecting that it's JSON and trying to be helpful)&lt;ul&gt;&lt;li&gt;&lt;a href="http://genderservice.heroku.com/resolve?name=bob"&gt;/resolve?name=bob&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://genderservice.heroku.com/resolve?name=pieter"&gt;/resolve?name=pieter&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://genderservice.heroku.com/resolve?name=henryetta"&gt;/resolve?name=henryetta&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://genderservice.heroku.com/resolve?name=san+juilliana"&gt;/resolve?name=san+juilliana&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://genderservice.herokuapp.com/resolve?name=pezra"&gt;/resolve?name=pezra&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;In case you're curious, I'm using ngramms, laplace smoothing, and a smallish labelled dataset to estimate male/female probabilities for a name. If that's interesting to you, and you're local to PDX, consider joining &lt;a href="http://groups.google.com/group/pdxai"&gt;pdxai on googlegroups&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Edit: I've added a confidence to the response. Clearly it's certain that I'm female: &lt;code&gt;{"name":"merlyn","male":false,"confidence":0.995}&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-5915849340930691576?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/5915849340930691576/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=5915849340930691576' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/5915849340930691576'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/5915849340930691576'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/12/1-heroku-gradle-graffiti-ai-2-3-profit.html' title='1. Heroku + Gradle + Graffiti + AI 2. ? 3. Profit!'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-9qi8NBSLXak/TvF4G_ep9jI/AAAAAAAAAao/5v1Y_SeEOZo/s72-c/heroku.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-7081582609867283944</id><published>2011-12-19T07:59:00.000-08:00</published><updated>2011-12-19T08:01:12.488-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ai'/><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><title type='text'>Building a Self-Driving Remote-Control Car</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://blog.davidsingleton.org/nnrccar"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 500px;" src="http://4.bp.blogspot.com/-cAI77tHydBc/Tu9flJk-3DI/AAAAAAAAAac/lY1VZHZoeFo/s400/NeuralNetwork.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5687869946223057970" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Impressive! Take a look at the &lt;a href="http://blog.davidsingleton.org/nnrccar"&gt;full blog post&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-7081582609867283944?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/7081582609867283944/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=7081582609867283944' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/7081582609867283944'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/7081582609867283944'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/12/building-self-driving-remote-control.html' title='Building a Self-Driving Remote-Control Car'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-cAI77tHydBc/Tu9flJk-3DI/AAAAAAAAAac/lY1VZHZoeFo/s72-c/NeuralNetwork.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-5317248297249427991</id><published>2011-11-25T20:38:00.000-08:00</published><updated>2011-11-25T20:51:02.083-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><title type='text'>Learn Me a Haskell</title><content type='html'>* &lt;code&gt;f a&lt;/code&gt; is like &lt;code&gt;f(a)&lt;/code&gt; in Java/C,&lt;br /&gt;* &lt;code&gt;map f [a, b]&lt;code&gt; is the same as [f a, f b]&lt;/code&gt;,&lt;br /&gt;* &lt;code&gt;a $ b $ c&lt;/code&gt; the same as &lt;code&gt;a (b c)&lt;/code&gt;,&lt;br /&gt;* &lt;code&gt;(f . g) x&lt;/code&gt; is the same as &lt;code&gt;f (g x)&lt;/code&gt;,&lt;br /&gt;* &lt;code&gt;digitToInt '1' == 1&lt;/code&gt;,&lt;br /&gt;* &lt;code&gt;"hi" == ['h', 'i']&lt;/code&gt;, and&lt;br /&gt;* &lt;code&gt;show 100 == "100"&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;So, all these expressions evaluate to 6:&lt;code&gt;&lt;pre&gt;Prelude Data.Char&gt; all (==6) [&lt;br /&gt;    sum (map digitToInt (show 123)),&lt;br /&gt;    sum $ map digitToInt $ show 123,&lt;br /&gt;    sum . map digitToInt $ show 123,&lt;br /&gt;    (sum . map digitToInt . show) 123]&lt;br /&gt;True&lt;/pre&gt;&lt;code&gt;It's surprising is how simple the definition for &lt;a href="http://hackage.haskell.org/packages/archive/base/latest/doc/html/Prelude.html#v:-36-"&gt;&lt;code&gt;$&lt;/code&gt;&lt;/a&gt; is:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;f $ x = f x&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-5317248297249427991?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/5317248297249427991/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=5317248297249427991' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/5317248297249427991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/5317248297249427991'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/11/learn-me-haskell.html' title='Learn Me a Haskell'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-1952483667160984517</id><published>2011-11-15T14:07:00.000-08:00</published><updated>2011-11-15T14:08:25.894-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><title type='text'>This Is The Life..</title><content type='html'>&lt;a href="http://1.bp.blogspot.com/-CzhRG7YVeL0/TsLip6BVJoI/AAAAAAAAAaQ/rEtSpo4Xc44/s1600/this%2Bis%2Bthe%2Blife.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 306px;" src="http://1.bp.blogspot.com/-CzhRG7YVeL0/TsLip6BVJoI/AAAAAAAAAaQ/rEtSpo4Xc44/s400/this%2Bis%2Bthe%2Blife.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5675347690017597058" /&gt;&lt;/a&gt;&lt;br /&gt;Sure it's a little chilly this time of year, but coding out on the deck by the fire. Nice!...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-1952483667160984517?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/1952483667160984517/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=1952483667160984517' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/1952483667160984517'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/1952483667160984517'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/11/this-is-life.html' title='This Is The Life..'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-CzhRG7YVeL0/TsLip6BVJoI/AAAAAAAAAaQ/rEtSpo4Xc44/s72-c/this%2Bis%2Bthe%2Blife.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-3913770821358101374</id><published>2011-11-02T21:16:00.000-07:00</published><updated>2011-11-02T21:42:00.352-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ai'/><category scheme='http://www.blogger.com/atom/ns#' term='octave'/><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><title type='text'>Cheating at the Prime Directive?</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://aichallenge.org"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 198px; height: 77px;" src="http://aichallenge.org/images/ants.png" border="0" alt="" /&gt;&lt;/a&gt;So it turns out that an analytic solution to the ant fighting for &lt;a href="http://aichallenge.org"&gt;aichallenge.org&lt;/a&gt; is, well, non-trivial. My new ant bot now does a pretty reasonable job of it, yet the lazy part of me wonders if there's an easier way.&lt;br /&gt;&lt;br /&gt;I've been taking the &lt;a href="http://ml-class.org"&gt;online Machine Learning course at Stanford&lt;/a&gt;, so naturally I wanted to apply last week's theory to it. I wouldn't expect a linear classifier (a one-vs-all linear logistic regression classifier) to actual perform all that well. But it does.&lt;br /&gt;&lt;br /&gt;So. I took replays JSON of games played by the #1 ranked bot. I put the replays through a simple-ish Groovy script, and every time an ant was in proximity to an enemy ant I captured the local surroundings and the corresponding order as a training data example. A few games yielded over 100k unique training data points - which I shuffled to remove any bias in the distribution for the training and test data sets.&lt;br /&gt;&lt;br /&gt;Using &lt;a href="http://www.gnu.org/software/octave/"&gt;Octave&lt;/a&gt; the actual programming for the training was very very simple. Here's a taste of how simple (I haven't posted the sigmoid.m, costFunctionReg.m, or predict.m because they're coursework answers):&lt;code&gt;&lt;pre&gt;clear ; close all; clc&lt;br /&gt;&lt;br /&gt;data = load('training.all.nodupes.shuffled.txt');&lt;br /&gt;yRaw = data(:, [1]); X = [ones(size(yRaw)) data(:, 2:size(data,2))];&lt;br /&gt;&lt;br /&gt;trainSize = 110000;&lt;br /&gt;testSize = length(yRaw)-trainSize;&lt;br /&gt;&lt;br /&gt;lambda = 300;&lt;br /&gt;&lt;br /&gt;fprintf('Training set size: %d\n', trainSize);&lt;br /&gt;fprintf('Test set size: %d\n', testSize);&lt;br /&gt;fprintf('Regularization lambda: %d\n', lambda);&lt;br /&gt;&lt;br /&gt;for yTarget=1:5&lt;br /&gt;  fprintf('Target classification label = %d ...\n', yTarget);&lt;br /&gt;  y = yRaw;&lt;br /&gt;  for i=1:length(y)&lt;br /&gt;    if (y(i) == yTarget)&lt;br /&gt;      y(i) = 1;&lt;br /&gt;    else&lt;br /&gt;      y(i) = 0;&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  trainX = X(1:trainSize, :);&lt;br /&gt;  trainY = y(1:trainSize, :);&lt;br /&gt;  testX = X(trainSize+1:trainSize+testSize, :);&lt;br /&gt;  testY = y(trainSize+1:trainSize+testSize, :);&lt;br /&gt;&lt;br /&gt;  [m, n] = size(trainX);&lt;br /&gt;  initial_theta = zeros(n, 1);&lt;br /&gt; &lt;br /&gt;  options = optimset('GradObj', 'on', 'MaxIter', 1000);&lt;br /&gt;  [theta, cost] = ...&lt;br /&gt;      fminunc(@(t)(costFunctionReg(t, trainX, trainY, lambda)),&lt;br /&gt;          initial_theta, options);&lt;br /&gt; &lt;br /&gt;  fprintf('Train set accuracy: %f\n',&lt;br /&gt;      mean(double(predict(theta, trainX) == trainY)) * 100);&lt;br /&gt;  fprintf('Test set accuracy: %f\n',&lt;br /&gt;      mean(double(predict(theta, testX) == testY)) * 100);&lt;br /&gt;&lt;br /&gt;end&lt;/pre&gt;&lt;/code&gt;And this is the output: (the target classification labels here are N, E, S, W, and - respectively)&lt;code&gt;&lt;pre&gt;octave-3.4.0:36&gt; train&lt;br /&gt;Training set size: 110000&lt;br /&gt;Test set size: 27180&lt;br /&gt;Regularization lambda: 300&lt;br /&gt;Target classification label = 1 ...&lt;br /&gt;Train set accuracy: 79.710909&lt;br /&gt;Test set accuracy: 79.337748&lt;br /&gt;Target classification label = 2 ...&lt;br /&gt;Train set accuracy: 78.755455&lt;br /&gt;Test set accuracy: 78.491538&lt;br /&gt;Target classification label = 3 ...&lt;br /&gt;Train set accuracy: 80.984545&lt;br /&gt;Test set accuracy: 81.111111&lt;br /&gt;Target classification label = 4 ...&lt;br /&gt;Train set accuracy: 78.599091&lt;br /&gt;Test set accuracy: 78.863135&lt;br /&gt;Target classification label = 5 ...&lt;br /&gt;Train set accuracy: 82.936364&lt;br /&gt;Test set accuracy: 83.153054&lt;/pre&gt;&lt;/code&gt;Impressive! Well, the proof is in the pudding. Once this is integrated into an Ant bot I first need to see if it can beat my current Bot.&lt;br /&gt;&lt;br /&gt;If you're reading the Octave source code and feeling cheated, yes, the magic happens inside the &lt;code&gt;fminunc&lt;/code&gt; function. This is part of the beauty of Octave. You don't have to sweat to write a hyper-efficient numerical methods implementation. You don't have to wade through questionable third-party libraries for something that might work. You can use one that's provided and does the job well. Very nice indeed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-3913770821358101374?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/3913770821358101374/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=3913770821358101374' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3913770821358101374'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3913770821358101374'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/11/cheating-at-prime-directive.html' title='Cheating at the Prime Directive?'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-4926477027339023082</id><published>2011-10-29T07:32:00.000-07:00</published><updated>2011-11-13T22:04:22.128-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ai'/><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><title type='text'>Ignore the Prime Directive!?</title><content type='html'>&lt;a href="http://aichallenge.org/profile.php?user=5108"&gt;My bot on aichallenge.org&lt;/a&gt; is doing a reasonable job (rank 205 of 3558 and climbing). Yay! Interestingly, it's doing so well despite not trying to score points and being totally unaware of the enemy.&lt;br /&gt;&lt;br /&gt;Here's a &lt;a href="http://aichallenge.org/visualizer.php?game=26789&amp;user=5108"&gt;recent replay&lt;/a&gt; (my bot is DaBunny, in white):&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-et_Ypl6tItM/TqwPRyiqBdI/AAAAAAAAAZs/4KniOtt5YRo/s1600/lucky.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 500px;" src="http://4.bp.blogspot.com/-et_Ypl6tItM/TqwPRyiqBdI/AAAAAAAAAZs/4KniOtt5YRo/s400/lucky.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5668922829251937746" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Edit: One day later, no changes to the bot code and it's now climbed to rank 93! It's on the &lt;a href="http://aichallenge.org/rankings.php"&gt;main rankings page&lt;/a&gt;. It's rank climbs in 9 out of 10 games it plays. Howsat!?&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-jwyPHOBRBFE/Tq1tTCI0fHI/AAAAAAAAAZ4/wI-hPFirHN8/s1600/ranking.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 500px;" src="http://4.bp.blogspot.com/-jwyPHOBRBFE/Tq1tTCI0fHI/AAAAAAAAAZ4/wI-hPFirHN8/s400/ranking.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5669307679688129650" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Edit: Some weeks later, the most recent incarnation of my bot is in the top 1% (45th of 6000+) and continues to climb (although not much further, I bet):&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-rKDDwSh2sz0/TsCvEnB7DJI/AAAAAAAAAaE/YqslfOi5lfw/s1600/better%2Brank.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 229px; height: 35px;" src="http://4.bp.blogspot.com/-rKDDwSh2sz0/TsCvEnB7DJI/AAAAAAAAAaE/YqslfOi5lfw/s400/better%2Brank.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5674728024218209426" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-4926477027339023082?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/4926477027339023082/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=4926477027339023082' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4926477027339023082'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4926477027339023082'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/10/ignore-prime-directive.html' title='Ignore the Prime Directive!?'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-et_Ypl6tItM/TqwPRyiqBdI/AAAAAAAAAZs/4KniOtt5YRo/s72-c/lucky.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-3963325599519729710</id><published>2011-10-24T06:34:00.001-07:00</published><updated>2011-10-24T06:37:01.123-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='octave'/><title type='text'>Octave on Mac OSX: Aquaterm window opens but GnuPlot window is not displayed</title><content type='html'>This one-liner fixed the problem for me:&lt;code&gt;&lt;pre&gt;sudo ln -s /Applications/GnuPlot.app/Contents/Resources/bin/gnuplot /usr/bin/gnuplot&lt;/pre&gt;&lt;/code&gt;Thanks to Ben Sheldon for the &lt;a href="http://www.island94.org/2007/09/setting-up-octave-and-gnuplot-on-osx/"&gt;solution&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-3963325599519729710?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/3963325599519729710/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=3963325599519729710' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3963325599519729710'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3963325599519729710'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/10/octave-on-mac-osx-aquaterm-window-opens.html' title='Octave on Mac OSX: Aquaterm window opens but GnuPlot window is not displayed'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-554055464112208225</id><published>2011-10-10T21:33:00.001-07:00</published><updated>2011-10-10T21:42:35.868-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='heroku'/><category scheme='http://www.blogger.com/atom/ns#' term='nodejs'/><title type='text'>NodeJS: Heroku push rejected, no Rails or Rack app detected</title><content type='html'>If you're seeing this error when you &lt;em&gt;git push heroku master&lt;/em&gt;:&lt;code&gt;&lt;pre&gt;-----&gt; Heroku receiving push&lt;br /&gt; !     Heroku push rejected, no Rails or Rack app detected&lt;/pre&gt;&lt;/code&gt;... or this error listed by &lt;em&gt;heroku logs&lt;/em&gt;:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;heroku[slugc]: Slug compilation failed: no Rails or Rack app detected&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Then most likely you didn't explicitly specify &lt;em&gt;Cedar&lt;/em&gt; as your heroku stack. You can fix this now by doing the following:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ heroku create --stack cedar&lt;br /&gt;Creating freezing-water-1234... done, stack is cedar&lt;br /&gt;http://freezing-water-1234.herokuapp.com/ | git@heroku.com:freezing-water-1234.git&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Now you need to correct your git remote definition for heroku. I just edited my .git/config file, like so:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;...&lt;br /&gt;[remote "heroku"]&lt;br /&gt; url = git@heroku.com:freezing-water-1234.git&lt;br /&gt;...&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Now &lt;em&gt;git push heroku master&lt;/em&gt; gets you on the right track.&lt;br /&gt;&lt;br /&gt;Hope that helps!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-554055464112208225?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/554055464112208225/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=554055464112208225' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/554055464112208225'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/554055464112208225'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/10/nodejs-heroku-push-rejected-no-rails-or.html' title='NodeJS: Heroku push rejected, no Rails or Rack app detected'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-192530599917612528</id><published>2011-10-10T20:33:00.000-07:00</published><updated>2011-10-10T20:34:53.388-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><title type='text'>Kill Comedy</title><content type='html'>Seriously!?!&lt;br /&gt;&lt;br /&gt;&lt;code&gt;~$ ps -ef | grep sudo&lt;br /&gt;    0 33853     1   0   0:00.01 ??         0:00.01 sudo gem install heroku&lt;br /&gt;    0 33880     1   0   0:00.01 ??         0:00.01 sudo kill -9 33853&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Perhaps this time?&lt;br /&gt;&lt;br /&gt;&lt;code&gt;~$ sudo kill -9 33853 33880&lt;br /&gt;^C^C^C^C^C^C^Z&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Grr...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-192530599917612528?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/192530599917612528/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=192530599917612528' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/192530599917612528'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/192530599917612528'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/10/kill-comedy.html' title='Kill Comedy'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-813698448184147224</id><published>2011-10-10T20:09:00.001-07:00</published><updated>2011-10-10T20:33:35.885-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ai'/><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><title type='text'>Online Stanford AI Course Very Promising!</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://a3.twimg.com/profile_images/1436818544/ai_face_reasonably_small.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 128px; height: 128px;" src="http://a3.twimg.com/profile_images/1436818544/ai_face_reasonably_small.jpg" border="0" alt="" /&gt;&lt;/a&gt;The &lt;a href="http://www.ai-class.com"&gt;online Stanford AI course&lt;/a&gt; started today, and it's looking very promising! The format works well and is particularly effective. They make good use of diagrams, and I particularly liked the chinese translation example with the soup menu. Keep up the good (free!) work, Stanform.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-813698448184147224?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/813698448184147224/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=813698448184147224' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/813698448184147224'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/813698448184147224'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/10/online-stanford-ai-course-very.html' title='Online Stanford AI Course Very Promising!'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-3259792655920799718</id><published>2011-10-06T09:05:00.000-07:00</published><updated>2011-10-06T09:13:44.532-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gradle'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Gradle: One-Time Maven2 pom.xml Dependencies Export</title><content type='html'>Got Maven? Want Gradle? If so, the first bump in the road is extracting all your pom.xml dependencies for your build.gradle. The &lt;a href="https://github.com/jbaruch/maven2gradle"&gt;maven2gradle&lt;/a&gt; tool aims to do this (and more) for you, however if you have a Maven2 pom.xml then you may be &lt;a href="https://github.com/jbaruch/maven2gradle/wiki/FAQ"&gt;out of luck&lt;/a&gt; for the time being.&lt;br /&gt;&lt;br /&gt;In the interim this Groovy 1.8.x script works fine for simple pom.xml files:&lt;code&gt;&lt;pre&gt;def project = new XmlSlurper().parse('pom.xml' as File)&lt;br /&gt;def dependencies = project.dependencies.dependency&lt;br /&gt;def compile = dependencies.findAll { it.scope?.text() != 'test' }&lt;br /&gt;def testCompile = dependencies.findAll { it.scope?.text() == 'test' }&lt;br /&gt;&lt;br /&gt;def printDependency = { type, dep -&gt;&lt;br /&gt;  def identifier =&lt;br /&gt;     "'${dep.groupId.text()}:${dep.artifactId.text()}:${dep.version.text()}'"&lt;br /&gt;  if (!dep.exclusions.size()) {&lt;br /&gt;    println "  $type $identifier"&lt;br /&gt;  } else {&lt;br /&gt;    println "  $type($identifier) {"&lt;br /&gt;    dep.exclusions.each {&lt;br /&gt;      println "    exclude module:'${dep.groupId.text()}', " +&lt;br /&gt;        "artifact: '${dep.artifactId.text()}'"&lt;br /&gt;    }&lt;br /&gt;    println "  }"&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;println "dependencies {"&lt;br /&gt;compile.each( printDependency.curry('compile') )&lt;br /&gt;println()&lt;br /&gt;testCompile.each( printDependency.curry('testCompile') )&lt;br /&gt;println "}"&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-3259792655920799718?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/3259792655920799718/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=3259792655920799718' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3259792655920799718'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3259792655920799718'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/10/gradle-one-time-maven2-pomxml.html' title='Gradle: One-Time Maven2 pom.xml Dependencies Export'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-4320914746443616123</id><published>2011-10-02T10:02:00.001-07:00</published><updated>2011-10-02T10:05:49.480-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='nodejs'/><title type='text'>NodeJS: Error: Cannot find module 'utils'</title><content type='html'>I get this error following the examples in &lt;em&gt;Node Up And Running&lt;/em&gt;:&lt;pre&gt;&lt;code&gt;Error: Cannot find module 'utils'&lt;/code&gt;&lt;/pre&gt;I presume &lt;em&gt;utils&lt;/em&gt; was renamed to &lt;em&gt;util&lt;/em&gt; at some point, because this works for me (in v0.4.12):&lt;pre&gt;&lt;code&gt;var utils = require('util');&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-4320914746443616123?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/4320914746443616123/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=4320914746443616123' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4320914746443616123'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4320914746443616123'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/10/nodejs-error-cannot-find-module-utils.html' title='NodeJS: Error: Cannot find module &apos;utils&apos;'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-7395126704959320919</id><published>2011-09-20T21:20:00.000-07:00</published><updated>2011-09-20T21:21:11.559-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gradle'/><title type='text'>Gradle Build Script Style</title><content type='html'>My thinking follows these lines: I put at the top the parts that will easily help the reader classify what kind of project it is. So, I put plugin declarations like groovy, java, war, etc at the top.&lt;br /&gt;&lt;br /&gt;The next most likely thing I think the reader wants to know when they open a build script is what the dependencies of the project look like. That's why I keep my repositories and dependency definitions very close to the top of the script. I group compile and testCompile dependencies separately, and within those I promote subproject dependencies to the top. I haven't settled on a consistent style for where I place dependencies that I use for JavaExec or ant.taskdef.&lt;br /&gt;&lt;br /&gt;The rest I consider to be the details and the reader can scroll down for those. I keep them following a logical flow from compile and processResources through to assembling artifacts.&lt;br /&gt;&lt;br /&gt;After those come the details of artifact publishing and IDE configuration. These can grow to be big chunks of configuration, that IMO aren't too interesting to the reader. In that case I pull them out into separate build scripts and include them using apply-from.&lt;br /&gt;&lt;br /&gt;The very bottom of the script is where I place functions I've defined and version and task class implementations that are small enough to live in the build script.&lt;br /&gt;&lt;br /&gt;I avoid documenting anything that someone familiar with Gradle would know. I only comment work-arounds or awkward fragments of configuration - anything that someone would miss the significance of in a dangerous way, or anything overly cryptic. A single-line comment normally suffices. Task descriptions I view as optional if the task name itself is explanatory. Task descriptions are a must for rules - however simple they may seem to the author.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-7395126704959320919?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/7395126704959320919/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=7395126704959320919' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/7395126704959320919'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/7395126704959320919'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/09/gradle-build-script-style.html' title='Gradle Build Script Style'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-5435667834692756573</id><published>2011-09-20T21:14:00.000-07:00</published><updated>2011-09-20T21:19:34.978-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gradle'/><title type='text'>Gradle: A POM cannot have multiple artifacts with the same type and classifier.</title><content type='html'>If you're getting this error then likely you were expecting to be publishing your custom jar or zip distribution:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;A POM cannot have multiple artifacts with the same type and classifier.&lt;/pre&gt;&lt;/code&gt;You can go the route of adding a pom filter to promote your artifact and implicitly suppress the publication of the java plugin's "jar" artifact. Yuck.&lt;br /&gt;&lt;br /&gt;Alternatively you can remove the jar artifact from the archives configuration. Due to the current Gradle API this is the most concise I've gotten it:&lt;code&gt;&lt;pre&gt;configurations.archives.removeArtifact( &lt;br /&gt;  configurations.archives.allArtifacts.find {&lt;br /&gt;    it.file == tasks.jar.archivePath } )&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-5435667834692756573?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/5435667834692756573/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=5435667834692756573' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/5435667834692756573'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/5435667834692756573'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/09/gradle-pom-cannot-have-multiple.html' title='Gradle: A POM cannot have multiple artifacts with the same type and classifier.'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-4470807977326014681</id><published>2011-09-20T20:25:00.000-07:00</published><updated>2011-09-20T20:27:49.192-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gradle'/><title type='text'>Running Gradle in a Debugger</title><content type='html'>Launch &lt;code&gt;org.gradle.debug.GradleRunConfiguration&lt;/code&gt; from the Gradle project, pointing it at your build script using &lt;code&gt;-b PATH_TO_SCRIPT/build.gradle&lt;/code&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-4470807977326014681?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/4470807977326014681/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=4470807977326014681' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4470807977326014681'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4470807977326014681'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/09/running-gradle-in-debugger.html' title='Running Gradle in a Debugger'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-3978781287137269463</id><published>2011-09-19T20:05:00.000-07:00</published><updated>2011-09-19T20:16:56.502-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><title type='text'>Three Git "Tricks" I Can't Do Without</title><content type='html'>For various reasons, I prefer command-line access to Git. The main "tricks" I use are (in order of fantasticness):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;I make heavy use of &lt;code&gt;git hist&lt;/code&gt; and &lt;code&gt;git hist --all&lt;/code&gt;. For this you need to add an alias to your .gitconfig:&lt;pre&gt;&lt;code&gt;[alias]&lt;br /&gt; hist = log --pretty=format:\"%h %ad | %s%d [%an]\" --graph --date=short&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;I help avoid mistakenly working on the wrong branch by including the branch name in my terminal prompt. I add this to my .bashrc or .profile file:&lt;pre&gt;&lt;code&gt;function parse_git_branch {&lt;br /&gt; git branch 2&gt; /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1)/'&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;PS1="\w \$(parse_git_branch)\$ "&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;When I want to look at a file on another branch or in a particular commit, I use &lt;code&gt;git show &amp;lt;branch/commit&gt;:&amp;ltfull path&gt;. For example:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;$ git show master:build.gradle&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;Close contenders for the top three are &lt;code&gt;git clean -n&lt;/code&gt; and &lt;code&gt;git cherry-pick &amp;lt;hash&gt;&lt;/code&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-3978781287137269463?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/3978781287137269463/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=3978781287137269463' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3978781287137269463'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3978781287137269463'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/09/three-git-tricks-i-cant-do-without.html' title='Three Git &quot;Tricks&quot; I Can&apos;t Do Without'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-4536384573729489417</id><published>2011-08-21T14:14:00.000-07:00</published><updated>2011-08-22T14:43:52.440-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ai'/><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><title type='text'>AI Challenge</title><content type='html'>There's a simple dice game that you could try your hand at coding an AI for. Interested?&lt;br /&gt;&lt;br /&gt;The game is &lt;a href="http://www.sjgames.com/dice/zombiedice/"&gt;Zombie Dice&lt;/a&gt;. You keep rolling until you either cash out with all your collected brains or you come up with three shotguns and get zero points.&lt;br /&gt;&lt;br /&gt;Improve on my base-line actor!&lt;code&gt;&lt;pre&gt;def actor(state) {&lt;br /&gt;  if (state.shotguns == 2) "stop"&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;The simulator is &lt;a href="https://github.com/curious-attempt-bunny/Braainz"&gt;here on GitHub&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It could be that this problem is too simple. This above benchmarks at an average score per turn of 2.4. This benchmarks at 2.5:&lt;code&gt;&lt;pre&gt;def actor = { state -&gt;&lt;br /&gt;  if (state.shotguns == 2 &amp;&amp; state.score &gt; 0) "stop"&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;And my best idea benchmarks at an average of 2.6. Not much variation, really.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-4536384573729489417?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/4536384573729489417/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=4536384573729489417' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4536384573729489417'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4536384573729489417'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/08/ai-challenge.html' title='AI Challenge'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-253876565998670234</id><published>2011-08-15T15:15:00.000-07:00</published><updated>2011-08-15T15:19:31.689-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jetty'/><title type='text'>Jetty 7.4 Embedded Examples</title><content type='html'>If you're finding that the Embedded Jetty documentation is out of date, then take a look at the source code for the Jetty examples in git:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ git clone git://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project.git&lt;br /&gt;$ cd org.eclipse.jetty.project/example-jetty-embedded/&lt;br /&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-253876565998670234?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/253876565998670234/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=253876565998670234' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/253876565998670234'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/253876565998670234'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/08/jetty-74-embedded-examples.html' title='Jetty 7.4 Embedded Examples'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-3033149862424586586</id><published>2011-07-27T21:13:00.000-07:00</published><updated>2011-07-27T21:21:14.977-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='time machine'/><category scheme='http://www.blogger.com/atom/ns#' term='mac os x'/><category scheme='http://www.blogger.com/atom/ns#' term='nas'/><title type='text'>Mac OSX Time Machine Backup to a NAS</title><content type='html'>This &lt;a href="http://www.readynas.com/?p=253"&gt;guide&lt;/a&gt; will explain all the steps necessary. I stuck with a SMB share rather than hack my NAS (DNS-343) to accept the AFP (Apple File Protocol). If you're like me, you didn't have enough space on your hard drive left to create the initial time machine image. (Why they can't create it directly on the mounted network folder is a mystery to me). In case the guide disappears, here's the essence of it:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ ifconfig en0 | grep ether&lt;br /&gt;$ hdiutil create -size 140g -fs HFS+J -volname "Backup of MACHINENAME" MACHINENAME_MACID.sparsebundle&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;E.g.:&lt;br /&gt;&lt;code&gt;$ hdiutil create -size 140g -fs HFS+J -volname "Backup of magpie" magpie_0016cbaf91d7.sparsebundle&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Then:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ cp magpie_0016cbaf91d7.sparsebundle PATH_TO_NETWORK_MOUNT&lt;br /&gt;$ defaults write com.apple.systempreferences TMShowUnsupportedNetworkVolumes 1&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;All of this will mean that Time Machine will skip the preparing step once you select your network mount and start the backup.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-3033149862424586586?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/3033149862424586586/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=3033149862424586586' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3033149862424586586'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3033149862424586586'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/07/mac-osx-time-machine-backup-to-nas.html' title='Mac OSX Time Machine Backup to a NAS'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-6285418931182448219</id><published>2011-07-27T11:00:00.000-07:00</published><updated>2011-07-27T11:06:30.360-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><category scheme='http://www.blogger.com/atom/ns#' term='community'/><title type='text'>API Hackday</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://apihackdaypdx.eventbrite.com/"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 180px;" src="http://1.bp.blogspot.com/-Akl7Kc90pKU/TjBTMRMRPiI/AAAAAAAAAZk/Nc2agJkFsF4/s320/api%2Bhack%2Bday.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5634094604078890530" /&gt;&lt;/a&gt;I'll be at &lt;a href="http://apihackdaypdx.eventbrite.com/"&gt;API Hackday PDX&lt;/a&gt;. Are you? If you didn't know already, this is what it's about:&lt;br /&gt;&lt;br /&gt;"API Hackday PDX brings developers together the Saturday after OSCON for an all-day coding fest focused on building apps and mashups with APIs. Developers of all experience levels can share ideas, collaborate on existing projects, start new ventures, and find out about great tools and new APIs to play with."&lt;br /&gt;&lt;br /&gt;12 hours of coding alongside other enthusiasts! What's not to like?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-6285418931182448219?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/6285418931182448219/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=6285418931182448219' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/6285418931182448219'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/6285418931182448219'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/07/api-hackday.html' title='API Hackday'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-Akl7Kc90pKU/TjBTMRMRPiI/AAAAAAAAAZk/Nc2agJkFsF4/s72-c/api%2Bhack%2Bday.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-6550331192736078355</id><published>2011-07-27T10:48:00.001-07:00</published><updated>2011-07-27T10:59:04.852-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gwt'/><category scheme='http://www.blogger.com/atom/ns#' term='gradle'/><title type='text'>Compiling Gwt Modules Using Gradle</title><content type='html'>Compiling Gwt modules using Gradle is pretty easy. Here's a nice way to avoid duplication if you have more than one:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;tasks.addRule('Pattern: &amp;lt;module&gt;Gwt') { taskName -&gt;&lt;br /&gt;  if (taskName.endsWith('Gwt')) {&lt;br /&gt;    task "$taskName" (dependsOn: 'classes', type: JavaExec) {&lt;br /&gt;      inputs.dir sourceSets.main.classesDir&lt;br /&gt;      outputs.dir "$buildDir/gen"&lt;br /&gt;      main = 'com.google.gwt.dev.Compiler'&lt;br /&gt;      classpath {&lt;br /&gt;        [ sourceSets.main.java.srcDirs,&lt;br /&gt;          sourceSets.main.runtimeClasspath,&lt;br /&gt;          configurations.gwt ]&lt;br /&gt;      }&lt;br /&gt;      args 'com.myplace.mypackage.' + (taskName - 'Gwt'),&lt;br /&gt;         '-war', "$buildDir/gen",&lt;br /&gt;         '-localWorkers', '2',&lt;br /&gt;         '-style', 'PRETTY',&lt;br /&gt;         '-draftCompile'&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;Note the &lt;code&gt;configurations.gwt&lt;/code&gt; which is a clean way of adding dependencies that are only required by the GWT compiler. E.g.:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;configurations {&lt;br /&gt;  gwt&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;dependencies {&lt;br /&gt;  gwt ( group:'javax.validation', name:'validation-api',&lt;br /&gt;        version:'1.0.0.GA', classifier:'sources' )&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-6550331192736078355?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/6550331192736078355/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=6550331192736078355' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/6550331192736078355'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/6550331192736078355'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/07/compiling-gwt-modules-using-gradle.html' title='Compiling Gwt Modules Using Gradle'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-3179361337250875768</id><published>2011-07-26T07:06:00.000-07:00</published><updated>2011-07-26T07:10:24.121-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><category scheme='http://www.blogger.com/atom/ns#' term='community'/><title type='text'>See You At ScaleOutCamp?</title><content type='html'>I'll be at &lt;a href="http://www.cloudcamp.org/pdx"&gt;ScaleOutCamp&lt;/a&gt; this evening. It's not too late to &lt;a href="http://cloudcamp-pdx.eventbrite.com/"&gt;sign up&lt;/a&gt; for the free event. See you there!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-3179361337250875768?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/3179361337250875768/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=3179361337250875768' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3179361337250875768'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3179361337250875768'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/07/see-you-at-scaleoutcamp.html' title='See You At ScaleOutCamp?'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-4969579240699177206</id><published>2011-07-26T07:02:00.000-07:00</published><updated>2011-07-26T07:05:41.576-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='graffiti'/><category scheme='http://www.blogger.com/atom/ns#' term='get your groovy on'/><title type='text'>Get Your Groovy On #2 - Graffiti</title><content type='html'>I've just posted my second &lt;a href="http://groovycasts.org/post/8085311782/get-your-groovy-on-graffiti"&gt;Get Your Groovy On&lt;/a&gt; screencast to &lt;a href="http://groovycasts.org"&gt;groovycasts.org&lt;/a&gt;. It's an example of simple RESTful web services in Groovy using Graffiti. &lt;a href="http://groovycasts.org/post/8085311782/get-your-groovy-on-graffiti"&gt;Take a look&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-4969579240699177206?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/4969579240699177206/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=4969579240699177206' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4969579240699177206'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4969579240699177206'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/07/get-your-groovy-on-2-graffiti.html' title='Get Your Groovy On #2 - Graffiti'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-6837217920716170180</id><published>2011-07-23T11:23:00.001-07:00</published><updated>2011-10-06T09:14:44.745-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='github'/><title type='text'>Getting Away With Bad Git Amend Behaviour</title><content type='html'>Ahem. Ever do this?&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ git commit ...&lt;br /&gt;$ git push&lt;br /&gt;$ git commit --amend ...&lt;br /&gt;$ git push&lt;br /&gt;To git@github.com:curious-attempt-bunny/gradle-github-deployer.git&lt;br /&gt; ! [rejected]        master -&gt; master (non-fast-forward)&lt;br /&gt;error: failed to push some refs to 'git@github.com:curious-attempt-bunny/gradle-github-deployer.git'&lt;br /&gt;To prevent you from losing history, non-fast-forward updates were rejected&lt;br /&gt;Merge the remote changes (e.g. 'git pull') before pushing again.  See the 'Note about fast-forwards' section of 'git push --help' for details.&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;BOOM! Whoops, yes, you forgot that you shouldn't be amending commits that you've already pushed to GitHub!&lt;br /&gt;&lt;br /&gt;Here's the hackster way out (very very bad if anyone happens to have pulled or pushed in the interim):&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ git push origin +master:master&lt;br /&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-6837217920716170180?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/6837217920716170180/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=6837217920716170180' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/6837217920716170180'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/6837217920716170180'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/07/getting-awat-with-bad-git-amend.html' title='Getting Away With Bad Git Amend Behaviour'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-1534367487968664599</id><published>2011-07-23T10:40:00.000-07:00</published><updated>2011-07-23T10:45:20.792-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gradle'/><category scheme='http://www.blogger.com/atom/ns#' term='github'/><title type='text'>Gradle - Could not find implementation class 'null' for plugin</title><content type='html'>I'm having fun hacking together a &lt;a href="https://github.com/curious-attempt-bunny/gradle-github-deployer"&gt;GitHub deployer plugin&lt;/a&gt; for Gradle. I just saw this error message. This means that there's a typo in your class name in your &lt;code&gt;META-INF/gradle-plugins/PLUGIN_NAME.properties&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Caused by: org.gradle.api.plugins.PluginInstantiationException: Could not find implementation class 'null' for plugin 'githubDeployer' specified in jar:file:/Users/user/Documents/fun/gradle/gradle-github-deployer/plugin/build/libs/gradle-github-deployer-hack-0.1-SNAPSHOT.jar!/META-INF/gradle-plugins/githubDeployer.properties&lt;br /&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-1534367487968664599?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/1534367487968664599/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=1534367487968664599' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/1534367487968664599'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/1534367487968664599'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/07/gradle-could-not-find-implementation.html' title='Gradle - Could not find implementation class &apos;null&apos; for plugin'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-2921914874550509481</id><published>2011-07-22T16:52:00.000-07:00</published><updated>2011-07-22T17:09:52.305-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='jai'/><title type='text'>Chess Board Computer Vision</title><content type='html'>This is a topic that I keep coming back to. This time for Chess. The goal is to extract chess notation for a game played in view of a webcam. This time I made it harder for myself by viewing the board from an angle. I wrote it in Groovy using platform-independent JAI (Java Advanced Imaging). I've cheated on the webcam capture, and used Photo Booth stills to begin with. This time, though, &lt;a href="https://github.com/curious-attempt-bunny/chess-board-computer-vision"&gt;I'm sharing the code on GitHub&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;For each frame I do the following:&lt;br /&gt;1. Convert to grayscale using "bandcombine":&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-L119xg4gVsQ/TioODdHHjTI/AAAAAAAAAY0/RFeWl9-CiCw/s1600/step1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://1.bp.blogspot.com/-L119xg4gVsQ/TioODdHHjTI/AAAAAAAAAY0/RFeWl9-CiCw/s320/step1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5632329736497106226" /&gt;&lt;/a&gt;&lt;br /&gt;2. Correct for perspective using PerspectiveTransform.getQuadToQuad and "warp": (I noted the pixel coordinates for the corners of the board by hand)&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-yXKbNFjL4Jg/TioODnHxnuI/AAAAAAAAAY8/bMSPI6G702Y/s1600/step2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 320px;" src="http://4.bp.blogspot.com/-yXKbNFjL4Jg/TioODnHxnuI/AAAAAAAAAY8/bMSPI6G702Y/s320/step2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5632329739184217826" /&gt;&lt;/a&gt;&lt;br /&gt;3. Binarize upper and lower bands of the image histogram and OR them together (so that a white pixel ideally identifies the presence of a piece on the board) -- using "histogram", "binarize", OrDescriptor, and SubtractDescriptor:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-kyHsJuViqbk/TioOD2YMWYI/AAAAAAAAAZE/iITzKIMEjOo/s1600/step3.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 320px;" src="http://4.bp.blogspot.com/-kyHsJuViqbk/TioOD2YMWYI/AAAAAAAAAZE/iITzKIMEjOo/s320/step3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5632329743279610242" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Then I take each processed frame and its following processed frame, and do the following:&lt;br /&gt;1. XOR the two frames using XorDescriptor:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-CCnzKlCLoco/TioOEPR77AI/AAAAAAAAAZM/4L-xnMB30fM/s1600/step4.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 320px;" src="http://4.bp.blogspot.com/-CCnzKlCLoco/TioOEPR77AI/AAAAAAAAAZM/4L-xnMB30fM/s320/step4.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5632329749964254210" /&gt;&lt;/a&gt;&lt;br /&gt;2. Erode the result using "erode":&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-KjIGa7pj8FU/TioOEX0uMeI/AAAAAAAAAZU/sMxcXYUNkwM/s1600/step5.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 320px;" src="http://4.bp.blogspot.com/-KjIGa7pj8FU/TioOEX0uMeI/AAAAAAAAAZU/sMxcXYUNkwM/s320/step5.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5632329752257638882" /&gt;&lt;/a&gt;&lt;br /&gt;3. Open it using "dilate" and then "erode":&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-VMimtJ9VRxI/TioOJt3TElI/AAAAAAAAAZc/_-2ZfrIav-4/s1600/step6.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 320px;" src="http://2.bp.blogspot.com/-VMimtJ9VRxI/TioOJt3TElI/AAAAAAAAAZc/_-2ZfrIav-4/s320/step6.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5632329844073370194" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The result would ideally show clusters of pixels in the board squares that have changed (e2 to e4 in this example). Unfortunately, a naive solution here isn't enough as pieces span multiple board locations. Also the piece detection algorithm in step 3 of frame processing is too weak.&lt;br /&gt;&lt;br /&gt;Feel free to ask questions if you're interested.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-2921914874550509481?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/2921914874550509481/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=2921914874550509481' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/2921914874550509481'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/2921914874550509481'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/07/chess-board-computer-vision.html' title='Chess Board Computer Vision'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-L119xg4gVsQ/TioODdHHjTI/AAAAAAAAAY0/RFeWl9-CiCw/s72-c/step1.png' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-3062954746406549634</id><published>2011-07-10T09:15:00.001-07:00</published><updated>2011-07-16T18:53:05.969-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='screencasts'/><category scheme='http://www.blogger.com/atom/ns#' term='get your groovy on'/><category scheme='http://www.blogger.com/atom/ns#' term='groovycasts'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Groovy Screencasts</title><content type='html'>This is an idea I've been wanting to act on for a while. There aren't a lot of screencasts around on Groovy. With that in mind, I've created &lt;a href="http://groovycasts.org"&gt;groovycasts.org&lt;/a&gt; and to kick things off I've recorded &lt;a href="http://groovycasts.org/post/7421137124/get-your-groovy-on"&gt;Get Your Groovy On&lt;/a&gt;. It's hard to cover much in 5 minutes, so this overview doesn't linger to go into detail. I'll gladly deep dive on a topic, though. What's of most interest to you? Let me know.&lt;br /&gt;&lt;br /&gt;Here's the screencast (now with corrected audio):&lt;br /&gt;&lt;br /&gt;&lt;iframe width="500" height="368" src="http://www.youtube.com/embed/-zcZVb_hR_Q?hl=en&amp;fs=1" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-3062954746406549634?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/3062954746406549634/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=3062954746406549634' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3062954746406549634'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3062954746406549634'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/07/groovy-screencasts.html' title='Groovy Screencasts'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://img.youtube.com/vi/-zcZVb_hR_Q/default.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-3529230978352867838</id><published>2011-06-05T23:35:00.000-07:00</published><updated>2011-06-05T23:38:50.657-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='community'/><category scheme='http://www.blogger.com/atom/ns#' term='saaraa'/><title type='text'>SAARAA Wins First Place at RHOK 3</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.rhok.org/"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 200px; height: 64px;" src="http://4.bp.blogspot.com/-m87cXQRO03U/TewLh2haiZI/AAAAAAAAAYM/3bPhFD6RGIc/s200/rhok_logo_CS4.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5614875511623420306" /&gt;&lt;/a&gt;Our &lt;a href="http://www.rhok.org/problems/saaraa-situational-awareness-and-rapid-assessment-application"&gt;SAARAA project&lt;/a&gt; for &lt;a href="http://www.rhok.org/"&gt;Seattle RHOK #3&lt;/a&gt; won first place! Woot!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-3529230978352867838?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/3529230978352867838/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=3529230978352867838' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3529230978352867838'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3529230978352867838'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/06/saaraa-wins-first-place-at-rhok-3.html' title='SAARAA Wins First Place at RHOK 3'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-m87cXQRO03U/TewLh2haiZI/AAAAAAAAAYM/3bPhFD6RGIc/s72-c/rhok_logo_CS4.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-4399468159754268173</id><published>2011-06-05T16:01:00.000-07:00</published><updated>2011-06-05T16:05:44.236-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><category scheme='http://www.blogger.com/atom/ns#' term='community'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Participated in RHOK #3 Seattle</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.rhok.org/"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 200px; height: 64px;" src="http://4.bp.blogspot.com/-m87cXQRO03U/TewLh2haiZI/AAAAAAAAAYM/3bPhFD6RGIc/s200/rhok_logo_CS4.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5614875511623420306" /&gt;&lt;/a&gt;I'm having a productive and engaging time here at RHOK #3 Seattle. I'm on the &lt;a href="http://www.rhok.org/problems/saaraa-situational-awareness-and-rapid-assessment-application"&gt;SAARAA (Situational Awareness And Rapid Assessment App)&lt;/a&gt; team. We've put together a client-server app using the Android SDK, Sinatra, and MongoDb.&lt;br /&gt;&lt;br /&gt;Our github repositories are here:&lt;br /&gt;* &lt;a href="https://github.com/chrismetcalf/saaraa"&gt;server-side&lt;/a&gt;&lt;br /&gt;* &lt;a href="https://github.com/curious-attempt-bunny/SAARAA"&gt;client-side&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-4399468159754268173?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/4399468159754268173/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=4399468159754268173' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4399468159754268173'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4399468159754268173'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/06/participated-in-rhok-3-seattle.html' title='Participated in RHOK #3 Seattle'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-m87cXQRO03U/TewLh2haiZI/AAAAAAAAAYM/3bPhFD6RGIc/s72-c/rhok_logo_CS4.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-6058310877117664743</id><published>2011-04-30T10:36:00.000-07:00</published><updated>2011-04-30T10:38:39.175-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><title type='text'>Updating a Forked Git Repository</title><content type='html'>I keep forgetting how to do this and have to hunt for the &lt;a href="http://help.github.com/fork-a-repo/"&gt;documentation&lt;/a&gt;. Here's the solution:&lt;code&gt;&lt;pre&gt;$ git remote add upstream git://github.com/teamrabu/rabu-schedule.git&lt;br /&gt;$ git fetch upstream&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-6058310877117664743?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/6058310877117664743/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=6058310877117664743' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/6058310877117664743'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/6058310877117664743'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/04/updating-forked-git-repository.html' title='Updating a Forked Git Repository'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-3631430647185520233</id><published>2011-04-29T19:40:00.000-07:00</published><updated>2011-04-29T19:42:30.206-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='community'/><title type='text'>I'm on the SAO QA Forum Panel June 2nd</title><content type='html'>I'm on the Panel for the Software Association of Oregon QA Forum June 2nd. There's a fee to attend:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.sao.org/events/event_details.asp?id=150727"&gt;Agile Death Match – Is QA obsolete in Agile?&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Agile turns 10 years old this year and for 9.999 years we have struggled to understand QA’s role in a Agile environment.  Come join us as some of the region’s top Agilest and Quality professionals share their real world experience implementing QA in a agile world.&lt;br /&gt; &lt;br /&gt;This lunch time presentation is ideal for the QA Engineer, Software Developer or IT leader who is trying implement or improve quality practices in a Agile team.&lt;br /&gt; &lt;br /&gt;The intent is not to promote or redefine the Agile model, but rather to discuss the various ways the QA role has been impacted and has adjusted to the current model.&lt;br /&gt;Please join us for this informative and interactive discussion followed by a Q&amp;A session.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-3631430647185520233?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/3631430647185520233/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=3631430647185520233' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3631430647185520233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3631430647185520233'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/04/im-on-sao-qa-forum-panel-june-2nd.html' title='I&apos;m on the SAO QA Forum Panel June 2nd'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-1413441978351392940</id><published>2011-04-03T20:04:00.000-07:00</published><updated>2011-04-03T20:14:07.609-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='test first challenge'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Test First Challenge - Modernized For The Lazy!</title><content type='html'>Did you ever try the &lt;a href="http://xp123.com/articles/test-first-challenge/"&gt;original&lt;/a&gt; Test First Challenge? You should have!&lt;br /&gt;&lt;br /&gt;So what have I done with it?&lt;br /&gt;&lt;br /&gt;* I've taken the tests and converted them to Spock specifications&lt;br /&gt;* A Gradle build script creates your IDE setup&lt;br /&gt;* The Gradle will add each new test as your code passes them&lt;br /&gt;&lt;br /&gt;Check out the &lt;a href="https://github.com/curious-attempt-bunny/test-first-challenge"&gt;test-first-challenge project on github&lt;/a&gt;. The project is ready to go for either a Java or Groovy solution to the challenge.&lt;br /&gt;&lt;br /&gt;Leave feedback here. Repository forks and pull requests welcome!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-1413441978351392940?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/1413441978351392940/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=1413441978351392940' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/1413441978351392940'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/1413441978351392940'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/04/test-first-challenge-modernized-for.html' title='Test First Challenge - Modernized For The Lazy!'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-7660412484848385613</id><published>2011-03-11T22:33:00.000-08:00</published><updated>2011-03-11T23:00:30.054-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='community'/><category scheme='http://www.blogger.com/atom/ns#' term='training'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Free Groovy Training Workshop in Portland</title><content type='html'>&lt;img style="float:right; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 203px; height: 100px; border:0px;" src="http://media.xircles.codehaus.org/_projects/groovy/_logos/medium.png" border="0" alt="Groovy training workshop"/&gt;Hey there!&lt;br /&gt;&lt;br /&gt;In preparation for Open Source Bridge 2011, I'm offering a Groovy training workshop at not cost to:&lt;ul&gt;&lt;li&gt;motivated Java developers,&lt;/li&gt;&lt;li&gt;from the Portland community,&lt;/li&gt;&lt;li&gt;with little-to-no Groovy experience&lt;/li&gt;&lt;/ul&gt;in exchange for feedback for improving the session.&lt;br /&gt;&lt;br /&gt;It'll be two hours long, collaborative, practical, and above all: fun! I haven't set a date yet. Follow up with me at: curious dot attempt dot bunny at gmail dot com with a subject line of &lt;em&gt;Free Groovy Training Workshop&lt;/em&gt;.&lt;br /&gt;&lt;br /&gt;Cheers,&lt;br /&gt;Merlyn&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-7660412484848385613?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/7660412484848385613/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=7660412484848385613' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/7660412484848385613'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/7660412484848385613'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/03/free-groovy-training-workshop-in.html' title='Free Groovy Training Workshop in Portland'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-3825887013957551473</id><published>2011-03-09T21:31:00.000-08:00</published><updated>2011-03-09T21:42:05.631-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='community'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Groovy For Java Developers - My Open Source Bridge Session</title><content type='html'>&lt;a href="http://opensourcebridge.org/?ref=2011submit125" &gt;&lt;img src="http://opensourcebridge.org/badges/2011/submit125.png" alt="I’m Submitting a Talk to Open Source Bridge – June 21–24, 2011 – Portland, OR" border="0" align="left" style="padding-right: 10px; border: 0px;"/&gt;&lt;/a&gt;&lt;br /&gt;I've submitted a session to &lt;em&gt;Open Source Bridge – June 21–24, 2011 – Portland, OR&lt;/em&gt;. Please comment on my proposal for a &lt;a href="http://opensourcebridge.org/proposals/573"&gt;Groovy For Java Developers&lt;/a&gt; session. Here's the teaser - follow the &lt;a href="http://opensourcebridge.org/proposals/573"&gt;link&lt;/a&gt; for the full description:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;Groovy is a powerful and concise language for the JVM that extends the capabilities of Java. Idiomatic Groovy can be intimidating to Java developers. This session will break the ice and reveal some of the power of Groovy as well as some of the traps.&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-3825887013957551473?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/3825887013957551473/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=3825887013957551473' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3825887013957551473'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3825887013957551473'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/03/groovy-for-java-developers-my-open.html' title='Groovy For Java Developers - My Open Source Bridge Session'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-7693794692908922329</id><published>2011-02-23T09:05:00.000-08:00</published><updated>2011-02-23T09:08:40.776-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gradle'/><title type='text'>Developing &amp; Testing Gradle Plugins</title><content type='html'>Here's a quick lazy post from me. I've been working on a &lt;a href="https://github.com/curious-attempt-bunny/gradle-onejar"&gt;Gradle OneJar plugin&lt;/a&gt;, and struggled along the way. This is a post to the gradle-user mailing list that I think it particularly helpful:&lt;code&gt;&lt;pre&gt;Thanks for this, Peter. It's very helpful information.&lt;br /&gt;&lt;br /&gt;On Wed, 2011-02-23 at 08:35 -0800, Peter Niederwieser wrote: &lt;br /&gt;&gt; &gt; I have a plugin I'm working on, and as far as I can tell I can't make a&lt;br /&gt;&gt; &gt; multiproject build where one subproject consumes the plugin artifact&lt;br /&gt;&gt; &gt; generated by the other subproject.&lt;br /&gt;&gt; &gt; &lt;br /&gt;&gt; &lt;br /&gt;&gt; I think that putting the plugin artifact on the other script's class path&lt;br /&gt;&gt; (with a buildscript {} section) should work.&lt;br /&gt;&lt;br /&gt;Hmm. It sounds like you're saying that the evaluation of subproject A&lt;br /&gt;can depend on the execution of a task in subproject B. I didn't think&lt;br /&gt;that was possible. &lt;br /&gt;&lt;br /&gt;&gt; &gt; Perhaps the gradle developers could shed some light on this. Which&lt;br /&gt;&gt; &gt; versions&lt;br /&gt;&gt; &gt; of the gradle java and groovy plugins does the gradle project itself&lt;br /&gt;&gt; &gt; consume&lt;br /&gt;&gt; &gt; during a build?&lt;br /&gt;&gt; &gt; &lt;br /&gt;&gt; &lt;br /&gt;&gt; Before Gradle's integration tests are run, a full distribution is built,&lt;br /&gt;&gt; which will then be used by the integration tests. So the tests will always&lt;br /&gt;&gt; use the latest Java and Groovy plugins.&lt;br /&gt;&lt;br /&gt;So for me there's good news and bad news. The bad news is that there's&lt;br /&gt;no magic to make this a simple matter of configuring my build script.&lt;br /&gt;The good news is that there are some gradle-core integration test&lt;br /&gt;support classes.&lt;br /&gt;&lt;br /&gt;For anyone else wanting to integration test their plugins, take a look&lt;br /&gt;at the org.gradle.integtests package in gradle-core - particularly&lt;br /&gt;org.gradle.integtests.fixtures. And for examples of their usage look at&lt;br /&gt;the gradle integ-test subproject.&lt;br /&gt;&lt;br /&gt;Thanks again, Peter!&lt;br /&gt;Merlyn&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-7693794692908922329?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/7693794692908922329/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=7693794692908922329' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/7693794692908922329'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/7693794692908922329'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/02/developing-testing-gradle-plugins.html' title='Developing &amp; Testing Gradle Plugins'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-716197341233013930</id><published>2011-02-10T09:00:00.000-08:00</published><updated>2011-02-13T19:33:29.815-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='community'/><title type='text'>My Agile Open NW 2011 Brain Dump</title><content type='html'>&lt;p&gt;These are potential talking points from AONW that I'm happy to discuss further:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Sessions I hosted: (flipchart photos uploaded)&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.agileopennorthwest.com/wiki/index.php/Getting_to_Thin_Releaseable_Slices_%26%26_Working_Tiny-er" class="external-link" rel="nofollow"&gt;Getting To Thin Releasable Slices &amp;amp; Working Tiny-er&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.agileopennorthwest.com/wiki/index.php/How_Meta-Programming_is_changing_the_way_you_think" class="external-link" rel="nofollow"&gt;How Meta-Programming Is Changing The Way You Think&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.agileopennorthwest.com/wiki/index.php/AONW_Feedback_Via_The_Perfection_Game" class="external-link" rel="nofollow"&gt;AONW Feedback Via The Perfection Game&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.agileopennorthwest.com/wiki/index.php/Improving_Your_Facilitation_Skills" class="external-link" rel="nofollow"&gt;Improving Your Facilitation Skills&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Sessions that made a big impression:&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.agileopennorthwest.com/wiki/index.php/Core_Protocols_%28Software_For_You_Head%29" class="external-link" rel="nofollow"&gt;Core Protocols "Software For Your Head"&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Coaching Dojo&lt;/li&gt;&lt;li&gt;Imago Dialogue&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Maxims I noted down:&lt;ul&gt;&lt;li&gt;(on process obstacles) "No precious resources" ... (regarding the solution) "Make it repeatable"&lt;/li&gt;&lt;li&gt;(on pairing) "We all have strengths in different areas. We can lead in different areas. Let's talk about it"&lt;/li&gt;&lt;li&gt;(on stunting leadership growth) "Find excuses to be out of the room"&lt;/li&gt;&lt;li&gt;(on talking about a sensitive topic) "What's the worst thing that could happen?"&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Ideas I noted down:&lt;ul&gt;&lt;li&gt;Use CI Servers to build VM Images with complete deployments&lt;/li&gt;&lt;li&gt;Coaching: Vent vs Help / Talk vs Answer&lt;/li&gt;&lt;li&gt;Coaching:&lt;ul&gt;&lt;li&gt;Paraphrase&lt;/li&gt;&lt;li&gt;Ask from more (how is it?)&lt;/li&gt;&lt;li&gt;What have you tried&lt;/li&gt;&lt;li&gt;Characterize the situation&lt;/li&gt;&lt;li&gt;How do others perceive it&lt;/li&gt;&lt;li&gt;Not being emotionally involved or taking sides&lt;/li&gt;&lt;li&gt;Pausing&lt;/li&gt;&lt;li&gt;Mirroring what's understood&lt;/li&gt;&lt;li&gt;Mirroring body language&lt;/li&gt;&lt;li&gt;Mirroring pace of speech&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;Edit: Jeremy Lightsmith pointed me at &lt;a href="http://grouppatternlanguage.org/wagn/Divergence_and_Convergence_Rhythm"&gt;Group Pattern Language&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-716197341233013930?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/716197341233013930/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=716197341233013930' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/716197341233013930'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/716197341233013930'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/02/my-agile-open-nw-2011-brain-dump.html' title='My Agile Open NW 2011 Brain Dump'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-2286028793806208124</id><published>2011-02-09T19:48:00.000-08:00</published><updated>2011-02-09T19:49:31.503-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='community'/><title type='text'>Agile Open Northwest 2011 Is Over</title><content type='html'>It's over! I put all the material I captured on the &lt;a href="http://www.agileopennorthwest.com/wiki/index.php/Agile_Open_Northwest_2011_Session_Notes"&gt;wiki page&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-2286028793806208124?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/2286028793806208124/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=2286028793806208124' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/2286028793806208124'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/2286028793806208124'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/02/agile-open-northwest-2011-is-over.html' title='Agile Open Northwest 2011 Is Over'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-3217087255624333889</id><published>2011-02-06T20:12:00.000-08:00</published><updated>2011-02-06T20:25:43.352-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><title type='text'>Installing Windows7 On A Machine Without Windows On It</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://blog.seattlepi.com/microsoft/library/20091125fail.jpg"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 200px;" src="http://blog.seattlepi.com/microsoft/library/20091125fail.jpg" alt="" border="0" /&gt;&lt;/a&gt;Okay. You'd think that Microsoft would make it easy for someone to convert to Windows, wouldn't you? Well, in fact, they don't. A friend was struggling to install Windows7 after paying for it online and downloading the installation files. I asked "What files do you have?", expecting an answer like "an ISO", or "an IMG". But no.. "An EXE, and two BOX files"!&lt;br /&gt;&lt;br /&gt;And things just got crazier after that. If this is the problem you're facing, then you'll want to &lt;a href="http://social.answers.microsoft.com/Forums/en-US/w7install/thread/46921dae-2192-45b1-a574-5ffefccb7812"&gt;start here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Before you do, know this: You absolutely, positively, need a Windows machine to get this working. Mind-blowing. Simply amazing.&lt;br /&gt;&lt;br /&gt;You will need to download the Windows Installation Kit. But you can't do that on any other kind of OS. You need to download it on a machine that can run a program to prove it's a Genuine Windows installation. Nice.&lt;br /&gt;&lt;br /&gt;Once you get that you'll have an IMG you can burn to DVD.&lt;br /&gt;&lt;br /&gt;Once you install the software on the DVD you'll need to trawl through the installation directory for Oscdimg.exe.&lt;br /&gt;&lt;br /&gt;Now you run your original EXE to extract data from the BOX files.&lt;br /&gt;&lt;br /&gt;From a Windows CMD prompt you can then type the incantation for Oscdimg to produce an ISO image for a DVD.&lt;br /&gt;&lt;br /&gt;You can then burn this ISO to a DVD, and you're good to go (it's possible that for this you may need to pay for some software that can burn ISOs to DVD).&lt;br /&gt;&lt;br /&gt;Seriously, that's how easy it is?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-3217087255624333889?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/3217087255624333889/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=3217087255624333889' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3217087255624333889'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3217087255624333889'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/02/installing-windows7-on-machine-without.html' title='Installing Windows7 On A Machine Without Windows On It'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-8849998892598249883</id><published>2011-02-04T18:50:00.000-08:00</published><updated>2011-02-04T18:55:29.639-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='community'/><title type='text'>PDX Software Development Site Offline</title><content type='html'>As of today &lt;a href="http://pdx-software-development.appspot.com/"&gt;http://pdx-software-development.appspot.com/&lt;/a&gt; is getting this exception talking to the Google Data API:&lt;code&gt;&lt;pre&gt;Caused by: com.google.gdata.util.ServiceForbiddenException: OK&lt;br /&gt;Maps Data api is now deprecated.&lt;br /&gt; at com.google.gdata.client.http.HttpGDataRequest.handleErrorResponse(HttpGDataRequest.java:593)&lt;br /&gt; at com.google.gdata.client.http.GoogleGDataRequest.handleErrorResponse(GoogleGDataRequest.java:563)&lt;br /&gt; at com.google.gdata.client.http.HttpGDataRequest.checkResponse(HttpGDataRequest.java:550)&lt;br /&gt; at com.google.gdata.client.http.HttpGDataRequest.execute(HttpGDataRequest.java:530)&lt;br /&gt; at com.google.gdata.client.http.GoogleGDataRequest.execute(GoogleGDataRequest.java:535)&lt;br /&gt; at com.google.gdata.client.Service.getFeed(Service.java:1101)&lt;br /&gt; at com.google.gdata.client.Service.getFeed(Service.java:972)&lt;br /&gt; at com.google.gdata.client.GoogleService.getFeed(GoogleService.java:617)&lt;br /&gt; at com.curiousattemptbunny.server.CompanyServiceImpl.refreshCompanies(CompanyServiceImpl.java:82)&lt;br /&gt; ... 37 more&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;For the time being you can refer to the &lt;a href="http://maps.google.com/maps/ms?ie=UTF8&amp;hl=en&amp;om=1&amp;source=embed&amp;msa=0&amp;msid=204796353134885170661.000438b5ea9d2b8818ac2&amp;ll=45.521864,-122.683296&amp;spn=0.060136,0.16737&amp;t=h&amp;z=13"&gt;underlying Google Map&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-8849998892598249883?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/8849998892598249883/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=8849998892598249883' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/8849998892598249883'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/8849998892598249883'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/02/pdx-software-development-site-offline.html' title='PDX Software Development Site Offline'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-6236945264631897520</id><published>2011-01-23T18:45:00.000-08:00</published><updated>2011-01-23T18:52:19.691-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='couchdb'/><category scheme='http://www.blogger.com/atom/ns#' term='grouch'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Grouch: A DSL For CouchDb</title><content type='html'>I put together a simple DSL for interacting with Groovy today. I'm calling it &lt;a href="https://github.com/curious-attempt-bunny/grouch"&gt;Grouch&lt;/a&gt;*. Using Grouch, using CouchDb is as easy as this:&lt;code&gt;&lt;pre&gt;import com.curiousattemptbunny.grouch.*&lt;br /&gt;&lt;br /&gt;grouch = new Grouch('http://localhost:5984')&lt;br /&gt;if (grouch.mydb.exists()) grouch.mydb.delete()&lt;br /&gt;grouch.mydb.create()&lt;br /&gt;grouch.mydb &lt;&lt; [_id: 'mydoc', aField: 'aValue' ]&lt;br /&gt;assert grouch.mydb.mydoc.aField == 'aValue'&lt;/pre&gt;&lt;/code&gt;* Thanks to Ben Acker for the name. Funnily enough someone else had the &lt;a href="https://github.com/search?type=Repositories&amp;q=grouch"&gt;same idea for a name&lt;/a&gt; but never pushed any code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-6236945264631897520?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/6236945264631897520/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=6236945264631897520' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/6236945264631897520'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/6236945264631897520'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/01/grouch-dsl-for-couchdb.html' title='Grouch: A DSL For CouchDb'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-8224735466191089032</id><published>2011-01-23T13:45:00.001-08:00</published><updated>2011-01-23T13:57:18.373-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tdd'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>Driving Your Coding</title><content type='html'>I think it's easy to end up coding the wrong thing or to speculate too much. No disagreement so far, right?&lt;br /&gt;&lt;br /&gt;Apply that thinking to TDD. What's driving your choice of test cases? If you're like me, then it's very easy to jump in somewhere in the middle of the design and go from there. That works. The problem here though is this is a form of speculation in it's own right, and we can easily be inefficient with our own time.&lt;br /&gt;&lt;br /&gt;Steven Freeman and others advocate an acceptance test driven TDD cycle. My thinking aligns with theirs on this to a certain degree. Explaining this to someone that's new to the concept leads to the reaction "So I have a test that's always red [until I'm done working on the feature]?". Answering "Essentially, yes." doesn't help too much it seems.&lt;br /&gt;&lt;br /&gt;So how about this. This is a fragment of my code for a potential open source API I'm toying with:&lt;pre&gt;&lt;code&gt;$ cat src/test/groovy/com/curiousattemptbunny/grouch/MotivatingExample.groovy&lt;br /&gt;package com.curiousattemptbunny.grouch&lt;br /&gt;&lt;br /&gt;couchdb = new Grouch('http://localhost')&lt;br /&gt;couchdb.mydb.delete()&lt;br /&gt;couchdb.mydb.create()&lt;br /&gt;couchdb.mydb &lt;&lt; [_id: 'mydoc', aField: 'aValue' ]&lt;br /&gt;assert couchdb.mydb.mydoc.aField == 'aValue&lt;/code&gt;&lt;/pre&gt;I like this for a number of reasons:&lt;br /&gt;1. It's clearly distinct from a regular unit test&lt;br /&gt;2. It's very concise&lt;br /&gt;3. It will fail if I'm not done with my tests&lt;br /&gt;&lt;br /&gt;I encourage you to try this yourself and let me know how it went.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-8224735466191089032?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/8224735466191089032/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=8224735466191089032' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/8224735466191089032'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/8224735466191089032'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/01/driving-your-coding.html' title='Driving Your Coding'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-5482722668141201165</id><published>2011-01-19T11:29:00.001-08:00</published><updated>2011-01-19T11:35:28.558-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>Impressive Date Parsing for JavaScript</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_AGVcmhlbFXA/TTc8tHd4q6I/AAAAAAAAAXY/8zJQdlMkQaw/s1600/datejs-logo.png"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 185px; height: 219px;" src="http://2.bp.blogspot.com/_AGVcmhlbFXA/TTc8tHd4q6I/AAAAAAAAAXY/8zJQdlMkQaw/s400/datejs-logo.png" alt="" id="BLOGGER_PHOTO_ID_5563982610435713954" border="0" /&gt;&lt;/a&gt;I'm impressed with &lt;a href="http://www.datejs.com/"&gt;datejs&lt;/a&gt; technically and even more so with the way its' function is communicated. If you take a look at their &lt;a href="http://www.datejs.com/"&gt;main page&lt;/a&gt; you'll see exactly what I mean. I was oscillating between two date formats '1/2/11 4:21:09 AM' and 'Sun Jan 02 04:21:19 PST 2011' and they both just worked out of the box and &lt;em&gt;I didn't have to download it to know I'd found what I needed&lt;/em&gt;. Very well done datejs folks!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-5482722668141201165?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/5482722668141201165/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=5482722668141201165' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/5482722668141201165'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/5482722668141201165'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/01/impressive-date-parsing-for-javascript.html' title='Impressive Date Parsing for JavaScript'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_AGVcmhlbFXA/TTc8tHd4q6I/AAAAAAAAAXY/8zJQdlMkQaw/s72-c/datejs-logo.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-8700251580865382064</id><published>2011-01-16T13:40:00.001-08:00</published><updated>2011-01-20T23:29:10.703-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ast'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Want To Inline JVM Bytecode Into Your Groovy Code?</title><content type='html'>Do you want to inline JVM bytecode into your Groovy code? Groovy's ASTs allowed the &lt;a href="https://github.com/melix/groovy-bytecode-ast/wiki"&gt;groovy-bytecode-ast project&lt;/a&gt; to come into existence. For instance, this method could be instead defined using the code that follows:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;public int fib(int i) {&lt;br /&gt;   return i&lt;2?i:fib(i-2)+fib(i-1);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&lt;pre&gt;@groovyx.ast.bytecode.Bytecode&lt;br /&gt;int fib(int i) {&lt;br /&gt;    iload 1&lt;br /&gt;    iconst_2&lt;br /&gt;    if_icmpge l1&lt;br /&gt;    iload 1&lt;br /&gt;    _goto l2&lt;br /&gt;   l1&lt;br /&gt;    aload 0&lt;br /&gt;    iload 1&lt;br /&gt;    iconst_2&lt;br /&gt;    isub&lt;br /&gt;    invokevirtual '.fib', '(I)I'&lt;br /&gt;    aload 0&lt;br /&gt;    iload 1&lt;br /&gt;    iconst_1&lt;br /&gt;    isub&lt;br /&gt;    invokevirtual '.fib' ,'(I)I'&lt;br /&gt;    iadd&lt;br /&gt;   l2&lt;br /&gt;    ireturn&lt;br /&gt;}&lt;br /&gt;println fib(40)&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;How is this done? Surprisingly, there's actually not very much in the way of code needed to support this. The key implementation details are in &lt;a href="https://github.com/melix/groovy-bytecode-ast/blob/master/src/main/groovy/groovyx/ast/bytecode/BytecodeASTTransformation.groovy"&gt;BytecodeASTTransformation.groovy&lt;/a&gt; - a &lt;a href="http://groovy.codehaus.org/Local+AST+Transformations"&gt;Local AST Transformation.&lt;/a&gt; Way to go Cédric Champeau!&lt;br /&gt;&lt;br /&gt;Update: now with new &lt;a href="http://www.jroller.com/melix/entry/asm_plugin_for_intellij_and"&gt;groovified syntax&lt;/a&gt; and matching &lt;a href="http://www.jroller.com/melix/entry/asm_plugin_for_intellij_and"&gt;IntelliJ ASM plugin&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-8700251580865382064?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/8700251580865382064/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=8700251580865382064' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/8700251580865382064'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/8700251580865382064'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/01/want-to-inline-jvm-bytecode-into-your.html' title='Want To Inline JVM Bytecode Into Your Groovy Code?'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-660928895162293991</id><published>2011-01-15T10:36:00.000-08:00</published><updated>2011-01-15T10:40:53.314-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='community'/><title type='text'>I'm Mentoring At Agile PDX's Tune-Up Workshop Jan Wednesday 19th</title><content type='html'>In case you're not following &lt;a href="http://twitter.com/agilepdx"&gt;AgilePDX on Twitter&lt;/a&gt; or keeping up to date with the [now poorly named] &lt;a href="http://tech.groups.yahoo.com/group/xpportland/"&gt;xpportland mailing list&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://calagator.org/events/1250459616"&gt;This event on Calagator&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;This month, come to the Agile PDX 'Agile Tune-Up' meeting and tune up your agile process! Our panel of experts and practitioners will give you personalized feedback on the issues you're facing in an informal workshop-like format.&lt;br /&gt;&lt;br /&gt;Before the session, visit &lt;a href="http://agile-pdx-tune-up.appspot.com/"&gt;http://agile-pdx-tune-up.appspot.com/&lt;/a&gt; for a brief questionnaire that will help you identify your areas of greatest risk. Then bring a printout with you to the session to get targeted advice on what to keep doing and what to change!&lt;br /&gt;&lt;br /&gt;This event is free and is at our new location, Puppet Labs. It begins at 6:30 pm with pizza, sponsored by PNSQC (Many thanks to both Puppet Labs and PNSQC for supporting agile in Portland).&lt;br /&gt;&lt;br /&gt;The program starts at 7:00 pm.&lt;br /&gt;&lt;br /&gt;After the program you're invited to join us for a no-host gathering at a nearby brewpub for further discussion.&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-660928895162293991?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/660928895162293991/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=660928895162293991' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/660928895162293991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/660928895162293991'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/01/im-mentoring-at-agile-pdxs-tune-up.html' title='I&apos;m Mentoring At Agile PDX&apos;s Tune-Up Workshop Jan Wednesday 19th'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-6212092089805031513</id><published>2011-01-15T10:33:00.000-08:00</published><updated>2011-01-15T10:45:19.707-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gradle'/><category scheme='http://www.blogger.com/atom/ns#' term='community'/><title type='text'>I'm Facilitating At PJUG January Tuesday 18th</title><content type='html'>This session isn't Java specific as it applies equally well to Groovy and Scala, so if you're not on the PJUG list you may miss this:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;Hi,&lt;br /&gt;&lt;br /&gt;I'm Merlyn, a Portland-based programmer with strong ties to both Agile&lt;br /&gt;PDX and Groovy. I'm also a member of an Agile team at YesMail, and I&lt;br /&gt;blog under the handle "curious attempt bunny".&lt;br /&gt;&lt;br /&gt;Come to the session if you want to participate in learning more about&lt;br /&gt;Gradle. Gradle is a powerful layer of Groovy built on top of a number&lt;br /&gt;of established tools and libraries. Smart guys have borrowed from the&lt;br /&gt;pioneering work of Ant, Maven, Gant, Buildr and come up with an&lt;br /&gt;expressive, concise, and convention-rich build tool for the Java&lt;br /&gt;family.&lt;br /&gt;&lt;br /&gt;For this session, there won't be any slides. I'm also not going to&lt;br /&gt;stand up and talk at you. Instead, I'm going to rely heavily on your&lt;br /&gt;involvement. I'll start with an introduction to Gradle, and then very&lt;br /&gt;quickly go into using it in practice. After a few minutes of that I'll&lt;br /&gt;open it up to go wherever we're most interested in. I'm not a Gradle&lt;br /&gt;expert, yet I believe that my Groovy background in conjunction with a&lt;br /&gt;few days of earnest usage have taught me a lot. This session will rely&lt;br /&gt;heavily on an internet connection, and we'll be googling for answers&lt;br /&gt;together if need be.&lt;br /&gt;&lt;br /&gt;Do this ahead of time:&lt;br /&gt;&lt;br /&gt;What is your intention for the session? Spend some time deliberately&lt;br /&gt;focusing on what it is you want out of the session. Bring that with&lt;br /&gt;you and share it with us. It will help us all focus on what's&lt;br /&gt;important and go some way to helping you get the most out of the&lt;br /&gt;session. Also, go have a quick read about Gradle on their website.&lt;br /&gt;That will save us all some time, help us get to the interesting&lt;br /&gt;details sooner, and be a good source of informed questions for you.&lt;br /&gt;&lt;br /&gt;I'll also be building in some time at the end of the session to gather&lt;br /&gt;feedback that will help me learn to become a better facilitator.&lt;br /&gt;&lt;br /&gt;Cheers,&lt;br /&gt;Merlyn&lt;br /&gt;&lt;br /&gt;PS Regardless of whether you come to the session, if you practice&lt;br /&gt;Agile at work, or are struggling to do so. then do plan to come to the&lt;br /&gt;Wednesday 19th Agile PDX Tune-Up Workshop where I and a number of&lt;br /&gt;local practitioners will be mentoring alongside James Shore. More&lt;br /&gt;details here:  &lt;a href="http://calagator.org/events/1250459616"&gt;http://calagator.org/events/1250459616&lt;/a&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-6212092089805031513?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/6212092089805031513/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=6212092089805031513' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/6212092089805031513'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/6212092089805031513'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/01/im-facilitating-at-pjug-january-tuesday.html' title='I&apos;m Facilitating At PJUG January Tuesday 18th'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-647391823780973160</id><published>2011-01-11T06:51:00.000-08:00</published><updated>2011-01-11T06:55:13.959-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gwt'/><title type='text'>Print Previw in GWT</title><content type='html'>This took me a while to find so I thought I'd share it with you. I'm assuming you're using a solution like this in your HTML:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&amp;lt;link rel="stylesheet" type="text/css" media="print" href="Print.css"&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;But what if you want the user to view the print preview inside the browser? In that case you can dynamically include your css like so:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;StyleInjector.inject("@import url(\"Print.css\");&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This doesn't address how to make this toggleable - that's for you to find out (and let me know how you did it). In my case I can simply reload the app:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;Window.Location.reload();&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-647391823780973160?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/647391823780973160/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=647391823780973160' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/647391823780973160'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/647391823780973160'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/01/print-previw-in-gwt.html' title='Print Previw in GWT'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-399564131017399359</id><published>2011-01-09T19:06:00.000-08:00</published><updated>2011-01-09T19:08:19.100-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>It Just Makes Sense</title><content type='html'>&lt;code&gt;&lt;b&gt;subscribe.groovy&lt;/b&gt;&lt;pre&gt;rss = new URL("http://day9tv.blip.tv/rss").text&lt;br /&gt;root = new groovy.util.XmlSlurper().parseText(rss)&lt;br /&gt;root.channel.item.each { item -&gt;&lt;br /&gt;  def url = item.enclosure.@url.text()&lt;br /&gt;  def name = new File(url).name&lt;br /&gt; &lt;br /&gt;  if (!new File(".$name").exists()) {&lt;br /&gt;    println "Downloading $name : $url"&lt;br /&gt;    new File(".$name").write("")&lt;br /&gt;  &lt;br /&gt;    def file = new File(name).newOutputStream()  &lt;br /&gt;    file &lt;&lt; new URL(url).openStream()  &lt;br /&gt;    file.close() &lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-399564131017399359?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/399564131017399359/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=399564131017399359' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/399564131017399359'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/399564131017399359'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/01/it-just-makes-sense.html' title='It Just Makes Sense'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-2443696583157996129</id><published>2011-01-09T08:27:00.000-08:00</published><updated>2011-01-09T08:34:31.228-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='environment'/><title type='text'>Night and Day - Working at the Right Place</title><content type='html'>This is an extract from a user group post someone made. What I'd like to highlight about it is specifically that you don't really know how bad you had it until you find somewhere heathy. And to managers and employers: a sane/humane working environment where you treat people with respect is invaluable (a medium-term requirement?).&lt;br /&gt;&lt;br /&gt;&lt;code&gt;Hi, [appologies for my earlier rant which must be] a symptom of my latent anger, at the lousy way [CompanyX] treated myself and some of my friends during the last decade.&lt;br /&gt;&lt;br /&gt;It  was brought  into perspective  because I am  so much happier in my current position, working with a  small group of software geeks, who all enjoy the creativity and attention to detail  that it takes  to write (and sell) our software.  So  my salary  is basically the same as it was  10 years ago ,  and the benefits aren't quite as comprehensive, but being empowered and able to speak out (constructively) and working with a  smart manager and smart bunch of people, * more than* makes up  for that.&lt;br /&gt;*SOME ADVICE:*&lt;br /&gt;1. You should be very careful  about what you sign up for, and *who you work with  and how they treat you*.  Don't just think about the  $$  and benefits. Look around the office  and talk to some of the developers (without anyone looking over your shoulder).&lt;br /&gt;2.* Look after your body and brain*. I  didn't know this until a few years ago,  but if you have to work where there is limited natural light , and you feel ill a lot,  see your  Doc  to get some  SSRI  'happy pills'. Many people get depressed or anxious because the levels of Serotonin in their Brains drops when they *have to work in the gloom*. Our profession is  *very sedentary* ...you need to keep moving  and walk or exercise ...otherwise you will get  out of shape  and that can lead  to some *very  *nasty problems. *Do not* sit at your desk all day!&lt;br /&gt;3. Germs and viruses spread like wildfire when you are  *cooped up in an office*. If your neighbor insists on  'sharing' their flu with you ... tell them to go home and take one of their sick days (if you get sick days) ..and remember to wash your hands before you eat,  or keep a tub  of Lysol wipes handy.&lt;br /&gt;4. IF you're not happy with the company or your manager, *don't take the crap*,  like I did,  find another job. It will be scary but you'll be so much wiser and happier!&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;So, how good do you have it?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-2443696583157996129?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/2443696583157996129/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=2443696583157996129' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/2443696583157996129'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/2443696583157996129'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2011/01/night-and-day-working-at-right-place.html' title='Night and Day - Working at the Right Place'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-501031391194483800</id><published>2010-12-16T10:42:00.001-08:00</published><updated>2010-12-16T10:46:04.332-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Ubuntu 10.10 &amp; HP Pavillion Erratic Touchpad</title><content type='html'>Having trouble selecting from drop down boxes or selecting blocks of text? Does the mouse cursor go crazy if you touch the pad with two fingers? Does right click not work? Does your mouse cursor jump to the bottom of the screen when you try to left click? If so, this &lt;a href="http://sansmicrosoft.blogspot.com/2010/10/pavilion-dm4-1160-touchpad-erratic-bis.html"&gt;script&lt;/a&gt; from &lt;a href="http://sansmicrosoft.blogspot.com"&gt;SansMicrosoft&lt;/a&gt; will fix your issues.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-501031391194483800?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/501031391194483800/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=501031391194483800' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/501031391194483800'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/501031391194483800'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/12/ubuntu-1010-hp-pavillion-erratic.html' title='Ubuntu 10.10 &amp; HP Pavillion Erratic Touchpad'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-5099197289255829686</id><published>2010-12-15T15:44:00.001-08:00</published><updated>2010-12-16T10:53:08.747-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Shrinking Your Windows 7 Partition So That You Can Install Ubuntu 10.10</title><content type='html'>Having trouble shrinking your NTFS partition on Windows 7 so that you can dual boot into Ubuntu 10.10? Windows7 Disk Manager sucked for me, suggesting that I could reclaim just 50% of my practically empty NTFS partition. What worked for me (and worked in literally 3 minutes) was &lt;a href="http://www.partitionwizard.com/free-partition-manager.html"&gt;Partition Wizard Home Edition&lt;/a&gt;. What's more, it's free to use!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-5099197289255829686?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/5099197289255829686/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=5099197289255829686' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/5099197289255829686'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/5099197289255829686'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/12/shrinking-your-windows-7-partition-so.html' title='Shrinking Your Windows 7 Partition So That You Can Install Ubuntu 10.10'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-5199646634392287279</id><published>2010-11-15T08:00:00.001-08:00</published><updated>2010-11-15T09:00:31.156-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><title type='text'>Setting Up Gitosis on Mac OSX</title><content type='html'>These appear to be the &lt;a href="http://scie.nti.st/2007/11/14/hosting-git-repositories-the-easy-and-secure-way"&gt;defacto instructions&lt;/a&gt; for setting up gitosis. And they worked very well for me. The only trouble I had was with the clone url. This form didn't work for me: &lt;code&gt;&lt;pre&gt;git clone git@YOUR_SERVER_HOSTNAME:gitosis-admin.git&lt;/pre&gt;&lt;/code&gt;Instead I needed to use this:&lt;code&gt;&lt;pre&gt;git clone git@YOUR_SERVER_HOSTNAME:~/repositories/gitosis-admin.git&lt;/pre&gt;&lt;/code&gt;Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-5199646634392287279?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/5199646634392287279/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=5199646634392287279' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/5199646634392287279'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/5199646634392287279'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/11/setting-up-gitosis-on-mac-osx.html' title='Setting Up Gitosis on Mac OSX'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-4250549459408271382</id><published>2010-11-14T10:48:00.000-08:00</published><updated>2010-11-14T10:57:55.204-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cometd'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Grails, CometD, and Lazy Initialization of Services</title><content type='html'>I've been giving &lt;a href="http://cometd.org/documentation/2.x/cometd-java"&gt;CometD&lt;/a&gt; a go in Grails. There's a good &lt;a href="http://metasieve.wordpress.com/2010/08/25/using-cometd-2-x-with-grails/"&gt;how-to&lt;/a&gt; on that. The problem I encountered immediately is that Grails doesn't eagerly construct my Service bean, so &lt;code&gt;bayeuxSession.handshake()&lt;/code&gt; never gets called. After trying in vain to find a clean way to have Service beans eagerly initialized, I settled on this change to BootStrap.groovy:&lt;code&gt;&lt;pre&gt;import org.codehaus.groovy.grails.commons.ApplicationAttributes&lt;br /&gt;&lt;br /&gt;class BootStrap {&lt;br /&gt;  def init = { servletContext -&gt;&lt;br /&gt;    def ctx =&lt;br /&gt;      servletContext.getAttribute(ApplicationAttributes.APPLICATION_CONTEXT) &lt;br /&gt;    ctx.getBean("lobbyService")&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  def destroy = {&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;Incidentally, if you're not finding the CometD 2.0.0 javadocs, it's because they're not online. Instead, grab the docs from maven - e.g. &lt;a href="http://repo2.maven.org/maven2/org/cometd/java/bayeux-api/2.1.0.beta2/bayeux-api-2.1.0.beta2-javadoc.jar"&gt;http://repo2.maven.org/maven2/org/cometd/java/bayeux-api/2.1.0.beta2/bayeux-api-2.1.0.beta2-javadoc.jar&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-4250549459408271382?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/4250549459408271382/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=4250549459408271382' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4250549459408271382'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4250549459408271382'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/11/grails-cometd-and-lazy-initialization.html' title='Grails, CometD, and Lazy Initialization of Services'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-2291200992163990086</id><published>2010-11-05T15:50:00.000-07:00</published><updated>2010-11-05T16:03:52.408-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='app'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><category scheme='http://www.blogger.com/atom/ns#' term='game'/><title type='text'>Writing a Game for the Android</title><content type='html'>I recently bought myself a G2 Android phone, and being a developer the first thing I had to do was write an app for it. Here are some of the useful tips I learnt along the way:&lt;br /&gt;&lt;h4&gt;Use a SurfaceView for graphics-biased apps&lt;/h4&gt;See the LunarLander SDK example. You'll want to &lt;code&gt;getHolder()&lt;/code&gt;, listen for &lt;code&gt;SurfaceHolder.Callback&lt;/code&gt; events, and create a worker thread to control the rendering.&lt;br /&gt;&lt;h4&gt;Listen to touch events&lt;/h4&gt;The SurfaceView can register for &lt;code&gt;onTouch&lt;/code&gt; events using &lt;code&gt;setOnTouchListener(this)&lt;/code&gt;.&lt;br /&gt;&lt;h4&gt;Draw bitmaps&lt;/h4&gt;Load resources using &lt;code&gt;BitmapFactory.decodeResource(res, R.drawable.someBitmap)&lt;/code&gt; and then &lt;code&gt;canvas.drawBitmap&lt;/code&gt; will do the job. For transparencies create a &lt;code&gt;Paint&lt;/code&gt; and call &lt;code&gt;paint.setAlpha(alpha)&lt;/code&gt;.&lt;br /&gt;&lt;h4&gt;Scale, translate, and rotate the canvas&lt;/h4&gt;&lt;code&gt;canvas.save()&lt;/code&gt; and &lt;code&gt;canvas.restore()&lt;/code&gt; are your friends along with methods such as &lt;code&gt;canvas.scale(scaleX, scaleY)&lt;/code&gt;.&lt;br /&gt;&lt;h4&gt;Make the app fullscreen&lt;/h4&gt;Put this in your manifest.xml for the Activity: &lt;code&gt;android:theme="@android:style/Theme.NoTitleBar.Fullscreen"&lt;/code&gt;&lt;br /&gt;&lt;h4&gt;Lock the orientation of your app&lt;/h4&gt;Put this in your manifest.xml for the Activity: &lt;code&gt;android:screenOrientation="portrait"&lt;/code&gt;&lt;br /&gt;&lt;h4&gt;Pop up dialogs - but not from the render thread!&lt;/h4&gt;&lt;code&gt;&lt;pre&gt;AlertDialog.Builder ad = new AlertDialog.Builder(context);&lt;br /&gt;ad.setTitle("You won!");&lt;br /&gt;ad.setMessage("Play again, sir!");&lt;br /&gt;ad.setPositiveButton("New Game", new OnClickListener() {&lt;br /&gt;  public void onClick(DialogInterface dialog, int which) {&lt;br /&gt;    newGame();&lt;br /&gt;  }&lt;br /&gt;});&lt;/pre&gt;&lt;/code&gt;&lt;h4&gt;Play sounds&lt;/h4&gt;&lt;code&gt;MediaPlayer mp = MediaPlayer.create(context, R.raw.someSound)));&lt;/code&gt; and then later: &lt;code&gt;mp.start();&lt;/code&gt;&lt;br /&gt;&lt;h4&gt;Make the volume controls change the media sounds and not the ringer&lt;/h4&gt;&lt;code&gt;setVolumeControlStream(AudioManager.STREAM_MUSIC);&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-2291200992163990086?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/2291200992163990086/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=2291200992163990086' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/2291200992163990086'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/2291200992163990086'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/11/writing-game-for-android.html' title='Writing a Game for the Android'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-4862033439350422095</id><published>2010-10-24T11:14:00.000-07:00</published><updated>2010-10-24T11:22:51.181-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>Refreshingly Concise Builds</title><content type='html'>&lt;a href="http://www.gradle.org/"&gt;Gradle&lt;/a&gt; has a direct tag line: "A better way to build". But is it really?&lt;br /&gt;&lt;br /&gt;To start with, Gradle's build configuration files themselves are very concise, e.g.:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;apply plugin: 'java'&lt;br /&gt;apply plugin: 'eclipse'&lt;br /&gt;&lt;br /&gt;sourceCompatibility = 1.5&lt;br /&gt;version = 0.1&lt;br /&gt;&lt;br /&gt;repositories {&lt;br /&gt;  mavenCentral()&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;dependencies {&lt;br /&gt;  compile (&lt;br /&gt;    "asm:asm-all:3.3",&lt;br /&gt;    "org.slf4j:slf4j-api:1.6.1"&lt;br /&gt;  )&lt;br /&gt;  testCompile (&lt;br /&gt;    "junit:junit:4.8.2"&lt;br /&gt;  )&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;Gradle isn't ashamed to take back information it's shown you. While it's running a build you'll see output relevant to it's current task, but if the task runs without issue it'll hide all the noise and give you just the overview.&lt;br /&gt;&lt;br /&gt;While in progress:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&amp;gt; Building &gt; :compileJava&lt;/pre&gt;&lt;/code&gt;When all goes well:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;$ gradle test&lt;br /&gt;:compileJava UP-TO-DATE&lt;br /&gt;:processResources UP-TO-DATE&lt;br /&gt;:classes UP-TO-DATE&lt;br /&gt;:compileTestJava UP-TO-DATE&lt;br /&gt;:processTestResources&lt;br /&gt;:testClasses&lt;br /&gt;:test&lt;br /&gt;&lt;br /&gt;BUILD SUCCESSFUL&lt;br /&gt;&lt;br /&gt;Total time: 8.149 secs&lt;/pre&gt;&lt;/code&gt;Contrary to other build tools, when things do not go well the output is verbose enough to be helpful while avoiding a scatter-shot let's-dump-out-everything-that-was-going-on approach.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-4862033439350422095?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/4862033439350422095/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=4862033439350422095' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4862033439350422095'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4862033439350422095'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/10/refreshingly-concise-builds.html' title='Refreshingly Concise Builds'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-319885149343642284</id><published>2010-09-08T20:29:00.000-07:00</published><updated>2010-09-08T20:31:28.221-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Java 1.7 ... Sometime?</title><content type='html'>First read this and capture your reaction: &lt;a href="http://blogs.sun.com/mr/entry/rethinking_jdk7"&gt;Java 1.7 Release Date&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Was it anything like this?&lt;br /&gt;&lt;span style="font-style:italic;"&gt;&lt;br /&gt;"Wow. Just... wow.&lt;br /&gt;&lt;br /&gt;2012. Really? /Really/?"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;:D&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-319885149343642284?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/319885149343642284/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=319885149343642284' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/319885149343642284'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/319885149343642284'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/09/java-17-sometime.html' title='Java 1.7 ... Sometime?'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-3273323423835053849</id><published>2010-08-31T08:40:00.000-07:00</published><updated>2010-08-31T08:43:41.108-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Java 1.7: What's In The Pipeline</title><content type='html'>Here's what will probably be going into &lt;a href="http://blogs.sun.com/darcy/entry/project_coin_final_five"&gt;Java 1.7 from Project Coin&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;For those who can't upgrade from Java 1.5, you may be able to find them in Groovy:&lt;br /&gt;&lt;br /&gt;"Supporting some of these JDK 7 aspects on JDK 5+ is also a nice appeal&lt;br /&gt;to Java developers who can't just upgrade"&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-3273323423835053849?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/3273323423835053849/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=3273323423835053849' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3273323423835053849'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3273323423835053849'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/08/java-17-whats-in-pipeline.html' title='Java 1.7: What&apos;s In The Pipeline'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-6642513091925632756</id><published>2010-07-24T11:09:00.000-07:00</published><updated>2010-07-24T11:24:44.207-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maps'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='gwt'/><title type='text'>Help Me Solve My Google Maps API Info Window Problem</title><content type='html'>I'm quite stuck. I'm using the Google Maps API via the &lt;a href="http://code.google.com/p/gwt-google-apis/wiki/MapsGettingStarted"&gt;gwt-google-apis&lt;/a&gt; project. The symptom of the problem is that I create a &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt; (that Firebug says has computed dimensions of 658 x 196) and Google Maps API wraps this with a &lt;code&gt;&amp;lt;div style="position: absolute; left: 16px; top: 16px; width: 658px; height: 142px; z-index: 10;"&amp;gt;&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;I haven't found any way to force the info window to be resized or to set it's height. This is what it looks like:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_AGVcmhlbFXA/TEsvC6rliVI/AAAAAAAAAXE/VXJ0xmNh2JA/s1600/layout+problems.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 178px;" src="http://2.bp.blogspot.com/_AGVcmhlbFXA/TEsvC6rliVI/AAAAAAAAAXE/VXJ0xmNh2JA/s400/layout+problems.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5497539497294137682" /&gt;&lt;/a&gt;&lt;br /&gt;Notice how the edit button floats off the bottom of the bubble. Yuck!&lt;br /&gt;&lt;br /&gt;Here's the &lt;a href="http://pdx-software-development.appspot.com/#tag=xp"&gt;link to the app&lt;/a&gt; (click the YesMail link after the list has loaded).&lt;br /&gt;&lt;br /&gt;Any ideas? I'm using this method to display the info window:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;FlexTable content = new FlexTable();&lt;br /&gt;//...&lt;br /&gt;map.getInfoWindow().open(company.getMarker(),&lt;br /&gt;  new InfoWindowContent(content));&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-6642513091925632756?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/6642513091925632756/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=6642513091925632756' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/6642513091925632756'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/6642513091925632756'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/07/help-me-solve-my-google-maps-api-info.html' title='Help Me Solve My Google Maps API Info Window Problem'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_AGVcmhlbFXA/TEsvC6rliVI/AAAAAAAAAXE/VXJ0xmNh2JA/s72-c/layout+problems.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-1341620929004590529</id><published>2010-07-22T22:02:00.000-07:00</published><updated>2010-07-22T22:04:46.967-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Groovy the #1 JVM scripting language</title><content type='html'>&lt;a href="http://www.infoworld.com/d/developer-world/top-five-scripting-languages-the-jvm-855?page=0,1#jvm1"&gt;"JVM scripting language No. 1: Groovy -- Powerful, high-level, enterprise-friendly"&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-1341620929004590529?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/1341620929004590529/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=1341620929004590529' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/1341620929004590529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/1341620929004590529'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/07/groovy-1-jvm-scripting-language.html' title='Groovy the #1 JVM scripting language'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-4065426469373674722</id><published>2010-07-20T21:44:00.000-07:00</published><updated>2010-07-20T21:54:33.305-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>com.google.gdata.util.ParseException: name must have a value</title><content type='html'>For some reason the Google Maps API gdata core recently started failing to read my feature feed. This is the error I see in my App Engine log:&lt;code&gt;&lt;pre style="font-size: 10px"&gt;&lt;br /&gt;Caused by: com.google.gdata.util.ParseException: [Line 1, Column 3457, element atom:name] name must have a value&lt;br /&gt; at com.google.gdata.util.XmlParser.throwParseException(XmlParser.java:730)&lt;br /&gt; at com.google.gdata.util.XmlParser.parse(XmlParser.java:693)&lt;br /&gt; at com.google.gdata.util.XmlParser.parse(XmlParser.java:576)&lt;br /&gt; at com.google.gdata.data.BaseFeed.parseAtom(BaseFeed.java:867)&lt;br /&gt; at com.google.gdata.wireformats.input.AtomDataParser.parse(AtomDataParser.java:68)&lt;br /&gt; at com.google.gdata.wireformats.input.AtomDataParser.parse(AtomDataParser.java:39)&lt;br /&gt; at com.google.gdata.wireformats.input.CharacterParser.parse(CharacterParser.java:100)&lt;br /&gt; at com.google.gdata.wireformats.input.XmlInputParser.parse(XmlInputParser.java:52)&lt;br /&gt; at com.google.gdata.wireformats.input.AtomDualParser.parse(AtomDualParser.java:66)&lt;br /&gt; at com.google.gdata.wireformats.input.AtomDualParser.parse(AtomDualParser.java:34)&lt;br /&gt; at com.google.gdata.client.Service.parseResponseData(Service.java:2165)&lt;br /&gt; at com.google.gdata.client.Service.parseResponseData(Service.java:2098)&lt;br /&gt; at com.google.gdata.client.Service.getFeed(Service.java:1136)&lt;br /&gt; at com.google.gdata.client.Service.getFeed(Service.java:998)&lt;br /&gt; at com.google.gdata.client.GoogleService.getFeed(GoogleService.java:631)&lt;br /&gt; at com.google.gdata.client.Service.getFeed(Service.java:1017)&lt;br /&gt; at com.curiousattemptbunny.server.CompanyServiceImpl.refreshCompanies(CompanyServiceImpl.java:80)&lt;br /&gt; ... 52 more&lt;br /&gt;Caused by: com.google.gdata.util.ParseException: name must have a value&lt;br /&gt; at com.google.gdata.data.Person$AtomHandler$NameHandler.processEndElement(Person.java:251)&lt;br /&gt; at com.google.gdata.util.XmlParser.endElement(XmlParser.java:1004)&lt;br /&gt; at org.xml.sax.helpers.ParserAdapter.endElement(Unknown Source)&lt;br /&gt; at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(Unknown Source)&lt;br /&gt; at com.sun.org.apache.xerces.internal.parsers.AbstractXMLDocumentParser.emptyElement(Unknown Source)&lt;br /&gt; at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)&lt;br /&gt; at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source)&lt;br /&gt; at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)&lt;br /&gt; at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown Source)&lt;br /&gt; at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)&lt;br /&gt; at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)&lt;br /&gt; at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)&lt;br /&gt; at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)&lt;br /&gt; at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)&lt;br /&gt; at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)&lt;br /&gt; at org.xml.sax.helpers.ParserAdapter.parse(Unknown Source)&lt;br /&gt; at com.google.gdata.util.XmlParser.parse(XmlParser.java:685)&lt;br /&gt; ... 67 more&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;The culprit appears to be the lack of an &amp;lt;atom:name&amp;gt; tag in the feature feed. Until the reason for this reveals itself or an update to the API is released, I'm using a custom build of the gdata-core-1.0.jar. I simply substituted a non-null value for the name in the Person.NameHandler class:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;if (value == null) {&lt;br /&gt;  //throw new ParseException(CoreErrorDomain.ERR.nameValueRequired);&lt;br /&gt;  value = "N/A";&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-4065426469373674722?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/4065426469373674722/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=4065426469373674722' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4065426469373674722'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4065426469373674722'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/07/comgooglegdatautilparseexception-name.html' title='com.google.gdata.util.ParseException: name must have a value'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-1185910242166037991</id><published>2010-07-20T21:12:00.000-07:00</published><updated>2010-07-20T21:13:37.180-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>Sun/Oracle - You Suck</title><content type='html'>&lt;code&gt;require.client.dependencies:&lt;br /&gt;&lt;br /&gt;BUILD FAILED&lt;br /&gt;/.../gdata-java-client/java/build-src/core.xml:394: missing jar file: /tmp/gdata_dep/mail.jar&lt;br /&gt;The GData client requires Sun's javamail API (version 1.4), which&lt;br /&gt;is not included in this distribution.&lt;br /&gt;&lt;br /&gt;You can download it from:&lt;br /&gt;  http://java.sun.com/products/javamail/downloads/index.html&lt;br /&gt;&lt;br /&gt;Then save it under:&lt;br /&gt;  /tmp/gdata_dep/mail.jar&lt;br /&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-1185910242166037991?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/1185910242166037991/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=1185910242166037991' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/1185910242166037991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/1185910242166037991'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/07/sunoracle-you-suck.html' title='Sun/Oracle - You Suck'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-6969274545288492333</id><published>2010-07-09T19:40:00.000-07:00</published><updated>2010-07-10T13:27:59.409-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='backup'/><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><title type='text'>Time Machine Backup Over The Network</title><content type='html'>Are you like me and want to back up just a few pet projects to another one of your computers on the network? If so it's not hard:&lt;br /&gt;&lt;br /&gt;On the machine you want to backup &lt;em&gt;to&lt;/em&gt;:&lt;br /&gt;* Share a new folder in the &lt;code&gt;System Preferences&lt;/code&gt; &gt; &lt;code&gt;Share&lt;/code&gt; page.&lt;br /&gt;&lt;br /&gt;On the machine you want to backup &lt;em&gt;from&lt;/em&gt;:&lt;br /&gt;* Open up the shared folder in Finder: &lt;code&gt;Go&lt;/code&gt; &gt; &lt;code&gt;Network&lt;/code&gt;.&lt;br /&gt;* From Terminal run:&lt;br /&gt;&lt;code&gt;defaults write com.apple.systempreferences \&lt;br /&gt;TMShowUnsupportedNetworkVolumes 1&lt;/code&gt;&lt;br /&gt;* Open up &lt;code&gt;Time Machine Preferences&lt;/code&gt; and exclude everything - you can shift-select everything on your HDD. Then selectivels remove from the list the things you don't want excluded - if you follow me.&lt;br /&gt;* Verify that the total calculated size is managable - less than 10Gb say.&lt;br /&gt;* Kick off a backup!&lt;br /&gt;* Come back in a day or so! :)&lt;br /&gt;&lt;br /&gt;Edit: My 9.7Gb backup over 11g wireless took just under 3 hours.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-6969274545288492333?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/6969274545288492333/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=6969274545288492333' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/6969274545288492333'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/6969274545288492333'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/07/time-machine-backup-over-network.html' title='Time Machine Backup Over The Network'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-8565804640570789844</id><published>2010-07-08T07:05:00.000-07:00</published><updated>2010-07-08T07:09:03.772-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>MapsService setUserCredentials Hang Problem</title><content type='html'>Is the Google Data Maps Feed API &lt;code&gt;MapsService.setUserCredentials&lt;/code&gt; hanging for you? You're probably using Java 1.5. Switch to Java 1.6 and the problem goes away. &lt;br /&gt;&lt;br /&gt;Best summary of the problem:&lt;br /&gt;&lt;br /&gt;"I'm seeing the same thing at the same spot. CharMatcher enters into an infinite loop in setBits() while initializing the SINGE_WIDTH static instance. However, it does NOT hang if I single step over, or through, the initialization in the Eclipse debugger. I can reproduce this hang outside of the setUserCredentials() method by simply forcing the CharMatcher class to be loaded."&lt;br /&gt;&lt;br /&gt;Solution found here:&lt;br /&gt;&lt;br /&gt;"A follow-up. I was able to switch back to using a 1.6 JVM (1.6.0_18) and found that the hang no longer occurs. Something must be screwed up with how a 1.5 JVM handles the byte code that was generated. Perhaps recompiling the code with a different version of the javac would change the behavior?"&lt;br /&gt;&lt;br /&gt;See &lt;a href="http://code.google.com/p/gdata-java-client/issues/detail?id=249"&gt;gdata-client issue 249&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-8565804640570789844?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/8565804640570789844/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=8565804640570789844' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/8565804640570789844'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/8565804640570789844'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/07/mapsservice-setusercredentials-hang.html' title='MapsService setUserCredentials Hang Problem'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-1364171476560800636</id><published>2010-07-07T21:31:00.000-07:00</published><updated>2010-07-07T21:45:49.032-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><category scheme='http://www.blogger.com/atom/ns#' term='grease monkey'/><title type='text'>Grease Monkey &amp; Cooks Illustrated Recipe Printing</title><content type='html'>Install this &lt;a href="http://userscripts.org/scripts/show/80985"&gt;script&lt;/a&gt; I wrote. Then:&lt;br /&gt;&lt;br /&gt;Navigate to a recipe on &lt;a href="http://CooksIllustrated.com/"&gt;CooksIllustrated.com&lt;/a&gt;. Click the Print link. Now click the Shrink button to eliminate the noise and have a recipe that will print to the width of an index card. &lt;br /&gt;&lt;br /&gt;To illustrate, here are the before and after screenshots:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Before&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_AGVcmhlbFXA/TDVXGL1CBBI/AAAAAAAAAW0/_UBpRiRvwHE/s1600/before.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 193px;" src="http://2.bp.blogspot.com/_AGVcmhlbFXA/TDVXGL1CBBI/AAAAAAAAAW0/_UBpRiRvwHE/s400/before.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5491391084414239762" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;b&gt;After&lt;/b&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_AGVcmhlbFXA/TDVXJpGvFgI/AAAAAAAAAW8/9oqmkAEijBo/s1600/after.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 188px;" src="http://1.bp.blogspot.com/_AGVcmhlbFXA/TDVXJpGvFgI/AAAAAAAAAW8/9oqmkAEijBo/s400/after.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5491391143812732418" /&gt;&lt;/a&gt;&lt;br /&gt;This is the code (also &lt;a href="http://userscripts.org/scripts/review/80985"&gt;here&lt;/a&gt;):&lt;br /&gt;&lt;br /&gt;&lt;code&gt;// ==UserScript==&lt;br /&gt;// @name           CooksIllustrated.com - shrink recipies to index card width for printing&lt;br /&gt;// @namespace      http://curious-attempt-bunny.blogspot.com/&lt;br /&gt;// @include        http://www.cooksillustrated.com/recipes/print/*&lt;br /&gt;// @require        https://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js&lt;br /&gt;// ==/UserScript==&lt;br /&gt;&lt;br /&gt;$('body').append('&amp;lt;div id="gm_shrink"&gt;shrink&amp;lt;/div&gt;');&lt;br /&gt;&lt;br /&gt;$('#gm_shrink').css(&lt;br /&gt; 'position', 'fixed').css(&lt;br /&gt; 'top', '2px').css(&lt;br /&gt; 'right', '2px').css(&lt;br /&gt; 'background-color', '#991111').css(&lt;br /&gt; 'color', 'white').css(&lt;br /&gt; 'cursor', 'pointer').css(&lt;br /&gt; 'padding', '2px 4px 2px 4px').css(&lt;br /&gt; 'border', 'solid 1px #000000').css(&lt;br /&gt; 'font-weight', 'bold').click(function() {&lt;br /&gt; var shrink = function(el) {&lt;br /&gt;  el.css('font-size', '8px').css('margin', '0')&lt;br /&gt;   .css('line-height', 'normal').css('font-size', '8px');&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; $('body').css('width', '310px');&lt;br /&gt; $('.pageSectionTop').after('&amp;lt;p&gt;&amp;lt;b&gt;'+$('h1').text()+'&amp;lt;/b&gt;&amp;lt;/p&gt;');&lt;br /&gt; $('b').css('font-size', '12px');&lt;br /&gt; $('.dek').hide();&lt;br /&gt; shrink($('em'));&lt;br /&gt; shrink($('p'));&lt;br /&gt; shrink($('td'));&lt;br /&gt; shrink($('a'));&lt;br /&gt; $('.pageSectionTop').hide();&lt;br /&gt; $('.pageSection').hide();&lt;br /&gt; $('img').hide();&lt;br /&gt; $('br').hide();&lt;br /&gt; $('td').css('padding', '0');&lt;br /&gt; $('#contentFooter').hide();&lt;br /&gt; $('.footerText').hide();&lt;br /&gt; $('#gm_shrink').hide();&lt;br /&gt;});&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-1364171476560800636?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/1364171476560800636/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=1364171476560800636' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/1364171476560800636'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/1364171476560800636'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/07/grease-monkey-cooks-illustrated-recipe.html' title='Grease Monkey &amp; Cooks Illustrated Recipe Printing'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_AGVcmhlbFXA/TDVXGL1CBBI/AAAAAAAAAW0/_UBpRiRvwHE/s72-c/before.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-8622576983733678270</id><published>2010-07-07T19:45:00.001-07:00</published><updated>2010-07-07T19:46:49.603-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><title type='text'>That Doesn't Happen Very Often!</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_AGVcmhlbFXA/TDU77Mu-erI/AAAAAAAAAWs/1Eo1zfD4bvE/s1600/good+times.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 275px; height: 160px;" src="http://2.bp.blogspot.com/_AGVcmhlbFXA/TDU77Mu-erI/AAAAAAAAAWs/1Eo1zfD4bvE/s400/good+times.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5491361208864766642" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-8622576983733678270?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/8622576983733678270/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=8622576983733678270' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/8622576983733678270'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/8622576983733678270'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/07/that-doesnt-happen-very-often.html' title='That Doesn&apos;t Happen Very Often!'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_AGVcmhlbFXA/TDU77Mu-erI/AAAAAAAAAWs/1Eo1zfD4bvE/s72-c/good+times.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-4017806869389559676</id><published>2010-07-07T19:27:00.001-07:00</published><updated>2010-07-07T19:48:10.619-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><title type='text'>Fifty Dangerous Things</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_AGVcmhlbFXA/TDU3o2MuVsI/AAAAAAAAAWk/XQ_N1KMVXtU/s400/fifty+dangerous+things.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 315px; height: 361px;" src="http://1.bp.blogspot.com/_AGVcmhlbFXA/TDU3o2MuVsI/AAAAAAAAAWk/XQ_N1KMVXtU/s400/fifty+dangerous+things.jpg" alt="" border="0" /&gt;&lt;/a&gt;Continuing on from &lt;a href="/2010/07/learning-as-fun.html"&gt;Learning as Fun&lt;/a&gt;: &lt;a href="http://www.fiftydangerousthings.com/"&gt;50 dangerous things&lt;/a&gt; (you should let your kid do)&lt;br /&gt;&lt;br /&gt;What a perfect book! Some of my favourites:&lt;br /&gt;* Play with the vacuum cleaner&lt;br /&gt;* Drop from high places&lt;br /&gt;* Break glass&lt;br /&gt;* Deconstruct an appliance&lt;br /&gt;* Poison your friends&lt;br /&gt;* Super glue your fingers together&lt;br /&gt;* Make a bomb in a bag&lt;br /&gt;* Boil water in a paper cup&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-4017806869389559676?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/4017806869389559676/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=4017806869389559676' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4017806869389559676'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4017806869389559676'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/07/fifty-dangerous-things.html' title='Fifty Dangerous Things'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_AGVcmhlbFXA/TDU3o2MuVsI/AAAAAAAAAWk/XQ_N1KMVXtU/s72-c/fifty+dangerous+things.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-7961397012974566026</id><published>2010-07-06T21:12:00.000-07:00</published><updated>2010-07-06T21:13:43.603-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gwt'/><title type='text'>AdSense and Gwt Apps?!?</title><content type='html'>So I have a GWT app with "zero content" because all the content is rendered by GWT. How do other people solve this?&lt;br /&gt;&lt;br /&gt;From Google AdSense:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;"Thank you for your interest in Google AdSense. Unfortunately, after&lt;br /&gt;reviewing your application, we're unable to accept you into Google AdSense&lt;br /&gt;at this time.&lt;br /&gt;&lt;br /&gt;We did not approve your application for the reasons listed below.&lt;br /&gt;&lt;br /&gt;Issues:&lt;br /&gt;&lt;br /&gt;- Under construction&lt;br /&gt;&lt;br /&gt;---------------------&lt;br /&gt;&lt;br /&gt;Further detail:&lt;br /&gt;&lt;br /&gt;Under construction: We've found that your site's pages are incomplete or&lt;br /&gt;under construction. To be considered for AdSense, we require websites to&lt;br /&gt;be fully launched and functioning, allowing users to navigate throughout&lt;br /&gt;your site with a menu, sitemap, or appropriate links. Your site must also&lt;br /&gt;contain enough content for our specialists to review and to display&lt;br /&gt;relevant ads. Once the majority of your site is complete and functional,&lt;br /&gt;we'll be happy to reconsider your application. &lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-7961397012974566026?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/7961397012974566026/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=7961397012974566026' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/7961397012974566026'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/7961397012974566026'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/07/adsense-and-gwt-apps.html' title='AdSense and Gwt Apps?!?'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-7480998288271832056</id><published>2010-07-06T21:10:00.000-07:00</published><updated>2010-07-06T21:11:02.989-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><title type='text'>Learning as Fun</title><content type='html'>&lt;img style="visibility:hidden;width:0px;height:0px;" border=0 width=0 height=0 src="http://counters.gigya.com/wildfire/IMP/CXNID=2000002.0NXC/bT*xJmx*PTEyNzg*NzU3NjUyMjQmcHQ9MTI3ODQ3NTc3MzIwNCZwPTEwMTkxJmQ9c3NfZW1iZWQmZz*yJm89ZmZmMTlkMmMzZTIz/NGM1ZDk4NjJjZDQ4YmEzNGYyNWEmb2Y9MA==.gif" /&gt;&lt;div style="width:425px" id="__ss_4381860"&gt;&lt;strong style="display:block;margin:12px 0 4px"&gt;&lt;a href="http://www.slideshare.net/dings/just-add-points-what-ux-can-and-cannot-learn-from-games" title="Just add points? What UX can (and cannot) learn from games"&gt;Just add points? What UX can (and cannot) learn from games&lt;/a&gt;&lt;/strong&gt;&lt;object id="__sse4381860" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=deterdinguxcampjustaddpoints100530-100601174613-phpapp01&amp;stripped_title=just-add-points-what-ux-can-and-cannot-learn-from-games" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed name="__sse4381860" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=deterdinguxcampjustaddpoints100530-100601174613-phpapp01&amp;stripped_title=just-add-points-what-ux-can-and-cannot-learn-from-games" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="padding:5px 0 12px"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/dings"&gt;Sebastian Deterding&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-7480998288271832056?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/7480998288271832056/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=7480998288271832056' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/7480998288271832056'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/7480998288271832056'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/07/learning-as-fun.html' title='Learning as Fun'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-1749814144677315117</id><published>2010-07-05T10:37:00.000-07:00</published><updated>2010-07-05T11:31:23.020-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='community'/><title type='text'>Updated: Places To Work Down-Town In Portland, OR</title><content type='html'>I've updated the map of the places a software developer might like to consider working at within a 2 mile radius of down-town Portland. I've changed the Collaboration settings to allow anyone to edit the map:&lt;br /&gt;&lt;br /&gt;&lt;iframe width="300" height="400" frameborder="no" scrolling="no" marginheight="0" marginwidth="0" src="http://maps.google.com/maps/ms?ie=UTF8&amp;hl=en&amp;om=1&amp;s=AARTsJoKdS8JzMFqCIJJaXO6bT-aimnYDw&amp;msa=0&amp;msid=106171862241309111490.000438b5ea9d2b8818ac2&amp;ll=45.524089,-122.683468&amp;spn=0.048107,0.051498&amp;z=13&amp;output=embed"&gt;&lt;/iframe&gt;&lt;br/&gt;&lt;a href="http://maps.google.com/maps/ms?ie=UTF8&amp;hl=en&amp;om=1&amp;msa=0&amp;msid=106171862241309111490.000438b5ea9d2b8818ac2&amp;ll=45.524089,-122.683468&amp;spn=0.048107,0.051498&amp;z=13&amp;source=embed" style="color:#0000FF;text-align:left;font-size:small"&gt;View Larger Map / See Full List&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-1749814144677315117?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/1749814144677315117/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=1749814144677315117' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/1749814144677315117'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/1749814144677315117'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/07/updated-places-to-work-down-town-in.html' title='Updated: Places To Work Down-Town In Portland, OR'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-2132235610025358142</id><published>2010-07-04T00:26:00.001-07:00</published><updated>2010-07-04T00:46:09.838-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='process'/><title type='text'>How Agile Are We?</title><content type='html'>&lt;a href="http://how-agile-are-we.appspot.com/"&gt;Assess your team's Agility&lt;/a&gt;, try out this app I've written - and give me some usability feedback!&lt;br /&gt;&lt;br /&gt;The app is hosted on appengine: &lt;a href="http://how-agile-are-we.appspot.com/"&gt;http://how-agile-are-we.appspot.com/&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://how-agile-are-we.appspot.com/"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 500px;" src="http://3.bp.blogspot.com/_AGVcmhlbFXA/TDA7X5Ed9-I/AAAAAAAAAWc/ssqSMew7vQA/s400/assess+your+agility2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5489953227407226850" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;All the material comes from &lt;a href="http://jamesshore.com/Agile-Book/assess_your_agility.html"&gt;The Art of Agile Development&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-2132235610025358142?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/2132235610025358142/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=2132235610025358142' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/2132235610025358142'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/2132235610025358142'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/07/how-agile-are-we.html' title='How Agile Are We?'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_AGVcmhlbFXA/TDA7X5Ed9-I/AAAAAAAAAWc/ssqSMew7vQA/s72-c/assess+your+agility2.png' height='72' width='72'/><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-8970879782618849452</id><published>2010-06-27T23:26:00.000-07:00</published><updated>2010-06-27T23:33:08.687-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='process'/><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><title type='text'>Assess Your Agility - The Lazy Way</title><content type='html'>I've put together a little GWT application based around the &lt;a href="http://jamesshore.com/Agile-Book/assess_your_agility.html"&gt;Assess Your Agility&lt;/a&gt; section of &lt;a href="http://jamesshore.com/Agile-Book/"&gt;The Art of Agile Development&lt;/a&gt;. It's work in progress using &lt;a href="http://code.google.com/p/gwt-graphics/wiki/Manual#Text"&gt;gwt-graphics&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_AGVcmhlbFXA/TChBDF5bz3I/AAAAAAAAAWU/BNQQ2UtHL4w/s1600/assess+your+agility.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 500px;" src="http://2.bp.blogspot.com/_AGVcmhlbFXA/TChBDF5bz3I/AAAAAAAAAWU/BNQQ2UtHL4w/s400/assess+your+agility.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5487707667329437554" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The idea is that it asks you to answer the questions first that will make the biggest difference to your agility assessment. That lets you stop as soon as you get tired of it, whilst giving you a full a picture as possible. Ideally you'd accumulate a weighted "to-improve" list of &lt;a href="http://jamesshore.com/Agile-Book/"&gt;Agile Practices&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-8970879782618849452?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/8970879782618849452/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=8970879782618849452' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/8970879782618849452'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/8970879782618849452'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/06/assess-your-agility-lazy-way.html' title='Assess Your Agility - The Lazy Way'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_AGVcmhlbFXA/TChBDF5bz3I/AAAAAAAAAWU/BNQQ2UtHL4w/s72-c/assess+your+agility.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-7667290704775080775</id><published>2010-05-31T22:05:00.000-07:00</published><updated>2010-05-31T22:09:20.148-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><title type='text'>A Cure For The Common Cold?</title><content type='html'>It's not a cure, but it most definitely is a combination of rarely* found together ingredients:&lt;br /&gt;&lt;br /&gt;#1 Celestial Tea's Wild Berry Zinger&lt;br /&gt;#2 Ribena&lt;br /&gt;#3 Jack Daniels&lt;br /&gt;&lt;br /&gt;This tastes good, but far more likely to be of use is a &lt;a href="http://en.wikipedia.org/wiki/Neti_pot"&gt;Neti Pot&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;* #1 and #2 being indigenous to separate continents.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-7667290704775080775?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/7667290704775080775/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=7667290704775080775' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/7667290704775080775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/7667290704775080775'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/05/cure-for-common-cold.html' title='A Cure For The Common Cold?'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-4646609277294539056</id><published>2010-05-29T14:45:00.001-07:00</published><updated>2010-05-29T14:46:02.435-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><title type='text'>Configuring TextWrangler To Edit Git Commit Comments</title><content type='html'>&lt;code&gt;git config core.editor "edit -w"&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-4646609277294539056?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/4646609277294539056/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=4646609277294539056' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4646609277294539056'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4646609277294539056'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/05/configuring-textwrangler-to-edit-git.html' title='Configuring TextWrangler To Edit Git Commit Comments'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-1172103602376208828</id><published>2010-05-27T22:15:00.000-07:00</published><updated>2010-05-27T22:26:00.454-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ai'/><category scheme='http://www.blogger.com/atom/ns#' term='dominion'/><title type='text'>Heuristics For Solo Dominion Play II</title><content type='html'>Next steps are to calculate values of different decks (to aid in choosing what to buy to add to them). Right now this is a money-only look at this calculation.&lt;br /&gt;&lt;br /&gt;Not sure what I'm talking about? Read the &lt;a href="http://curious-attempt-bunny.blogspot.com/2010/05/heuristics-for-solo-dominion-play.html"&gt;previous post in this thread&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;As a quick test, what's the expected value of a starting hand?&lt;br /&gt;&lt;br /&gt;&lt;code&gt;Deck [Copper:7, Estate:3] has mean hand money value of 3.50 with variance 0.583&lt;br /&gt;Distribution of hand values:&lt;br /&gt;2: 0.083%&lt;br /&gt;3: 0.42%&lt;br /&gt;4: 0.42%&lt;br /&gt;5: 0.083%&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_AGVcmhlbFXA/S_6GH-JY8yI/AAAAAAAAAWM/8ImHyPURPUE/s400/solo+game.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 153px;" src="http://4.bp.blogspot.com/_AGVcmhlbFXA/S_6GH-JY8yI/AAAAAAAAAWM/8ImHyPURPUE/s400/solo+game.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;To test out some ideas. If it were possible to choose between buying 2 Silver or 1 Gold, which would be better?&lt;br /&gt;&lt;br /&gt;Early in the game 2 Silver beat 1 Gold:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;Deck [Copper:7, Estate:3, Gold:1] has mean hand money value of 4.55 with variance 1.88&lt;br /&gt;Distribution of hand values:&lt;br /&gt;2: 0.045%&lt;br /&gt;3: 0.23%&lt;br /&gt;4: 0.24%&lt;br /&gt;5: 0.18%&lt;br /&gt;6: 0.23%&lt;br /&gt;7: 0.076%&lt;br /&gt;Deck [Copper:7, Estate:3, Silver:2] has mean hand money value of 4.58 with variance 1.30&lt;br /&gt;Distribution of hand values:&lt;br /&gt;2: 0.027%&lt;br /&gt;3: 0.15%&lt;br /&gt;4: 0.29%&lt;br /&gt;5: 0.32%&lt;br /&gt;6: 0.17%&lt;br /&gt;7: 0.044%&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Later in the game 1 Gold beats* 2 Silver:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;Deck [Copper:7, Estate:3, Silver:7, Gold:5] has mean hand money value of 8.18 with variance 3.88&lt;br /&gt;Distribution of hand values:&lt;br /&gt;2: 0.00080%&lt;br /&gt;3: 0.0058%&lt;br /&gt;4: 0.023%&lt;br /&gt;5: 0.059%&lt;br /&gt;6: 0.11%&lt;br /&gt;7: 0.17%&lt;br /&gt;8: 0.19%&lt;br /&gt;9: 0.18%&lt;br /&gt;10: 0.14%&lt;br /&gt;11: 0.078%&lt;br /&gt;12: 0.032%&lt;br /&gt;13: 0.0093%&lt;br /&gt;14: 0.0013%&lt;br /&gt;15: 3.8e-05%&lt;br /&gt;Deck [Copper:7, Estate:3, Silver:5, Gold:6] has mean hand money value of 8.33 with variance 4.32&lt;br /&gt;Distribution of hand values:&lt;br /&gt;2: 0.0010%&lt;br /&gt;3: 0.0069%&lt;br /&gt;4: 0.023%&lt;br /&gt;5: 0.057%&lt;br /&gt;6: 0.10%&lt;br /&gt;7: 0.16%&lt;br /&gt;8: 0.18%&lt;br /&gt;9: 0.18%&lt;br /&gt;10: 0.14%&lt;br /&gt;11: 0.088%&lt;br /&gt;12: 0.044%&lt;br /&gt;13: 0.015%&lt;br /&gt;14: 0.0037%&lt;br /&gt;15: 0.00029%&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;* beats means here: it maximizes your expected hand value.&lt;br /&gt;&lt;br /&gt;As a side note. The algorithm for calculating this data is a pretty interesting one. Give it a shot.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-1172103602376208828?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/1172103602376208828/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=1172103602376208828' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/1172103602376208828'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/1172103602376208828'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/05/heuristics-for-solo-dominion-play-ii.html' title='Heuristics For Solo Dominion Play II'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_AGVcmhlbFXA/S_6GH-JY8yI/AAAAAAAAAWM/8ImHyPURPUE/s72-c/solo+game.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-5605568511656666410</id><published>2010-05-27T20:22:00.000-07:00</published><updated>2010-05-27T20:38:51.592-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>Test Data Builders Part II</title><content type='html'>Following on from &lt;a href="http://curious-attempt-bunny.blogspot.com/2009/03/building-test-data.html"&gt;Test Data Builders Part I&lt;/a&gt;, one of the authors of &lt;a href="http://www.growing-object-oriented-software.com/"&gt;Growing Object Oriented Software&lt;/a&gt; has produced a small DSL framework, called &lt;a href="http://code.google.com/p/make-it-easy/"&gt;MakeItEasy&lt;/a&gt;, for writing test data builders. Once you have written the code for the builders, using them reads like this:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;Maker&lt;Person&gt; anOldPerson = a(Person, with(age, 80));&lt;br /&gt;doSomethingWith(make(anOldPerson));&lt;br /&gt;&lt;br /&gt;Maker&lt;Person&gt; anOldWoman = anOldPerson.but(with(name, "Alice"));&lt;br /&gt;Maker&lt;Person&gt; anOldMan = anOldPerson.but(with(name, "Bill"));&lt;br /&gt;doSomethingElseWith(make(anOldWoman));&lt;br /&gt;doWhateverWith(make(anOldMan));&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This DSL makes for easy reading. It's still going to be a pain to write all the &lt;a href="http://code.google.com/p/make-it-easy/source/browse/#svn/trunk/src/example/fruit"&gt;boilerplate code&lt;/a&gt; for the builders, though. Perhaps some intelligent application of &lt;a href="http://groovy.codehaus.org/Local+AST+Transformations"&gt;Groovy Local ASTs&lt;/a&gt;, presenting Java-friend interfaces, could save the day?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-5605568511656666410?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/5605568511656666410/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=5605568511656666410' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/5605568511656666410'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/5605568511656666410'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/05/test-data-builders-part-ii.html' title='Test Data Builders Part II'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-1250093638601846644</id><published>2010-05-27T07:38:00.000-07:00</published><updated>2010-05-27T09:15:43.892-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ai'/><category scheme='http://www.blogger.com/atom/ns#' term='dominion'/><title type='text'>Heuristics For Solo Dominion Play</title><content type='html'>Have you tried &lt;a href="http://www.boardgamegeek.com/boardgame/36218/dominion"&gt;Dominion&lt;/a&gt; yet? It's a lot of fun! Like all good strategy games Dominion just send me into a spin of "how would I code a computer to play this game?"&lt;br /&gt;&lt;br /&gt;Here's how I've scaled down the game for very simple solo play:&lt;br /&gt;&lt;br /&gt;1. Only money cards and the Province are purchasable&lt;br /&gt;2. There are five Province cards&lt;br /&gt;&lt;br /&gt;A quick overview of the rules: you start with a deck of seven Copper and three Estates (Estates are worthless in this solo play game as they don't help you win). You keep drawing five cards from your deck, shuffling you discards to make a new deck as needed. You sum up the purchasing power of each money card in your hand and optionally buy a card (0 for Copper, 3 for Silver, 6 for Gold, 8 for Province). The bought card and the hand of five cards then go into the discard. The game ends when the fifth and final Province card is purchased. The aim of the game is to finish after the fewest number of hands drawn.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_AGVcmhlbFXA/S_6GH-JY8yI/AAAAAAAAAWM/8ImHyPURPUE/s1600/solo+game.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 153px;" src="http://4.bp.blogspot.com/_AGVcmhlbFXA/S_6GH-JY8yI/AAAAAAAAAWM/8ImHyPURPUE/s400/solo+game.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5475961668428690210" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;So what's the best strategy for play in the very very simplified version of the game? You'd hope that it would be "buy the highest value card that I can with the money that I have".&lt;br /&gt;&lt;br /&gt;It turns out that that's close, but there is better. I wrote a simulation for the game and coded up a number of different heuristics. In the style of Contract Bridge (essentially n games with fixed random seeds for each) I compared all the heuristics using a little ad-hoc parameter value tuning along the way. After that I ran a million-game simulation to compare them all. It turns out that the most effective strategy was to never ever buy copper coins (go without instead), to otherwise always buy the most expensive card you can with the exception of Province cards which you only buy on or after your eighth hand.&lt;br /&gt;&lt;br /&gt;Howsat!?&lt;br /&gt;&lt;br /&gt;I tried to come up with something more to do with the money-value distribution instead of the hand number but they performed worse. Here's the breakdown:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;Calculation for a sample size of 1000000 games:&lt;br /&gt;buyHighestPossible: 19.229789 average number of hands to finish&lt;br /&gt;buyHighestPossibleBeforeRoundEight: 19.189278 average number of hands to finish&lt;br /&gt;buyHighestPossibleBeforeRoundEightButNeverCopper: 19.086139 average number of hands to finish&lt;br /&gt;buyHighestPossibleBeforeRoundEightButNeverCopperExceptInTheFirstTwoHands: 19.129784 average number of hands to finish&lt;br /&gt;buyMoneyUntilAverageHandValueExceedsSixPointSix: 19.194762 average number of hands to finish&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;It's still a very small difference. You'd have to play ten games before you'd have a reasonable chance of noticing the difference between the #1 and #2 strategy.&lt;br /&gt;&lt;br /&gt;Edit: Wow. With the averages being so similar the variance would be very useful information.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-1250093638601846644?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/1250093638601846644/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=1250093638601846644' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/1250093638601846644'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/1250093638601846644'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/05/heuristics-for-solo-dominion-play.html' title='Heuristics For Solo Dominion Play'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_AGVcmhlbFXA/S_6GH-JY8yI/AAAAAAAAAWM/8ImHyPURPUE/s72-c/solo+game.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-3340079115032601902</id><published>2010-05-16T12:25:00.000-07:00</published><updated>2010-05-16T12:35:33.315-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='starcraft2'/><title type='text'>Calculating StarCraft2 Build Order Templates: Part II</title><content type='html'>Wow. It works. Now that I've integrated a proper model of the economy this is pretty accurate! Here's what my program output:&lt;br /&gt;&lt;code&gt;Goals are: [prism, warp, blink]&lt;br /&gt;Required plan elements are: [prism, warp, blink, robotics, cyber, gate, twilight, assim]&lt;br /&gt;&lt;br /&gt;Searching...&lt;br /&gt;Best so far: [gate, cyber, assim, warp, robotics, prism, twilight, blink]: 8:12&lt;br /&gt;Best so far: [gate, assim, cyber, warp, robotics, prism, twilight, blink]: 7:25&lt;br /&gt;Best so far: [assim, gate, cyber, warp, robotics, twilight, prism, blink]: 7:03&lt;br /&gt;Best so far: [assim, gate, cyber, warp, robotics, twilight, blink, prism]: 7:01&lt;br /&gt;Best so far: [assim, gate, cyber, warp, twilight, blink, robotics, prism]: 6:53&lt;br /&gt;Best so far: [assim, gate, cyber, warp, twilight, robotics, blink, prism]: 6:48&lt;br /&gt;There are 3 equivalently optimal plan(s):&lt;br /&gt;[assim, gate, cyber, warp, twilight, robotics, blink, prism]: 6:48&lt;br /&gt;[assim, gate, cyber, twilight, warp, robotics, blink, prism]: 6:48&lt;br /&gt;[assim, gate, cyber, twilight, robotics, warp, blink, prism]: 6:48&lt;br /&gt;&lt;br /&gt;Detail for [assim, gate, cyber, warp, twilight, robotics, blink, prism]:&lt;br /&gt;@ 75 minerals (~8/10) -&gt; assim (~0:32..1:02)&lt;br /&gt;@ 150 minerals (~12/18) -&gt; gate (~2:13..3:18)&lt;br /&gt;@ gate (~16/18) -&gt; cyber (~3:18..4:08)&lt;br /&gt;@ cyber (~19/26) -&gt; warp (~4:08..6:28)&lt;br /&gt;@ 150 minerals, 100 gas (~19/26) -&gt; twilight (~4:08..4:58)&lt;br /&gt;@ 200 minerals, 100 gas (~19/26) -&gt; robotics (~4:21..5:26)&lt;br /&gt;@ twilight (~21/26) -&gt; blink (~4:58..6:48)&lt;br /&gt;@ robotics (~23/26) -&gt; prism (~5:26..6:16)&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Trying to follow this, my actual timings were:&lt;br /&gt;&lt;code&gt;8/10 (0:37) assim&lt;br /&gt;8/10 (1:00) pylon&lt;br /&gt;12/16 (2:12) gate&lt;br /&gt;14/16 ?? pylon&lt;br /&gt;16/16 (3:19) cyber&lt;br /&gt;18/26 ?? warp&lt;br /&gt;18/26 (4:20) twilight -- 10 seconds late&lt;br /&gt;18/26 (4:25) robotics&lt;br /&gt;24/26 ?? pylon&lt;br /&gt;?? ?? blink&lt;br /&gt;25/26 (5:33) prism -- 10 seconds late&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;I call that a success! Seriously, what were the chances that the simulation would be that accurate!?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-3340079115032601902?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/3340079115032601902/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=3340079115032601902' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3340079115032601902'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3340079115032601902'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/05/calculating-starcraft2-build-order_16.html' title='Calculating StarCraft2 Build Order Templates: Part II'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-7635889715533797408</id><published>2010-05-15T21:59:00.000-07:00</published><updated>2010-05-15T22:03:40.153-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='starcraft2'/><title type='text'>Optimal Economy Strategies in StarCraft2</title><content type='html'>The main problem I had with &lt;a href="http://curious-attempt-bunny.blogspot.com/2010/05/calculating-starcraft2-build-order.html"&gt;Calculating StarCraft2 Build Order Templates&lt;/a&gt; was having such an inaccurate model of the economy. I've made some progress on that front, and have posted my findings on the TeamLiquid strategy forum &lt;a href="http://www.teamliquid.net/forum/viewmessage.php?topic_id=125620"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-7635889715533797408?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/7635889715533797408/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=7635889715533797408' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/7635889715533797408'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/7635889715533797408'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/05/optimal-economy-strategies-in.html' title='Optimal Economy Strategies in StarCraft2'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-2319077983503592546</id><published>2010-05-11T22:47:00.001-07:00</published><updated>2010-05-12T08:47:37.369-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='starcraft2'/><title type='text'>Calculating StarCraft2 Build Order Templates</title><content type='html'>So, you're interested in StarCraft2, and you have a plan for your game, e.g.: I want to attack using stalkers, with the blink upgrade, and ferry them to the enemy in a warp prism. Okay, but it could take a while to work out a sensible basic order to build these things in so that you can attack at the earliest possible time. This is where I apply my programming hammer to my StarCraft2-experience-deficit nail:&lt;code&gt;&lt;/code&gt;&lt;pre&gt;// name, mineral cost, gas cost, time to build&lt;br /&gt;cyber = new Item("cyber", 150, 0, 50)&lt;br /&gt;warp = new Item("warp", 50, 50, 140)&lt;br /&gt;robotics = new Item("robotics", 200, 100, 65)&lt;br /&gt;prism = new Item("prism", 200, 0, 50)&lt;br /&gt;twilight = new Item('twilight', 150, 100, 50)&lt;br /&gt;blink = new Item('blink', 150, 150, 110)&lt;br /&gt;&lt;br /&gt;warp.requires = cyber&lt;br /&gt;robotics.requires = cyber&lt;br /&gt;prism.requires = robotics&lt;br /&gt;twilight.requires = cyber&lt;br /&gt;blink.requires = twilight&lt;/pre&gt;I've started coding up something naive with a friend and have it outputting this (with lots of assumptions and simplifications, e.g. time starts at 0:00 with a gateway in existence, no new probes are made, arbitrary mining rate used, ignored gas cost):&lt;br /&gt;&lt;br /&gt;&lt;code&gt;0:38..1:28: cyber&lt;br /&gt;2:06..2:56: twilight&lt;br /&gt;2:19..4:39: warp&lt;br /&gt;3:09..4:14: robotics&lt;br /&gt;3:47..5:37: blink&lt;br /&gt;5:04..5:54: prism&lt;br /&gt;&lt;br /&gt;Critical path:&lt;br /&gt;0:38..1:28: cyber&lt;br /&gt;3:09..4:14: robotics&lt;br /&gt;5:04..5:54: prism&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;If this pans out, it should lead to:&lt;br /&gt;&lt;br /&gt;* an ideal order in which to build,&lt;br /&gt;* build triggers / approximate food timing,&lt;br /&gt;* the earliest a plan could be realized,&lt;br /&gt;* the key components that being slow on would delay the plan.&lt;br /&gt;&lt;br /&gt;Edit: We've made some more progress. This is more complete but is still missing a good model of the economy's probe building and behaviour:&lt;br /&gt;&lt;code&gt;Goals are: [prism, warp, blink]&lt;br /&gt;Required plan elements are: [prism, warp, blink, robotics, cyber, gate, twilight, assim]&lt;br /&gt;&lt;br /&gt;Searching...&lt;br /&gt;Best so far: [gate, cyber, assim, warp, robotics, prism, twilight, blink]: 6:33&lt;br /&gt;Best so far: [gate, assim, cyber, warp, robotics, prism, twilight, blink]: 5:58&lt;br /&gt;Best so far: [gate, assim, cyber, warp, robotics, twilight, prism, blink]: 5:42&lt;br /&gt;Best so far: [assim, gate, cyber, warp, robotics, twilight, prism, blink]: 5:22&lt;br /&gt;Best so far: [assim, gate, cyber, warp, robotics, twilight, blink, prism]: 5:15&lt;br /&gt;There are 6 equivalently optimal plan(s):&lt;br /&gt;[assim, gate, cyber, warp, robotics, twilight, blink, prism]: 5:15&lt;br /&gt;[assim, gate, cyber, warp, twilight, robotics, blink, prism]: 5:15&lt;br /&gt;[assim, gate, cyber, robotics, warp, twilight, blink, prism]: 5:15&lt;br /&gt;[assim, gate, cyber, robotics, twilight, warp, blink, prism]: 5:15&lt;br /&gt;[assim, gate, cyber, twilight, warp, robotics, blink, prism]: 5:15&lt;br /&gt;[assim, gate, cyber, twilight, robotics, warp, blink, prism]: 5:15&lt;br /&gt;&lt;br /&gt;First plan detail:&lt;br /&gt;@ 75 minerals -&gt; assim (~0:05..0:35)&lt;br /&gt;@ 150 minerals -&gt; gate (~0:32..1:37)&lt;br /&gt;@ gate -&gt; cyber (~1:37..2:27)&lt;br /&gt;@ cyber -&gt; warp (~2:27..4:47)&lt;br /&gt;@ 200 minerals, 100 gas -&gt; robotics (~2:27..3:32)&lt;br /&gt;@ 150 minerals, 100 gas -&gt; twilight (~2:27..3:17)&lt;br /&gt;@ 150 minerals, 150 gas -&gt; blink (~3:25..5:15)&lt;br /&gt;@ robotics -&gt; prism (~3:32..4:22)&lt;br /&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-2319077983503592546?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/2319077983503592546/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=2319077983503592546' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/2319077983503592546'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/2319077983503592546'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/05/calculating-starcraft2-build-order.html' title='Calculating StarCraft2 Build Order Templates'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-2263735087037913064</id><published>2010-05-07T21:26:00.000-07:00</published><updated>2010-05-07T21:33:16.231-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='haskell'/><title type='text'>Experimenting With Haskell</title><content type='html'>I tried implementing a simple solution in Haskell as many ways as I could think of. The problem:&lt;br /&gt;&lt;br /&gt;Take a list of numbers and do something similar to run length encoding. So &lt;code&gt;[1,1,2,2,2,4,3,3]&lt;/code&gt; should become &lt;code&gt;[(1,2),(2,3),(4,1),(3,2)]&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;At the end are the solutions I came up with. I like the final solution the best. Are there other ways that you know of?&lt;br /&gt;&lt;br /&gt;It bugs me that I can't define implicit guards so that instead of &lt;code&gt;f a b | a == b = ...&lt;/code&gt; I could say &lt;code&gt;f a a = ...&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&lt;pre&gt;-- auxilary method and pattern matching and an accumulator&lt;br /&gt;{-&lt;br /&gt;rle [] = []&lt;br /&gt;rle (h:t) = rle_acc t h 1&lt;br /&gt;&lt;br /&gt;rle_acc [] b c = [(b,c)]&lt;br /&gt;rle_acc (a:t) b c | a == b = rle_acc t b (c+1)&lt;br /&gt;rle_acc (a:t) b c = [(b,c)] ++ rle_acc t a 1&lt;br /&gt;-}&lt;br /&gt;&lt;br /&gt;-- auxilary method and pattern matching and two accumulators, and tail recursion&lt;br /&gt;{-&lt;br /&gt;rle [] = []&lt;br /&gt;rle (h:t) = rle_acc t h 1 []&lt;br /&gt;&lt;br /&gt;rle_acc [] b c acc = acc ++ [(b,c)]&lt;br /&gt;rle_acc (a:t) b c acc | a == b = rle_acc t b (c+1) acc&lt;br /&gt;rle_acc (a:t) b c acc = rle_acc t a 1 (acc ++ [(b,c)])&lt;br /&gt;-}&lt;br /&gt;&lt;br /&gt;-- using foldl&lt;br /&gt;{-&lt;br /&gt;rle list = reverse $ foldl (rle_acc) [] list&lt;br /&gt;&lt;br /&gt;rle_acc [] b = [(b,1)]&lt;br /&gt;rle_acc ((last, count):rest) b | b == last = ((b, count+1):rest)&lt;br /&gt;rle_acc acc b = ((b, 1):acc)&lt;br /&gt;-}&lt;br /&gt;&lt;br /&gt;-- without an accumulator&lt;br /&gt;rle (a:b:rest) | a == b = let (_, count):rest2 = rle (b:rest)&lt;br /&gt;                             in (b,count+1):rest2&lt;br /&gt;rle (a:rest) = (a,1):rle rest&lt;br /&gt;rle [] = []&lt;br /&gt;&lt;br /&gt;main = print $ rle [1,1,2,2,2,4,3,3]&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-2263735087037913064?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/2263735087037913064/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=2263735087037913064' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/2263735087037913064'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/2263735087037913064'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/05/experimenting-with-haskell.html' title='Experimenting With Haskell'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-5334464454350568988</id><published>2010-04-24T23:03:00.001-07:00</published><updated>2010-04-24T23:06:53.499-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='imagemagick'/><title type='text'>Stop Animation</title><content type='html'>I keep looking up how to create an animated gif using ImageMagick and then forgetting, so here it is:&lt;code&gt;&lt;pre&gt;convert mypref_??.jpg myanim.gif&lt;/pre&gt;&lt;/code&gt;Here's one made from photos I took a while ago:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://img27.imageshack.us/img27/6039/candleanim.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 480px; height: 320px;" src="http://img27.imageshack.us/img27/6039/candleanim.gif" border="0" alt="" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-5334464454350568988?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/5334464454350568988/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=5334464454350568988' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/5334464454350568988'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/5334464454350568988'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/04/stop-animation.html' title='Stop Animation'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-7514197980817753600</id><published>2010-04-22T18:56:00.000-07:00</published><updated>2010-04-22T19:02:17.020-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='process'/><title type='text'>Were You Born To Be Agile?</title><content type='html'>&lt;a href="http://blog.odd-e.com/blog/"&gt;Bas Vodde&lt;/a&gt; put together a &lt;a href="http://www.odd-e.com/material/2010/scrum_shanghai/culture.pdf"&gt;presentation&lt;/a&gt; that to me suggests that Americans are going to be culturally less compatible with Agile than Scandinavians:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_AGVcmhlbFXA/S9D_OrfyJTI/AAAAAAAAAWE/vKnkuCc7vSA/s1600/cultural+agility+index.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 500px;" src="http://3.bp.blogspot.com/_AGVcmhlbFXA/S9D_OrfyJTI/AAAAAAAAAWE/vKnkuCc7vSA/s400/cultural+agility+index.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5463146975659697458" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-7514197980817753600?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/7514197980817753600/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=7514197980817753600' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/7514197980817753600'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/7514197980817753600'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/04/where-you-born-to-be-agile.html' title='Were You Born To Be Agile?'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_AGVcmhlbFXA/S9D_OrfyJTI/AAAAAAAAAWE/vKnkuCc7vSA/s72-c/cultural+agility+index.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-5247135749175107730</id><published>2010-04-17T08:42:00.000-07:00</published><updated>2010-04-17T09:04:18.838-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bittorrent'/><title type='text'>BitTorrent URL BootStrap Idea</title><content type='html'>So finally &lt;a href="http://www.teamliquid.net/forum/viewmessage.php?topic_id=104154"&gt;Day[9]&lt;/a&gt; has found a host site, &lt;a href="http://blip.tv/file/3486428"&gt;Blip.TV&lt;/a&gt;, which allows the users to download the video rather than watch it online and risk playback issues. Great. So what's the problem? It still takes a fair while to download 200Mb+ at a max of 100K/s.&lt;br /&gt;&lt;br /&gt;Here's my idea:&lt;br /&gt;&lt;br /&gt;BitTorrent's could be seeded by an HTTP URL. That way when downloading users can supplement the limited bandwidth of the host with portions that other users had downloaded. This isn't a totally new idea, Blizzard's download tool bootstraps in this way. Random access to the HTTP content is also possible through the use of the HTTP &lt;code&gt;Content-Range&lt;/code&gt; header field, so it appears to be workable without any custom server-side support.&lt;br /&gt;&lt;br /&gt;Perhaps this is something that could happily be turned into a browser plug-in? It could work something like this:&lt;br /&gt;&lt;br /&gt;1. The plugin detects that a download has started and that the file size is over some limit, say 100Mb.&lt;br /&gt;2. It then looks for a dht hash of the URL from an indexing service.&lt;br /&gt;3. If a dht exists then it begins searching for other peers.&lt;br /&gt;4. If no dht exists then once the download completes it generates a hash for the content and submits it to the indexing service.&lt;br /&gt;&lt;br /&gt;In either case there would be some sort of seeding necessary by the plug-in. The main hassle would probably be working with or overriding the browsers default download strategy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-5247135749175107730?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/5247135749175107730/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=5247135749175107730' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/5247135749175107730'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/5247135749175107730'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/04/bittorrent-url-bootstrap-idea.html' title='BitTorrent URL BootStrap Idea'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-6340203046092209642</id><published>2010-03-28T11:21:00.001-07:00</published><updated>2010-03-28T11:24:00.858-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Great Use of Groovy ASTs</title><content type='html'>Take a look at &lt;a href="http://grails-inside.blogspot.com/2010/03/contract-oriented-programming-with.html"&gt;gcontracts&lt;/a&gt;. Here's their example usage:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;@Invariant({ firstName != null &amp;&amp; lastName != null })&lt;br /&gt;class Person {&lt;br /&gt;  String firstName&lt;br /&gt;  String lastName&lt;br /&gt;  String name&lt;br /&gt;&lt;br /&gt;  public Person() {}&lt;br /&gt;&lt;br /&gt;  public Person(final String firstName, final String lastName) {&lt;br /&gt;    this.firstName = firstName&lt;br /&gt;    this.lastName = lastName&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Override&lt;br /&gt;  @Requires({ firstName.size() &gt; 0 &amp;&amp; lastName.size() &gt; 0 })&lt;br /&gt;  def String toString() {&lt;br /&gt;    return "${firstName} und ${lastName}"&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Requires({ delimiter in ['.', ',', ':'] })&lt;br /&gt;  @Ensures({ name.size() &gt; 1 } )&lt;br /&gt;  def initCompleteName(String delimiter) {&lt;br /&gt;    name = "${firstName}${delimiter}${lastName}"&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;&lt;code&gt;Requires&lt;/code&gt; are the preconditions and &lt;code&gt;Ensures&lt;/code&gt; are the post-conditions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-6340203046092209642?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/6340203046092209642/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=6340203046092209642' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/6340203046092209642'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/6340203046092209642'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/03/great-use-of-groovy-asts.html' title='Great Use of Groovy ASTs'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-9184803088100171584</id><published>2010-03-19T12:39:00.000-07:00</published><updated>2010-03-22T11:28:40.540-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='starcraft2'/><title type='text'>StarCraft2 AI Coding</title><content type='html'>So I was curious as to how come the StarCrack AI folks are finding it so easy to develop new and improved AI for StarCraft 2. It turns out that there's an SC2Data file that's an mpq archive. So I downloaded their AI distribution and extracted their code. The first thing I noticed is that there's more than AI in here, there's actual game balancing information. E.g.:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&amp;lt;CWeaponLegacy id="Marauder"&gt;&lt;br /&gt;  &amp;lt;EditorCategories value="Race:Terran"/&gt;&lt;br /&gt;  &amp;lt;DisplayEffect value="MarauderU"/&gt;&lt;br /&gt;  &amp;lt;DisplayAttackCount value="1"/&gt;&lt;br /&gt;  &amp;lt;TargetFilters value="Ground,Visible;Missile,Stasis,Dead,Hidden,Invulnerable"/&gt;&lt;br /&gt;  &amp;lt;Range value="6"/&gt;&lt;br /&gt;  &amp;lt;Period value="1.5"/&gt;&lt;br /&gt;  &amp;lt;DamagePoint value="0"/&gt;&lt;br /&gt;  &amp;lt;Backswing value="0"/&gt;&lt;br /&gt;  &amp;lt;Effect value="MarauderLM"/&gt;&lt;br /&gt;  &amp;lt;Icon value="Assets\Textures\btn-upgrade-terran-infantryweaponslevel1.dds"/&gt;&lt;br /&gt;&amp;lt;/CWeaponLegacy&gt;&lt;/pre&gt;&lt;/code&gt;That makes me wonder if it's possible to edit these files in order to artificially make an opposing race harder or easier to play against.&lt;br /&gt;&lt;br /&gt;Looking at the contents of TriggerLibs, this all looks very much like C code. Sweet. My next thought is that this can probably be translated into one big Groovy script without too much hassle, and then these StarCrack folks could write test harnesses! It must be a real pain to have to crank up StarCraft itself to see if you coded the right thing. I don't see all the TriggerDebugOutput logging as being a good substitute.&lt;br /&gt;&lt;br /&gt;Edit: I gave this a quick stab. The first real problem with this idea is that there are multiple declarations of the method InitCounters.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-9184803088100171584?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/9184803088100171584/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=9184803088100171584' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/9184803088100171584'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/9184803088100171584'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/03/starcraft2-ai-coding.html' title='StarCraft2 AI Coding'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-8734844278363619860</id><published>2010-02-28T19:29:00.000-08:00</published><updated>2010-02-28T19:31:39.757-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='starcraft'/><title type='text'>Where Does the Time Go?</title><content type='html'>&lt;a href="http://wiki.teamliquid.net/starcraft/Strategy"&gt;Here&lt;/a&gt;, &lt;a href="http://wiki.teamliquid.net/starcraft/Day%289%29_Podcasts"&gt;here&lt;/a&gt;, &lt;a href="http://www.teamliquid.net/forum/viewmessage.php?topic_id=104154"&gt;here&lt;/a&gt;, and &lt;a href="http://www.youtube.com/user/diggitySC"&gt;here&lt;/a&gt;. With all that, who's got time for technology and blogging? ...Seriously.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-8734844278363619860?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/8734844278363619860/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=8734844278363619860' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/8734844278363619860'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/8734844278363619860'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/02/where-does-time-go.html' title='Where Does the Time Go?'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-6275773387415117588</id><published>2010-01-20T16:55:00.000-08:00</published><updated>2010-01-20T16:59:01.227-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maven'/><category scheme='http://www.blogger.com/atom/ns#' term='aspectj'/><title type='text'>Mvn Voodoo - eclipse:eclipse Doesn't Include AspectJ in the Classpath</title><content type='html'>Nice huh? Well, the answer is in &lt;a href="http://jira.codehaus.org/browse/MECLIPSE-544"&gt;MECLIPSE-544&lt;/a&gt;. I added this to my pom.xml to fix the problem:&lt;code&gt;&lt;pre&gt;&amp;lt;build&gt;&lt;br /&gt;  &amp;lt;plugins&gt;&lt;br /&gt;    &amp;lt;plugin&gt;&lt;br /&gt;      &amp;lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;&lt;br /&gt;      &amp;lt;artifactId&gt;maven-eclipse-plugin&lt;/artifactId&gt;&lt;br /&gt;      &amp;lt;configuration&gt;&lt;br /&gt;        &amp;lt;!-- http://jira.codehaus.org/browse/MECLIPSE-544 --&gt;&lt;br /&gt;        &amp;lt;ajdtVersion&gt;none&lt;/ajdtVersion&gt;&lt;br /&gt;      &amp;lt;/configuration&gt;&lt;br /&gt;    &amp;lt;/plugin&gt;&lt;br /&gt;  &amp;lt;/plugins&gt;&lt;br /&gt;&amp;lt;/build&gt;&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-6275773387415117588?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/6275773387415117588/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=6275773387415117588' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/6275773387415117588'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/6275773387415117588'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/01/mvn-voodoo-eclipseeclipse-doesnt.html' title='Mvn Voodoo - eclipse:eclipse Doesn&apos;t Include AspectJ in the Classpath'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-8336389643315487456</id><published>2010-01-17T21:56:00.001-08:00</published><updated>2010-01-17T21:57:06.571-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><title type='text'>Upgrade Complete</title><content type='html'>if you've played any online flash games you may well find this amusing:&lt;br /&gt;&lt;br /&gt;[&lt;a href="http://armorgames.com/play/3955/upgrade-complete"&gt;Upgrade Complete&lt;/a&gt;]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-8336389643315487456?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/8336389643315487456/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=8336389643315487456' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/8336389643315487456'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/8336389643315487456'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/01/upgrade-complete.html' title='Upgrade Complete'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-3578580681212489775</id><published>2010-01-16T17:52:00.000-08:00</published><updated>2010-01-16T18:01:07.321-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='arduino'/><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>Test &amp; Code Edit Patterns - Part III</title><content type='html'>Okay. It works. Here's a picture with the Arduino showing that my main code is 8 minutes older than my test code. 0-2 minutes: one LED, 2-4 minutes: two LEDs, 4-8 minutes three LEDs, 8-15 minutes: four LEDs, 15+ minutes: four flashing LEDs:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_AGVcmhlbFXA/S1JtqYfmbGI/AAAAAAAAAV8/ARTwUn93bhA/s1600-h/testncode.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 361px;" src="http://4.bp.blogspot.com/_AGVcmhlbFXA/S1JtqYfmbGI/AAAAAAAAAV8/ARTwUn93bhA/s400/testncode.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5427521075831794786" /&gt;&lt;/a&gt;&lt;br /&gt;Here's my Arduino code for driving the display:&lt;code&gt;&lt;pre&gt;#define RED 10&lt;br /&gt;#define GREEN 11&lt;br /&gt;&lt;br /&gt;void setup() {&lt;br /&gt;  pinMode(RED, OUTPUT);&lt;br /&gt;  pinMode(GREEN, OUTPUT);&lt;br /&gt;&lt;br /&gt;  Serial.begin(9600);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int code = 0;&lt;br /&gt;int test = 0;&lt;br /&gt;&lt;br /&gt;void loop() {&lt;br /&gt;  if (Serial.available() &gt; 0) {&lt;br /&gt;    int incomingByte = Serial.read();&lt;br /&gt;&lt;br /&gt;    code = incomingByte / 16;&lt;br /&gt;    test = incomingByte % 16;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  draw(code, 2);&lt;br /&gt;  draw(test, 8);&lt;br /&gt;  &lt;br /&gt;  if (code == 15 || test == 15) {&lt;br /&gt;    delay(100);&lt;br /&gt;    if (code == 15) {&lt;br /&gt;      erase(2);&lt;br /&gt;    }&lt;br /&gt;    if (test == 15) {&lt;br /&gt;      erase(8);&lt;br /&gt;    }    &lt;br /&gt;    delay(900);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void draw(int value, int base) {&lt;br /&gt;  digitalWrite(base+0, (value &gt;= 1) ? HIGH : LOW);&lt;br /&gt;  digitalWrite(base+1, (value &gt;= 2) ? HIGH : LOW);&lt;br /&gt;  digitalWrite(base+2, (value &gt;= 4) ? HIGH : LOW);&lt;br /&gt;  digitalWrite(base+3, (value &gt;= 8) ? HIGH : LOW);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void erase(int base) {&lt;br /&gt;  digitalWrite(base+0, LOW);&lt;br /&gt;  digitalWrite(base+1, LOW);&lt;br /&gt;  digitalWrite(base+2, LOW);&lt;br /&gt;  digitalWrite(base+3, LOW);&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;Here's my sloppy Groovy code for providing the data:&lt;code&gt;&lt;pre&gt;import gnu.io.CommPortIdentifier&lt;br /&gt;import gnu.io.SerialPort&lt;br /&gt;&lt;br /&gt;CommPortIdentifier portId =&lt;br /&gt;  CommPortIdentifier.getPortIdentifier(&lt;br /&gt;    "/dev/tty.usbserial-A9007OMY")&lt;br /&gt;&lt;br /&gt;SerialPort serialPort = (SerialPort) portId.open("Test", 5000) &lt;br /&gt;&lt;br /&gt;serialPort.setSerialPortParams(9600, &lt;br /&gt;  SerialPort.DATABITS_8, &lt;br /&gt;  SerialPort.STOPBITS_1, &lt;br /&gt;  SerialPort.PARITY_NONE) &lt;br /&gt;&lt;br /&gt;serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE) &lt;br /&gt;&lt;br /&gt;// give the Arduino time to reset and Serial.begin&lt;br /&gt;Thread.sleep(3000) &lt;br /&gt;&lt;br /&gt;OutputStream outStream = serialPort.getOutputStream() &lt;br /&gt;&lt;br /&gt;walk = { root -&gt;&lt;br /&gt;  root.eachFile { file -&gt;&lt;br /&gt;    if (file.name.endsWith(".java")) {&lt;br /&gt;      if (file.name.endsWith("Test.java")) {&lt;br /&gt;        if (test == null || file.lastModified() &gt; test.lastModified()) {&lt;br /&gt;          test = file&lt;br /&gt;        }&lt;br /&gt;      } else {&lt;br /&gt;        if (code == null || file.lastModified() &gt; code.lastModified()) {&lt;br /&gt;          code = file&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  root.eachDir { dir -&gt;&lt;br /&gt;    if (!dir.name.startsWith(".")) {&lt;br /&gt;      walk(dir)&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;while(true) {&lt;br /&gt;  newestTest = 0&lt;br /&gt;  test = null&lt;br /&gt;  newestCode = 0&lt;br /&gt;  code = null&lt;br /&gt;  &lt;br /&gt;  walk(new File("&lt;your directory here&gt;"))&lt;br /&gt;  &lt;br /&gt;  def now = System.currentTimeMillis()&lt;br /&gt;  def codeAge = (now - code.lastModified())/60000&lt;br /&gt;  def testAge = (now - test.lastModified())/60000&lt;br /&gt;  &lt;br /&gt;  println "Test (minutes old): $testAge ($test)"&lt;br /&gt;  println "Code (minutes old): $codeAge ($code)"&lt;br /&gt;  new File("monitor.csv").&lt;br /&gt;    append("$now, $codeAge, $testAge\r\n")&lt;br /&gt;  &lt;br /&gt;  int encodedTest = (int)Math.max(Math.min(15,testAge-codeAge), 0)&lt;br /&gt;  int encodedCode = (int)Math.max(Math.min(15,codeAge-testAge), 0)&lt;br /&gt;  &lt;br /&gt;  if (encodedTest == 0 &amp;&amp; encodedCode == 0) {&lt;br /&gt;    if (codeAge &gt; testAge) {&lt;br /&gt;      encodedCode = 1&lt;br /&gt;    } else {&lt;br /&gt;      encodedTest = 1&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  int encoded = encodedCode * 16 + encodedTest&lt;br /&gt;  &lt;br /&gt;  outStream.write((byte)encoded)&lt;br /&gt;  outStream.flush()&lt;br /&gt;  &lt;br /&gt;  Thread.sleep(20000);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;outStream.close()&lt;br /&gt;serialPort.close()&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-3578580681212489775?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/3578580681212489775/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=3578580681212489775' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3578580681212489775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/3578580681212489775'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/01/test-code-edit-patterns-part-iii.html' title='Test &amp; Code Edit Patterns - Part III'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_AGVcmhlbFXA/S1JtqYfmbGI/AAAAAAAAAV8/ARTwUn93bhA/s72-c/testncode.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-4913008402395506211</id><published>2010-01-16T16:54:00.001-08:00</published><updated>2010-01-16T17:37:26.931-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='arduino'/><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><title type='text'>Test &amp; Code Edit Patterns - Part II</title><content type='html'>I'm having some success with this project. I can communicate with the Arduino using RXTX and Serial.read(). I'm deriving my last-edit times and encoding them as a byte and sending it over the USB to the Arduino. It can read the byte and update my row of LEDs accordingly.&lt;br /&gt;&lt;br /&gt;But.&lt;br /&gt;&lt;br /&gt;This only works for some reason if I have the Serial Monitor window open in the Arduino IDE. There must be some communication going on with the Arduino that puts it in a happy state for receiving data. The only hint is that the LED marked L flashes when I open and also when I close the Serial Monitor window. Something is going on there...&lt;br /&gt;&lt;br /&gt;Do you know the answer to my problem? I'm downloading the Arduino IDE code now to see if I can find out what's going on.&lt;br /&gt;&lt;br /&gt;Edit: I've been using &lt;a href="http://www.arduino.cc/playground/Interfacing/Java"&gt;this guide&lt;/a&gt;. From looking at the source code &lt;code&gt;app/src/processing/app/Serial.java&lt;/code&gt; I'm using the same API and constructing it similarly:&lt;br /&gt;&lt;br /&gt;Their code:&lt;code&gt;&lt;pre&gt;port = (SerialPort)portId.open("serial madness", 2000);&lt;br /&gt;input = port.getInputStream();&lt;br /&gt;output = port.getOutputStream();&lt;br /&gt;port.setSerialPortParams(rate, databits, stopbits, parity);&lt;br /&gt;port.addEventListener(this);&lt;br /&gt;port.notifyOnDataAvailable(true);&lt;/pre&gt;&lt;/code&gt;My code:&lt;code&gt;&lt;pre&gt;SerialPort serialPort = (SerialPort) portId.open("Test", 5000) &lt;br /&gt;&lt;br /&gt;serialPort.setSerialPortParams(9600, &lt;br /&gt;  SerialPort.DATABITS_8, &lt;br /&gt;  SerialPort.STOPBITS_1, &lt;br /&gt;  SerialPort.PARITY_NONE) &lt;br /&gt;&lt;br /&gt;serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE) &lt;br /&gt;&lt;br /&gt;OutputStream outStream = serialPort.getOutputStream()&lt;/pre&gt;&lt;/code&gt;I've found no documentation for the &lt;code&gt;CommPortIdentifier.open&lt;/code&gt; method - just this &lt;a href="http://users.frii.com/jarvi/rxtx/doc/gnu/io/CommPortIdentifier.html"&gt;javadoc&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I'm going to try mimicking the Arduino IDE code more closely...&lt;br /&gt;&lt;br /&gt;Edit: I think I have the solution!&lt;br /&gt;&lt;br /&gt;Opening communication with the Arduino &lt;em&gt;resets&lt;/em&gt; it! &lt;code&gt;Serial.begin&lt;/code&gt; is the first thing my Arduino code does in it's &lt;code&gt;setup&lt;/code&gt; method and that seems to need some time to settle down before anything can be read using &lt;code&gt;Serial.read&lt;/code&gt;. Furthermore, closing communication with the Arduino &lt;em&gt;resets&lt;/em&gt; the damn thing again! I hope this is configurable somewhere...&lt;br /&gt;&lt;br /&gt;Edit: Humph. It's by design. You can find out more about it &lt;a href="http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1234284114"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-4913008402395506211?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/4913008402395506211/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=4913008402395506211' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4913008402395506211'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/4913008402395506211'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/01/test-code-edit-patterns-part-ii.html' title='Test &amp; Code Edit Patterns - Part II'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3376508392331888241.post-7506701668688641616</id><published>2010-01-15T08:24:00.000-08:00</published><updated>2010-01-15T08:30:41.393-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Test &amp; Code Edit Patterns</title><content type='html'>I put together a Groovy script to monitor my coding pattern of behaviour. The idea is that I can monitor when I last changed a source file or a test source file. Initially I plan to record a few days of data and graph it. My grand plan is to use my Arduino to drive some LEDs to tell me how long it's been and indicate when I've spent to long coding, writing tests, etc.&lt;code&gt;&lt;pre&gt;newestTest = 0&lt;br /&gt;newestCode = 0&lt;br /&gt;&lt;br /&gt;def walk(root) {&lt;br /&gt;  root.eachFile { file -&gt;&lt;br /&gt;    if (file.name.endsWith(".java")) {&lt;br /&gt;      if (file.name.endsWith("Test.java")) {&lt;br /&gt;        newestTest = Math.max(newestTest, file.lastModified())&lt;br /&gt;      } else {&lt;br /&gt;        newestCode = Math.max(newestCode, file.lastModified())&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  root.eachDir { dir -&gt;&lt;br /&gt;    if (!dir.name.startsWith(".")) {&lt;br /&gt;      walk(dir)&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;walk(new File("&lt;your directory goes here&gt;"))&lt;br /&gt;&lt;br /&gt;def now = System.currentTimeMillis()&lt;br /&gt;def code = (now - newestCode)/60000&lt;br /&gt;def test = (now - newestTest)/60000&lt;br /&gt;&lt;br /&gt;println "Test (minutes old): $test"&lt;br /&gt;println "Code (minutes old): $code"&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3376508392331888241-7506701668688641616?l=www.curiousattemptbunny.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.curiousattemptbunny.com/feeds/7506701668688641616/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3376508392331888241&amp;postID=7506701668688641616' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/7506701668688641616'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3376508392331888241/posts/default/7506701668688641616'/><link rel='alternate' type='text/html' href='http://www.curiousattemptbunny.com/2010/01/test-code-edit-patterns.html' title='Test &amp; Code Edit Patterns'/><author><name>Curious Attempt Bunny</name><uri>http://www.blogger.com/profile/04654980649772473807</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://bp0.blogger.com/_AGVcmhlbFXA/SFyTZJ-m_6I/AAAAAAAAAKU/S00uPUCHONs/S220/minime.png'/></author><thr:total>0</thr:total></entry></feed>
