<?xml version="1.0"?>
<rss version="2.0">
  <channel>
    <title>Advogato blog for dan</title>
    <link>http://www.advogato.org/person/dan/</link>
    <description>Advogato blog for dan</description>
    <language>en-us</language>
    <generator>mod_virgule</generator>
    <pubDate>Mon, 22 Mar 2010 10:01:01 GMT</pubDate>
    <item>
      <pubDate>Wed, 24 Feb 2010 17:10:39 GMT</pubDate>
      <title>Musical Interludes</title>
      <link>http://www.advogato.org/person/dan/diary.html?start=124</link>
      <guid>http://ww.telent.net/diary/Musical_Interludes</guid>
      <description>&lt;p&gt;Part II of the financial thingy is on its way, along with a subjective evaluation of the merits of rspec (I quite like it), but in the meantime have a look at &lt;a href="http://github.com/telent/pacioli" class="external" &gt;http://github.com/telent/pacioli&lt;/a&gt; which is where the work in "progress" is going.  I say "progress" because that's a daytime job and, well, something else came up at work.

&lt;/p&gt;&lt;p&gt;In the meantime, please feel free to wander across to &lt;a href="http://telent.posterous.com/" class="external" &gt;http://telent.posterous.com/&lt;/a&gt; which is where I'm describing my attempts to put an embedded "Mini2440" Linux system in the &lt;a href="http://www.coruskate.net/Firebrox" class="external" &gt;Firebrox&lt;/a&gt; pedalled sound system
&lt;/p&gt;</description>
    </item>
    <item>
      <pubDate>Tue, 9 Feb 2010 15:11:35 GMT</pubDate>
      <title>The Programmer's Guide to Financial Book-keeping, Part I</title>
      <link>http://www.advogato.org/person/dan/diary.html?start=123</link>
      <guid>http://ww.telent.net/diary/The_Programmer_s_Guide_to_Financial_Book_keeping__Part_I</guid>
      <description>&lt;p&gt;Once upon a time I knew enough about bookkeeping to implement a a
rudimentary accounting system for the consulting business I was
running at the time.  Then I got a real job, and after that I forgot
most of it.  Recently I've had to relearn it all, and as the
accountancy/bookkeeping web pages that I've found on the Internet are
decidedly mixed (an honourable mention here
for the Gnucash manual, which is actually quite good), this time I'm
writing it down.

&lt;/p&gt;&lt;p&gt;The intended audience for this is chiefly me and people like me:
computer programmer types who have to make their systems talk to
accounts departments and accountants.  If you are looking for more
information on bookkeeping or accountancy from a professional
perspective, it is less likely to be useful.

&lt;/p&gt;&lt;p&gt;It should not be necessary - though it probably is - to state that &lt;b&gt;I
hold no professional qualifications and have had no training in the
field&lt;/b&gt;, and if you want proper advice you'll have to pay for it from
someone entitled to give it.  &lt;b&gt;This information is offered as-is, and
no warranties as to its correctness, usefulness or completeness are
offered&lt;/b&gt;.

&lt;/p&gt;&lt;p&gt;Feedback welcome - see the page footer for details.

&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;h2&gt; Definition

&lt;/h2&gt;&lt;p&gt;Let us define &lt;b&gt;bookkeeping&lt;/b&gt; as: the collection and processing of
financial records for an entity, with the object that interested
parties can learn (1) as of a specified time, how much money (and
other valuable stuff) it owns, against how much it owes to other
entities; (2) over a specified period of time, how much has come in
and how much has gone out.  Bookkeeping deals not just with money but
with all kinds of valuable stuff: cash, shares, financial instruments,
land, saleable equipment, stock in trade, etc etc - in the rest of
this post I'll be lumping it all together as "value".

&lt;/p&gt;&lt;h2&gt; End results

&lt;/h2&gt;&lt;p&gt;In the UK, the end processes of bookkeeping/accountancy for a company
or other trading entity are usually produced annually -

&lt;/p&gt;&lt;p&gt;&lt;ul&gt;&lt;li&gt; the &lt;b&gt;Balance Sheet&lt;/b&gt; - a document of type (1), which lists the assets
(stuff we've got) and liabilities (stuff we owe) broken down by
category, at the end of the trading year.  We start with assets,
listed in order from most liquid (e.g. money at hand or in the bank)
to least liquid (things we own that would be complicated to sell),
then we subtract liabilities (usually ordered from short-term to
long-term), then the bottom line is what we're worth.  This is often
referred to as the &lt;b&gt;Accounting Equation&lt;/b&gt;: 
&lt;center&gt;Assets - Liabilities = Equity&lt;/center&gt;
although other people will say that Equity is &lt;i&gt;really&lt;/i&gt; what the company owes its owners (e.g. the shareholders) so the equity will appear as a liability account and the equation is "Assets = Liabilities".  Mathematically it makes no difference.

&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;&lt;ul&gt;&lt;li&gt; the &lt;b&gt;Profit and Loss account&lt;/b&gt;, or P&amp;L - also known in the US as 
the &lt;b&gt;Income Statement&lt;/b&gt;.  This is a document of type (2) which lists what's
come in and what's gone out over the course of the year.

&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;We probably also want quarterly reports for &lt;b&gt;VAT&lt;/b&gt; (that's "Sales Tax"
in other countries), and ad-hoc reports for credit control (we need to
know who owes us money so we can chase them) and management
accounting.

&lt;/p&gt;&lt;h2&gt; Derivation

&lt;/h2&gt;&lt;p&gt;Obviously, if your trading entity is you and you alone and there's no
regulatory requirement on you to show anyone else the figures, you can
choose any categories you like.  But for most of us, there are
accepted rules about the breakdown that people want to see, what
you're allowed to assign to which categories, and what you'd actually &lt;b&gt;want&lt;/b&gt; to assign to which categories (which might be a question with
different answers depending on whether you're trying e.g. to maximise
profit for the investors or minimise it for the taxman).  This kind of
decision is what you have an &lt;b&gt;accountant&lt;/b&gt; for: keeping the numbers is
what you have a bookkeeper for.  So, look on the difference between
those two roles as a policy/mechanism distinction (and a big
difference in hourly rate: don't pay an accountant to do a
bookkeeper's job)

&lt;/p&gt;&lt;h2&gt; Accounts and transactions

&lt;/h2&gt;&lt;p&gt;So, with the aid of an accountant we can establish how we need to
categorise our assets and liabilities for the reports we need to
produce.  Each category (or sub-category, or sub-sub-category) is an &lt;b&gt;account&lt;/b&gt;: each transfer of value from one account to another is a &lt;b&gt;transaction&lt;/b&gt;.  A transaction is usually associated with a &lt;b&gt;source
document&lt;/b&gt; (for example, a purchase order, or an invoice, or a receipt)
- the so-called &lt;b&gt;paper trail&lt;/b&gt; is not necessarily kept on actual carbon
laminate these days, but it's still important.  In essence, what we do is 
record the transactions.

&lt;/p&gt;&lt;h2&gt; Credit and Debit

&lt;/h2&gt;&lt;p&gt;We record each financial transaction as a flow of value from one (or
several) accounts into another (or several others).  Historically,
bookkeepers don't get on with the concept of negative numbers - this
is possibly because it can be confusing to have your "Income" account
get steadily more negative as the year goes on (we'll come back to why
this happens), or maybe just because the principles of double-entry
bookkeeping were invented in a time and place (Renaissance Italy) that
hadn't really yet heard of negative numbers.  Whatever.  But the
upshot is that they made their own words up instead: the account that
loses value is said to be &lt;b&gt;"credited"&lt;/b&gt;; the account which gains value
is &lt;b&gt;"debited"&lt;/b&gt;.  

&lt;/p&gt;&lt;p&gt;This is, of course, completely bass-ackwards from the perspective of
normal people, though it has been claimed that the problem is that &lt;b&gt;we're&lt;/b&gt; backwards.  When the bank send you your statement of account
it's printed from their point of view, not yours.  So, if you deposit
&#xA3;50 in the Royal NatMid, in their eyes that creates a liability to you
(after all, it's money they have but you own).  The more money you
give them the more they can transfer (debit) to Assets/BranchSafe or
Assets/Vault or Assets/SubPrimeMortgages, but they have to credit that
transaction to Liabilties/AP/YourNameHere.  So the effect is that we
perceive being in credit with the bank as a good thing: they see it as
a bad thing.  It's just a matter of perspective.

&lt;/p&gt;&lt;p&gt;(I am slightly suspicious of this explanation.  "Credit" and "Debit"
are both from Latin roots: /creditum/: "a loan, thing entrusted to
another", and /debilitum/: "thing owed," neut pp. of /debere/ "to
owe".  In the end they're just words, but it's still confusing enough to be just more fuel for my
scepticism towards the claim that negative numbers are avoided because
they cause confusion.  Maybe that's just me.)

&lt;/p&gt;&lt;h2&gt; Double-entry

&lt;/h2&gt;&lt;p&gt;The principle of double-entry accounting is that &lt;b&gt;the value credited
in a transaction must equal the value debited&lt;/b&gt; - value cannot be
created or destroyed.  The name comes from paper-based systems: if we
have two accounts affected by a transaction, we must enter the
transaction details into both.  Using a computer, of course, we can
enter it once and it will appear in both, but that's not the point.
We are interested in the principle of "conservation of value", not so
much in the mechanism of how we achieved that in the old days.

&lt;/p&gt;&lt;p&gt;A simple example: our shop runs out of float in the till, so on Monday
we must visit the bank and get some more cash.  We record this as a
transfer from the bank account (which is credited) to the till account
(which is debited).

&lt;/p&gt;&lt;p&gt;Here we're moving value between two asset accounts: they both
represent monies that we own - just in different places.  So it's
pretty easy to see that "conservation of value" holds true.  But the
principle of double-entry bookkeeping is that the debits and credits
in any transaction must &lt;b&gt;always&lt;/b&gt; balance, so the astute reader will
now be wondering how we do that for a transaction that actually makes
the company money. For example, if we do some work and get paid, then
the value in the transaction is clearly going into the bank account,
but where is it coming &lt;i&gt;from&lt;/i&gt;?

&lt;/p&gt;&lt;h2&gt; Income and expenses

&lt;/h2&gt;&lt;p&gt;The answer is that we create "Income" accounts which serve as a proxy
for the outside world as it affects our company.  So, if we get $200
for configuring Joe's web server, our bank account is debited $200 and
the outside world, as represented by our Income (or Income/Sales, or
whatever subcategorisation we want to use) account, is credited $200.
Expenses accounts serve a similar but opposite role: we pay for stuff
(like stationery, utilities, salaries) that makes us poorer (our
assets are credited) and the outside world richer (our expenses are debited).

&lt;/p&gt;&lt;p&gt;Income and Expense accounts are key to the P&amp;L statement that we will
produce at the end of the year, because they act as summaries of our
interactions with the world - which is what P&amp;L is all about.  The
USAnian name for them "Income statement" hints as much.

&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;h2&gt; Accruals

&lt;/h2&gt;&lt;p&gt;Another key concept is &lt;b&gt;accruals&lt;/b&gt;.  In most businesses there is a
delay between when we provide something of value (e.g. do some work)
and when we actually get paid: there is also often a delay between
when we receive something of value and when we have to pay for it.  In
a cash accounting system there's nothing we can do about that, but in
an accruals system we can create "accounts receivable" and "accounts
payable" for these sums which are "in the post".  This allows our
accounts to say that we are worth $4000 because we have that amount
expected to come in from Michael next week, even though we haven't got
it in the bank yet.  So, this makes payment a two-stage process: first
we send an invoice and transfer $4000 from Income/Sales to
Assets/AR/Michael, then when he pays it four weeks later (or perhaps
four months later if he's a public sector body) we transfer $4000 from
Assets/AR/Michael to Assets/Bank.  We haven't actually made any new
money in that second transaction, but at least it now exists in the
bank and not just on paper.

&lt;/p&gt;&lt;p&gt;Accounts Payable is similar but opposite.  We order office furniture
on account, it gets sent with an invoice, and we log that transaction
as a transfer from Liabilities/AP/IKEA to Assets/Furniture.  When the
invoice is due (or three weeks later if you have really good credit
control) we send them a cheque and we do another transaction from
(crediting) Assets/Bank to (debiting) Liabilities/AP/IKEA, which
hopefully reduces the balance of the latter account to zero.

&lt;/p&gt;&lt;p&gt;Most of the examples later in this post ignore accruals in much the
same way and for the same reason as Kernighan and Ritchie ignore error
checking: it slightly obscures the pedagogical point, but that doesn't
mean you won't do it for real.

&lt;/p&gt;&lt;h2&gt; Sale of goods

&lt;/h2&gt;&lt;p&gt;If you're selling services, the transaction is
Income/Sales-&gt;Assets/Bank.  That's simple.  If you're selling goods,
though, (1) you have to buy them first

&lt;/p&gt;&lt;p&gt;&#xA3;6 cr. Assets/Bank = dr. Assets/Inventory/Widgets

&lt;/p&gt;&lt;p&gt;and then (2) when you sell them you are selling at a different price. 

&lt;/p&gt;&lt;p&gt;&#xA3;10 cr. Income/Sales = dr. Assets/Bank&lt;br&gt;
&#xA3;6 cr. Assets/Inventory/Widgets = dr. Expenses/Cost of sales

&lt;/p&gt;&lt;p&gt;The net effect is to increase Income by a tenner and Expenses by an
unwell cephalopod (that's "sick quid" to you.  Sorry).  Thus both
effects of the transaction will be represented on the appropriate P&amp;L
rows.

&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;h2&gt; VAT / Sales Tax

&lt;/h2&gt;&lt;p&gt;VAT in the UK is not really ever money we have earnt, it's just money
we are collecting on behalf of the nice people at HMRC.  So, if we are
registered for VAT we must collect it on each sale into a holding account 
which we send them later, but it's not "ours" and doesn't show in Sales.

&lt;/p&gt;&lt;p&gt;&#xA3;20 cr. Income/Sales + 3.50 cr. Liabilities/VAT = 23.50 dr. Assets/Bank

&lt;/p&gt;&lt;p&gt;Watch out for the credit/debits in that transaction.  We should end up
with cash in the bank (a debit), some of which is owed to the VAT man
(credit).  If they don't sum to zero, you've done something wrong.

&lt;/p&gt;&lt;p&gt;Similarly we can also claim back VAT on purchases from our
VAT-registered suppliers

&lt;/p&gt;&lt;p&gt;11.75 cr. Assets/Bank = 10.00 dr. Assets/Inventory + 1.75 dr. Assets/Input_VAT

&lt;/p&gt;&lt;p&gt;At the end of the quarter, we pay HMRC what we owe them, less what
they owe us

&lt;/p&gt;&lt;p&gt;1.75 cr. Assets/Input_VAT + 1.75 cr. Assets/Bank = 3.50 dr. Liabilities/VAT 

&lt;/p&gt;&lt;p&gt;Note that this is not reflected in any Expense account - it shouldn't
be, because it wasn't in an Income account to start with

&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;h2&gt; Year end

&lt;/h2&gt;&lt;p&gt;We've already talked about producing the Balance Sheet and P&amp;L.  The
other action we take at end of year is to close the accounts: in the
case of Income and Expenses, we will want to start the following year
with a clean sheet.  How to do this: after producing the end-of-year
reports, move the entire contents of Income and Expenses accounts into 
a summary "Retained Earnings" account, debiting and crediting as appropriate. 

&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;h2&gt; Contingent concepts

&lt;/h2&gt;&lt;p&gt;We have not talked about: journals, day books, cash books, general
ledgers, T accounts, and trial balances.  Most of these are historical
practices that are necessary in manual systems either because the
latency of entering everything directly in double-entry form is high
(so transactions are initially recorded elsewhere instead), or because
there is no automatic checking that the accounts are in balance, or
because obtaining summaries of groups of accounts (answering queries
like "what's the total AP for &lt;b&gt;all&lt;/b&gt; suppliers") isn't a trivial bit of
SQL.

&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;h2&gt; Where next?

&lt;/h2&gt;&lt;p&gt;This is Part I of a two-part series.  In the second part I'm going to
write about my experience implementing all this in Ruby, but that will
have to wait until I've done the actual implementation.

&lt;/p&gt;&lt;p&gt;Hopefully though, this post should provide you with a view of the
principles such that you can google for anything else you see and you
have a framework to hang it on.

&lt;/p&gt;</description>
    </item>
    <item>
      <pubDate>Sat, 23 Jan 2010 00:10:32 GMT</pubDate>
      <title>Oh.  Ouch,  Sorry</title>
      <link>http://www.advogato.org/person/dan/diary.html?start=122</link>
      <guid>http://ww.telent.net/diary/Oh___Ouch___Sorry</guid>
      <description>&lt;p&gt;I've only just spotted this host didn't come back cleanly after last night's power-cut-induced outage.  Well, here it is now

&lt;/p&gt;&lt;p&gt;In the meantime, I have found the stunningly attractive &lt;a href="http://wiki.github.com/ffi/ffi/" class="external" &gt;Ruby FFI gem&lt;/a&gt; and written some &lt;a href="http://pastebin.com/f49cb8a6b" class="external" &gt;rather gross code&lt;/a&gt; to play music through PortAudio with it.  Unfortunately it turns out that PortAudio's &lt;tt&gt;Pa_OpenDefaultStream&lt;/tt&gt; function is &lt;a href="http://www.portaudio.com/trac/ticket/49" class="external" &gt;buggy&lt;/a&gt; (either the code or the spec) and it defaults to OSS anyway.  Still, a step closer
&lt;/p&gt;</description>
    </item>
    <item>
      <pubDate>Tue, 19 Jan 2010 23:11:55 GMT</pubDate>
      <title>Changing OSS in mid-stream</title>
      <link>http://www.advogato.org/person/dan/diary.html?start=121</link>
      <guid>http://ww.telent.net/diary/Changing_OSS_in_mid_stream</guid>
      <description>&lt;p&gt;It was always a given that the Oliver OSS (that's "/dev/dsp" to you) interface would eventually need to be swapped out for something else, just because it doesn't work on many machines other than mine.

&lt;/p&gt;&lt;p&gt;Now Oliver has reached the point that it functions as a rudimentary music player for general use (i.e. it presents me a list of my music on the left that I can drag into the playqueue on the right), I realise that "eventually" is sooner than I was expecting, simply because it opens the dsp exclusively and forces all other audio programs (e.g. youtube vids) to fail.  In short, it doesn't work acceptably well on my machine either.  Fail.  I'd forgotten how miserable Linux audio used to be.

&lt;/p&gt;&lt;p&gt;In other news

&lt;/p&gt;&lt;p&gt;&lt;ul&gt;&lt;li&gt; webkit doesn't support javascript 1.7, which is a grave disappointment as this is the one with proper lexical scope (via &lt;a href="https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Working_with_Closures#Creating_closures_in_loops.3a_A_common_mistake" class="external" &gt;let&lt;/a&gt; )

&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;&lt;ul&gt;&lt;li&gt; minor edit to previous post for comprehensibility, as re-reading it I realised it made more sense in my head than on the page.  

&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;&lt;ul&gt;&lt;li&gt; as tweeted: "there is a fine line between genius and idiot, and I'm still not sure on which side of it to place the jquery api".  Selecting document elements using CSS syntax, yes, great idea.  Returning those elements in an object sufficiently similar to an array that Firebug prints it as square brackets, but then making it respond to &lt;tt&gt;map&lt;/tt&gt; in an entirely different way to the real Array - no, stupid idea.  Hours of my life I won't get back
&lt;/ul&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <pubDate>Sat, 16 Jan 2010 01:12:49 GMT</pubDate>
      <title>Testes on testing</title>
      <link>http://www.advogato.org/person/dan/diary.html?start=120</link>
      <guid>http://ww.telent.net/diary/Testes_on_testing</guid>
      <description>&lt;p&gt;Lest the reader assume from my previous post that I'm against
automated testing: no, I'm not. In fact, Oliver hacking time over the
last couple of days has been all about writing tests for the
playqueue and turning the hacked together OSS interface into something
that can pass them.

&lt;/p&gt;&lt;p&gt;I offer for your consideration, though, that the benefits of writing a
test suite are not so much about "having an executable specification"
or even catching regressions as they are about &lt;i&gt;making the software
easier to test&lt;/i&gt;, by (1) decoupling interfaces so that units may be
tested without a plethora of complicated test doubles (stubs, mocks)
which may themselves contain bugs, and (2) reducing their dependence
on complicated state.  The easiest code to test is the purely
functional, and happily this is also the easiest code to statically
reason about (thus reducing our need to write tests in the first
place).

&lt;/p&gt;&lt;p&gt;There are other considerations: I object to the false confidence of
"our change passes tests, so we can feel good because it must be
correct" - though I suspect I'm fighting a straw man there anyway - and
I am not sure that even attempting to write tests for some classes of
bug (say, race conditions) is a more productive use of ones time than,
say, Thinking Very Hard at the program to be tested.  And there's the
whole issue of whether the executable specification (probably written
by a computer programmer) is a fair reflection of the business
requirement (if written by the "customer", probably much less precise
and probably not even consistent), but by that point we just have to
accept that, well, TDD won't fix world hunger either.  Chiefly my
message is that writing (and more importantly, maintaining) tests is
Not Free nor axiomatically Good, and therefore is only to be
commended when there is some expected benefit from it.

&lt;/p&gt;&lt;p&gt;I leave you with two final thoughts that are vaguely related but don't fit into the overall argument anywhere else...  

&lt;/p&gt;&lt;p&gt;First: correct me if I'm wrong here, but

&lt;/p&gt;&lt;p&gt;&lt;ul&gt;&lt;li&gt; &lt;b&gt;Test-Driven Development&lt;/b&gt; is what, back in the XP days, they called
  "test-first programming": you write the unit tests before the code
  that they test.  In Ruby, Test::Unit is/was the tool for running
  unit tests

&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;&lt;ul&gt;&lt;li&gt; &lt;b&gt;Behaviour-Driven Development&lt;/b&gt; is an exercise in redefining concepts,
   to change the emphasis from unit tests (which typically operate on
   a particular class) to functional tests (which may span several
   classes, and address user stories or whole-system behaviour).  In
   Ruby, RSpec was developed with this end.

&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;&lt;ul&gt;&lt;li&gt; &lt;b&gt;Missing the point&lt;/b&gt;, therefore, must be the practice of editing all
   your Test::Unit cases into RSpec syntax to pretend more
   convincingly to the new orthodoxy.  They don't magically turn into
   functional tests just because &lt;tt&gt;test_barf_when_value_negative&lt;/tt&gt; is
   now written &lt;tt&gt;it &amp;#34;should barf when value negative&amp;#34;&lt;/tt&gt;.  Er?  Do they?

&lt;/ul&gt;&lt;/p&gt;&lt;p&gt;Second: a powerful driver for a good test suite, from my experience
with SBCL, is that of checking the program is not broken by
environmental changes (new os, new cpu architecture, whatever). When
working on that project I saw test suite breakages far more often in
those circumstances than I ever did from hacking the code they were
supposed to protect.
&lt;/p&gt;</description>
    </item>
    <item>
      <pubDate>Fri, 15 Jan 2010 18:07:28 GMT</pubDate>
      <title>Streaming XHR with Ruby and Mongrel</title>
      <link>http://www.advogato.org/person/dan/diary.html?start=119</link>
      <guid>http://ww.telent.net/diary/Streaming_XHR_with_Ruby_and_Mongrel</guid>
      <description>&lt;p&gt;An entirely pun-free post title today, and still it sounds like something you'd see a vet about.  Hey ho.

&lt;/p&gt;&lt;p&gt;Suppose you are writing a web app in which the server needs to update the client when things change, and you don't want to do it by polling.  It turns out there is a technique for this that is probably more than two years old: you make the client do an XMLHttpRequest (aside: that name is almost as bad as its capitalization) to the server, and then the server sends its response v e r y &amp;nbsp; s l o w l y.  The clients XmLhTtPReQuEst object will get an onreadystatechange event every time a new packet arrives, and just has to pull the new data out of xhr.responseText and decide what to do with it.

&lt;/p&gt;&lt;p&gt;Well, that's the theory.  There are a variety of more-or-less-documented bugs and pitfalls to do with browser compatibility, as there always are (google "Comet", there are lots of resources and none of them I have the personal experience to recommend), but the new wrinkle I observed when doing this yesterday was a quarter-of-a-second lag between the server sending and the client receiving.  Odd.  Ruby can't be &lt;i&gt;that&lt;/i&gt; slow, can it?

&lt;/p&gt;&lt;p&gt;Wel, no,  it's not.  After monkeying with wget and netcat and wireshark and mostly failing to find out what was going on, I did
&lt;tt&gt; strace -e setsockopt ruby server.rb &lt;/tt&gt; and connected to it, and lo, what should I find but that something in Ruby or something in Mongrel was setting the &lt;tt&gt;TCP_CORK&lt;/tt&gt; socket option

&lt;/p&gt;&lt;p&gt;&lt;pre&gt;
setsockopt(5, SOL_TCP, TCP_CORK, [1], 4) = 0
&lt;/pre&gt;

&lt;/p&gt;&lt;p&gt;&lt;dl&gt;
&lt;dt&gt;       TCP_CORK (since Linux 2.2)&lt;/dt
&lt;dd&gt;              If set, don't send  out  partial  frames.   All  queued  partial
              frames  are sent when the option is cleared again.  This is use&#x2010;
              ful for prepending headers before calling  sendfile(2),  or  for
              throughput  optimization.   As currently implemented, there is a
              200 millisecond ceiling on the time for which output  is  corked
              by  TCP_CORK.   If  this ceiling is reached, then queued data is
              automatically transmitted.  This option  can  be  combined  with
              TCP_NODELAY  only since Linux 2.5.71.  This option should not be
              used in code intended to be portable.&lt;/dd&gt;&lt;/dl&gt;

&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;Now I don't know where it's being set - a cursory grep of the mongrel sources says probably not there, but it's simple enough to unset again.  So, here's one I made earlier.  Note that you can't use the 
&lt;tt&gt;response.start&lt;/tt&gt; method (or at least, I don't see how) - you have to reach a little deeper into Mongrel::HttpResponse
&lt;pre&gt;
class StatusHandler &lt; Mongrel::HttpHandler
  def process(request, response)
    fh=nil
    response.status=200
    response.send_status(nil)
    response.header['Content-Type'] = "application/x-www-form-urlencoded"
    response.send_header
    # something inside Ruby or inside Mongrel is setting TCP_CORK,
    # which is bad for latency.  I suspect Ruby C code, because 
    # the interpreter complains there is no definition for Socket::TCP_CORK
    # &lt;linux/tcp.h&gt;:#define TCP_CORK 3 /* Never send partially complete segments */
    response.socket.setsockopt(Socket::SOL_TCP, 3, 0)
    response.socket.setsockopt(Socket::SOL_TCP, Socket::TCP_NODELAY, 1)
    response.write("# gubbins for webkit bug "+("." * 256)+ "\n");
    response.write("# stuff follows\n");

&lt;/p&gt;&lt;p&gt;    300.times.each do
      response.write("stuff\n")
      response.socket.flush
      sleep 30
    end   
    response.done
  end  
end
&lt;/pre&gt;

&lt;/p&gt;&lt;p&gt;We limit the response to 300 lines in case of browser timeout or connection interruption or just to stop the client-side memory going up unboundedly as &lt;tt&gt;responseText&lt;/tt&gt; grows without let or limit.  It's simple for the javascript to kick off another handler when this one dies.

&lt;/p&gt;&lt;p&gt;For completeness, here's some client-side code to go with it
&lt;pre&gt;
// XXX we made the_req global just so that we can look at 
// what's going on in firebug.  It's not required in normal use
var the_req;
function json_watch_stream(url,callback) {
    var req =new XMLHttpRequest();
    the_req = req;
    req.open("GET",url,true);
    req.last_seen=0;
    req.onreadystatechange = function() {
	if(req.responseText) {
	    callback(req.readyState,req.status,
		     req.responseText.substr(req.last_seen))
	    req.last_seen=req.responseText.length;
	}
    };
    req.send(null);
}
function json_start_status_receiver (){
    json_watch_stream
	('/status',
	 function(ready,status,text) {
	    if(ready==4) {
		// server response concluded, need to start again
		json_start_status_receiver ();
	    }
	    text.split("\n").map(function(line) {
		    if(!line) { return; };
		    var data=line.substr(1);
		    switch(line[0]) {
		    case '#': break;
		    case 'O': update_track_timer(data); break;
		    case 'P': update_track_number(data); break;
		    case 'S': stop_track_timer(); break;
		    default: 
			console.log("status stream: unrecognised flag ",
				    line[0],data);
		    }
		});
	});
}
&lt;/pre&gt;
&lt;/p&gt;</description>
    </item>
    <item>
      <pubDate>Fri, 15 Jan 2010 18:07:28 GMT</pubDate>
      <title>OSSes for Courses</title>
      <link>http://www.advogato.org/person/dan/diary.html?start=118</link>
      <guid>http://ww.telent.net/diary/OSSes_for_Courses</guid>
      <description>&lt;p&gt;I'd like to talk today about the state of audio output APIs that are
implemented on Linux and accessible to Ruby, but there aren't any.

&lt;/p&gt;&lt;p&gt;That's an oversimplification, I know.  Oliver is now quite happily
streaming PCM data to my headphones, so it's not even a good
oversimplification.  But whereas any of portaudio, pulseaudio, jack or
alsa are the conventionally accepted routes to getting the speakers to
squeak, what did I end up using?  OSS.  Yes, that's right, the Evil!
Bad! Wrong! Deprecated! API invented by proprietary coders and left
unmaintained for years that doesn't even support AC3-encoded 7.1 HDMI
audio with reverse-phased channels and unlimited software mixing.
Because ... well, because it Just Works.  Open a file, send it a few
ioctls for sample format and rate, and for the all-important "we don't
care about latency that much" switch that lets interpreted code keep
up without stuttering, then just chuck PCM data at it until we're out
of PCM data.  And it's quite well documented, and because it's all
file-based it plays nice with Ruby's green threads: I just set
the dsp stream to non-blocking mode and the audio keeps on going even
while it's serving HTML and doing JSON calls.

&lt;/p&gt;&lt;p&gt;Let me know when the massive ALSA DLL - or any of the plethora of
other Modern audio libraries - becomes that simple to use (and
preferably becomes usable without resorting to C), and I might give
them another go.  Yes, I am aware that under the hood the OSS API is
implemented using ALSA drivers: how ironic.

&lt;/p&gt;&lt;p&gt;Oh well.  This isn't supposed to be the computer contrarian's blog,
but some days it just feels like it.

&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.googlefight.com/index.php?lang=en_GB&amp;word1=alsa+audio&amp;word2=oss+audio

" class="external" &gt;http://www.googlefight.com/index.php?lang=en_GB&amp;word1=alsa+audio&amp;word2=oss+audio

&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <pubDate>Fri, 15 Jan 2010 18:07:28 GMT</pubDate>
      <title>Back after the break</title>
      <link>http://www.advogato.org/person/dan/diary.html?start=117</link>
      <guid>http://ww.telent.net/diary/Back_after_the_break</guid>
      <description>&lt;p&gt;If anyone reading this is presently as disillusioned with
computing/hacking/coding as I was a few months ago, I cannot recommend
Peter Seibel's "Coders at Work" highly enough.  

&lt;/p&gt;&lt;p&gt;Why my discontent?  I don't trust anyone who elevates a programming
practice (or indeed, almost anything else) to the status of a
religion, and it seemed to me that "Test Driven Development" shares
the important characteristics of UML, J2EE, pair programming, and
"goto considered harmful" in that it promotes a high-ceremony dogma
that is on the face of it really rather unlikely to save you time, on
the professed basis mostly that it will make you a Better Person.
And, presumably, get your reward in heaven.

&lt;/p&gt;&lt;p&gt;But herein lies the problem.  If you want to write stuff for a Unixoid
platform right now, after discounting the really tedious heavyweight
stuff like C and its variants your choice is basically Ruby.  Or, at a
pinch, Javascript.  Common Lisp is - for all that I spent the last
decade or so hacking on SBCL (more about that soon) - a platform not
just a language, and a platform that nobody really wants to stand on;
Perl is basically moribund; Python is dull and patronises its users
(ESR likes it, which fits because he is also dull and patronising);
the Schemes are fragmented and don't have momentum; and Java and C# -
well, honestly they're out of the realms of everyday religion and
straight into the flagellation: not my kink at all.

&lt;/p&gt;&lt;p&gt;(Did I miss anyone?)

&lt;/p&gt;&lt;p&gt;Anyway, Ruby is actually quite OK apart from the syntax (as a Lisper,
I don't actually care what the syntax is, that it has one is the
problem), it'll have acceptable performance in 1.9, and the lack of
macros/programs-as-data is &lt;b&gt;mostly&lt;/b&gt; - I don't say entirely, but mostly
- made up for by a lexically succint notation for blocks, which do
most of what you might want to do with them.  (It's actually a minor
source of amusement to me that Ruby folk are so mad keen on DSLs when
they have to jury-rig them all into method syntax, but that's a story
for another time).  Anyway, if I can still remember my original point,
I think it was that Ruby is currently the nearest thing around to a
programming language that is both interesting and useful, but what
about the TDD weenies?

&lt;/p&gt;&lt;p&gt;So, back to Coders at Work.  I bought it after it seeing that JWZ's
interview had generated a certain amount of controversy with the unit
testing dweebs, and reading it over the space of a couple of days I
was immensely cheered to find that none of the other interviewees -
interesting people, great hackers and luminaries among them - were
blind adherents of that particular orthodoxy either.  And, bizarre and
pathetic as it sounds, that gave me the innoculation against TDD mind
control that I thought I'd need in a group of Ruby programmers, so I
have started (1) making some kind of an effort to get to the &lt;a href="http://lrug.org/" class="external" &gt;London
Ruby Users Group&lt;/a&gt; meetings, (2) making a good-faith
attempt to actually learn the language.  

&lt;/p&gt;&lt;p&gt;LRUG?  Well, the first meeting was all about reinforcing the
stereotype: a "Coding Dojo", or "what do you get if you try to scale
pair programming".  Answer is, you get mob programming: one active
pair and ten to fifteen other onlookers.  Which doesn't mean it wasn't &lt;a href="http://lists.lrug.org/pipermail/chat-lrug.org/2009-September/004069.html" class="external" &gt;thought-provoking&lt;/a&gt; , of course

&lt;/p&gt;&lt;p&gt;The &lt;a href="http://lrug.org/meetings/2009/09/18/october-2009-meeting/" class="external" &gt;second meeting&lt;/a&gt; 
I turned up principally for the functional programming talk, which 
seemed to create quite a buzz in the pub (that's a good thing) and 
left me quite reassured that at least some part of the Ruby community
"get it".

&lt;/p&gt;&lt;p&gt;And learning the language?  I'm writing a program.  It has bits of
Ruby, bits of Javascript, bits of audio coding (fairly noddy audio
coding, as getting Ruby to run fast enough for anything more
interesting looks like a challenge) and will eventually embed webkit.
Yes, I'm writing an mp3 player/library manager, just on the basis that
the downgrade from Amarok 1.4 to 2 in Debian has left me without a working music player that will export playlists to my phone, but that I already have a Twitter client.  More on that as it progresses.

&lt;/p&gt;&lt;p&gt;I'm never quite sure what "normal" is around here, but
hacking-and-blogging service has been resumed.

&lt;/p&gt;&lt;p&gt;[ posted a day later.  But look what else I found since - Eleanor McHugh's &lt;a href="http://feyeleanor.livejournal.com/127046.html#cut" class="external" &gt;On Agility&lt;/a&gt; rant.  This is not &lt;i&gt;exactly&lt;/i&gt; what I wanted to say about TDD and BDD, but it has themes I'm going to pick up on ]
&lt;/p&gt;</description>
    </item>
    <item>
      <pubDate>Fri, 15 Jan 2010 18:07:28 GMT</pubDate>
      <title>Meet the new box (same as the old box)</title>
      <link>http://www.advogato.org/person/dan/diary.html?start=116</link>
      <guid>http://ww.telent.net/diary/Meet_the_new_box__same_as_the_old_box_</guid>
      <description>&lt;p&gt;My two-year-old Conmpaq NC2400 laptop came to an untimely end last month, as a result of being dunked in a rucksack with a pool of GT85 (long story).  The screen developed slightly psychedelic oil bubbles which moved slowly around, the disk stopped working (or at least, stopped booting), and I really didn't fancy the task of stripping it down to rinse out all the electronics and still not know for definite that I could resuscitate it.

&lt;/p&gt;&lt;p&gt;Ypou would think, wouldn't you, that after two years there'd be something better available at around the same price point (~ &#xA3;600)?  No.  I took a long look at netbooks, which are all variously too small (1024x600 pixels?  Don't be daft), too slow (Atom CPUs were never really the performance demon, even compared to my elderly U2500), and/or fail of VT (Atom again) and decided that the best thing to do was buy exactly the same computer again.  Which I did, from Ebay, for &#xA3;170

&lt;/p&gt;&lt;p&gt;I still felt the need to do something to make it seem like an upgrade, though.  As reviewers mostly seemed to agree that the bottleneck in the NC2400 was the 1.8" disk, I added a new 2.5" disk in the optical bay - never really used the DVD anyway - and migrated everything to it.  

&lt;/p&gt;&lt;p&gt;To do this you will need an optical bay caddy, such as the ones from &lt;a href="http://www.newmodeus.com" class="external" &gt;Newmode US&lt;/a&gt; whose praises I will gladly sing.  After having ordered the wrong caddy for my machine (in part due to an arguably misleading web page on their site, now corrected) I emailed them to explain and they sent out the correct one for the $8 price difference, without asking for the old one back or for the international postage to be paid again.  This is service far in excess of what I was expecting.

&lt;/p&gt;&lt;p&gt;A nice fast 2.5" pata disk, like the &lt;a href="http://www.amazon.co.uk/Samsung-Spinpoint-160GB-HM160HC-Laptop/dp/B002ESLJ8S/ref=wl_it_dp_o?ie=UTF8&amp;coliid=I263UB25ZM8IY8&amp;colid=327F2EC4QN8B9" class="external" &gt;Samsung HM160HC&lt;/a&gt; also helps, that being the point of the exercise

&lt;/p&gt;&lt;p&gt;The hardware assembly is fairly straightforward, when you have the right sized caddy.  Watch out for setting the jumper on the drive before installing it: it shares an IDE channel with the original disk, so needs to be jumpered to "slave".

&lt;/p&gt;&lt;p&gt;The software installation obviously varies according to what you previously had.  When I put Debian on this machine it gave me an encrypted disk with LVM on top of it, so &lt;a href="http://www.debian-administration.org/article/How_To_Migrate_to_a_full_encrypted_LVM_system" class="external" &gt;http://www.debian-administration.org/article/How_To_Migrate_to_a_full_encrypted_LVM_system&lt;/a&gt; was the key to working out what it had done and how.

&lt;/p&gt;&lt;p&gt;The result according to hdparm:

&lt;/p&gt;&lt;p&gt; /dev/hda:
 Timing buffered disk reads:   64 MB in  3.06 seconds =  20.91 MB/sec
 
 /dev/hdb:
 Timing buffered disk reads:  184 MB in  3.01 seconds =  61.15 MB/sec

&lt;/p&gt;&lt;p&gt;The result according to my subjective experience: far faster and less laggy.  Power consumption does for some reason seem to have jumped from 10W to 13W with concomitant decrease in battery life but I strongly suspect &lt;a href="https://bugs.launchpad.net/ubuntu/+source/linux/+bug/373245

" class="external" &gt;that's unrelated&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <pubDate>Fri, 15 Jan 2010 18:07:28 GMT</pubDate>
      <title>Gnus over ssh</title>
      <link>http://www.advogato.org/person/dan/diary.html?start=115</link>
      <guid>http://ww.telent.net/diary/Gnus_over_ssh</guid>
      <description>&lt;p&gt;Suppose you had a broadband account with a static IP address (or small network) and an NNTP service, and that you wanted to read news from places other than the broadband network.  Suppose further that your newsreader of choice is Gnus.

&lt;/p&gt;&lt;p&gt;The intersection of all these assumptions is that you'd probably be me.  In which case you already have incoming ssh access to the machine(s) on the  broadband and all you need do is add the emacs magic to connect back from wherever in The Cloud(sic) you are through your home net to your news service
&lt;pre&gt;
(defun nntp-open-via-ssh-stream (buffer)
  "Open a nntp connection by ssh to coruskate then then nc to zen"
  (let ((command '("ssh" "me.homeip.example.com" "nc" "news.myisp.example.com" "119"))
	proc)
    (setq proc (apply 'start-process "nntpd" buffer command))
    (save-excursion
      (set-buffer buffer)
      (nntp-wait-for-string "^\r*20[01]")
      (beginning-of-line)
      (delete-region (point-min) (point))
      proc)))

&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;(setq gnus-select-method '(nntp "news"
				(nntp-open-connection-function 
				 nntp-open-via-ssh-stream)))
&lt;/pre&gt;
I was a bit surprised there's aparently no canned function for this.  I crafted this by cut and paste from &lt;tt&gt;nntp-open-telnet-stream&lt;/tt&gt;, which seemed simpler than trying to bend it to my will by editing the variables therein

&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.zen.co.uk" class="external" &gt;Zen Internet&lt;/a&gt; come highly recommended as usual
&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
