Bugsplat2012-01-01T10:01:14+00:00Pete Keenpete@bugsplat.infoA Robust Reporting System for Ledger3a32a2012-01-01T10:01:14+00:00<p><em>Note: you can find much more information about ledger on <a href="http://ledger-cli.org">ledger-cli.org</a>, including links to official documentation and other implementations</em></p>
<p>For the last five years I've kept my personal finances in order using the ledger system, a sophisticated command line program that consumes a lightly formatted text file. It's helped me repay debts and get everything in order, helping me financially absorb an injury last month that would have been extremely detrimental just a few years prior.</p>
<p>The stock ledger program is exclusively command-line oriented. For quick checks and <code>grep</code>ing over output, this is fine. For some time, though, I've wanted a more graphical, more robust way of looking at my finances. I've also wanted a more familiar query language, since version 2.0's queries were someone limited and version 3.0's query syntax is not very well documented yet. Last year I wrote a <a href="/2011-07-09-program-your-finances-reporting-for-fun-and-profit.html">simple system</a> that pushed monthly reports out to static HTML files, which got me part of the way there but I really wanted something more flexible. Something where I can just write an arbitrary query and have the output dumped to HTML.</p>
<p>Thus, I present <a href="https://github.com/peterkeen/ledger-web">Ledger Web</a>. In Ledger Web, your ledger is kept in a text file, just the same as always, reports are ERB files, and queries are SQL. Ledger Web watches your ledger file and whenever it changes dumps it into a PostgreSQL database table. It's also quite customizable, letting you set hooks both before and after row insertion and before and after ledger file load.</p>
<h3>Installation</h3>
<p>Ledger Web installation is pretty simple. First make sure you have PostgreSQL version 9.0 or greater installed on your machine. Then, run these commands:</p>
<pre><code>$ gem install ledger_web
$ createdb ledger
$ ledger_web
</code></pre>
<p>Then, open your web browser to <a href="http://localhost:9090/">http://localhost:9090/</a> where you'll see some simple example reports. </p>
<h3>Example Report</h3>
<p>Let's walk through a simple pair of reports that shows off most of Ledger Web's features. Yesterday I ran across this <a href="http://earlyretirementextreme.com/your-budget-is-like-sinking-ship.html">blog post</a> which draws a comparison between a typical person's budget and a wooden ship, always springing leaks and at risk of sinking to the bottom. I decided to write a report that shows my expenses both summed by year and broken out into individual lines. First, the Leaky Ship report itself:</p>
<pre><code><% @query = query({:pivot => "Year"}) do %>
select
account as "Account",
xtn_year as "Year",
coalesce(sum(amount), 0) as "Amount"
from
accounts_years
left outer join (
select
xtn_year,
account,
amount
from
ledger
) x using (account, xtn_year)
where
account ~ '(Income|Expenses)'
and xtn_year <= date_trunc('year', cast(:to as date))
group by
account,
xtn_year
order by
account,
xtn_year
<% end %>
<div class="page-header">
<h1>Leaky Ship</h1>
</div>
<%= table(@query, :links => {/\d{4}-\d{2}-\d{2}/ =>
'/reports/register?account=:0&year=:title'}) %>
</code></pre>
<p>It starts off with a database query, defined using a helper named <code>query</code>. It uses a table named <code>ledger</code>, which is where your ledger data will be dumped, as well as a view named <code>accounts_years</code>, which is the cross product of every account by every year. This makes sure that rows show up properly even if there's no data for that particular year. Also, it uses <code>:pivot => "Year"</code>, which will <em>pivot</em> the report such that each <code>xtn_year</code> will become it's own column.</p>
<p>The <code>:to</code> param in the <code>where</code> clause is automatically populated with the second date in the range at the top of all reports.</p>
<p>Next, it uses some basic <a href="http://twitter.github.com/bootstrap">Twitter Bootstrap</a> HTML markup to display a nice title, and then uses the <code>table</code> helper to actually dump the query results to an HTML table. The <code>:links</code> option tells the <code>table</code> helper to link the values in any column who's title matches the regular expression <code>/\d{4}-\d{2}-\d{2}/</code> to <code>/reports/register?account=:0&year=:title</code>, where <code>:0</code> will get replaced with the value in column 0 (starting from the left, 0 indexed) and <code>:title</code> will be replaced by the title of the column.</p>
<p>Here's a screenshot of what this report looks like (Note: this uses the Stan example ledger that I generated for my previous reporting system):</p>
<p><a href="/leaky_ship.png"><img src="/leaky_ship_small.png"></a></p>
<p>The register report that Leaky Ship links to is pretty trivial in comparison. Here's the source:</p>
<pre><code><% expect ['account', 'year'] %>
<% @query = query do %>
select
xtn_date as "Date",
account as "Account",
note as "Payee",
amount as "Amount"
from
ledger
where
xtn_year = :year
and account = :account
order by
xtn_date
<% end %>
<div class="page-header">
<h1>Register</h1>
</div>
<%= table @query %>
</code></pre>
<p>The only thing new that this does is use the <code>expect</code> helper to ensure that <code>account</code> and <code>year</code> are query params. If they are not, <code>expect</code> throws an exception rather than showing bad data. Here's what this one looks like:</p>
<p><a href="/register.png"><img src="/register_small.png"></a></p>
<p>Both of these reports, as well as a few others, can be found in <a href="https://github.com/peterkeen/ledger-web-config">my Ledger Web configuration</a>. My config also shows off some of the more advanced customizations you can do.</p>
<p>The <a href="https://github.com/peterkeen/ledger-web">README</a> goes into much more detail on how the helpers work and the various config settings work. Please, install it and let me know what you think!</p>
Program Your Finances: Automated Transactionsea00f2011-12-18T18:32:27+00:00<p><em>Note: you can find much more information about ledger on <a href="http://www.ledger-cli.org">ledger-cli.org</a>, including links to official documentation and other implementations</em></p>
<p>I've been using <a href="http://www.ledger-cli.org">Ledger</a> for almost five years now to keep track of my personal finances. For three of those years I've lived with a roommate of one form or another. Part of living with a roommate is splitting up bills. Some people decide to do this by dividing the bills up between roommates. For example, Pete pays the electric and gas bills and Andrew pays the water and the cable. Other roommates decide to nominate one person to have all of the bills in their name and post the amounts due every month for everyone to see. This is what my girlfriend and have been doing and it's been working great. All of the bills are in my name and I give her a summary every month and she hands me a check. Easy peasy.</p>
<p>Of course, being a complete and utter nerd means that I have to make this more complicated than it needs to be in the name of reducing the amount of work I have to do.</p>
<h3>Automated Transactions</h3>
<p>Ledger has an extremely handy feature named <em>automated transactions</em>. The basic idea is that you provide a template transaction and a pattern to match, and <code>ledger</code> will insert the filled-in template transaction every time the pattern matches. Here's an example:</p>
<pre><code>= /Expenses:Utils:/
$account -0.5
Assets:Receivable 0.5
</code></pre>
<p>This instructs ledger to insert a transaction for 50% of the total
transaction amount every time a transaction matches the given regexp (<code>/Expenses:Utils:/</code>). The template variable <code>$account</code> will be replaced with the matched account. So if we have this transaction:</p>
<pre><code>2011/12/18 Electric Company
Expenses:Utils:Electric $50
Assets:Checking
</code></pre>
<p>ledger will automatically insert this immediately following:</p>
<pre><code>2011/12/18 Electric Company
Expenses:Utils:Electric $-25
Assets:Receivable $25
</code></pre>
<p>I use an automatic transaction identitcal to this one in my personal ledger file to split utilities with my girlfriend. From there I can run a simple report and copy and paste the results into an email once a month.</p>
<h3>Virtual Transactions</h3>
<p>I wanted to mention another advanced ledger feature that I use every day. For various reasons I keep most of my money in my interest-paying checking account. I have most of it allocated away into various "funds", which are just fake buckets that only exist for me. It's the same idea as <a href="http://www.getrichslowly.org/blog/2008/07/02/how-to-open-multiple-accounts-at-ing-direct/">ING subaccounts</a>, but implemented in ledger instead of at the bank.</p>
<p>I've implemented these buckets using ledger's <em>virtual transaction</em> feature. Basically, if you surround an account name in square brackets, ledger treats that portion of the transaction as <em>virtual</em>. Ledger will include this transaction in all reports unless you include the <code>--real</code> flag in your report command. Here's an example:</p>
<pre><code>$ ledger bal checking
$1000 Assets:Checking
</code></pre>
<p>Then, we insert this transaction:</p>
<pre><code>2011/12/01 * Establish Emergency Fund
[Funds:Emergency] $1,000.00
[Assets:Checking]
</code></pre>
<p>and run some more reports</p>
<pre><code>$ ledger bal checking funds
$500 Assets:Checking
$500 Funds:Emergency
--------------------
$1000
$ ledger --real bal checking funds
$1000 Assets:Checking
</code></pre>
<h3>By our powers combined...</h3>
<p>On their own, these two features are pretty useful. It's when you combine them that the awesome power of ledger starts appearing. As some of you may remember, I has a <a href="http://bugsplat.info/2011-11-30-another-tiny-webapp.html">bit of a medical emergency</a> a few weeks ago and being a citizen of these great United States I have private insurance, so of course I'm going to be paying a not-inconsiderable sum out of pocket. How much? Only time will tell. I can't live like that though, I have to put some kind of structure to it or I'll go crazy. So, I looked up my <a href="http://healthinsurance.about.com/od/healthinsurancetermso/g/OOP_maximums_definition.htm">out of pocket maximum</a> and carved out a portion of my emergency fund into a new medical fund:</p>
<pre><code>2011/12/18 * Establish Medical Fund
[Funds:Medical] $4,000
[Funds:Emergency]
</code></pre>
<p>I also added an automatic transaction that will withdraw from the medical fund whenever I record a medical expense:</p>
<pre><code>= /^Expenses:Medical/
[Funds:Medical] -1.0
[Assets:Checking] 1.0
</code></pre>
<p>Putting it all together, adding a transaction like this:</p>
<pre><code>2011/12/18 * Corner Drug Store
Expenses:Medical:OTC $15.00
Assets:Checking
</code></pre>
<p>Will result in these reports:</p>
<pre><code>$ ledger reg funds:medical
11-Dec-01 Establish Medical Fund [Funds:Medical] $4000.00 $4000.00
11-Dec-18 Corner Drug Store [Funds:Medical] $-15.00 $3985.00
$ ledger reg checking
11-Nov-01 Checking Deposit Assets:Checking $10000.00 $10000.00
11-Dec-01 Establish Emergency Fund [Assets:Checking] $-5000.00 $5000.00
11-Dec-18 Corner Drug Store Assets:Checking $-15.00 $4985.00
[Assets:Checking] $15.00 $5000.00
$ ledger --real reg checking
11-Nov-01 Checking Deposit Assets:Checking $10000.00 $10000.00
11-Dec-18 Corner Drug Store Assets:Checking $-15.00 $9985.00
</code></pre>
<p>As you can see, the transaction for Corner Drug Store pulled $15 from <code>Assets:Checking</code> which was then automatically replaced from <code>Funds:Medical</code>. The virtual amount available in checking stays the same but the real amount goes down by $15 without any additional input. These two features combined let me spend directly from a virtual account while keeping track of everything for me.</p>
<p>If you go to the <a href="http://www.ledger-cli.org">Ledger website</a> you can find the manual which has been recently greatly expanded and enhanced. There you'll see that the expression for an automated transaction can be much more advanced if you want it to be. Check it out.</p>
Yet Another (not very) Static Blog Generator7e0742011-12-14T18:30:26+00:00<p>The <a href="/2010-03-28-yet-another-static-html-generator.html">very first post on this blog</a> was about how I wanted a completely static blog and how it'll be great and wonderful and boy howdy was it ever. Over 500 lines of rather dense perl plus almost 20 separate template files because the kind-of-<a href="http://mustache.github.com/">mustache</a> that I decided to implement can't handle inlined templates for loops so I have to do everything as partials. </p>
<p>Needless to say, it isn't very fun to work on. It mostly does what I want but adding new things is pretty painful, as is changing any of the templates. Yesterday I decided that I would see what a <a href="http://www.sinatrarb.com/">Sinatra</a> port would look like. Why Sinatra? It's fun, that's why. Ruby and Sinatra make writing new webapps easy and fun.</p>
<h4>Details</h4>
<p>The new version is called <a href="http://github.com/peterkeen/bugsplat.rb">bugsplat.rb</a>. It's 200 lines of ruby, which is actually more than I wanted but there a lot of functionality packed in there. Here's the complete feature set:</p>
<ul>
<li>Entries are written in Markdown and checked into the app repo</li>
<li>Entries have a MIME-style header</li>
<li>Entries can have a <code>--fold--</code> marker that specifies which content should be on the index page</li>
<li>Supports blog posts and static entries that can optionally be linked from the side navigation</li>
<li>Reads all entries into memory at startup</li>
<li>Uses ERB for templates</li>
<li>Caches rendered pages in memory</li>
</ul>
<p>The production site is hosted on <a href="http://www.heroku.com">Heroku</a> and uses a <a href="http://unicorn.bogomips.org/">unicorn</a> extremely similar to <a href="http://bugsplat.info/2011-11-27-concurrency-on-heroku-cedar.html">FivePad's setup</a> without the background worker stuff.</p>
<h4>Why not some other blog engine?</h4>
<p>A while ago I tried porting to <a href="https://github.com/mojombo/jekyll">Jekyll</a> but without heavy modification I wouldn't have been able to keep the URLs I've built up over the last year and a half. Also for some reason I couldn't wrap my head around liquid templates.</p>
<p>Wordpress or some other dynamic CMS? I could have done that, sure, but that would introduce other dependencies and I really like the emacs-centric workflow of writing markdown files and generating a site. A web-based CMS would have let me write from anywhere but then I'd have to write in the browser, which isn't my idea of fun.</p>
<h4>Results</h4>
<p>It's not a static site anymore but I think with the caching I have set up it's almost as fast as one. I could even transparently make it one by pre-rendering everything and stashing it in <code>public</code> using a <code>rake</code> task named <code>assets:precompile</code> that Heroku conveniently runs if it exists.</p>
<p>I don't think I'll do that, though. I like the flexibility that this setup gives me. </p>
<h4>Re-using</h4>
<p>I wouldn't recommend it. There's nothing that precludes someone else forking <a href="http://github.com/peterkeen/bugsplat.rb">bugsplat.rb</a> on github, deleting the entries, rewriting the templates, and running their own site, of course, but it wouldn't be trivial. If you actually want to use it on your own site, <a href="mailto:pete@bugsplat.info">email me</a> or leave a comment below and we'll work something out.</p>
Another Tiny Webappfefc42011-11-30T11:46:50+00:00<p>Literally ten minutes after hitting the publish button on my <a href="/2011-11-27-concurrency-on-heroku-cedar.html">last post</a> I took a little tumble and broke a rather important bone in my back, and now I'm on medical leave from work for awhile.</p>
<p>That doesn't stop me from doing fun things, though, so this morning I cooked up a tiny webapp using <a href="http://www.sinatrarb.com/">Sinatra</a>, <a href="http://datamapper.org/">DataMapper</a>, and <a href="http://twitter.github.com/bootstrap">Bootstrap</a> that will help me keep track of when I take painkillers. It's called <a href="https://github.com/peterkeen/painkillerjane">Painkiller Jane</a> after the comic book character.</p>
<p><img src="https://github.com/peterkeen/painkillerjane/raw/master/public/screenshot.png"></p>
<p>There's not much interesting going on here to be honest. Basically it's just one database table and an in-app configuration hash that lays out what pills are available, their dosage, and their cooldown period. I can click the buttons when the cooldown is over, but when it's not they tell me what time I can take the next dose.</p>
<p>The only other feature that I might add is a lockout so that it helps me manage which pill to take when because I'm alternating tylenol and advil.</p>
Concurrency on Heroku Cedar50b7f2011-11-27T18:52:36+00:00<p>I started a small product a few weeks ago called <a href="https://www.fivepad.me">FivePad</a>, a simple easy way to organize your apartment search. It's basically the big apartment search spreadsheet that you and me and everyone we know has made at least three times, except FivePad is way smarter.</p>
<p>The initial versions of FivePad did everything in the web request cycle, including sending email and pulling down web pages. The other day I was about to add my third in-cycle process when I threw up my arms in disgust. The time had come to integrate <a href="https://github.com/defunkt/resque">resque</a>, a great little <a href="http://redis.io">redis</a> based job queueing system. Except if I ran it the way Heroku makes things easy my costs would get a little bit out of control for a project that isn't making much money yet.</p>
<h3>Backstory</h3>
<p>First, a little backstory. Earlier in 2011 <a href="http://www.heroku.com">Heroku</a> announced their new cedar stack, which is a much more general platform for running webapps than their previous platforms. Cedar lets you describe the processes you want to run using a Procfile. Your processes can use one of a large selection of languages, but FivePad is all ruby. Here's what a Procfile can look like:</p>
<pre><code>web: bundle exec rails server
worker: bundle exec rake resque:work QUEUE=*
scheduler: bundle exec ruby ./config/clock.rb
</code></pre>
<p>This creates three different types of processes, <code>web</code>, <code>worker</code>, and <code>scheduler</code>. Heroku intends that you run one of each of these on three different dynos which all charge by the hour, but you get 750 hours free every month.</p>
<h3>Options</h3>
<p>The official way to do this, of course, is to just spin up multiple dynos. Heroku makes this extremely easy:</p>
<pre><code>$ heroku scale web=2 worker=3
</code></pre>
<p>Bam. Done. Two web dynos and three worker dynos all running your code and talking to the same database. Gets to be a bit expensive for hobby/tiny projects, though.</p>
<p>Another option is to <a href="http://blog.nofail.de/2011/07/heroku-cedar-background-jobs-for-free/">run multiple Heroku apps</a> with a shared database. This is decent, in that you get multiple full-powered dynos for free. However, it's kind of a pain to manage. You have to deploy to multiple git repos whenever you do a deploy and you have to make sure all of your environment variables are synced. I've tried it, it's not very much fun.</p>
<p>Yet another option is to <a href="http://verboselogging.com/2010/07/30/auto-scale-your-resque-workers-on-heroku">auto-scale your workers</a>. The basic idea here is that when a job comes in, the <code>resque</code> client triggers a worker to start up in another dyno, process the job, and then shut down when there are no more jobs left. I tried using this for a long time with <a href="https://www.remindlyo.com">Remindlyo</a> and experienced an annoying set of race conditions due to how long rails takes to start. Jobs would get lost and dropped kind of randomly.</p>
<h3>Cheating With Style</h3>
<p>The system that I've devised for FivePad was inspired by <a href="http://michaelvanrooijen.com/articles/2011/06/01-more-concurrency-on-a-single-heroku-dyno-with-the-new-celadon-cedar-stack/">this post</a> by Michael van Rooijen. There, he describes how best to run your rails app on <a href="http://unicorn.bogomips.org/">Unicorn</a>, a simple pre-forking rack server. Here's my <code>Procfile</code>:</p>
<pre><code>web: unicorn -p $PORT -c ./config/unicorn.rb
</code></pre>
<p>Not much to it. Here's what that <code>config/unicorn.rb</code> file looks like:</p>
<pre><code>worker_processes 3
timeout 30
@resque_pid = nil
before_fork do |server, worker|
@resque_pid ||= spawn("bundle exec rake " + \
"resque:work QUEUES=scrape,geocode,distance,mailer")
end
</code></pre>
<p>This starts out pretty simply. Three worker processes and a 30 second request timeout. But then there's that <code>before_fork</code> hook. This simply runs a specified <code>rake</code> task if and only if it hasn't been run before, immediately prior to forking off the next web worker. In this case, it runs the <code>resque:work</code> task, which is how <code>resque</code> processes jobs.</p>
<p>This will actually result in six processes in each web dyno:</p>
<ul>
<li>1 unicorn master</li>
<li>3 unicorn web workers</li>
<li>1 resque worker</li>
<li>1 resque child worker when it actually is processing a job</li>
</ul>
<p>This may be a bit much if your application is super heavy, but for FivePad it's working pretty well. Things are much faster now that all of the heavy duty stuff is done in the background, and scaling up to another dyno automatically scales the workers as well. One thing to consider in the future is to drop the web workers down to two and add another dyno, but I'm not going to do that until it actually has significant revenue coming in.</p>
<p>Another drawback of this is that if the worker falls over for some reason I'll have to restart the whole dyno, but the chances of that happening are pretty low. Resque forks off a child worker for every job it processes, which insulates the master worker from any problems with jobs. </p>
<p>Anyway, for now this is how FivePad is running. Scaling up is will be simple in the future when it's necessary and I can control costs right now when that's really important. </p>
Introducing FivePad855502011-11-17T17:17:12+00:00<p>For over two years I've been ruminating on an idea for a webapp that would help people coordinate apartment searches amongst roommates. Finding a place is pretty tough, and finding the right place for you and one or more other people is even harder. Emails, phone calls, spreadsheets, links, bookmarks. It's a mess. So, I built <a href="https://www.fivepad.me">FivePad</a>. More details after the fold.</p>
<p>You can add places by simply pasting in a Craigslist URL or typing in the street address, and FivePad takes care of building a page that shows you where it is in the city and the street view of the address. You can add notes to your places, too. If you're searching with roommates you can add invite them and they'll get emails whenever you add stuff, and you'll get emails when they add stuff.</p>
<p>If the place you're looking at has an email address, you can send a note to that address with one click. When they respond their email will get attached to the right place.</p>
<p>The basic product is there but I have a list of features a mile long that I want to add. Expect more postings here as I add stuff :)</p>
<p>It's free to try, so <a href="https://www.fivepad.me">give it a run</a> and let me know what you think.</p>
What sucks about apartment hunting?5e62c2011-10-19T06:31:23+00:00<p>I want to brainstorm everything that sucks about searching for an apartment. Why is it always so painful? Does it have to suck so much? I have some ideas but I haven't done this in almost a year so the pain, it is not so fresh.</p>
<p>Here's what I've got so far:</p>
<ul>
<li><strong>Keeping track of everything</strong>. Losing phone numbers, did I call that one back, wait is that a duplicate or another unit in the same building?</li>
<li><strong>The uncertainty</strong>. Will this landlord suck? How can I find out? Is the neighborhood ok?</li>
<li><strong>Finding some place close</strong>. What's the commute time? Where is the nearest grocery store?</li>
<li><strong>Coordinating with roommates or significant others</strong>. Will they like it? I guess I could email them...</li>
</ul>
<p>In the past I've had a few solutions to this, as I'm sure everyone else has too. The first time I searched for a place I didn't really keep track of anything except in my email inbox. It was kind of a disaster. By the time I picked one place I had already lost the others, but didn't find out until after I called them back. The next time was a little better but still I think my roommate and I mostly communicated via email. The third time I built a tiny Rails site for my girlfriend and I to keep track of stuff, but I never really fleshed it out and we kind of just sat next to eachother on the couch and shared craigslist links over IM.</p>
<p>What I'm looking for here is everything else that sucks about searching for a place and why, and what kind of solutions you've duct taped together to make it work. Websites that make any aspect of it easier would also be super helpful. Everybody who responds gets $2.00 of <a href="https://www.remindlyo.com">Remindlyo credit</a> :)</p>
Remindlyo is a Go93cd72011-10-08T17:24:56+00:00<p>Eight weeks ago I embarked, almost by accident, on one of the most interesting challenges that I've ever set up for myself. I've created something new, something that I don't think the world has had before, and that makes me feel good. So, if you're reading this, go check out <a href="https://www.remindlyo.com">Remindlyo</a>, because it's as done as it's going to get for now.</p>
<p>Remindlyo, at it's core, is about procrastination and forgetfulness. Do you forget to call someone important? Do you "forget" because you can't bring yourself to actually dial the phone? Remindlyo helps out with that, since the friction of hitting a single button on a keypad is so much lower than that of dialing the phone in the first place. You've already answered the phone, might as well keep the ball rolling.</p>
<p>For those of you who care about such things, here's the tech stack:</p>
<ul>
<li><a href="http://rubyonrails.org/">Rails 3</a></li>
<li><a href="http://www.heroku.com">Heroku</a></li>
<li><a href="http://www.sendgrid.com">Sendgrid</a></li>
<li><a href="http://www.twilio.com">Twilio</a></li>
<li><a href="https://www.stripe.com">Stripe</a></li>
</ul>
<p>I'm doing this on my own without much feedback, so if you have any please share it. I would really appreciate anything you have to say.</p>
<p>Join the discussion on <a href="http://news.ycombinator.com/item?id=3089267">Hacker News</a>.</p>
Random Remindlyo Thingsccb8f2011-09-25T15:49:33+00:00<p>I think everyone is due for an update on my <a href="http://www.remindlyo.com">remindlyo</a> progress, but I don't really have an organized post. Here's a bunch of random thoughts instead.</p>
<h3>WePay is awesome</h3>
<p>Instead of the tried and true but well-known-to-be-horrible PayPal, I've decided to go with <a href="http://www.wepay.com">WePay</a> for my payments integration. I made this decision last weekend and today I finally hit the "Submit for Approval" button on remindlyo's application page. The staging server made it trivial to write my integration layer, except that I found a bug when trying to test some things. What makes WePay so awesome is the fact that I was able to email some random person at WePay support and they put their team on the problem right away. Gives me great confidence on them having my back when actual production payment-related things go wrong.</p>
<h3>GitHub and Heroku are great too</h3>
<p>I've been using GitHub for a number of years now but this is the first project where I've extensively used a private repository. Seamless experience all around.</p>
<p>I also have no complains about Heroku. Being able to get this thing up and running and scaleable with basically no efford has be a lifesaver. </p>
<h3>Rails? Eh. It's ok.</h3>
<p>I've been building remindlyo in rails at the same time I've been working on another side project (<a href="http://twitter-fiction-reader.herokuapp.com">Twitter Fiction Reader</a>, go check it out) in sinatra, and while they're both ruby web development frameworks, they're worlds apart. Rails is heavy, opinionated, all-the-batteries-you-will-ever-need-included framework, while sinatra is svelte and agile and fun. The one saving grace of Rails is that there's an awful lot of people out there struggling with it too, so it's easy to find different ways of going about things. </p>
<h3>Launching</h3>
<p>I'm pretty sure I'm close to launching this sucker. There are only a few things things holding me back right now. WePay, but I'm assuming the people that approve applications don't work on Sunday so hopefully they'll get back to me tomorrow. The only other thing is the marketing site, which needs some love. I might just go buy a template from Theme Forest that includes the bits I need, because making attractive web pages is definitely not something I'm good at.</p>
<p>So, maybe next week? We'll see.</p>
Quadrotor Update 3 8d9db2011-09-11T21:06:12+00:00<p>Quick update on the quadrotor. I went through all of the motor wiring and found that the motors were hooked up to the wrong terminals! [This diagram][multiwii-diagram] plus watching the orientation of the machine on the configuration software helped me figure out where I had gone wrong. After that, I calibrated the throttle range on all of the speed controllers and then tried flying again.</p>
<p>Except, it still doesn't really work. I played around with it for quite awhile but one of the speed controllers is still basically either on or off. No proportional control at all. Also, I relocated the gyro and accelerometer board to dead center of the body, which helped a little.</p>
<p>And then, when I was holding it and playing with the throttle and trim on the transmitter, one of the motors stalled out somehow. I'm wondering if maybe the battery is low again. Going to throw it on the charger for awhile tomorrow and try again.</p>
Quadrotor Update Part 2abbee2011-09-09T19:39:35+00:00<p>The new propellers came today. I ordered a pair of sets of 10x4.5 propellers from Amazon and promptly failed to get them to work with the motors. Turns out they're hard to mount! I ended up making a trip to the hardware store to pick up some O-rings, which are much more stable than the little rubber bands the motors came with. Here's what it looks like:</p>
<p><a href="http://www.flickr.com/photos/zrail/6131971044/" title="Untitled by zrail, on Flickr"><img src="http://farm7.static.flickr.com/6209/6131971044_478741cee2.jpg" width="500" height="374" alt=""></a></p>
<p>And here's the mess of wires close up:</p>
<p><a href="http://www.flickr.com/photos/zrail/6131970770/" title="Untitled by zrail, on Flickr"><img src="http://farm7.static.flickr.com/6210/6131970770_854a09b6dc.jpg" width="500" height="374" alt=""></a></p>
<p>Awesome, right? Right! I hooked up the battery, turned on the transmitter, and gave it a shot.</p>
<p>Aaaaaaaaand....</p>
<p>It promptly flipped over.</p>
<iframe width="560" height="345" src="http://www.youtube.com/embed/pBJ8EOaraEk" frameborder="0" allowfullscreen></iframe>
<p>After a few more or less comical runs of this I read up a little bit, and it turns out sometimes this happens because they battery is low. Put it on the charger for awhile and then tried again with no luck. So then I put the small props back on and held the thing in my hand while reving it up, and it turns out one of the motors is <em>way</em> more powerful than the others. I'm not sure why, but I think maybe one of the speed controllers isn't configured right. Now to figure out how to calibrate them without taking everything apart.</p>
<p>In any case, I'm pretty happy about having it together and making some progress. Maybe by this time next week I'll actually have a flying machine!</p>
Quadrotor Update6d01e2011-09-05T11:34:33+00:00<p>After too many days of everything <a href="http://www.remindlyo.com">remindlyo</a> I decided that today would be the day I finally got off my ass and finished putting together my <a href="2011-04-24-quadrotor-5-is-alive!.html">quadrotor</a>. There were a bunch of minor dramas that made me drop it for much too long, all detailed below the fold.</p>
<p>Drama number one was trying to get my Wii Motion Plus knockoff working. It never did, and in fact I'm pretty sure I completely fried it somehow. The software stopped reading the sensor, and some test software I wrote made it apparent that the sensor, even if it was responding to I2C protocol, was only responding with zeroes.</p>
<p>So, that sucked. I eventually pulled myself out of that deep black hole and ordered a <a href="http://www.sparkfun.com/products/10121">replacements sensor from SparkFun</a>. It was pretty expensive but it includes a three axis gyro and a three axis accelerometer on one tiny little board. Ordered, shipped, received. As I was soldering pins onto it I noticed a little 'VCC 3.3v' mark on it. Uh oh. My Arduino is 5v! Back into the deep black hole!</p>
<p>Literally months later I circled back and ordered <a href="http://www.sparkfun.com/products/8745">this little part</a>, a 5v to 3.3v logic level converter. Oh, and a 5v to 3.3v regulator. Oh actually two of each, in case I blew something up again. Took me awhile to get around to actually putting it together, which brings us to today. Soldered up the level converter, hooked everything up, put the propellers on, aaaaaaaaand....</p>
<p>It's too heavy. </p>
<p>The propellers flew off the motors before it moved even an inch above the floor.</p>
<p>Crap.</p>
<p>Anybody have suggestions for better propellers, or how to calculate what kind of propellers I need? As is, the whole thing is 445 grams incluing the battery.</p>
Bootstrapping a Side Business - First Steps5ff612011-09-04T08:38:05+00:00<p>For the past few weeks I've been working on a little product that I'm calling <a href="http://www.remindlyo.com">remindlyo</a>, which I'm hoping to turn into a secondary income stream. The basic idea is that you put events about the important people in your life, like birthdays, anniversaries, or what have you, into remindlyo. On the day of the event, remindlyo calls you to remind you and connects you to them, all on the same phone call. You can read more about it on the <a href="http://www.remindlyo.com">main remindlyo site</a>. In this post I want to talk more about the <strong>why</strong> instead of the <strong>what</strong>.</p>
<p>Since I first figured out what a business does, I've wanted to get in on it. I think I was 12 when I first said to my mom "I want to start a business. I don't want a regular job." Of course, like any responsible mother, she replied "How about you go to college and get a few years experience before starting?" Not exactly satisfactory, but it was sound advice. Now, 15 years later, I'm in a position where I can actually follow through.</p>
<p>I've been aware of <a href="http://www.kalzumeus.com/">Patrick McKenzie</a> for a few years now, but I recently came across his <a href="http://www.kalzumeus.com/greatest-hits/">Greatest Hits list</a> and over the course of maybe two days I devoured every single post. They're all great. I had already had an idea for a little project like remindlyo, but Patrick's posts inspired me to expand it into something that I could actually sell.</p>
<p>So then the problem was, what to sell? What can I build that people will buy? I've had a few ideas in the past, but then a few weeks ago my girlfriend kind of dropped the idea for remindlyo in my lap one day. When I told another developer at Emma about it he suggested a whole suite of improvements, which pretty much leads directly to the marketing site I have up and running today.</p>
<p>I can hear you asking "but what if people don't buy it?". That's the biggest fear, but also the most irrelevant, at least for me. I'm doing this first and foremost to learn how a business works from the inside. A very close second is the chance a bunch of technologies that I haven't played with until now, including <a href="http://rubyonrails.org/">Ruby on Rails</a>, <a href="http://www.twilio.com/">Twilio</a>, and <a href="http://www.heroku.com/">Heroku</a>, as well as how web marketing and the good kind of SEO works. The opportunity to gain an additional income stream is a somewhat distant third.</p>
Program Your Finances: Vacation Tracking7e4792011-08-04T16:47:48+00:00<p><em>Note: you can find much more information about ledger on <a href="http://ledger-cli.org">ledger-cli.org</a>, including links to official documentation and other implementations</em></p>
<p>Recently my girlfriend and I visited the wonderful city of Vancouver, Canada. While out of country we tend to use my <a href="http://www.schwab.com/public/schwab/banking_lending/checking">Schwab Investor Checking</a> account because it carries no fees whatsoever, including currency conversions, and it refunds all ATM fees. Last year when we went to Ireland we just kept all of the receipts and figured it out when we got back, which was excrutiatingly painful. Lost receipts, invisible cash transactions, ugh. It hurts to even think about it. This year, I decided to cobble together a simple system so we could track on the fly. Read on to see how it came together.</p>
<p>This system has the following moving parts:</p>
<ul>
<li><a href="http://www.dropbox.com">Dropbox</a></li>
<li><a href="http://www.ledger-cli.org">Ledger</a></li>
<li><a href="http://nebulousapps.net/notes.html">Nebulous Notes</a>, a text editor for iOS that syncs with Dropbox</li>
<li>an always-online machine hooked up to Dropbox and capable of running a python script every once in a while</li>
</ul>
<p>The workflow is pretty simple. Whenever we spent some money, I recorded it in a very simplified manner at the bottom of a ledger file that lives in Dropbox. Here's a few examples:</p>
<pre><code>2011/07/23 Cash
Cash 160.00 CAD
ATM Fees 2.50 CAD
Checking
2011/07/23 SkyTrain tickets
Transit 5.00 CAD
Cash
2011/07/24 Acme Cafe
Food:Breakfast 29.40 CAD
Checking
</code></pre>
<p>Note that, while simple, these are all valid ledger entries. They just have a different account structure than what my main ledger uses. I used a different file and an abbreviated account structure for a few reasons. First, using shorter account names means I didn't have to type as much on the iPhone screen. Second, this was an experiment, so having a separate file means I didn't have to worry about corrupting my main ledger. Third, loading up my main ledger on the phone slowed Nebulous Notes to a crawl, which wouldn't have been fun dealing with on the move.</p>
<p>Nebulous Notes also has a great macro system, so I was able to program a few interesting templates. "Go to the bottom of the file", Food, and Transit were all one button.</p>
<p>So, now that we have transactions going in and being synced, let's get a little fancy. This was a frugal vacation, so I wanted to see totals by account while we were out and about. Here's that python script:</p>
<pre><code>#!/usr/bin/env python
import sys
import re
amount_by_account = {}
ledger_file = sys.argv[1]
summary_file = sys.argv[2]
with open(ledger_file) as f:
for line in f.readlines():
if len(line.strip()) == 0:
continue
match = re.match("\s+([\w:]+) \s+([0-9.]+) CAD", line)
if match is not None:
account = match.group(1)
amount = match.group(2)
prev_amount = amount_by_account.get(account, 0.0)
amount_by_account[account] = prev_amount + \
float(amount)
with open(summary_file, "w+") as f:
total = 0
for account in sorted(amount_by_account.keys()):
total += amount_by_account[account]
f.write("{0:<20}{1:>10}\n".format(account, "%.2f" %
(amount_by_account[account])))
f.write("------------------------------\n")
f.write("{0:<20}{1:>10}\n".format("Total", "%.2f" % total))
</code></pre>
<p>Why python and not ledger itself? The machine that I had available to run this thing is a PowerPC Mac mini, which I've never been able to get ledger running properly on. So, python it is! Basically, it looks for lines in <code>ledger_file</code> matching the pattern of a ledger posting, totals up the amounts, and prints them out in alphabetical order to <code>summary_file</code>, which also lives on Dropbox. I had this on a one-minute <code>cron</code> schedule, so whenever I wanted to see our totals (and was in wifi range) I could just open <code>summary_file</code> in Nebulous and sync it up.</p>
<p>I could have used one of any number of iOS expense tracking apps, and that might have been the smarter way to go, but what fun would that be? Also, this system automatically backs itself up whenever Nebulous connects to Dropbox AND it lets me do another fun thing: import (almost) directly into my main ledger.</p>
<p>I say "almost" both because of the simplified account structure and because it's in Canadian dollars and my ledger is exclusively US dollars. Problematic! The easiest way to fix this was by applying the power of perl:</p>
<pre><code>#!/usr/bin/perl
use strict;
use warnings;
my %rates = (
'2011/07/23' => 1.0531,
'2011/07/24' => 1.0531,
'2011/07/25' => 1.0595,
'2011/07/26' => 1.0596,
'2011/07/27' => 1.0619,
'2011/07/28' => 1.0615,
'2011/07/29' => 1.0615,
);
my $current_date = undef;
while (<>) {
if (/(\d{4}\/\d{2}\/\d{2})/) {
$current_date = $1;
}
if (/(\s+)([\w\d: ]+) (\d+(\.\d+)?)/) {
$_ = sprintf(
"%sExpenses:%s \$%.2f\n",
$1,
$2,
($3 * $rates{$current_date})
);
}
s/ Cash/ Expenses:Cash/;
s/Checking/Assets:Schwab:Checking/;
print $_
}
</code></pre>
<p>Oh perl. So useful. So ugly. For every line, if it looks like a date, save off the date. If it looks like a transaction line, do the currency conversion (rates are calculated by picking a sample transaction from the bank and backing into it). If it looks like a <code>Cash</code> or <code>Checking</code> account, replace it with the long form of the account name. Finally, print it back out. This got me most of the way there, but I had to tweak some of the amounts due to posting lag at the bank and using a different day's conversion rate. I also piped it through ledger to get the formatting cleaned up:</p>
<pre><code>$ convert-vancouver-ledger.pl vancouver_ledger.txt | \
ledger -f - print > final_ledger_file.txt
</code></pre>
<p>A few quick adjustments and sanity checks later and I was able to copy and paste into my main ledger. I also added some metadata so I could get a report for my girlfriend so she could see what we spent and write me a check for half. Frugal, remember? The final transactions ended up looking like this:</p>
<pre><code>2011/07/23 * Cash
; :vancouver:
Expenses:Cash $168.51
Expenses:ATM Fees $2.63
Assets:Schwab:Checking
2011/07/23 * SkyTrain tickets
; :vancouver:
Expenses:Transit $5.27
Expenses:Cash
2011/07/24 * Acme Cafe
; :vancouver:
Expenses:Food:Breakfast $31.15
Assets:Schwab:Checking
</code></pre>
<p>I think it turned out pretty well. I spent less than an hour the day after we got home getting everything cleaned up and copied into my main ledger. When we next go out of the country, I'm sure I'll use this same system. I'll probably put the summarizer script in Dropbox, though, so I can tweak it if necessary.</p>
<p><em>Have you been in this situation and done something different? Leave a comment!</em></p>
Program your Finances: Reporting for Fun and Profit4b79e2011-07-09T08:14:55+00:00<p><em>Note: you can find much more information about ledger on <a href="http://ledger-cli.org">ledger-cli.org</a>, including links to official documentation and other implementations</em></p>
<p><em>Another note: I've written a new version of this that is much more dynamic and flexible named <a href="/2012-01-01-a-robust-reporting-system-for-ledger.html">Ledger Web</a>.</em></p>
<p>Last year I wrote what ended up being the most popular article on this blog ever, <a href="http://bugsplat.info/2010-05-23-keeping-finances-with-ledger.html">Program Your Finances: Command-line Accounting</a>. That post went over how I track and report on my finances using a program called <a href="http://www.ledger-cli.org">Ledger</a> along with a few helper scripts. Recently I expanded that toolset quite a bit and wanted to show how keeping meticulous track of your finances can give you superpowers. Read on for the gory details.</p>
<h3>Stan the Example Man</h3>
<p>Talking about personal finances is kind of a tricky thing. If you want to give anything more than a cursory treatment of the subject you have to have some data but the closest source of data to hand is always your own. <a href="http://www.getrichslowly.org">Some</a> <a href="http://www.consumerismcommentary.com/category/monthly-update/">people</a> have decided to talk publicly about their data but I'm not quite ready to to that. Instead, I've written a <a href="https://github.com/peterkeen/Ledger-Tools-Demo/blob/master/generate.py">little python tool</a> to generate a plausible but random history when given a simple json config file. Here's a super simple example: </p>
<pre><code>[
{
"payee": "Kettleman Bagels",
"dow": 3,
"postings": [
["Expenses:Food:Breakfast", [7.20, 7.80]],
["Assets:Checking"]
]
}
]
</code></pre>
<p>This says, "Every day on Thursday, buy breakfast at Kettleman Bagel Company. It should cost between $7.20 and $7.80." The <code>dow</code> key is the day number, where 0 is Monday and 6 is Sunday. The <code>postings</code> array gives a list of Ledger postings that should be inserted for this entry. The first element is the account name, the second is one of: a single float representing the amount in dollars; empty, meaning that this entry should be the balance of all the other entries; or an array of arguments to pass to Python's <a href="http://docs.python.org/library/random.html#random.triangular">random.triangular</a> function. There are a bunch more options that I won't get into here but you can see in the github repo.</p>
<p>Using <code>generate.py</code> and <a href="https://github.com/peterkeen/Ledger-Tools-Demo/blob/master/stan.json">this config</a>, I've created a <a href="https://github.com/peterkeen/Ledger-Tools-Demo/blob/master/stan.txt">ledger file</a> for a gentleman who we'll call Stan. Why "Stan"? Because he's the man, that's why. Stan is an unattached twenty-something software developer living in Portland, Oregon. He has a car, a moderately sized student loan, and a pretty decent apartment in a so-so area of town. He's been tracking his expenses for almost four years using Ledger, and he's pretty good at it now. (For the curious, Stan is loosely based on me. Simplified in places, exaggerated in others, cheerfully optimistic in salary.)</p>
<h3>Reporting? What's that mean?</h3>
<p>Collecting all of this data wouldn't be worth a whole lot if I couldn't analyze it in various ways. Ledger lets me look at things lots of really interesting ways, but sometimes it's a little bit too low level. Too nitty gritty. Too miss-forest-for-the-trees. Sometimes I want to step back and get a bigger view of where my financial life has been, and were I can expect it to lead, and maybe where I should make some changes. When a business wants to do this, they create a series of financial reports. Lots of businesses are compelled to do this by the SEC because they're public corporations, but every well-run business will create these reports regularly to help them keep on track.</p>
<p>Well, I'm kind of a business, right? I do work and receive money as the result of that work. I have short and long term debt, investments, equitiy, assets, etc etc. My sole motivation isn't profit, of course, but in a lot of other respects I try to run my finances as if they were a business. To that end, I've made a series of tools that produce a <a href="static/stan-demo-report.html">suite of reports</a> that are fairly similar to what a business would want. From top to bottom we have:</p>
<ul>
<li><strong>Balance sheet</strong> A snapshot of important accounts and a general idea of "net worth" over time. </li>
<li><strong>Net worth chart</strong> A monthly overview of the "Total" line from the balance sheet for all available months.</li>
<li><strong>Income Statement</strong> A monthly breakdown of income, expenses, and liability payments. </li>
<li><strong>Burn Rate</strong> Given Stan spends the "Burn" column on average every month for the trailing 12 months and assuming he'll spend about that same amount going forward, his savings will last him "Months" months. He'll run out of money sometime in February 2012.</li>
</ul>
<h3>But Ledger is a command line program!</h3>
<p>Ledger is a command-line program, that's true. I couldn't go directly from my ledger file to pretty html reports with charts and tables, so I invoked two of my favorite chainsaws to hack this out: <a href="http://www.postgresql.org/">PostgreSQL</a> and <a href="http://www.python.org/">python</a>. PostgreSQL is a wonderfully powerful database that happens to be open source and community driven, and also very easy to use. Python is, well, it wouldn't have been my first choice until pretty recently, but now that I've started using it perl has kind of dropped off my radar. It's pretty great.</p>
<p>Here's the outline of how this thing works:
1. Start maintaining a ledger file
1. Create a PostgreSQL database with the <a href="https://github.com/peterkeen/Ledger-Tools-Demo/blob/master/ledger-schema.sql">ledger schema</a></p>
<ol>
<li>Export the ledger to csv using <code>ledger csv</code> and load it into PostgreSQL using <a href="https://github.com/peterkeen/Ledger-Tools-Demo/blob/master/load_ledger.sh">load_ledger.sh</a></li>
<li>Run some sort-of complicated queries and dump them into HTML tables using <a href="https://github.com/peterkeen/Ledger-Tools-Demo/blob/master/run_reports.py">run_reports.py</a></li>
<li>Style the html tables using <a href="http://www.datatables.net/">jquery.datatables</a> and build a chart using <a href="http://www.jqplot.com/">jqplot</a> </li>
</ol>
<p>When I started this I knew I wanted a sql database. I chose PostgreSQL in particular over sqlite both out of familiarity, but also because it handles dates so well. Date is a top-level data type in postgres, instead of having to do weird things with strings like in sqlite.</p>
<p>Why a SQL database instead of just futzing with stuff in python data structures? Because in SQL I can express a rotated dataset pretty easily, whereas in python it would have been a <em>lot</em> of code. See run_reports.py for examples of this. Also, it lets me index the hell out of the tables, build summary tables with weird conditions, and still be able to do neat queries.</p>
<h3>Neat Queries You Say?</h3>
<p>Honestly, with a lot of work these reports could have been expressed using straight ledger without involving the database at all. It would have been nastier and terser and kind of weird, but I could have done it.</p>
<p>Here's a query that ledger would not have been able to do as far as I know, however:</p>
<pre><code>select
xtn_month,
sum(case when pay_period = 1 then amount else 0 end) as pp1,
sum(case when pay_period = 2 then amount else 0 end) as pp2
from
aggregated_accounts
where
account ~ 'Expenses'
and account !~ 'Taxes'
and account !~ 'Interest'
group by
xtn_month
where
xtn_month >= '2011-01-01'
order by
xtn_month;
xtn_month | pp1 | pp2
------------+---------+---------
2011-01-01 | 418.79 | 1249.39
2011-02-01 | 477.18 | 1146.11
2011-03-01 | 432.92 | 1316.65
2011-04-01 | 439.95 | 1274.56
2011-05-01 | 385.60 | 1417.73
2011-06-01 | 547.77 | 1193.86
2011-07-01 | 189.75 | 0
</code></pre>
<p>Being able to group by completely arbitrary things in ledger has been a pain point for me since I started using it. In this case, I'm grouping by <code>pay_period</code>, a column that has this definition in aggregated_accounts:</p>
<pre><code>CASE
WHEN (
xtn_date >= '2010-12-05'
and extract('day' from xtn_date) between 1 and 14
) THEN 1
WHEN (
xtn_date < '2010-12-05'
and (
extract('day' from xtn_date) between 1 and 6
or extract('day' from xtn_date) between 22 and 31
)
) THEN 1
ELSE 2
END as pay_period
</code></pre>
<p>The "Burn" calculations are another example. Before I had the data in postgres I had an extremely messy shell script that invoked <code>ledger</code>, <code>date</code>, and <code>dc</code> to calculate it, and if anything broke it all fell down with a weird error.</p>
<h3>Drawbacks</h3>
<p>The only drawback right now is that the postgres/python setup can't handle differing commodities very well. I track my investment accounts in ledger right along side my transactional accounts and ledger has the ability to go download price quotes for the holdings in those accounts whenever you want and do various calculations on them, but the way I'm doing the CSV export right now doesn't do any of that.</p>
<h3>Conclusion</h3>
<p>With this setup, I'm able to keep my financial data in a simple, easy to use format and retain the ability to do quick checks on it using <code>ledger</code>. In addition, I can do compilcated queries that would get extremely nasty in straight ledger. It's really the best of both worlds. I've put the tools on <a href="https://github.com/peterkeen/Ledger-Tools-Demo/">GitHub</a> if you want to check them out and maybe install them and try them out.</p>
<p><em>Whew! Did you stick it out? Questions? Comments? Post'em below.</em></p>
Quadrotor Motors Are Alive!38b562011-04-24T14:48:36+00:00<p>I found some time today to work on my quadrotor project some more. A few weeks ago I got one motor mounted and spinning, just using the RC receiver and trasmitter. Today, I mounted the motors and set up a little test program on the arduino to make them spin. Check it out:</p>
<iframe title="YouTube video player" width="550" height="390" src="http://www.youtube.com/embed/TuMfhkaHe0w" frameborder="0" allowfullscreen></iframe>
<p>Test program and more info after the fold.</p>
<p>Among other things, this entailed soldering the speed controllers to the motors, mounting the motors, putting more headers on the arduino, and figuring out the basic wiring. Here's the test program:</p>
<pre><code>#include <Servo.h>
#define ARMING_SPEED 900
#define ZERO_SPEED 1300
#define MAX_SPEED 1850
Servo front;
Servo right;
Servo back;
Servo left;
void write_speed(int in_speed) {
front.writeMicroseconds(in_speed);
right.writeMicroseconds(in_speed);
back.writeMicroseconds(in_speed);
left.writeMicroseconds(in_speed);
}
void setup() {
front.attach(10);
right.attach(11);
back.attach(12);
left.attach(13);
write_speed(ARMING_SPEED);
delay(10000);
}
int speed = 0;
void loop() {
for(speed = ZERO_SPEED; speed < MAX_SPEED; speed++) {
write_speed(speed);
delay(20);
}
for(speed = MAX_SPEED; speed > ZERO_SPEED; speed--) {
write_speed(speed);
delay(20);
}
}
</code></pre>
<p>All this does is setup four instances of the built-in Servo object on four different pins. After attaching the servo objects to pins, it sets them all to <code>ARMING_SPEED</code>, which is really just a speed that the speed controllers recognize as the throttle being completely off. Then, it waits for 10 seconds and then starts sweeping from <code>ZERO_SPEED</code> (idle but running) to <code>MAX_SPEED</code> (could be up to 2000 but the propellers have a tendency to fall off at that speed). </p>
<p>One note about these speeds. The way an RC receiver controls a servo is via PWM, "pulse width modification". The receiver sends out a train of pulses, each 2000 microseconds apart, to the servo. A width of 1000 indicates "full left", a width of 2000 indicates "full right", and 1500 "centered". A speed controller uses the same protocol, except it can't reverse direction and the range is a little bigger. 1300 is about idle, 2000 is full power, 900 is "safe". </p>
<p>The next step is to get the frame together the rest of the way and mounting the electronics. Oh, and adding in the Wii Motion Plus and Nunchuck boards to get the six axis IMU running. That's for another day, though.</p>
ProcLaunch v1.2061e12011-04-15T12:58:59+00:00<p>Just a few bug fixes this time:</p>
<ul>
<li>When you send proclaunch <code>SIGHUP</code>, it will send all of the profiles their respective stop signals and then wait for them to shut down. You can tell proclaunch to stop without waiting by sending <code>SIGHUP</code> again.</li>
<li>You can pass the <code>--log-path</code> command line option to change where proclaunch writes it's log. By default this is <code>$profile_dir/error.log</code></li>
</ul>
<p>Get it from <a href="http://github.com/peterkeen/proclaunch">github</a>! These changes were generously sponsored by <a href="http://www.ziplinegames.com/">Zipline Games</a>, who are using proclaunch to launch lua <a href="http://mongrel2.org/">mongrel2</a> handlers as part of their <a href="http://getmoai.com">Moai Cloud platform</a>.</p>
ProcLaunch Improvements and v1.161d352011-03-04T16:31:23+00:00<p>ProcLaunch has learned a bunch of new things lately. I've fixed a few bugs and implemented a few new features, including:</p>
<ul>
<li>A <code>--log-level</code> option, so you can set a level other than <code>DEBUG</code></li>
<li>Kill profiles that don't exist</li>
<li>Instead of killing the process and restarting, proclaunch can send it a signal using the <code>reload</code> file</li>
<li>Instead of always sending <code>SIGTERM</code>, the <code>stop_signal</code> file can contain the name of a signal to send when proclaunch wants to stop a profile</li>
<li>Pid files are properly cleaned up after processes that don't do it themselves</li>
<li>You won't get two copies of proclaunch if one is already running as root</li>
</ul>
<p>Get version 1.1 from <a href="http://github.com/peterkeen/proclaunch">github</a>! Thanks a bunch to Matt, who hunted down the bugs and helped me figure out the features.</p>
<p>(Also, I added <a href="http://softwaremaniacs.org/soft/highlight/en/">highlight.js</a> syntax highlighting. Hope you like it!)</p>
I Soldered Something!917142011-02-15T17:57:31+00:00<p>The <a href="http://arduino.cc">Arduino</a> is a cool little development board, actually a series of them, that make it a snap to get up and running with embedded development. I've wanted to get my hands on one for awhile but I haven't really had an application. That is, I didn't until I saw this:</p>
<iframe title="YouTube video player" width="580" height="390" src="http://www.youtube.com/embed/sHAa2H-_3yo" frameborder="0" allowfullscreen></iframe>
<p>And then I did some research and found this: </p>
<iframe title="YouTube video player" width="580" height="390" src="http://www.youtube.com/embed/hkMuKHYwfbQ" frameborder="0" allowfullscreen></iframe>
<p>This is an r/c quadcopter, a four bladed helicopter that uses an Arduino running the <a href="http://www.multiwii.com/">MultiWii</a> software wired up to some knock-off Wii sensors to stabilize itself. The concept is similar to an F-22 or F-117, in that the thing is completely unstable and would probably fall out of the sky without computer control. This is then connected to a four channel r/c receiver, controlled by a normal r/c transmitter.</p>
<p>So.</p>
<p>Cool.</p>
<p>Of course I immediately started scheming to get one of these up and running. The biggest problem was that I had no tools, nor an Arduino, nor any r/c equipment, nor materials to put this thing together. Naturally, I turned to <a href="http://www.sparkfun.com/">SparkFun</a> to set me up. They're a great online store that has all kinds of useful bits, including most everything electronics-wise that I'll need to get this project off the ground.</p>
<p>The box arrived today!</p>
<p><a href="http://www.flickr.com/photos/zrail/5449798142/" title="The box is here! by zrail, on Flickr"><img src="http://farm6.static.flickr.com/5051/5449798142_0587cc63e2.jpg" width="500" height="374" alt="The box is here!" /></a></p>
<p>And here's what was inside it:</p>
<p><a href="http://www.flickr.com/photos/zrail/5449777782/" title="Order Contents by zrail, on Flickr"><img src="http://farm6.static.flickr.com/5299/5449777782_5f153c6533.jpg" width="500" height="374" alt="Order Contents" /></a></p>
<p>(click the picture to see Flickr notes)</p>
<p>Basically I needed everything, so I got a cheap but solid soldering iron, solder, wires, headers, a brass "sponge" for cleaning the iron, and of course a pair of <a href="http://www.sparkfun.com/products/9218">Arduino Pro Mini 16MHz 5v</a> as well as the appropriate programming cable.</p>
<p>After unboxing I installed the Arduino software, the USB driver, and tried getting the simple blink example to install on one of the Arduinos without soldering on some headers. Wouldn't program very reliably, so I broke down and actually heated up the iron and melted some stuff. Here's the result:</p>
<p><a href="http://www.flickr.com/photos/zrail/5449776654/" title="Arudino Pro Mini up and running by zrail, on Flickr"><img src="http://farm6.static.flickr.com/5058/5449776654_43c8491b4a.jpg" width="500" height="374" alt="Arudino Pro Mini up and running" /></a></p>
<p>Most of the joints are fine, but TX0 didn't get much solder through the hole so I'm going to have to watch it. In any case, it works. I got the blink example working and then wrote up a stupid little S-O-S blinking program and installed it. Pretty lame in the grand scheme of things, but I got it all running, including the soldering, in less than an hour. Extremely gratifying and a great start.</p>
<p>Now to buy sensors, motors, propellers, r/c equipment, and batteries, build the frame, etc etc. I'm thinking strongly about refactoring and rewriting large chunks of MultiWii, but that will come after I get it flying with the stock code.</p>
Using the Transmission RPC Interface to Organize Torrentsfb9072010-11-27T18:53:04+00:00<p>I've been using my Mac mini as a torrent downloader and media server for a few years now using <a href="http://www.transmissionbt.com/">Transmission</a>. Tonight I got fed up with my torrents being in one unsorted mass so I learned the <a href="https://trac.transmissionbt.com/browser/trunk/extras/rpc-spec.txt">HTTP RPC api</a> and wrote a simple blocking client that organizes them.</p>
<p>I tried out an <a href="https://github.com/dsander/transmission-client">existing client</a> that I found on GitHub, but it was sort of difficult to use, involving EventMachine and evented techniques. If this was part of a long-running processes I would spend the time to learn how to do this stuff, but this is just a simple script so a blocking technique is just fine.</p>
<p>Here's the client class:</p>
<pre><code>require 'rubygems'
require 'mechanize'
require 'json'
class TransmissionClient
attr_reader :agent,
:header_name,
:header_val,
:password,
:port,
:server,
:username
def initialize(params)
@username = params['username']
@password = params['password']
@server = params['server']
@port = params['port'] || "9091"
@agent = Mechanize.new
@agent.auth(username, password)
@header_name = ""
@header_val = ""
end
def server_uri
return "http://#{server}:#{port}/transmission/rpc"
end
def send(method, params)
resp = ""
begin
resp = agent.post(
server_uri,
JSON.generate({
"method" => method,
"arguments" => params
}),
header_name => header_val
)
resp_obj = JSON.parse(resp.body)
if resp_obj["result"] == "success" then
return resp_obj["arguments"]
else
raise RuntimeError resp.body
end
rescue Mechanize::ResponseCodeError => e
@header_name, @header_val =
e.page.search("code").first.content.split(/: /)
retry
end
end
end
</code></pre>
<p>The only real surprise here is that Transmission sends a session ID in an error response (http code 409) and expects that session ID to be sent as a header in every request thereafter. Because of how the ruby version of Mechanize works, it's hard to get the headers from the exception that gets thrown on errors, so instead I extract it directly from the response page. Conveniently the <code>page</code> property on the exception acts like a <a href="http://nokogiri.org/">nokogiri</a> object so I can just search for the single <code>code</code> block on the page and grab the conveniently formatted header.</p>
<p>Here's some code that uses the above class to relocate torrents into folders:</p>
<pre><code>def get_folder_from_name(name)
name_parts = name.split(/\./)
series_parts = []
if name_parts[0].match(/^[0-9]+/) then
series_parts.push name_parts.shift
end
name_parts.each do |p|
break if p.match(/(s?)\d/i)
series_parts.push p
end
if series_parts.length > 0 then
return series_parts.map{|s| s.downcase}
.join("_")
.gsub("aaf-", "")
else
return nil
end
end
server_info_str = IO.read("/Users/Peter/.transmission_server");
server_info = JSON.parse(server_info_str)
client = TransmissionClient.new(server_info)
torrents = client.send(
"torrent-get",
"fields" => %w{id name downloadDir}
);
torrents["torrents"].each do |t|
series_name = get_folder_from_name(t["name"])
next unless series_name
name = t['name']
id = t['id']
download_dir = t['download_dir']
puts "Moving #{name} (#{id}) from #{download_dir} to #{series_name}";
client.send(
"torrent-set-location",
"ids" => t["id"],
"location" => "/Users/Peter/Movies/#{series_name}",
"move" => true
)
end
</code></pre>
<p>This instanciates a new client and grabs the <code>id</code>, <code>name</code>, and <code>downloadDir</code> fields for each currently active torrent. Then, it extracts a folder name from torrent's name and tells the client to move the torrent into the proper location. The paths are hardcoded because as I said before, this is a pretty stupid simple script. There's no reason they couldn't be in the config file that holds the server info. Also, the function that extracts a folder name is very specific to the torrents I'm working with.</p>
ProcLaunch v1.00d5b32010-09-23T19:39:47+00:00<p>I kind of started <a href="http://github.com/peterkeen/proclaunch">ProcLaunch</a> as a lark. Can I actually do better than the existing user space process managers? It turns out that at least a few people think so. I've gotten a ton of great feedback from <a href="http://github.com/thijsterlouw">thijsterlouw</a>, who actually filed bug reports and helped me work through a bunch of issues. ProcLaunch even has some tests now!</p>
<p>As of today, I'm releasing ProcLaunch v1.0, which you can download from the <a href="http://github.com/peterkeen/proclaunch/downloads">github downloads page</a>. Interesting changes from the initial version:</p>
<ul>
<li><p>Moved to an explicit state machine</p>
<p>In the first version there were a lot of edge cases where proclaunch would have a seemingly random sleep, or some other weird thing. I've removed all of the edge cases by creating an explicit state machine. Profiles have a <code>_status()</code> attribute, which is always one of <code>stopped</code>, <code>starting</code>, <code>running</code>, or <code>stopping</code>. The only <code>sleep()</code> is at the end of the main loop.</p>
<p>The main motivation for this change is because the old version was just plain bad design. Every iteration of the main loop woule create a whole new set of <code>Profile</code> objects, overwriting the old list. Awp, but what happens to profiles that should stop? Let's keep track of their pids and keep trying to kill them over and over until they finally die. But what happens if proclaunch dies before those pids die? Do they just live forever, the eternal zombies of a daemon gone wrong?</p>
<p>The new design eliminates both the repeated kill and the overwriting. Now, profiles are kept in a hash keyed on name and are never replaced after creation. Profiles that get stopped are put in the <code>stopping</code> state, which will check up on the pid every second until it finally dies, then moved to <code>stopped</code>, ready to be restarted.</p></li>
<li><p>Improved logging</p>
<p>Log lines have a static format: <code><Timestamp> <Log Level> <Tag> <Message></code>. <code><Tag></code> is either <code>ProcLaunch</code> or the name of the profile. If a message mentiones a pid, it will always be stated as <code>pid <PID></code>. This change should make it easier to grep through the logs and automatically parse them for monitoring through nagios or what-have-you. </p></li>
</ul>
<p>Please check it out and beat it up. If you notice any issues, don't hesitate to <a href="http://github.com/peterkeen/proclaunch/issues">submit an issue</a> or <a href="mailto:pete@bugsplat.info">email me</a>, or just leave a comment below.</p>
Perl with a Lisp7497d2010-08-22T14:22:36+00:00<p>Browsing around on <a href="http://news.ycombinator.com">hacker news</a> one day, I came across a <a href="http://news.ycombinator.com/item?id=1591112">link</a> to a paper entitled "<a href="http://www.ee.ryerson.ca/%7Eelf/pub/misc/micromanualLISP.pdf">A micro-manual for Lisp - Not the whole truth</a>" by John McCarthy, the self-styled discoverer of Lisp. One commentor stated that they have been using this paper for awhile as a <em>code kata</em>, implementing it several times, each in a different language, in order to better learn that language. The other day I was pretty bored and decided that maybe doing that too would be a good way to learn something and aleviate said boredom. My first implementation is in perl, mostly because I don't want to have to learn a new language <em>and</em> lisp at the same time. The basic start is after the jump.</p>
<p>Building a lisp seems to center around two key decisions. First, how do you represent your core data structure? A two-element array? A struct? Something a little more complex? Second, what are your scoping rules. Lexical? Dynamic? Global? After that, everything else is gold plating. Substrate-langauge interop, how you represent scopes, how to get closures right, macros, etc, all can be determined later.</p>
<p>I've chosen to write this first implementation in perl. I know perl pretty well but more importantly I don't know lisp very well at all. I've done a little elisp hacking, but not much. I certainly don't know how all of the pieces fit together quite yet. This first post is really more about getting the fundamental data structure and list-manipulation routines and the reader down. Later posts will elaborate on <code>eval</code> and friends, as well as closures, scoping, and perl interop.</p>
<h3>Data Structure</h3>
<p>Lisp represents most things fundamentally in terms of what's known as a <em>cons cell</em>. This is some sort of object that has two slots for other objects, be they primitives or other cons cells. Being a good little modern perl programmer, I've chosen to implement this as a small Moose-based <a href="http://github.com/peterkeen/kata/blob/master/perl/lib/Cell.pm">class</a>:</p>
<pre><code>package Cell;
use Moose;
use overload
'bool' => sub { return !shift->is_nil() },
'fallback' => 1
;
has 'car' => (is => 'rw');
has 'cdr' => (is => 'rw');
has 'is_nil' => (is => 'ro', default => 0);
1;
</code></pre>
<p>Using Moose, we define an object with two read-write slots named <code>car</code> and <code>cdr</code>. This is due entirely to historical precident: <code>car</code> is the first element in the pair, <code>cdr</code> is the second. <code>is_nil</code> is there to allow us to define a fixed <code>nil</code> value later on. The <code>overload</code> allows us to use a <code>Cell</code> in a boolean context. Anything that doesn't have <code>is_nil</code> set is <code>true</code>;</p>
<h3>Fundamental Functions</h3>
<p>Now that we've got the data structure done, let's define a few <a href="http://github.com/peterkeen/kata/blob/master/perl/lib/Functions.pm">fundamental functions</a> to work with it.</p>
<pre><code>our $NIL = Cell->new(is_nil => 1);
sub nil
{
return $NIL;
}
our $T = "t";
sub t
{
return $T;
}
sub equal
{
my ($a, $b) = @_;
return t if $a eq $b;
return nil;
}
</code></pre>
<p>Notice how <code>$NIL</code> is just hanging out there. It's the only Cell that will ever have <code>_is_nil</code> set. We return the reference to the singleton from the <code>nil</code> function. <code>t</code> is the opposite. We just return the atom <code>t</code>. <code>equal</code> exploits perl's built-in comparison operator <code>eq</code> to compare two things.</p>
<p>Now, the good stuff. List manipulation:</p>
<pre><code>sub cons
{
my ($thing, $list) = @_;
return Cell->new(car => $thing, cdr => $list);
}
sub list
{
reduce { cons($b, $a) } (nil, reverse @_);
}
sub car
{
my $thing = shift;
confess "Argument to car must be a list"
unless ref($thing) && ref($thing) eq 'Cell';
return defined($thing->car()) ? $thing->car() : nil;
}
sub cdr
{
my $thing = shift;
confess "Argument to cdr must be a list"
unless ref($thing) && ref($thing) eq 'Cell';
return defined($thing->cdr()) ? $thing->cdr() : nil;
}
</code></pre>
<p><code>cons</code> creates new <code>Cell</code>s, setting their <code>car</code> and <code>cdr</code> as appropriate. The <code>list</code> function is a pure convenience thing to make setting up singly-linked lists easy. <code>car</code> and <code>cdr</code> do a small amount of error checking and call out to the given <code>Cell</code>'s <code>car()</code> and <code>cdr()</code> methods.</p>
<p><a href="http://github.com/peterkeen/kata/blob/master/perl/lib/Functions.pm">Functions</a> also defines some functions that will be used later, as well as some things that can walk lists and trees made from cons cells and do something with them. It implements a <code>list_string</code> function which will be imported as the <code>(print)</code> function, once we have symbol tables and function importing defined.</p>
<p>There are a bunch of tests for these functions in <a href="http://github.com/peterkeen/kata/blob/master/perl/t/01_list_manipulation.t">01<em>list</em>manipulation.t</a>. </p>
<h3>Reader</h3>
<p>Lisp's parser is referred to as the <em>reader</em>. Generally you interact with it using the <code>(read)</code> function, which pulls off of the input stream and returns the next parsed form as an AST. This reader consists of a hand-rolled recursive descent parser in <a href="http://github.com/peterkeen/kata/blob/master/perl/lib/Read.pm">Read.pm</a> that implements these constraints:</p>
<ul>
<li>Numbers consist only of numeric charcters and decimal points.</li>
<li>Symbols start with <code>[a-zA-Z]</code> and can contain anything within that range, as well as numbers, the '<code>:</code>' character, underscores, and dashes.</li>
<li>String literals start and end with the '<code>"</code>' character. Escaping is not implemented yet.</li>
<li>Lists start with '<code>(</code>', end with '<code>)</code>', and contain one or more whitespace-delimited things.</li>
<li>Whitespace is skipped.</li>
</ul>
<p>This most basic of readers is only 113 lines of perl, but it can parse a string of characters that look like lisp and turn it into a tree of cons cells, ready to be evaluated. Tests and examples can be found in <a href="http://github.com/peterkeen/kata/blob/master/perl/t/02_read.t">02_read.t</a>.</p>
<p>Well, that's all for now. It's a good start, but doesn't really deal with any of the interesting bits yet. Next up: <code>(eval)</code>.</p>
<p><em>What's your personal code kata? Have you written a lisp before? Have any tips for me?</em></p>
Managing Your Processes with ProcLaunch.c385f2010-08-08T12:30:37+00:00<p><em>Edit 2010-08-08 17:47: ProcLaunch now has a CPAN-compatible install process. See below for details.</em></p>
<p>I finally got the chance to work some more on <a href="http://github.com/peterkeen/proclaunch">proclaunch</a>, my implementation of a <em>user space process manager</em>, like runit or mongrel or god. I wrote up a big overview of the currently available options [previously][12], but in summary: all of the existing options suck. They're either hard to setup, have memory leaks, have a weird configuration language, or are just plain strange. The only viable option was <a href="http://mongrel2.org/doc/tip/docs/manual/book.wiki#x1-380004.1.1">procer</a>, and even that was just sort of a tech demo put together for the <a href="http://mongrel2.org/doc/tip/docs/manual/book.wiki">Mongrel2 manual</a>.</p>
<p>That's why I started putting together proclaunch. I need some of the features of runit, namely automatic restart, with none of the wackyness, and I wanted it to be easy to automatically configure. I also wanted it to be standalone so I wouldn't have to install a pre-alpha version of Mongrel2 just to manage my own processes.</p>
<h3>What of it?</h3>
<p>Grab the latest version off of github, unpack it, and run this in the unpacked directory:</p>
<pre><code>$ perl Build.PL
$ ./Build
$ ./Build install
</code></pre>
<p>If everything went smoothly you'll have <code>proclaunch</code> somewhere in your path. Now, fire it up:</p>
<pre><code>$ mkdir -p /path/to/some/state/directory
$ sudo proclaunch \
--debug \
--foreground \
/path/to/some/state/directory \
example_profiles/
</code></pre>
<p>If everything goes according to plan, you'll see a bunch of debug info scroll past showing that it scanned the profiles directory, found one called <code>sleeper</code>, and kicked it off. Then, every five seconds you'll see it rescan. If you look in your process list for <code>sleep</code> you'll see bash happily kicking off a <code>sleep 10</code> in an infinite loop as the <code>nobody</code> user. Now, run this:</p>
<pre><code>$ sudo kill `cat /path/to/some/state/directory/proclaunch.pid`
</code></pre>
<p>You should still see the sleep going on, but <code>proclaunch</code> shouldn't show up anywhere. If you launch <code>proclaunch</code> again, you'll see it startup but never start <code>sleeper</code>, since it's already running. This may seem really mundane, but you can't make runit behave this way without some major hacks. Oh, and to actually make <code>proclaunch</code> kill everything before dying, kill it with -HUP:</p>
<pre><code>$ sudo kill -HUP `cat /path/to/some/state/directory/proclaunch.pid`
</code></pre>
<p>Now for the automatic restart. Change something about the profiles directory:</p>
<pre><code>$ touch example_profiles/
</code></pre>
<p>In the log you should see that <code>proclaunch</code> saw something changed and rescanned immediately. Now change something about <code>sleeper</code>:</p>
<pre><code>$ touch example_profiles/sleeper
</code></pre>
<p>Within a few seconds, <code>proclaunch</code> will notice that something happened and restart <code>sleeper</code>. Specifically, it will send <code>sleeper</code>'s pid a <code>SIGTERM</code>, wait up to 7 seconds for it to actually die, and then send it a <code>SIGKILL</code>. Now something a little more drastic:</p>
<pre><code>$ sudo mv example_profiles/sleeper example_profiles/sleeper2
</code></pre>
<p><code>proclaunch</code> will notice that <code>sleeper</code> is gone, tell it to stop, then start <code>sleeper2</code> since it obviously isn't running. You can use this to setup really simple deploys, especially if you're deploying with <a href="http://www.capify.org/index.php/Capistrano">Capistrano</a>. Just commit your profiles directory to version control and point <code>proclaunch</code> at that directory in the <code>current</code> symlink, making sure that the pid_file is within the deploy directory somewhere. Within 5 seconds of your deploy, <code>proclaunch</code> will see that the inode on the profiles directory changed.</p>
<h3>What is a profile, anyway?</h3>
<p>If you look in the <code>sleeper</code> directory, you'll see this set of files:</p>
<pre><code>run
pid_file
user
</code></pre>
<p><code>run</code> is a small script that <code>proclaunch</code> expects to execute and have it return in short order, having backgrounded itself and written it's pid to the path contained in <code>pid_file</code>. This forms the core of both <code>proclaunch</code> and <code>procer</code>. Really simple to setup and automate, since there isn't any complicated config file to manage. The <code>user</code> file is special to <code>proclaunch</code>, and tells it what user to start <code>run</code> as. By default, <code>proclaunch</code> will start <code>run</code> as <code>root</code>, which is generally not what you want. <code>procer</code> can do some fun things that <code>proclaunch</code> can't do yet, like manage dependencies between profiles. If there's any demand I'll work on adding that but I don't currently need it.</p>
<h3>A small digression into Mac OS X</h3>
<p>Initially I wanted to use <a href="http://search.cpan.org/%7Etlbdk/Privileges-Drop-1.01/lib/Privileges/Drop.pm">Privilege::Drop</a> from CPAN to drop privileges when spawning profiles. It's a really clean pure perl module that has no dependencies other than perl itself. It even does a bunch of sanity checking to ensure that the privileges you dropped to are specifically what you wanted to drop to. However, on OS X with perl 5.10, it seems that you can't drop a large number of auxiliary groups that Privilege::Drop doesn't know about, at least not in the way that it's currently written. That's why the code for dropping privileges is inlined in <code>App::ProcLaunch::Profile</code>. It still checks to make sure that the group you tried to drop to is in the list, but it doesn't assert the list matches exactly what you wanted to do.</p>
<p><em>Is this something you'd use if it were packaged up nicely on CPAN? Want to use it even before that? Let me know in the comments.</em></p>
Blog Generator Updates132010-08-06T23:04:47+00:00<p>I've made some small changes to the way bugsplat.info is generated. First, I refactored <code>publish.pl</code> quite extensively. Instead of being a huge mess of spaghetti-perl, it's nicely factored out into functions, each one doing as little as possible. It got a little longer, but I think it's worth the tradeoff in readability.</p>
<p>Second, I added self-generated shortlinks. Each post on the site has an internal id, which is actually a monotonically increasing sequence number. The short link for a post is <code>http://bugsplat.info/<id></code>. For this post, it's <a href="http://bugsplat.info/13">http://bugsplat.info/13</a>. These are implemented as <code>mod_rewrite</code> rules in <code>.htaccess</code> which are generated using a template, just like every other piece of content on the site.</p>
<p>Third, I wrote a new convenience script named <code>next-entry.pl</code>, the idea for which I shamelessly stole from <a href="http://technosorcery.net">technosorcery</a>. Basically, it'll prompt me for a post title using bash's <code>read</code> function, then generate a URL and some date strings, as well as comb through the <code>entries/</code> directory to find the highest <code>id</code>, then increase it by one. It writes all this to a file and then opens <code>emacsclient</code> right at the correct spot to start typing an entry.</p>
<p>Fourth, I worked on the CSS a little bit. Hopefully it looks a little snazzier than it did before.</p>
Daemons are Our Picky, Temperamental Friends122010-08-01T18:09:00+00:00<p>Modern web applications are complicated beasts. They've got database processes, web serving processes, and various tiers of actual application services. The first two generally take care of themselves. PostgreSQL, MySQL, Apache, Nginx, lighttpd, they all have well-understood ways of starting and keeping themselves up and running.</p>
<p>But what do you do if you have a bunch of processes that you need to keep running that <em>aren't</em> well understood? What if they're well-understood to crash once in a while and you don't want to have to babysit them? You need a <em>user space process manager</em>. Zed Shaw seems to have coined this term specifically for the <a href="http://mongrel2.org/doc/tip/docs/manual/book.wiki">Mongrel2 manual</a>, and it describes pretty accurately what you'd want: some user-space program running above init that can launch your processes and start them again if they stop. Dropping privilages would be nice. Oh, and it'd be cool if it were sysadmin-friendly. Oh, and if it could automatically detect code changes and restart that'd be nifty too.</p>
<p>There are quite a few of these things out there, and as Zed points out all of them suck to various degrees. Here's a list of just a few that I've come across.</p>
<ul>
<li><p><strong><a href="http://smarden.org/runit/">runit</a></strong></p>
<p>We actually use runit at work quite a bit. It's... interesting. Essentially you control it through specially-laid-out directories full of named pipes and control files and whatnot. The learning curve is rather steep, especially since it cannot control things that are already daemons, which flies in the face of everything Unix. It's also bizzarely difficult to get started, since it can't daemonize itself.</p></li>
<li><p><strong><a href="http://god.rubyforge.org/">God</a></strong></p>
<p>God is a process manager written in ruby. You configure everything with an internal ruby DSL and it takes care of the rest. It'll even kill things when they start taking up too much memory, which is nice, and it looks pretty extensible as far as adding new conditions. It also has a really nice notifications system, with built-in emailing and twittering and campfiring, if that's your thing. Unfortunately, it also looks kind of complicated. You have to have ruby loaded, you have to write your config in ruby, and it's way of loading configs is sort of weird. Oh, and it has memory leaks.</p></li>
<li><p><strong><a href="http://github.com/arya/bluepill">bluepill</a></strong></p>
<p>Bluepill was written in reaction to god's shortcomings. It's also written in ruby, it's got a ruby DSL, but some things are slightly different. Mostly it's similar to God but without the memory leak, and without the nice notification support.</p></li>
<li><p><strong><a href="http://mmonit.com/monit/">monit</a></strong></p>
<p>The industrial-sized solution, monit seems to compete in the same space as Nagios, except with process management tacked on. Big web interface, mostly for whole-system management. I haven't personally tried it.</p></li>
<li><p><strong><a href="http://supervisord.org/">supervisord</a></strong></p>
<p>Written in python, supervisord looks more like what we're looking for. It's specifically written for tracking application-level processes. I haven't personally tried it but I've heard nice things. However, the config system looks pretty intimidating, and it doesn't look to have a nice system for managing dynamic configs.</p></li>
<li><p><strong><a href="http://mongrel2.org/doc/tip/docs/manual/book.wiki#x1-380004.1.1">procer</a></strong></p>
<p>Procer is what started me on this whole adventure. After struggling with runit for almost an entire week, procer was a breath of fresh air. It is structured in the same way as runit, as a directory full of directories full of files. The most basic config is just a directory containing a <code>run</code> script that daemonizes and writes a pid to the path that the <code>pid_file</code> file contains. Procer can also handle dependencies between services, which is nice if process A just <em>has</em> to be running for process B to even start.</p></li>
</ul>
<p>Of all of these, procer seems like the easiest to understand and get going with. However, it's sort of a side project inside of the mongrel2 effort and was written specifically for the manual. It doesn't really handle the code changing underneath it. You have to kill off your processes and let procer restart them for you. Also it depends on a core library from mongrel2, which doesn't really make it suitable for other uses.</p>
<p>That being said, I started rolling my own user space process manager yesterday. It's called <a href="http://github.com/peterkeen/proclaunch">proclaunch</a>, and it's heavily inspired by procer. Right now it's mainly just a toy. It can launch and restart processes and maintain pid files, but it has no idea how to drop privilages or restart when something changes. Written in core perl with no external dependencies, it should eventually be suitable at least for my specific use cases, and hopefully it will be for yours too.</p>
<p><em>Have I missed a process manager? Did I misrepresent one of them? Leave a comment and let me know.</em></p>
Data Mining "Lost" Tweets Part 1102010-06-02T17:45:00+00:00<p>As some of you might know, <a href="http://twitter.com">Twitter</a> provides a <a href="http://apiwiki.twitter.com/Streaming-API-Documentation">streaming API</a> that pumps all of the tweets for a given search to you as they happen. There are other stream variants, including a sample feed (a small percentage of all tweets), "Gardenhose", which is a stastically sound sample, and "Firehose", which is every single tweet. All of them. Not actually all that useful, since you have to have some pretty beefy hardware and a really nice connection to keep up. The filtered stream is much more interesting if you have a target in mind. Since there was such a hubbub about "Lost" a few weeks ago I figured I would gather relevant tweets and see what there was to see. In this first part I'll cover capturing tweets and doing a little basic analysis, and in the second part I'll go over some deeper analysis, including some pretty graphs!</p>
<h2>Capturing</h2>
<p>Let me preface: I have never watched a single episode of "Lost". When it started I had way too much stuff going on to pay attention to television and since then I've sort of conciously stayed away. I pass no judgements on anyone who is a fan or not, or who is evil or not.</p>
<p>The streaming API is pretty easy to work with. You basically give it a comma separated list of search terms and it will give you any and all tweets that match those terms. For example, if you were to run this command:</p>
<pre><code>$ curl -q http://stream.twitter.com/1/statuses/filter.json\?track=bpcares \
-uYourTwitterName:YourTwitterPass
</code></pre>
<p>you would get a stream of semi-humorous tweets about the oil spill.<br>
I wrote a little <a href="http://gist.github.com/423346#file_capture_tweets.pl">perl wrapper</a> around curl which will automatically stop capturing after a given number of hours or until it has captured a given number of megabytes. It will also reconnect when the stream dies for any reason. To capture a workable number of tweets, I launched this script on May 23rd at 4:14pm PDT like this:</p>
<pre><code>$ capture-tweet-stream.pl 24 10000 ~/data/lost-finale-tweets.txt \
'lost,locke,jack,sawyer,smokemonster,theisland,jacob,shepard'
</code></pre>
<p>This means, capture any tweets matching those terms for 24 hours or 10 gb, whichever comes first.</p>
<h2>A little analysis</h2>
<p>For a while as I was running the capture I was tailing the output file and would pause the output whenever a gem of a tweet scrolled past, just so I could retweet it. Here's my favorite two:</p>
<p><!-- http://twitter.com/BorowitzReport/status/14591815901 --> <style type='text/css'>.bbpBox14591815901 {background:url(http://a3.twimg.com/profile<em>background</em>images/102523121/AndySeated2.jpg) #9AE4E8;padding:20px;} p.bbpTweet{background:#fff;padding:10px 12px 10px 12px;margin:0;min-height:48px;color:#000;font-size:18px !important;line-height:22px;-moz-border-radius:5px;-webkit-border-radius:5px} p.bbpTweet span.metadata{display:block;width:100%;clear:both;margin-top:8px;padding-top:12px;height:40px;border-top:1px solid #fff;border-top:1px solid #e6e6e6} p.bbpTweet span.metadata span.author{line-height:19px} p.bbpTweet span.metadata span.author img{float:left;margin:0 7px 0 0px;width:38px;height:38px} p.bbpTweet a:hover{text-decoration:underline}p.bbpTweet span.timestamp{font-size:12px;display:block}</style> <div class='bbpBox14591815901'><p class='bbpTweet'>If characters who died on <a href="http://twitter.com/search?q=%23LOST" title="#LOST" class="tweet-url hashtag" rel="nofollow">#LOST</a> stayed dead, the finale would be nine minutes long.<span class='timestamp'><a title='Mon May 24 01:26:18 +0000 2010' href='http://twitter.com/BorowitzReport/status/14591815901'>less than a minute ago</a> via web</span><span class='metadata'><span class='author'><a href='http://twitter.com/BorowitzReport'><img src='http://a1.twimg.com/profile_images/882447100/clowntown2_normal.jpg' /></a><strong><a href='http://twitter.com/BorowitzReport'>Andy Borowitz</a></strong><br/>BorowitzReport</span></span></p></div> <!-- end of tweet --></p>
<p><br />
<!-- http://twitter.com/EdBattes/status/14592099261 --> <style type='text/css'>.bbpBox14592099261 {background:url(http://s.twimg.com/a/1274899949/images/themes/theme9/bg.gif) #1A1B1F;padding:20px;} p.bbpTweet{background:#fff;padding:10px 12px 10px 12px;margin:0;min-height:48px;color:#000;font-size:18px !important;line-height:22px;-moz-border-radius:5px;-webkit-border-radius:5px} p.bbpTweet span.metadata{display:block;width:100%;clear:both;margin-top:8px;padding-top:12px;height:40px;border-top:1px solid #fff;border-top:1px solid #e6e6e6} p.bbpTweet span.metadata span.author{line-height:19px} p.bbpTweet span.metadata span.author img{float:left;margin:0 7px 0 0px;width:38px;height:38px} p.bbpTweet a:hover{text-decoration:underline}p.bbpTweet span.timestamp{font-size:12px;display:block}</style> <div class='bbpBox14592099261'><p class='bbpTweet'>I hope Dexter shows up on Lost and kills them all. <a href="http://twitter.com/search?q=%23FuckLost" title="#FuckLost" class="tweet-url hashtag" rel="nofollow">#FuckLost</a><span class='timestamp'><a title='Mon May 24 01:31:22 +0000 2010' href='http://twitter.com/EdBattes/status/14592099261'>less than a minute ago</a> via <a href="http://itunes.apple.com/app/twitter/id333903271?mt=8" rel="nofollow">Twitter for iPhone</a></span><span class='metadata'><span class='author'><a href='http://twitter.com/EdBattes'><img src='http://a1.twimg.com/profile_images/283390162/user200_1563_normal.jpg' /></a><strong><a href='http://twitter.com/EdBattes'>Ed Battes</a></strong><br/>EdBattes</span></span></p></div> <!-- end of tweet --></p>
<p>I happen to be a fan of Dexter, and would have gladly paid money for a crossover. Anyway.</p>
<p>If you want to play along the data is on <a href="http://dl.dropbox.com/u/5193213/lost-finale-tweets.txt.gz">my dropbox</a> and the code is all on <a href="http://gist.github.com/423346">github</a>. First, let's get an idea of how much raw data we're working with. Twitter sends carriage-return separated JSON blobs. Awk to the rescue!</p>
<pre><code>$ gzcat lost-finale-tweets.txt.gz | awk 'BEGIN{RS="\r"}{n+=1}END{print n}'
779750
$
</code></pre>
<p>Almost 780,000 tweets. Tweeps were busy! Ok, so what were they saying? A normal approach would be to run through all of the tweets and count up occurances of each word, but because there's so much output I can't do it on my laptop or I'd run out of memory. Instead, here's a map and two stage reduce process. The map is a fairly small perl script that everyone and their mother can pretty much write from memory, the word count mapreduce example:</p>
<script src="http://gist.github.com/423346.js?file=stem.pl"></script>
<p>This one has a few modifications, though. First, it removes all punctuation except '#' and lowercases everything. Second, it will count each individual word as well as each two and three word phrase in the tweet. We can run it like this:</p>
<pre><code>$ gzcat lost-finale-tweets.txt.gz | ./stem.pl | split -l 1000000 - output/out.txt
</code></pre>
<p>The reduce happens in two phases, both using this even smaller perl script that just sums the output from the first one:</p>
<script src="http://gist.github.com/423346.js?file=sum.pl"></script>
<p>Which we run like this:</p>
<pre><code>$ find output -exec ./sum.pl {} \; | ./sum.pl | sort -t $'\t' -k 2,2nr > stems.txt
</code></pre>
<p>Sort of like a poor man's Hadoop, no? No, you're right. Not really. But it gets the job done, and that's what counts.</p>
<p>Ok, so now we have our word counts. Here's the top 26 words and phrases that people mentioned in these tweets after removing really common english words:</p>
<pre><code>lost 104181
#lost 53188
finale 25322
watching 11204
de lost 10475
tonight 9588
final 9107
lost finale 9101
series 9000
watch 8105
series finale 7487
the lost 7444
jack 5747
episode 5507
lost series 5062
end 4806
lost series finale 4696
watching lost 4179
the lost finale 3631
final de lost 3519
the end 2981
to watch 2964
watching the 2920
spoiler 2804
love 2768
the finale 2765
#lost finale 2579
</code></pre>
<p>In amongst all the tiny junk words, we have some really nice indicators that we can use in the next phase to filter to just the tweets that are actually talking about lost the tv show vs their lost kitten named Mittens. Interestingly, the phrase "you all everybody" only showed up 67 times. Sad.</p>
Iterating Elements in boost::tuple, template style92010-05-30T18:15:00+00:00<p>In my day job I use a mix of perl and C++, along with awk, sed, and various little languages. In our C++ we use a lot of boost, especially simple things like the <a href="http://www.boost.org/doc/libs/1_43_0/doc/html/date_time.html">date_time</a> libraries and <code>tuple</code>. <a href="http://www.boost.org/doc/libs/1_43_0/libs/tuple/doc/tuple_users_guide.html">Tuple</a> is a neat little thing, sort of like <code>std::pair</code> except it lets you have up to 10 elements of arbitrary type instead of just the two. One of the major things that it gives you is a correct <code>operator<</code>, which gives you the ability to use it as a key in <code>std::map</code>. Very handy. One tricky thing, though, is generically iterating over every element in the <code>tuple</code>. What then?</p>
<p>It's easy to get at individual elements when you know how many there are and what their types are:</p>
<pre><code>typedef tuple<int, string, bool> delicious_tuple;
delicious_tuple foo(1, "hi", false);
// get<N>(tuple_type) gives you a reference to the Nth element
cout << get<0>(foo) << endl
<< get<1>(foo) << endl
<< get<2>(foo) << endl;
</code></pre>
<p>But what if you don't know those things? A really common situation where this comes up is serialization, where you have a diverse set of tuples and you don't want to write a whole bunch of glue code. <code>tuple</code> overrides <code>operator<<</code> and <code>operator>></code> for <code>ostream</code>s and <code>istreams</code>, which by default read and write strings:</p>
<pre><code>delicious_tuple foo(2, "there", true);
cout << foo << endl; // prints "(2 another one true)"
</code></pre>
<p>Sometimes that just doesn't cut it, though. If you want to serialize to JSON or XML or something, you have to be able to generically get at each element. You could write a macro using the boost preprocessor or just by itself, but that's kinda lame. You could dig into the guts of <code>tuple</code>, which is actually just a compile-time set of <code>cons</code> cells, but that gets complex. Let's break out a little template metaprogramming and see where we get:</p>
<pre><code>template<typename tuple_type, typename F, int Index, int Max>
struct foreach_tuple_impl {
void operator()(tuple_type & t, F f) {
f(boost::get<Index>(t), Index);
foreach_tuple_impl<tuple_type, F, Index + 1, Max>()(t, f);
}
};
template<typename tuple_type, typename F>
void foreach_tuple_element(tuple_type & t, F f)
{
foreach_tuple_impl<
tuple_type,
F,
0,
boost::tuples::length<tuple_type>::value - 1
>()(t, f);
}
</code></pre>
<p>Simple, right? Let's start at the bottom. <code>foreach_tuple_element</code> takes any old tuple and any old function as arguments. It then instantiates a <code>foreach_tuple_impl</code> with those arguments, as well as two additional template arguments. First, a <code>0</code>, which is the index to start iterating at. Second, the length of the tuple minus one, which we'll get to in a second. <code>foreach_tuple_impl</code> calls <code>f</code> with the value at index <code>Index</code> using <code>boost::get<Index>(t)</code> and then recursively calls itself with <code>Index + 1</code>. Great! Done! Time for a beer and a bratwurst and a happy Memorial Day!</p>
<p>Compile that, though, and you'll notice a little problem. Namely that the compiler will never actually finish. It'll spin faster and faster, spewing an infinite stream of error messages to <code>stderr</code>. In order to actually stop the recursion you'll need to add one more functor:</p>
<pre><code>template<typename tuple_type, typename F, int Max>
struct foreach_tuple_impl<tuple_type, F, Max, Max> {
void operator()(tuple_type & t, F f) {
f(boost::get<Max>(t), Max);
}
};
</code></pre>
<p>This gets called when <code>Index</code> and <code>Max</code> are the same number and does not recurse. Now you can use <code>foreach_tuple_element</code> like so:</p>
<pre><code>struct print_element
{
template<typename T>
void operator()(const T & t, const int index)
{
cout << index << ": " << t << endl;
}
};
...
delicious_tuple strawberry(10, "chocolate", true);
foreach_tuple_element( strawberry, print_element() );
// prints this:
// 1: 10
// 2: chocolate
// 3: true
</code></pre>
<p>The fact that it's a recursive solution involving templates might scare some people off, but because tuples are guarateed to only have 10 elements it's pretty safe to say you're not going to blow the stack. Is there a better way to do this? Probably. This was a fun diversion to go with my Sunday morning bagel and coffee, though.</p>
<p><em>Note: this was inspired by a forum post in <a href="http://www.c-plusplus.de/forum/viewtopic-var-p-is-1474821.html#1474821">this German c++ forum</a> but since I can't read German I had to puzzle it out and I thought I'd share.</em></p>
Everyone Needs Goals82010-05-27T20:37:00+00:00<p>Creating <a href="2010-05-12-actionable-information.html">actionable information</a> out of raw data is sometimes pretty simple, requiring only small changes. Of the few feature requests that I've received for <a href="http://github.com/peterkeen/calorific">Calorific</a>, most (all) of them have been for goals. Always listen to the audience, that's my motto! With the latest version you can set up goals like this:</p>
<pre>
- goals:
- kcal: 2200
- protein: [ 100, 200 ]
- 2010-05-27 breakfast:
- 1000 kcal
- 25 protein
- 2010-05-27 lunch:
- 850 kcal
- 50 protein
- 2010-05-27 lunch:
- 500 kcal
- 50 protein
</pre>
<p>This example is super simplified, of course, but you can see how it works. Creating an entry with the special name <code>goals</code> with one component for each nutrient you have a goal for. The value of each component is either a single number, which will be taken as a maximum, or a two element range.</p>
<p>Right now these are displayed by changing the color of the values on aggregate reports (daily and weekly). Red means "outside the range" and green means "inside the range".</p>
<pre>
$ calorific
2010-05-27 <total> <font color="red">2350</font> kcal
<font color="green">125</font> prot
</pre>
<p>Colors are done using <a href="http://perldoc.perl.org/Term/ANSIColor.html">Term::ANSIColor</a>, which is included in core perl. Adding them was fairly easy, because of a simple function <code>colored</code>, which takes a scalar or an arrayref of scalars and a color argument and returns the scalar wrapped in the correct ANSI codes. Future display options could be displaying how much of each nutrient you have left for the day, maybe in a little progress bar type thing. Feature requests and comments are welcome, as always.</p>
Program your Finances: Command-line Accounting72010-05-23T15:15:00+00:00<p><em>Note: you can find much more information about ledger on <a href="http://ledger-cli.org">ledger-cli.org</a>, including links to official documentation and other implementations</em></p>
<p>About three years ago I was in some serious financial straits. I had just started my first job out of college that I had moved across the country for and had to bootstrap almost my whole life. This meant buying furniture, buying a car, outfitting a kitchen, etc. Every two weeks I would get a salary deposit, and within two weeks it would be almost completely gone from my checking account. I actually bounced a rent check or two in there. After the second time that happened I vowed it wouldn't happen again and started keeping track of every penny that I spent using a program called <a href="http://wiki.github.com/jwiegley/ledger/">ledger</a>. This was, in hindsight, exactly what I needed to get myself back on track. Actually seeing money moving in and out of my accounts forced me to modify my behavior. At the time, <a href="http://www.mint.com/">Mint</a> wasn't around, but I don't think it would have helped nearly as much. Forcing myself to actually type out the transactions was the key to changing behavior.</p>
<p>Ledger is almost the most boring, austere accounting program you could think of. There's no pretty graphs, no online interaction, no GUI of any sort. It's basically a command-line driven calculator with a lot of specializations that make it ideal for tracking finances, which is what makes it so ideal for someone who spends a lot of time inside a text editor. It's very easy to script around and it has a very rich query language that lets you get at the data that you want with a minimum of fuss. It's very much the inspiration for <a href="http://github.com/peterkeen/calorific">Calorific</a>.</p>
<p>The basic idea is that you write down all of your financial transactions in a text file with an easy-to-master syntax and then run the <code>ledger</code> command on them to generate reports. Here's a simplified extract from my ledger file:</p>
<pre>
2010/05/20 * Opening Balances
Assets:Checking $500.00
Liabilities:Amex $-10.00
Equity
2010/05/21 * Salary
Assets:Checking $1,000.00
Expenses:Taxes:Federal $250.00
Expenses:Taxes:State $100.00
Expenses:Taxes:Social Security $80.00
Expenses:Insurance:Medical $20.00
Expenses:Insurance:Dental $2.00
Income:Salary $-1,452.00
2010/05/21 Rent
Expenses:Rent $600.00
Assets:Checking
2010/05/21 Pacific Power
Expenses:Utils:Electric $61.75
Assets:Checking
2010/05/21 * AT&T Wireless
Expenses:Cell Phone $88.46
Assets:Checking
2010/05/22 NW Natural
Expenses:Utils:Gas $20.31
Assets:Checking
2010/05/22 Pizzicato
Expenses:Food:Lunch $7.90
Assets:Checking
2010/05/23 Comcast
Expenses:Cable $60.00
Liabilities:Amex
</pre>
<p>This is actually a complete ledger file (you can download it <a href="ledger.sample.txt">here</a>) that illustrates a few key points. First, ledger is a double-entry accounting system. Every entry has at least one <em>from</em> and at least one <em>to</em>. Generally, the first line of the entry is where the money goes <em>to</em>, and it's a positive amount, with the second line being where the money comes <em>from</em>. If you leave off the amount of one of the lines ledger will automatically fill it in and make the entry balance. If you have an accounting background you can think of <em>from</em> and <em>to</em> in terms of debits and credits, but ledger doesn't force that. Second, accounts have a hierarchical namespace, which we can see like this:</p>
<pre>
$ ledger -f ledger.sample.txt -s bal
$721.58 Assets:Checking
$-490.00 Equity
$1,290.42 Expenses
$60.00 Cable
$88.46 Cell Phone
$7.90 Food:Lunch
$22.00 Insurance
$2.00 Dental
$20.00 Medical
$600.00 Rent
$430.00 Taxes
$250.00 Federal
$80.00 Social Security
$100.00 State
$82.06 Utils
$61.75 Electric
$20.31 Gas
$-1,452.00 Income:Salary
$-70.00 Liabilities:Amex
</pre>
<p>This arrangement of accounts helps to maintain some sanity when dealing with lots of accounts, and it jives with the basic accounting equation: <code>assets = liabilities + equity + (income - expenses)</code>. You'll notice that accounts just appear when you use them, sort of variables in perl without <code>use strict;</code>. This is both a blessing and a curse, because sometimes it's not obvious that you're misspelling things until you run reports and they look funny. The risk of messing up is mitigated if you use emacs by the bundled <code>ledger.el</code> major mode, which sets up tab completion for you.</p>
<p>Again using the example file, we can run some more detailed reports. For example, here's our checkbook register:</p>
<pre>
$ ledger -f ~/Documents/blog/static/ledger.sample.txt -r reg checking
2010/05/20 Opening Balances Liabilities:Amex $10.00 $10.00
Equity $490.00 $500.00
2010/05/21 Salary Expenses:Taxes:Federal $-250.00 $250.00
Expenses:Taxes:State $-100.00 $150.00
Ex:Ta:Social Security $-80.00 $70.00
Ex:Insurance:Medical $-20.00 $50.00
Ex:Insurance:Dental $-2.00 $48.00
Income:Salary $1,452.00 $1,500.00
2010/05/21 Rent Expenses:Rent $-600.00 $900.00
2010/05/21 Pacific Power Ex:Utils:Electric $-61.75 $838.25
2010/05/21 AT&T Wireless Expenses:Cell Phone $-88.46 $749.79
2010/05/22 NW Natural Expenses:Utils:Gas $-20.31 $729.48
2010/05/22 Pizzicato Expenses:Food:Lunch $-7.90 $721.58
</pre>
<p>Ledger will abbreviate account names as necessary when printing to make it fit in 80 columns. If you have a wider terminal you can pass the <code>-w</code> option to make it fit to 132 columns.</p>
<p>The power of ledger really comes into focus when you have more data available. One of the most interesting reports that I run gives me an idea of how I'm doing month-to-month by showing how much my assets have changed (negative numbers are better, in this case): <code>ledger -MAn reg income expenses liabilities</code>. The <code>-M</code> option groups transactions by month, <code>-A</code> will show the running average in the second column. By default it will show the running total. <code>-n</code> will group all transactions together, instead of showing one subtotal for each account. It's sort of boring with the sample file, though:</p>
<pre>
$ ledger -f ~/Documents/blog/static/ledger.sample.txt -MAn reg income expenses
2010/05/01 - 2010/05/23 <Total> $-161.58 $-161.58
</pre>
<p>In any of these examples you can change the output format to suit your needs. There are a lot of options here that are detailed in the <a href="http://github.com/downloads/jwiegley/ledger/ledger.pdf">manual</a> (pdf), but here's one example. I have a little program in my bin directory called <code>transpose</code>, which takes three-column pipe-separated data and turns it into tab-separated values ready to be inserted into a spreadsheet. The first column is the row, the second column is the column, the third is the value to put in that cell. We can tell ledger to output, for example, a basic expense report formatted for transpose like this:</p>
<pre>
$ ledger -f ~/Documents/blog/static/ledger.sample.txt -F '%A|%D|%t\n' -M reg income expenses
Expenses:Cable|2010/05/01|$60.00
Expenses:Cell Phone|2010/05/01|$88.46
Expenses:Food:Lunch|2010/05/01|$7.90
Expenses:Insurance:Dental|2010/05/01|$2.00
Expenses:Insurance:Medical|2010/05/01|$20.00
Expenses:Rent|2010/05/01|$600.00
Expenses:Taxes:Federal|2010/05/01|$250.00
Expenses:Taxes:Social Security|2010/05/01|$80.00
Expenses:Taxes:State|2010/05/01|$100.00
Expenses:Utils:Electric|2010/05/01|$61.75
Expenses:Utils:Gas|2010/05/01|$20.31
Income:Salary|2010/05/01|$-1,452.00
</pre>
<p>With more data, this lets you easily compare month-to-month where you are spending money.</p>
<p>If you want to pull your financial life together but don't want to spend money on something like Quicken or trust Mint with your account credentials, I highly encourage you to try out ledger in addition to the other open source solutions like gnucash. All of these examples assume you're using version 2.6.2 of ledger, which you can download from the "Downloads" tab in github. Version 3.0 is just around the corner and it adds all kinds of neat things, including better automated transactions and a much more robust query language.</p>
Building Battle Bots with Clojure62010-05-16T23:00:00+00:00<p>Once in a while at <a href="http://www.rentrak.com">Rentrak</a> we have programming competitions, where anyone who wants to, including sysadmins and DBAs, can submit an entry for whatever the problem is. The previous contest involved writing a poker bot which had to play two-card hold'em, while others have involved problems similar in spirit to the Netflix Prize. This time we chose to build virtual robots that shoot each other with virtual cannons and go virtual boom! We'll be using <a href="http://realtimebattle.sourceforge.net/">RealTimeBattle</a>, which is a piece of software designed specifically to facilitate contests of this sort. It's kind of like those other robot-battle systems, except instead of requiring you to write your robot in their own arbitrary, broken, horrible language, this lets you write your bot in any language that can talk on stdin and stdout.</p>
<p>Based on my previous entries the natural choice would be perl, right? I thought about it, actually. Started stubbing something out. Wrote some code to emulate enums and it worked on the first try, which brought to light the fact that I hadn't learned a new language in quite a long time and by <em>not</em> using a new language I was missing a golden opportunity. So, which language? The only real constraint that we, the Happy Fun Robot Times Killing Group, decided on was that it had to be easily installable on Ubuntu, which leaves the field pretty much wide open. Ruby? Already know it in passing. Python? Haven't done much with it for a few years but I don't think it's changed that much. Lisp? Hm. Intriging. <a href="http://clojure.org/">Clojure</a> looks interesting, and it's a good chance to figure out multithreading.</p>
<p>The RealTimeBattle system is conceptually pretty simple. Your robot is a little doughnut-shaped thing that can go forward, backward, accelerate, brake, and turn. In addition, it has a big cannon and a radar system, both of which can rotate independent of the bot itself. The radar is the only sensor you can rely on, although in some configurations you'll get coordinates relative to your start position every few game ticks.</p>
<p>When the game starts, the system will start up your bot in a child process and attach to stdin and stdout, so from the bot's point of view it's just talking a <a href="http://realtimebattle.sourceforge.net/Documentation/RealTimeBattle-4.html">simple text protocol</a>. In perl, talking this protocol would be a trivial combination of <code>while(<>){ }</code> and <code>print</code>, but in clojure it seems to be a might bit more complicated:</p>
<pre>
(loop []
(let [in (read-line)]
(if (not (nil? in))
(do
(println in)
(recur)))))
</pre>
<p>Just writing that bit took me down about a dozen false starts, but I learned a whole lot about clojure in the process so I'm pretty sure it was worth it.</p>
<p>Ok, so now this little bot can listen, let's make it talk. RealTimeBattle has a command that your bot can send to the server to make it print out something in the message log. We can wrap that in a function like so:</p>
<pre>
(defn message [m & rest]
(println (str "Print " m rest)))
</pre>
<p>and call that like this:</p>
<pre>
(message "Hi there my name is Botty McBotterson!")
</pre>
<p>The two other basic commands that I've implmented so far are <code>Initialize</code>, which will get sent when the system is ready to find out what name your bot has, and <code>GameOption</code>, which tells you all kinds of information about the environment that the bot lives in. Here's the whole program as it stands:</p>
<pre>
(def game-option-types [
:robot_max_rotate
:robot_cannon_max_rotate
:robot_radar_max_rotate
:robot_min_acceleration
:robot_max_acceleration
:robot_start_energy
:robot_max_energy
:robot_energy_levels
:shot_speed
:shot_min_energy
:shot_max_energy
:shot_energy_increase_speed
:timeout
:debug_level
:send_robot_coordinates])
(def options (ref {}))
(defn message [m & rest]
(println (str "Print " m rest)))
(defn robot-initialize [[first-round]]
(if first-round
(println "Name kabot")))
(defn robot-set-option
[[option-number value]]
(let [option-key (get
game-option-types
(Integer/parseInt option-number))
option-val (Double/parseDouble value)]
(dosync
(alter options (fn [opts] (assoc opts option-key option-val))))
(message (deref options))))
(defn process-input [m]
(let [tokens (seq (.split m " "))
function-name (first tokens)
args (next tokens)]
(message (str function-name " " args))
(cond
(= function-name "Initialize") (robot-initialize args)
(= function-name "GameOption") (robot-set-option args)
:else (message (str function-name " not implemented")))))
(loop []
(let [in (read-line)]
(if (not (nil? in))
(do
(process-input in)
(recur)))))
</pre>
<p>This is pretty trivial at the moment. My basic design is to have the main thread deal with all of the I/O and updating a global state object, while another thread deals with analyzing this state and figuring out what to do. I haven't decided on any concrete strategies yet but for the first contest it'll probably be pretty stupid. </p>
<p>A few fun things to note: clojure provides very simple interop with Java classes and methods. For example, <code>(.split m " ")</code> calls the <code>split</code> method on <code>m</code>, which is actually just a Java <code>String</code>. The result of that is a <code>String[]</code>, which isn't too useful in clojure so we immediately wrap it in a <code>seq</code>, which is sort of like a lazy <code>cons</code> list. Another example of this really trivial interop is the number parsing done in <code>robot-set-option</code>. I figured this out only after about an hour of thrashing about trying to figure out why passing a string as a vector index wasn't DWIMing like it does in perl. This is another example of why I need to do this project in another language. Perl has rotted my brain.</p>
<p>By the way, if there are things that I'm doing in this code that aren't idomatic clojure, please correct me. I just started learning today, after all. I found a pretty good <a href="http://java.ociweb.com/mark/clojure/article.html">tutorial</a> which has guided me through basic types and stuff, but shortly I'll be branching beyond that into threading and agents and other fun things that it doesn't cover very well.</p>
Actionable Information52010-05-12T08:53:00+00:00<p>Let's pretend, just for a second, that you want to make some money on the stock market. Sounds easy, right? Buy low, sell high, yadda yadda blah blah blah. Except, how do you know when to buy and when to sell? Not so easy. Being a nerd, you want to teach your computer how to do this for you. But where to start? I discovered a few months ago that there are <a href="http://www.activfinancial.com/">services</a> <a href="http://www.interactivedata-rts.com/index.shtml">out</a> <a href="http://www.dtniq.com/">there</a> that will sell you a data feed that literally blasts every single anonymous transaction that happens on any market in the US in real time. They'll also sell you access to a historical feed that provides the same tick-level information going back for several years.</p>
<p>So, ok, you've got a whole lot of raw data. All kinds of fun problems come from having a huge glug of raw data, especially when you're getting blasted more of it every day. Where to store it, how to store it, how to index it so you can get at certain segments quickly, etc. Let's pretend that you've solved all of those and it's time to get to the meat of this exercise: figuring out when to buy. You write a little program that searches through your historical data looking for signs of business cycles in various sized companies and gives you the top five that you should buy and how long you should probably hold onto them. That list is <em>actionable information</em> that you created out of raw data that you can use to make some money. Maybe. Hopefully. If the world doesn't end. Again.</p>
<p>Ok, that's a pretty small example. Let's do something bigger. Let's pretend that you're Google. You have truck loads of cash just laying around waiting for you to do something with it. Hey, data centers are cool, why not build some new ones! But where?</p>
<p>You know immediate things, like where your users are coming from and where the bottlenecks in your network are that prevent them from looking at your sweet sweet ads. Now remember, you're Google. You have a large chunk of all accumulated human knowledge at your fingertips. In addition to that stuff that every good company would know, you also know, somewhere deep down in your giant cache, things like where the zoning codes are favorable, where you have private fiber connections to and from, where you can get cheap electricity, voting patterns, histories of war riots and famine for every location on the planet. Lots of data. So, you write some <a href="http://labs.google.com/papers/sawzall.html">Sawzall</a> programs that go out and mine all this data and give you back likely locations, ranked by 10 year projected return on investment, and then you build at the top five places. Done. Easy.</p>
<p>In my admittedly limited time as a professional developer I've learned that probably close to 2/3 of my job is figuring out ways to suss out actionable information from vast quantities of low-level data. Be it displaying graphs or maps on a web page in the most understandable way, or trolling though a billion television remote clicks to determine who watched the Today Show this morning, it all boils down to providing some information to someone that they can act on.</p>
<p>In my personal life I need to have actionable information once in a while today. Before today <a href="http://github.com/peterkeen/calorific">Calorific</a> could only tell exactly what I ate in its entirety or daily totals. That's somewhat useful, but sometimes I want to know what my weekly averages are, or limit the daily or detail reports to just a couple of days. To address those issues I added <code>--begin</code> and <code>--end</code> filters which will limit any report to just that day range. Specifying just one will leave the other as an open range. Calorific parses dates using <a href="http://search.cpan.org/%7Eschubiger/DateTime-Format-Natural-0.86/">DateTime::Format::Natural</a>, which means it does the right thing with basically any date format you throw at, including relative dates like <code>yesterday</code> or <code>3 days ago</code> . Also, I added a weekly report which prints daily averages for each week in the day range. This is the new default, which actually I'm not really sure about. Easy to change.</p>
<p>The next features on the docket are <em>goals</em>, which will let you set goal ranges for each base nutrient, an option to show you each day total or week average against the goal, and a summary report that shows you how much of each nutrient you've eaten today and how close you are to your goals. Stay tuned!</p>
Moose vs Mouse and OOP in Perl42010-05-09T08:00:00+00:00<p>After using <a href="http://github.com/peterkeen/calorific">Calorific</a> for a month two things have become very clear. First, I need to eat less. Holy crap do I need to eat less. I went on to <a href="http://www.sparkpeople.com/">SparkPeople</a> just to get an idea of what I <em>should</em> be eating, and it told me between 2300 and 2680 kcal. I haven't implemented averaging yet, but a little grep/awk magic tells me I'm averaging 2793 kcal per day. This is <em>too much</em>. So. One thing to work on.</p>
<p>Second, in the morning after I come back from lifting and sit down to enter my breakfast, I just add three lines to my calories file:
<pre>
- 2010-05-07 breakfast:
- 1 workout breakfast (blues)
</pre></p>
<p>and then type <code>calorific</code> in my shell, it takes <em>ages</em> to start up. Literally several seconds on a cold cache. I was pretty sure that this was due to the fact that I use <a href="http://search.cpan.org/dist/Moose/">Moose</a> to help me define the four classes that compose Calorific. Now, Moose is great. Before writing Calorific I had only used a really old version of <a href="http://search.cpan.org/dist/Class-MethodMaker/">Class::MethodMaker</a> or <a href="http://search.cpan.org/%7Ejesse/perl-5.12.0/lib/Class/Struct.pm">Class::Struct</a> to build classes. That or build them myself, which is always fun (FUN FACT blessed array refs are wicked fast if you can get away with them). Moose is sort of a revelation. In the simplest case, you can say
<pre>
package Foo::Bar;</p>
<p>use Moose;</p>
<p>has [qw/ baz blah frob /] => (is => 'rw');</p>
<p>1;
</pre>
And you have yourself a fully functional class with three properties with read-write accessors. Pretty snazzy. However, you can get way more advanced:
<pre>
package Calorific;</p>
<p>use Moose;</p>
<p>has 'filename' => (
is => 'ro',
required => 1,
);</p>
<p>has 'recipes' => (
is => 'ro',
traits => [ 'Hash' ],
isa => 'HashRef',
lazy => 1,
default => sub { {} },
handles => {
get<em>recipe => 'get',
set</em>recipe => 'set',
},
);</p>
<p>has 'entries' => (
is => 'rw',
traits => [ 'Array' ],
isa => 'ArrayRef',
lazy => 1,
default => sub { [] },
handles => {
add<em>entries => 'push',
filter</em>entries => 'grep',
num<em>entries => 'count',
all</em>entries => 'elements',
sorted_entries => 'sort',
},
);</p>
<p>1;
</pre></p>
<p>This is directly from Calorific. It defines three properties: a read-only simple scalar named <code>filename</code> which is required to be present in the call to new(), a <code>recipes</code> property which contains a hash ref and gets two accessors, <code>get_recipe</code> and <code>set_recipe</code>, which you call like this:
<pre>
$calorific<em>instance->set</em>recipe('foo', 'bar');
$calorific<em>instance->get</em>recipe('foo'); # returns 'bar'
</pre></p>
<p>In addition, it sets up one more property named <code>entries</code> which contains an array ref and defines five accessors. There are actually more accessors defined than the code uses, but they're basically free so why not? You can see what they do and their calling conventions in the <a href="http://search.cpan.org/%7Eflora/Moose-1.03/lib/Moose/Meta/Attribute/Native/Trait/Array.pm">Moose::Meta::Attribute::Native::Trait::Array</a> docs. </p>
<p>Ok, so Moose is great! Except, it's slow. Way slow. Wicked slow, especially on a groggy cache like my laptop has when I rudely wake it up in the morning and demand it actually do something for me for once. Geeze.</p>
<p>HOWEVER, there's a neat little project called <a href="http://search.cpan.org/dist/Mouse/">Mouse</a>, which has the lofty goal of emulating all of the sugar of Moose without any of the fat. Meaning, it doesn't pay nearly as large of a compile-time penalty that Moose does while retaining most of it's meta-y goodness. I ran one little command on the source tree yesterday evening and <em>bam</em>, just like that, everything was three times as fast.
<pre>
find . -name '*.pm' | xargs perl -pi -e 's/Moose/Mouse/g'
</pre>
Actually I had to install <a href="http://search.cpan.org/dist/MouseX-NativeTraits/">MouseX::NativeTraits</a> from CPAN before everything worked but that's just details.</p>
<p>Anyway, the moral of the story is that Moose is great and makes building classes really easy and all, but if you care about startup speed and not so much about delving into meta classes and such, Mouse should be your go-to class. And in fact, you don't have to make that choice. There's another project called <a href="http://search.cpan.org/%7Esartak/Any-Moose-0.12/lib/Any/Moose.pm">Any::Moose</a>, which will load Mouse unless you declare you want Moose, which can be set with an environment variable. Pretty neat.</p>
Calorific, a Simple Calorie Tracker32010-04-08T19:00:00+00:00<p>I'm a nerd. I write software for a living. I spend a lot of my day either sitting in a chair in front of a computer, or laying on my couch using my laptop. I'm not what you'd call... athletic. I <em>did</em> start lifting weights about six months ago but that's really just led to gaining more weight, not losing it. A few years back I started counting calories and I lost some weight, and then stopped counting calories and gained it all back. Time to change that.</p>
<p>Now, I could use one of the <a href="http://www.sparkpeople.com/">many</a>, <a href="http://caloriecount.about.com/">many</a> online calorie trackers. They're all ok and they have the advantage of being able to enter data whenever and where ever you are, but most of them have ads and using a web interface is kind of slow and staring at ads sucks. Also, the reports you can generate from them are always a bit limited. What if I want to see a monthly average of how many calories I ate as snacks? Or how many calories I shoved down my gullet from fast food? Or maybe I want to track another nutrient, like grams of protein. Doing all of this through a limited web interface would be tricky, to say the least. There has to be a better way.</p>
<p>I've been using this program called <a href="http://wiki.github.com/jwiegley/ledger/">ledger</a> for more than three years now to keep track of my finances. The idea is that you maintain a text file that contains all of your transactions in a really simple format, and then you can run basically arbitrary reports on it. I always have <a href="http://www.gnu.org/software/emacs/">emacs</a> open, so maintaining that file is a snap. I'd like to maintain my calorie history in the same way, using a lightly formatted text file. I actually tried to use ledger for this purpose but the syntax just wasn't right. What I really wanted was a way to build up foods from simpler foods, and have those be built from other, simpler foods, all the way down to calories. Something like this:</p>
<pre>
1 cup milk = 100 kcal
1 scoop protein powder = 65 kcal
1 protein shake =
1.5 cup milk,
2 scoop protein powder
2010-04-08 breakfast
1 protein shake
</pre>
<p>I danced around this format for quite awhile, trying to parse it line-wise and trying to parse it with <a href="http://search.cpan.org/dist/Parse-RecDescent">Parse::RecDescent</a> and <a href="http://treetop.rubyforge.org/">treetop</a>, and nothing ever really fit. Then, I punted. What's a lightweight, human readable format that already has a parser built? Why, <a href="http://www.yaml.org/">YAML</a> of course! Here's the same thing as a YAML snippet:</p>
<pre>
- 1 cup milk: 100 kcal
- 1 scoop protein powder: 65 kcal
- 1 protein shake:
- 1.5 cup milk
- 2 scoop protein powder
- 2010-04-08 breakfast:
- 1 protein shake
</pre>
<p>The basic idea revolves around the concept of a <em>recipe</em>. Essentially, a recipe is a count, a label, and a bunch of components that can also be recipes. "100 kcal" is actually a recipe all by itself. Entries are just recipes that have a date instead of a count. At run-time, we resolve all the labels into recipes and then recursively get the values. Ideally everyhing will resolve down to a handful of base units, like "kcal" or "g protein", but if something doesn't resolve it'll get included right into the output.</p>
<p>So, ok, now I just need a program to analyze this stupid thing and print me some reports. That's where <a href="http://github.com/peterkeen/calorific">Calorific</a> comes in. It's a little application (<500 lines, actually) that parses that YAML file and prints out either a detail or daily report. I have some big plans for it, including a report that gives the monthly average of daily totals, options to limit the date range you want to report, and 30 day moving averages. Installation instructions are in the readme file, if you'd like to try it out.</p>
Adding RSS and Other Things22010-03-29T20:34:00+00:00<p>Someone at work today demanded that I add an RSS feed, so here you go: <a href="index.xml">atom</a>. It didn't take very much to <a href="http://github.com/peterkeen/bugsplat.info/commit/82c41e3a5a27906421692120e2f93ce8869db02f">hack it in</a>. Basically, all I had to do was install a few more CPAN modules, specifically <a href="http://search.cpan.org/dist/DateTime-Format-Natural">DateTime::Format::Natural</a>, <a href="http://search.cpan.org/dist/DateTime-Format-W3CDTF">DateTime::Format::W3CDTF</a>, and finally <a href="http://search.cpan.org/dist/XML-Atom-SimpleFeed">XML::Atom::SimpleFeed</a>. The first two are so I can put natural-looking dates in my entries and still be able to get full-fledged DateTime objects out of them, and the second is to save me the pain of writing out the Atom format's preferred datetime format. Also, I get neat date formatting in blog entires almost for free with the CLDR syntax.</p>
<p>Another thing to notice: <a href="http://search.cpan.org/dist/File-Slurp">File::Slurp</a> instead of my own <code>read_file_contents</code> and <code>write_file_contents</code>. It works just as well as mine, except it's more sensitive to list vs scalar context.</p>
Yet Another Static HTML Blog12010-03-28T22:15:00+00:00<p>I'm a strict believer in learning by doing. It's how I learn best. In the spirit of learning, then, here's how I built the engine that powers this blog.</p>
<p>Right away I decided that there's no point in having a database to back this thing. The only useful thing that a database brings to the table is comments, and those are way more hassle than they're worth. Better to leave the comments at <a href="http://reddit.com">reddit</a> or <a href="http://news.ycombinator.com">hacker news</a>, where they already know how to deal with spam. Not having to worry about a database freed me up to worry about more important things, like how to put text on the screen. I'm most familiar with <a href="http://www.perl.org">perl</a> at the moment so I decided that the best way to build it would be a client-side script that generates some static html.</p>
<p>Current features:</p>
<ul>
<li>Absolutely no database</li>
<li>Generates fully static html</li>
<li>Automatically ships it to my server</li>
<li>A really cheesy template system because I didn't want to learn <a href="http://search.cpan.org/dist/Template::Toolkit">Template::Toolkit</a> just yet</li>
<li>Archives for everything, and only show the last 10 entries on the front page</li>
<li>Static pages (although currently there aren't any)</li>
<li>Markdown parsing for entries</li>
</ul>
<p>If you want to see the source for it (including all the entries), it's on <a href="http://github.com/peterkeen/bugsplat.info">github</a>, but I warn you it's kind of lame. The template system in particular is not really what I want it to be yet. It's non-recursive, so <a href="http://github.com/peterkeen/bugsplat.info/blob/master/publish.pl">publish.pl</a> basically acts like the top-level template. I'll probably end up converting it to <a href="http://search.cpan.org/dist/Template::Toolkit">Template::Toolkit</a> at some point.</p>