<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 <title>prb.io</title>
 <link href="http:///atom.xml" rel="self"/>
 <link href="http:///"/>
 <updated>2011-11-22T21:51:38-08:00</updated>
 <id>http:///</id>
 <author>
   <name>Paul R. Brown</name>
   <email>prb@mult.ifario.us</email>
 </author>
 
   <entry>
     <title>Moved Yet Again</title>
     <link href="http://moved-yet-again.html"/>
     <updated>2011-11-20T00:00:00-08:00</updated>
     <id>http://./moved-yet-again</id>
     <content type="html">&lt;p&gt;I had been meaning to move this blog outside of the &lt;a href='http://mult.ifario.us'&gt;mult.ifario.us&lt;/a&gt; domain for a while. I initially thought about getting &lt;a href='https://github.com/prb/perpubplat' title='perpubplat'&gt;perpubplat&lt;/a&gt; updated to take account for newer versions of GHC and Twitter&amp;#8217;s switch to OAuth for API access and del.icio.us being deprecated (in favor of &lt;a href='http://pinboard.in'&gt;Pinboard&lt;/a&gt;) and maybe &lt;a href='http://akismet.com'&gt;Akismet&lt;/a&gt; integration and&amp;#8230;, but that&amp;#8217;s a good bit of work for a project that is truly just for fun.&lt;/p&gt;

&lt;p&gt;Instead, partially as an experiment for getting &lt;a href='http://fasterxml.com'&gt;FasterXML&lt;/a&gt; content moved into &lt;a href='http://pages.github.com' title='Github pages'&gt;Github pages&lt;/a&gt; and partially because the push-to-publish workflow is appealing, I decided to give &lt;a href='http://github.com/mojombo/jekyll' title='Jekyll'&gt;Jekyll&lt;/a&gt; via Github pages a go as a replacement for &lt;a href='https://github.com/prb/perpubplat' title='perpubplat'&gt;perpubplat&lt;/a&gt;. It turns out that &lt;a href='https://github.com/prb/perpubplat' title='perpubplat'&gt;perpubplat&lt;/a&gt;&amp;#8217;s post metadata is close enough to &lt;a href='http://github.com/mojombo/jekyll' title='Jekyll'&gt;Jekyll&lt;/a&gt;&amp;#8217;s YAML &lt;a href='https://github.com/mojombo/jekyll/wiki/yaml-front-matter'&gt;front matter&lt;/a&gt; that it&amp;#8217;s easy (~50 total lines of Scala) to write a quick conversion. Permalinks that don&amp;#8217;t end in an unsightly &lt;code&gt;.html&lt;/code&gt;, comments past and future, and tag-based navigation and feeds are all casualties of the conversion, and I&amp;#8217;m OK with that. (I&amp;#8217;ve come around to the idea that &lt;em&gt;your&lt;/em&gt; comment is &lt;em&gt;your&lt;/em&gt; content, and if it&amp;#8217;s important enough, you can publish it somewhere else yourself.)&lt;/p&gt;</content>
   </entry>
 
   <entry>
     <title>Crunching Java Class Versions with &lt;code&gt;bash&lt;/code&gt;-fu</title>
     <link href="http://crunching-java-class-versions-with-bash-fu.html"/>
     <updated>2010-08-20T00:00:00-07:00</updated>
     <id>http://./crunching-java-class-versions-with-bash-fu</id>
     <content type="html">&lt;p&gt;I recently needed to root out the JDK 6 classes lurking in an application that was supposed to run
on JDK 5, and it turns out that it's not that difficult with a little &lt;code&gt;bash&lt;/code&gt;-fu.  After
unpacking all of the constituent JAR files:&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;$ find . -name *.class | tee -a classes | xargs -n 1 head -n 1 | \
  cut -b 8 | xargs -IX printf '%d\n' &quot;'X&quot; | \
  paste -d ' ' - classes | grep '^50'&lt;/pre&gt;

&lt;p&gt;Et, voila!  I have the culprit:&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;50 ./jlayer-1.0.1.jar/javazoom/jl/converter/Converter$PrintWriterProgressListener.class
50 ./jlayer-1.0.1.jar/javazoom/jl/converter/Converter$ProgressListener.class
[...]&lt;/pre&gt;

&lt;p&gt;A rebuild of the JLayer library, and all's well again.&lt;/p&gt;

</content>
   </entry>
 
   <entry>
     <title>Come Work for Me</title>
     <link href="http://come-work-for-me.html"/>
     <updated>2010-05-12T00:00:00-07:00</updated>
     <id>http://./come-work-for-me</id>
     <content type="html">&lt;p&gt;Multifarious has been running comfortably and profitably for the
past couple of years with just me and the occasional subcontractor,
but it's time to grow the business: I'm looking for an &lt;a
href=&quot;http://mult.ifario.us/corp/jobs/sw_eng.html&quot;&gt;engineer&lt;/a&gt; to
come and work for me full-time.&lt;/p&gt;

&lt;p&gt;The basic &quot;win&quot; for the position is obvious &amp;#8212; great pay, great
environment, challenging work &amp;#8212; but the bigger picture should be
compelling as well.  As I described &lt;a
href=&quot;http://blog.prb.io/up-to-what-i-am.html&quot;&gt;last year&lt;/a&gt;,
Multifarious is intended to be a springboard for an ongoing series of
business experiments, and this is a place where the right candidate
can gain knowledge and experience that they wouldn't otherwise have
access to in a purely engineering context.&lt;/p&gt;

</content>
   </entry>
 
   <entry>
     <title>Splitting XML Well with XSLT 2</title>
     <link href="http://splitting-xml-well-with-xslt-2.html"/>
     <updated>2009-09-30T00:00:00-07:00</updated>
     <id>http://./splitting-xml-well-with-xslt-2</id>
     <content type="html">&lt;p&gt;I recently had the need to split up a result set from a &lt;a
href=&quot;http://lucene.apache.org/solr/&quot;&gt;Solr&lt;/a&gt; query into a collection
of smaller groups of &lt;code&gt;add&lt;/code&gt; requests for POSTing into a
different core.
There are some ways to make the split work with text processing tools
(&lt;code&gt;split&lt;/code&gt; and friends), but it's always an open question
whether an ad hoc approach will trip over some markup &amp;#8212; it's
just better to use XML tooling.  By no coincidence (based on features missing from 
&lt;a href=&quot;http://www.w3.org/TR/xslt&quot;&gt;&lt;/a&gt;), &lt;a href=&quot;http://www.w3.org/TR/xslt20/&quot;&gt;XSLT&amp;#160;2&lt;/a&gt; makes it
easy to do the right thing.&lt;/p&gt;

&lt;p&gt;First up is grouping in chunks of 2000 records:&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;&amp;lt;xsl:for-each-group select=&quot;/response/result/doc&quot;
                    group-by=&quot;round(position() div 2000)&quot;&gt;
...
&amp;lt;/xsl:for-each-group&gt;&lt;/pre&gt;

&lt;p&gt;Outputting each hunk to a file named for the index of the
group is also a one-liner:&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;&amp;lt;xsl:result-document href=&quot;{current-grouping-key()}_out.xml&quot;&gt;
  &amp;lt;add&gt;
    &amp;lt;xsl:for-each select=&quot;current-group()&quot;&gt;
      &amp;lt;doc&gt;
        &amp;lt;xsl:apply-templates /&gt;
      &amp;lt;/doc&gt;
    &amp;lt;/xsl:for-each&gt;
  &amp;lt;/add&gt;
&amp;lt;/xsl:result-document&gt;&lt;/pre&gt;

&lt;p&gt;And that's it.  The only trick is choosing an XSLT&amp;#160; processor,
and the superlative &lt;a
href=&quot;http://saxon.sourceforge.net/&quot;&gt;Saxon&lt;/a&gt; (from &lt;a
href=&quot;http://www.saxonica.com/&quot;&gt;Saxonica&lt;/a&gt;) is my default choice.&lt;/p&gt;

</content>
   </entry>
 
   <entry>
     <title>Commandline Puzzler</title>
     <link href="http://commandline-puzzler.html"/>
     <updated>2009-09-25T00:00:00-07:00</updated>
     <id>http://./commandline-puzzler</id>
     <content type="html">&lt;p&gt;Suppose that you have to files that consist of records, one per line, and you want to ensure that none of the records in the second file appear in the first.  How do you do it with only the text processing commandline tools commonly available on *nix systems?&lt;/p&gt;

</content>
   </entry>
 
   <entry>
     <title>NoNoSQL</title>
     <link href="http://nonosql.html"/>
     <updated>2009-09-23T00:00:00-07:00</updated>
     <id>http://./nonosql</id>
     <content type="html">&lt;p&gt;&lt;a href=&quot;http://blog.b3k.us/&quot;&gt;Ben Black&lt;/a&gt;, one of the organizers
of &lt;a href=&quot;http://nosqleast.com/&quot;&gt;&lt;code&gt;no:sql(east).&lt;/code&gt;&lt;/a&gt;
conference, &lt;a
href=&quot;http://twitter.com/benjaminblack/status/4296043561&quot;&gt;tweeted&lt;/a&gt;,
and I twote:&lt;/p&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img alt=&quot;my current vote for renaming #nosql is #altdb. what are your ideas?&quot; src=&quot;http://blog.prb.io/images/bbtweetnosqlaltdb.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Chris Williams, another &lt;code&gt;no:sql(east).&lt;/code&gt; organizer, has had &lt;a
href=&quot;http://voodootikigod.com/nosql-a-modest-proposal&quot;&gt;similar
sentiments&lt;/a&gt;, but what really needs to happen is for people to stop
using the &quot;NoSQL&quot; term.  I originally &lt;a
href=&quot;http://twitter.com/paulrbrown/status/3847403891&quot;&gt;proposed&lt;/a&gt;
&quot;dbng&quot; for next-generation database (and with an intended allusion to
&lt;a href=&quot;http://www.relaxng.org/&quot;&gt;RELAX NG&lt;/a&gt;), but I'm warming up to
Ben Black's suggestion of &quot;altdb&quot; for the hint of Usenet &lt;a
href=&quot;http://en.wikipedia.org/wiki/Alt.*_hierarchy&quot;&gt;alt.*&lt;/a&gt; if
nothing else.&lt;/p&gt;

&lt;p&gt;I propose a new movement called the &lt;em&gt;NoNoSQL&lt;/em&gt; movement.  It
is a movement for those interested in alternative and next-generation
databases but not in the inaccurate &quot;NoSQL&quot; neologism.&lt;/p&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;http://blog.prb.io/images/nonosql.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Seems like some cool altdb schwag (t-shirts, mugs, etc.) is in
order &amp;#8212; &quot;Not your daddy's database.&quot; or &quot;Joiners need not apply.&quot; or...&lt;/p&gt;

</content>
   </entry>
 
   <entry>
     <title>Voldemort-Based Twitter Clone Talk at OSCON</title>
     <link href="http://voldemort-based-twitter-clone-talk-at-oscon.html"/>
     <updated>2009-07-23T00:00:00-07:00</updated>
     <id>http://./voldemort-based-twitter-clone-talk-at-oscon</id>
     <content type="html">&lt;p&gt;&lt;a href=&quot;http://netzooid.com&quot;&gt;Dan&lt;/a&gt; and I just finished up our &lt;a
href=&quot;http://en.oreilly.com/oscon2009/public/schedule/detail/8362&quot;&gt;talk&lt;/a&gt;
at OSCON.  You can download the &lt;a
href=&quot;http://bit.ly/4dP7zY&quot;&gt;slides&lt;/a&gt; or &lt;a
href=&quot;http://bit.ly/MDyVj&quot;&gt;view&lt;/a&gt; it on Slideshare.  I'll probably
take it down at some point in the near future, but the sample system
from the presentation is &lt;a href=&quot;http://tat1.datapr0n.com:8080&quot;&gt;up
and running&lt;/a&gt; for the moment.&lt;/p&gt;

&lt;p&gt;We got started on the material for the talk several months back
with the Twitter one-to-many publishing problem as a motivating
problem to play with various non-relational data stores, and after
some dabbling with &lt;a href=&quot;http://bit.ly/EdUEt&quot;&gt;Cassandra&lt;/a&gt; and &lt;a
href=&quot;http://bit.ly/Zck7F&quot;&gt;HBase&lt;/a&gt;, we ended up focusing on &lt;a
href=&quot;http://bit.ly/ocBX0&quot;&gt;Voldemort&lt;/a&gt; as an initial backend for the
system.  It is very likely that we'll craft some additional backends,
and I'd particularly like to get to a more forgiving model for storing
lists.  (I'm already part way there on &lt;a
href=&quot;http://bit.ly/12AYmf&quot;&gt;Dynomite&lt;/a&gt; with &lt;a
href=&quot;http://bit.ly/BYMdW&quot;&gt;Osmos&lt;/a&gt; as the storage engine.)&lt;/p&gt;

&lt;p&gt;The system described in the talk uses a small (two nodes) Voldemort
cluster and a small cluster of web nodes (JAX-RS with a jQuery
front-end) to implement enough microblogging functionality to be
interesting &amp;#8212; users, follow/followed, publishing &amp;#8212; along
with a simple dashboard implemented with Cacti and rudimentary
deployment automation.  The &lt;a href=&quot;http://bit.ly/koe3D&quot;&gt;source&lt;/a&gt;
is out on GitHub if you want to take a look.  (Feel free to fork with
it...)&lt;/p&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;&lt;img alt=&quot;[dashboard snapshot]&quot;
src=&quot;http://blog.prb.io/images/v_dboard.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Dan's blog entry on the presentation is &lt;a
href=&quot;http://bit.ly/3ciEo6&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

</content>
   </entry>
 
   <entry>
     <title>If you have nothing to say, say nothing</title>
     <link href="http://if-you-have-nothing-to-say-say-nothing.html"/>
     <updated>2009-06-05T00:00:00-07:00</updated>
     <id>http://./if-you-have-nothing-to-say-say-nothing</id>
     <content type="html">&lt;p&gt;There is never a good reason to announce that you're going to make
an announcement.  This rule came to mind when I saw this tweet scroll
by this morning:&lt;/p&gt;
 
&lt;p style=&quot;text-align:center&quot;&gt;&lt;img
src=&quot;http://blog.prb.io/files/nonannouncement.jpg&quot; alt=&quot;[screenshot of tweet]&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This belongs in the same category of non-actions as a blog post to
say you haven't been blogging, telling people about your &quot;stealth&quot;
startup, or a statement like &quot;with all due respect&quot;.&lt;/p&gt;

</content>
   </entry>
 
   <entry>
     <title>Speaking at OSCON 2009</title>
     <link href="http://speaking-at-oscon-2009.html"/>
     <updated>2009-05-28T00:00:00-07:00</updated>
     <id>http://./speaking-at-oscon-2009</id>
     <content type="html">&lt;p&gt;&lt;a
href=&quot;http://en.oreilly.com/oscon2009/public/schedule/detail/8362&quot;&gt;&lt;img
src=&quot;http://assets.en.oreilly.com/1/event/27/oscon2009_banner_speaking_210x60.gif&quot;
style=&quot;float: right;&quot; alt=&quot;speaking @OSCON&quot; /&gt;&lt;/a&gt; With &lt;a
href=&quot;http://netzooid.com/blog/&quot;&gt;Dan Diephouse&lt;/a&gt;, I'll be &lt;a
href=&quot;http://en.oreilly.com/oscon2009/public/schedule/detail/8362&quot;&gt;speaking&lt;/a&gt;
at OSCON on July&amp;#160;23.&lt;/p&gt;

&lt;p&gt;Taking the abstract literally, the talk looks like it is about
building a Twitter clone with open source components, but it is not at
all intended to be armchair quarterbacking about Twitter's early
problems with availability.  (We should all have these problems!)
Rather, the talk is intended to be about some of the current crop of
interesting open source distributed storage technologies &amp;#8212; &lt;a
href=&quot;http://incubator.apache.org/cassandra/&quot;&gt;Cassandra&lt;/a&gt;, &lt;a
href=&quot;http://project-voldemort.com/&quot;&gt;Voldemort&lt;/a&gt;, &lt;a
href=&quot;http://code.google.com/p/redis/&quot;&gt;Redis&lt;/a&gt; (where the folks have
already done some &lt;a
href=&quot;http://code.google.com/p/redis/wiki/TwitterAlikeExample&quot;&gt;thinking&lt;/a&gt;
about Twitter-like apps), &lt;a
href=&quot;http://couchdb.apache.org/&quot;&gt;CouchDB&lt;/a&gt;, &lt;a
href=&quot;http://hadoop.apache.org/hbase/&quot;&gt;HBase&lt;/a&gt;, &lt;a
href=&quot;http://github.com/cliffmoon/dynomite&quot;&gt;Dynomite&lt;/a&gt; &amp;#8212; as
well as how to attack some of the operational problems (e.g.,
deployment, instrumentation, application updates) that come with using
new tools in multi-node environments.&lt;/p&gt;

&lt;p&gt;That's obviously quite a bit to fit into a relatively short
speaking slot, but Dan and I plan to blog or otherwise publish
material that won't fit.&lt;/p&gt;

</content>
   </entry>
 
   <entry>
     <title>Integrating Github and Redmine</title>
     <link href="http://integrating-github-and-redmine.html"/>
     <updated>2009-05-26T00:00:00-07:00</updated>
     <id>http://./integrating-github-and-redmine</id>
     <content type="html">&lt;p&gt;I've been a fan and user of Atlassian's excellent &lt;a
href=&quot;http://www.atlassian.com/software/jira/&quot;&gt;Jira&lt;/a&gt; since the
company was founded back in 2002, but I needed the ability to set up
some quick-hit bug/task/wiki sites for smaller consulting projects and
neither the month-to-month hosted model nor the enterprise license
made good economic sense.  I opted for the an install of &lt;a
href=&quot;http://www.redmine.org/&quot;&gt;Redmine&lt;/a&gt;, and while it's no Jira,
I've been reasonably happy with it.  (The one big headache was getting
SMTP over TLS working.)&lt;/p&gt;

&lt;p&gt;Redmine supports integration with &lt;a
href=&quot;http://www.git-scm.org/&quot;&gt;Git&lt;/a&gt; repositories on a per-project
basis and will link commits to issues based on the presence of
keywords and issue identifiers (e.g., &quot;&lt;code&gt;refs #123&lt;/code&gt;&quot;).  The
way the integration is implemented works well if the Git repository is
hosted on the same machine as the Remine instance, but I host all
customer and internal work on &lt;a href=&quot;http://github.com&quot;&gt;github&lt;/a&gt;.
Here's a quick recipe to bridge the gap.&lt;/p&gt;

&lt;p&gt;First, add an ssh key for the &lt;code&gt;redmine&lt;/code&gt; user to your
github account.&lt;/p&gt;

&lt;p&gt;Next, create a home for the following shell script, e.g.,
&lt;code&gt;/opt/redmine_extras/bin&lt;/code&gt; and a home for Git repositories
on the server, e.g., &lt;code&gt;/var/redmine/git_repositories&lt;/code&gt; and
ensure that the &lt;code&gt;redmine&lt;/code&gt; user has write privileges for the
repositories.  Here's the &lt;code&gt;pull_git&lt;/code&gt; script:&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;#!/bin/bash
export REPOS=/var/redmine/git_repositories
export REDMINE_HOME=/opt/redmine-0.8.2
export LOGFILE=/var/log/redmine_extras.log

function log_prefix {
        echo -n `date '+%Y/%m/%d %H:%M:%S'`&quot; [&quot;$$&quot;] ${2}&quot;
}

for i in `ls -d ${REPOS}/*.git`; do 
  cd $i;
  log_prefix &amp;amp;&amp;amp; echo 'Processing git repository from '${i}'...';
  /usr/local/bin/git --bare fetch origin :master
done

cd ${REDMINE_HOME}
log_prefix &amp;amp;&amp;amp; echo 'Updating Redmine...'
/usr/local/bin/ruby script/runner &quot;Repository.fetch_changesets&quot; -e production&lt;/pre&gt;

&lt;p&gt;Then (I'm logged in as &lt;code&gt;root&lt;/code&gt;) add the command to the
&lt;code&gt;redmine&lt;/code&gt; user's crontab:&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;# echo '*/10 * * * *    /opt/redmine_extras/bin/pull_git 2&amp;gt;&amp;amp;1 &amp;gt;&amp;gt; /var/log/redmine_extras.log'\
 | crontab -u redmine -&lt;/pre&gt;

&lt;p&gt;Now, for each repository, say &lt;code&gt;foo&lt;/code&gt; and your github user
is &lt;code&gt;bar&lt;/code&gt;, you will track from Redmine, do:&lt;/p&gt;

&lt;pre class=&quot;code&quot;&gt;# cd /var/redmine/git_repositories
# sudo -u redmine -H git clone --bare git@github.com:bar/foo.git
# cd foo.git
# sudo -u redmine -H git --bare remote add origin git@github:bar/foo.git&lt;/pre&gt;

&lt;p&gt;Ensure that the Redmine project points to the local copy of the
Git repository, and the revisions should start getting syncronized
every ten minutes.&lt;/p&gt;

</content>
   </entry>
 
</feed>


