<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
  <channel>
    <title>Vidar Hokstad V2.0</title>
    <link>http://www.hokstad.com/</link>
    <description>Vidar Hokstad's blog posts</description>
    <pubDate>Thu, 05 Nov 2009 08:05:14 -0500</pubDate>
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/VidarHokstad" type="application/rss+xml" /><feedburner:emailServiceId>VidarHokstad</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><feedburner:browserFriendly>This is an XML content feed. It is intended to be viewed in a newsreader or syndicated to another site.</feedburner:browserFriendly><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
      <title>A pitfall of the Ruby Range class</title>
      <link>http://feedproxy.google.com/~r/VidarHokstad/~3/b2UfbTBFYkg/a-pitfall-of-the-ruby-range-class.html</link>
      <description>&lt;p&gt;I tweeted about this, but figured it deserve a more lasting treatment.&lt;/p&gt;

&lt;p&gt;If you've ever used &lt;code&gt;Range#min&lt;/code&gt; or &lt;code&gt;Range#max&lt;/code&gt; you may have inadvertently slowed
your code significantly.&lt;/p&gt;

&lt;p&gt;Both of those ought to be O(1) - constant time. After all, a Range in Ruby
consist of two values, and though you can't be assured whether or not the
first one or the last one is the smallest/biggest one, the obvious implementation
is this:&lt;/p&gt;

&lt;pre class="ruby"&gt;&lt;code&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;min&lt;/span&gt;
      &lt;span class="ident"&gt;first&lt;/span&gt; &lt;span class="punct"&gt;&lt;=&lt;/span&gt; &lt;span class="ident"&gt;last&lt;/span&gt; &lt;span class="punct"&gt;?&lt;/span&gt; &lt;span class="ident"&gt;first&lt;/span&gt; &lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;last&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;.. and the equivalent one for &lt;code&gt;Range#max&lt;/code&gt;. Except that's not what happens,
as you can easily convince yourself by doing:&lt;/p&gt;

&lt;pre class="ruby"&gt;&lt;code&gt;
    &lt;span class="global"&gt;$ &lt;/span&gt;&lt;span class="ident"&gt;irb&lt;/span&gt;
    &lt;span class="ident"&gt;irb&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;main&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;&lt;span class="number"&gt;001&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;&gt;&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;..&lt;/span&gt;&lt;span class="number"&gt;10000000&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;max&lt;/span&gt;
    &lt;span class="punct"&gt;=&gt;&lt;/span&gt; &lt;span class="number"&gt;10000000&lt;/span&gt;
    &lt;span class="ident"&gt;irb&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;main&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;&lt;span class="number"&gt;002&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;&gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;... and see how slow it is. Eww. The explanation is that min/max are only provided in generic versions
that iterate over the full Range (so that the same implementation also works
on other collections).&lt;/p&gt;

&lt;p&gt;If your app, like mine, frequently needs the smallest or greatest value in
a Range, it may be time to monkey patch:&lt;/p&gt;

&lt;pre class="ruby"&gt;&lt;code&gt;
    &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Range&lt;/span&gt;
      &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;min&lt;/span&gt;
        &lt;span class="ident"&gt;first&lt;/span&gt; &lt;span class="punct"&gt;&lt;=&lt;/span&gt; &lt;span class="ident"&gt;last&lt;/span&gt; &lt;span class="punct"&gt;?&lt;/span&gt; &lt;span class="ident"&gt;first&lt;/span&gt; &lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;last&lt;/span&gt;
      &lt;span class="keyword"&gt;end&lt;/span&gt;
          
      &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;max&lt;/span&gt;
        &lt;span class="ident"&gt;first&lt;/span&gt; &lt;span class="punct"&gt;&gt;=&lt;/span&gt; &lt;span class="ident"&gt;last&lt;/span&gt; &lt;span class="punct"&gt;?&lt;/span&gt; &lt;span class="ident"&gt;first&lt;/span&gt; &lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;last&lt;/span&gt;
      &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
    
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;For the app that made me notice this problem, adding the above monkey patch
caused a &lt;strong&gt;30% speedup&lt;/strong&gt;. Of course, if most of your ranges are small, or you
don't use &lt;code&gt;Range#min&lt;/code&gt; or &lt;code&gt;Range#max&lt;/code&gt; anywhere, you may not notice any difference
at all.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=b2UfbTBFYkg:deYOB1ZHFZ8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=b2UfbTBFYkg:deYOB1ZHFZ8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=b2UfbTBFYkg:deYOB1ZHFZ8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=b2UfbTBFYkg:deYOB1ZHFZ8:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=b2UfbTBFYkg:deYOB1ZHFZ8:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=b2UfbTBFYkg:deYOB1ZHFZ8:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=b2UfbTBFYkg:deYOB1ZHFZ8:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=b2UfbTBFYkg:deYOB1ZHFZ8:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=b2UfbTBFYkg:deYOB1ZHFZ8:iYEzUNWTmVE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=iYEzUNWTmVE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=b2UfbTBFYkg:deYOB1ZHFZ8:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=b2UfbTBFYkg:deYOB1ZHFZ8:Jnkt3q6G96E"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=b2UfbTBFYkg:deYOB1ZHFZ8:Jnkt3q6G96E" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VidarHokstad/~4/b2UfbTBFYkg" height="1" width="1"/&gt;</description>
      <category>ruby</category>
      <category> range</category>
      <category> programming</category>
      <category> monkey patch</category>
      <pubDate>Thu, 05 Nov 2009 08:05:14 -0500</pubDate>
      <dc:date>2009-11-05T08:05:14-05:00</dc:date>
    <feedburner:origLink>http://www.hokstad.com/a-pitfall-of-the-ruby-range-class.html</feedburner:origLink></item>
    <item>
      <title>Writing a (Ruby) compiler in Ruby bottom up - step 21</title>
      <link>http://feedproxy.google.com/~r/VidarHokstad/~3/Bxp5RUYrU14/writing-a-compiler-in-ruby-bottom-up-step-21.html</link>
      <description>&lt;p&gt;I've been lazy lately... Well, not really, I've been extremely busy, but I
ought to have fit this in earlier. It's gotten harder and harder to get done
too, since it's now more work since I had to go back and figure out a lot of
the reasons for what I'd done.&lt;/p&gt;


&lt;p&gt;Anyway, finally a new part, though short.&lt;/p&gt;


&lt;h2&gt;Down the rabbit hole: attr_(reader|writer|accessor)&lt;/h2&gt;


&lt;p&gt;Adding attr_reader / "attr_writer" / "attr_accessor" Should be easy, right?
After all, all they do is allow read/write or both of member variables.&lt;/p&gt;


&lt;p&gt;Trouble is you can't &lt;em&gt;know&lt;/em&gt; that in advance.&lt;/p&gt;


&lt;pre class="ruby"&gt;
    class Class
      def attr_reader foo
        puts "Hah!"
      end
    end

    class Foo
      attr_reader :bar
    end

    foo = Foo.new
    p foo.bar
&lt;/pre&gt;


&lt;p&gt;Ouch. This is part of what makes Ruby exceptionally painful to compile.&lt;/p&gt;


&lt;p&gt;It doesn't mean we can't make some assumptions, though, as long as we can &lt;em&gt;handle&lt;/em&gt;
the worst case where someone does something &lt;em&gt;stupid&lt;/em&gt; (later we may want to add an
option to make it assume you're not being stupid, and enable additional optimizations).&lt;/p&gt;


&lt;p&gt;So how do we do this then?&lt;/p&gt;


&lt;p&gt;Well, the obvious answer is to implement it in Ruby. Here are naive initial
implementations (that only handle a single symbol, not an array like the real thing):&lt;/p&gt;


&lt;pre class="ruby"&gt;
    def attr_accessor sym
      attr_reader sym
      attr_writer sym
    end

    def attr_reader sym
      define_method sym do
         %s(ivar self sym)
      end
    end

    def attr_writer sym
      define_method "#{sym.to_s}=".to_sym do |val|
        %s(assign (ivar self sym) val)
      end
    end
&lt;/pre&gt;


&lt;p&gt;Note the s-expressions that rely on a new "ivar" primitive (that's not been added yet).
That part is simple enough to add, but what else does the above require to be added to
the compiler?&lt;/p&gt;


&lt;p&gt;That's the ugly part. Here's a (possibly incomplete) list:&lt;/p&gt;


&lt;ul&gt;
&lt;li&gt;define_method&lt;/li&gt;
&lt;li&gt;Real Symbol class&lt;/li&gt;
&lt;li&gt;Symbol#to_s&lt;/li&gt;
&lt;li&gt;Real String class&lt;/li&gt;
&lt;li&gt;String.to_sym&lt;/li&gt;
&lt;li&gt;Indirectly the :lambda s-expression construct needs to have support for variables&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;This is part of the reason I picked attr_* as the next thing to implement: It's an important,
frequently used piece of functionality that snowballs and help drive implementation of
functionality that is actually likely to be used.&lt;/p&gt;


&lt;h2&gt;Baby steps&lt;/h2&gt;


&lt;p&gt;First take a look at &lt;a href="http://github.com/vidarh/writing-a-compiler-in-ruby/commit/6e7edd638265503c129fdc0a7b44a301cc3ca4f7"&gt;this commit&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;This is one of our assumptions (in between some other cruft): If you use attr_accessor
etc., you &lt;em&gt;are&lt;/em&gt; likely to need a vtable entry for that method.&lt;/p&gt;


&lt;p&gt;Remember, we still don't implement a proper "fallback" in the form of a hash table for
cases where the vtable gets "too big" (whatever we decide too big is) so for now we &lt;em&gt;need&lt;/em&gt; this,
but even later it'll be a useful optimization for many cases.&lt;/p&gt;


&lt;p&gt;Worst case? We waste a vtable slot.&lt;/p&gt;


&lt;p&gt;&lt;a href="http://github.com/vidarh/writing-a-compiler-in-ruby/commit/7fc8ee47332115bede8531f749543136a79833f3#diff-0"&gt;Next is where we actually add the basic implementations shown above&lt;/a&gt;, plus some debug statements, and stub for "define_method".&lt;/p&gt;


&lt;p&gt;The comments bring us to an important question:&lt;/p&gt;


&lt;h2&gt;To type-tag or not to type-tag?&lt;/h2&gt;


&lt;p&gt;&lt;a href="http://www.hokstad.com/ruby-object-model.html"&gt;In MRI Symbol objects are "type tagged" integers&lt;/a&gt;.
That is, they are not real objects at all, rather each symbol is represented
by a specific 32 bit value, and those values can be identified as symbols
by looking for a specific bit-pattern in the least significant byte.&lt;/p&gt;


&lt;p&gt;This has the advantage of saving space - no actual instances need to be
constructed. In this instance, however, it creates a lot of complication,
by requiring the type tags to be checked on each and every method call.&lt;/p&gt;


&lt;p&gt;For this reason we will, at least for now, avoid it.&lt;/p&gt;


&lt;p&gt;(For Fixnum we will run into this problem again, and it will be even more
tricky - for Symbol the number of objects can be expected to be reasonably
small, but what about Fixnum? Ugh... Lets think about that later)&lt;/p&gt;


&lt;p&gt;Instead we will keep a hash table of allocated symbols, which we will
use to return the same object for the same symbol literal&lt;/p&gt;


&lt;p&gt;I'm going to skip over most of the commits here, and show you the current
state of the Symbol class and its associated compiler changes, since
I must admit my commits have been quite messy and all over the place
while putting in place these changes, and it's not very condusive to
explaining the actual changes.&lt;/p&gt;


&lt;pre class="ruby"&gt;
    class Symbol
      # Using class instance var instead of class var
      # because the latter is not properly implemented yet,
      # though in this case it may not make a difference
      #  @symbols = {} # FIXME: Adding values to a class ivar like this is broken
      
      # FIXME: Should be private, but we don't support that yet
      def initialize(name)
        @name = name
      end
    
      def to_s
        @name
      end

      # FIXME
      # The compiler should turn ":foo" into Symbol.__get_symbol("foo").
      # Alternatively, the compiler can do this _once_ at the start for 
      # any symbol encountered in the source text, and store the result.
    #  def self.__get_symbol(name)
    #    Symbol.new(name)       
    #    sym = @symbols[name]  
    #    if !sym               
    #      sym = Symbol.new(name)
    #    end
    #    sym
    #  end
    end

    def __get_symbol(name)
      Symbol.new(name)
    end
&lt;/pre&gt;


&lt;p&gt;Uh, yes. I started out with actually having it turn symbols from text into
an object at runtime, but I quickly realized this makes no sense for the case
where a literal symbol is present in the program.&lt;/p&gt;


&lt;p&gt;Note that we still need a proper Symbol#__get_symbol as commented out here
later, because it is necessary to handle things like String#to_sym. However
for now I've skipped it for a simple reason:&lt;/p&gt;


&lt;p&gt;It requires implementing a hash table. It's not that hash tables are hard.
But currently implementing Hash in pure Ruby likely will require features that
are not in place yet... So, lets sort out the literal Symbols first, and then
work our way up.&lt;/p&gt;


&lt;p&gt;The trivial version above is well and good, but &lt;a href="http://github.com/vidarh/writing-a-compiler-in-ruby/commit/f3a38a8d9085178709428107a9a13d6b484c5c99"&gt;we need to make the compiler
call __get_symbol.&lt;/a&gt;.&lt;/p&gt;


&lt;p&gt;So we replace Compiler#intern with this:&lt;/p&gt;


&lt;pre class="ruby"&gt;
    # Allocate a symbol
    def intern(scope,sym)
      # FIXME: Do this once, and add an :assign to a global var, and use that for any
      # later static occurrences of symbols.
      args = get_arg(scope,sym.to_s.rest)
      get_arg(scope,[:sexp,[:call,:__get_symbol, sym.to_s]])
    end
&lt;/pre&gt;


&lt;p&gt;As you can see from my comment, it really makes no sense to call &lt;tt&gt;__get_symbol&lt;/tt&gt; over
and over - it's inefficient. But it works for now. We'll go back and fix that later.&lt;/p&gt;


&lt;p&gt;Also note that this doesn't exactly match the above commit, but also incorporate a change
from a later commit: We do [:sexp ..] there because :sexp nodes don't get rewritten to a
:callm, and &lt;tt&gt;__get_symbol&lt;/tt&gt; here is indeed a function not a method (this distinction
doesn't really exist in Ruby, but it exist at the implementation level in our compiler,
because it eases interoperability with C - this may change whenever I get to the point
where it makes sense to implement &lt;a href="http://kenai.com/projects/ruby-ffi"&gt;FFI support&lt;/a&gt;)&lt;/p&gt;


&lt;p&gt;The other changes are simply there to reflect the fact that &lt;tt&gt;intern&lt;/tt&gt; now returns
the result of a &lt;tt&gt;get_arg&lt;/tt&gt; instead of some arbitrary integer:&lt;/p&gt;


&lt;pre class="ruby"&gt;
    -      return [:int,intern(name.rest)] if name[0] == ?:
    +      return intern(scope,name.rest) if name[0] == ?:
&lt;/pre&gt;


&lt;h2&gt;That's it for now, folks&lt;/h2&gt;


&lt;p&gt;I promise it won't be nearly as long to the next part. I need to untangle my changes for
splat operator support, method_missing debug improvements, and work on the Array and
String classes. I'll likely give each one of them a short part each before I get fully
"back on track" - I intend to write the future parts in parallel with actually
making the code changes.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=Bxp5RUYrU14:0abYsmMNcyc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=Bxp5RUYrU14:0abYsmMNcyc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=Bxp5RUYrU14:0abYsmMNcyc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=Bxp5RUYrU14:0abYsmMNcyc:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=Bxp5RUYrU14:0abYsmMNcyc:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=Bxp5RUYrU14:0abYsmMNcyc:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=Bxp5RUYrU14:0abYsmMNcyc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=Bxp5RUYrU14:0abYsmMNcyc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=Bxp5RUYrU14:0abYsmMNcyc:iYEzUNWTmVE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=iYEzUNWTmVE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=Bxp5RUYrU14:0abYsmMNcyc:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=Bxp5RUYrU14:0abYsmMNcyc:Jnkt3q6G96E"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=Bxp5RUYrU14:0abYsmMNcyc:Jnkt3q6G96E" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VidarHokstad/~4/Bxp5RUYrU14" height="1" width="1"/&gt;</description>
      <category>ruby</category>
      <category> compiler</category>
      <category> programming</category>
      <category> compiler in Ruby bottom up</category>
      <category> tutorial</category>
      <category> symbol</category>
      <pubDate>Sun, 01 Nov 2009 17:38:38 -0500</pubDate>
      <dc:date>2009-11-01T17:38:38-05:00</dc:date>
    <feedburner:origLink>http://www.hokstad.com/writing-a-compiler-in-ruby-bottom-up-step-21.html</feedburner:origLink></item>
    <item>
      <title>Vacation over</title>
      <link>http://feedproxy.google.com/~r/VidarHokstad/~3/AF1AekXSLTQ/vacation-over.html</link>
      <description>Just got back from a short vacation on the &lt;a href="http://www.iwight.com/just_visiting/"&gt;Isle of Wight&lt;/a&gt; and &lt;a href="http://www.thenewforest.co.uk/"&gt;New Forest&lt;/a&gt; on Sunday night... Since then we've been relaxing at home, apart from a two hour detour to the office.&lt;br&gt;&lt;br&gt;&lt;br&gt;Tristan and me on the Esplanade in&amp;nbsp;&lt;a&gt;&lt;/a&gt;&lt;a&gt;Ventnor&lt;/a&gt;:&lt;br&gt;&lt;a&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;&lt;img  src="/static/images/ventnor09.jpg" alt=""&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;The trip was nice - we had some trepidation in advance about bringing Tristan on another vacation at just a bit over 3 months. He was very good in Norway earlier this summer, but then we&amp;nbsp;were around family and my mom and her partner used the opportunity to take him off our hands a lot of the time. Especially since we don't drive, and so took a cab to the station, train from Croydon to Portsmouth, ferry from Portsmouth to Ryde, train from Ryde Pier Head (the station - below - lies&amp;nbsp;&lt;a href="http://maps.google.com/maps?client=safari&amp;oe=UTF-8&amp;amp;ie=UTF8&amp;amp;q=ryde+pier+head&amp;amp;fb=1&amp;amp;split=1&amp;amp;cid=3779577315004358706&amp;amp;li=lmd&amp;amp;ll=50.738519,-1.160388&amp;amp;spn=0.016866,0.045276&amp;amp;t=h&amp;amp;z=15&amp;amp;iwloc=A"&gt;&lt;/a&gt;&lt;a&gt;&lt;/a&gt;&lt;a href="http://maps.google.com/maps?client=safari&amp;amp;oe=UTF-8&amp;amp;ie=UTF8&amp;amp;q=ryde+pier+head&amp;amp;fb=1&amp;amp;split=1&amp;amp;cid=3779577315004358706&amp;amp;li=lmd&amp;amp;ll=50.738519,-1.160388&amp;amp;spn=0.016866,0.045276&amp;amp;t=h&amp;amp;z=15&amp;amp;iwloc=A"&gt;half a mile off the shore&lt;/a&gt;, as the ferries can't safely get closer) to Shanklin and cab from Shanklin to Ventnor just to get to our hotel. But he was calm the whole time.&lt;br&gt;&lt;br&gt;&lt;img  src="/static/images/ryde09.jpg" width="450" align="left" style="padding-right:30px; padding-bottom: 20px;" alt="" class="selected     "&gt;

After a few days on Isle of Wight we went to Lyndhurst, New Forest and spent the weekend there, with visits to Lymington, Beaulieu (compulsory complaint: Why, oh why must the English pronounce everything inconsistently - the "English" pronunciation of Beaulieu just refuses to stick in my head; I guess that's what I get from actually knowing how the French "beau lieu" which the name comes from is pronounced; also: Lynd-hurst, but Ash-urst) and Exbury gardens.&lt;br&gt;&lt;br&gt;Next time we'll probably spend a bit longer in one place - dragging all the extra stuff required for a baby with us made it a bit stressful, and scheduling everything around his feeding and nap times and diaper changes made things a bit frantic.&lt;br&gt;&lt;br&gt;Last three days we haven't even left the house apart from my little office trip. "Recovering" from the trip I guess... Besides, it's been far too hot out today.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;strong&gt;... otherwise&lt;/strong&gt;&lt;br&gt;&lt;br&gt;... I've finally been hacking a bit on my Ruby compiler project again today (and I did a few bits and pieces whenever I could find a spare minute in the last week or so before I went off on vacation), and just got a couple more things I want to wrap up before posting another part in my series. I hope to post another part in a week or two.&lt;br&gt;&lt;br&gt;Specifically I'm working towards making #attr_reader/writer/accessor work, which seems simple, but it led me down a rabbit hole to implement basics of Symbol, #define_method, as well as fix a number of bugs. On the upside getting this in place also means adding better debug output to #method_missing becomes simpler, and I have reasons to think that execution of the compiled version of the compiler itself will get a massive step closer.&lt;br&gt;&lt;br&gt;Best way of keeping an eye on what's going on in the meantime is to follow my &lt;a href="http://github.com/vidarh/writing-a-compiler-in-ruby/tree/master"&gt;Github commits&lt;/a&gt;, or my &lt;a href="http://twitter.com/vhokstad"&gt;Twitter feed&lt;/a&gt;.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=AF1AekXSLTQ:0TJaVBY1-C4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=AF1AekXSLTQ:0TJaVBY1-C4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=AF1AekXSLTQ:0TJaVBY1-C4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=AF1AekXSLTQ:0TJaVBY1-C4:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=AF1AekXSLTQ:0TJaVBY1-C4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=AF1AekXSLTQ:0TJaVBY1-C4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=AF1AekXSLTQ:0TJaVBY1-C4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=AF1AekXSLTQ:0TJaVBY1-C4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=AF1AekXSLTQ:0TJaVBY1-C4:iYEzUNWTmVE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=iYEzUNWTmVE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=AF1AekXSLTQ:0TJaVBY1-C4:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=AF1AekXSLTQ:0TJaVBY1-C4:Jnkt3q6G96E"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=AF1AekXSLTQ:0TJaVBY1-C4:Jnkt3q6G96E" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VidarHokstad/~4/AF1AekXSLTQ" height="1" width="1"/&gt;</description>
      <category>vacation</category>
      <category> family</category>
      <category> isle of wight</category>
      <category> new forest</category>
      <pubDate>Wed, 19 Aug 2009 20:03:19 -0400</pubDate>
      <dc:date>2009-08-19T20:03:19-04:00</dc:date>
    <feedburner:origLink>http://www.hokstad.com/vacation-over.html</feedburner:origLink></item>
    <item>
      <title>Proof of concept SVG editor gadget for Google Wave</title>
      <link>http://feedproxy.google.com/~r/VidarHokstad/~3/nPz_wh3eudM/svg-editor-gadget-for-google-wave.html</link>
      <description>A couple of days ago I presented a "emulator" of sorts to run Google Wave gadgets without sandbox access because Google hadn't started giving out access yet. They have now, to Google IO attendees at least but not to the rest of us (or have they?) so I still don't have mine (&lt;strong&gt;&lt;em&gt;hint, hint&lt;/em&gt;&lt;/strong&gt;)&lt;br&gt;&lt;br&gt;Anyway, what good would it do to write that gadget emulator without using it, so I've put together a very rough proof of concept for a shared graphics editor gadget using SVG. I didn't write all of it myself, mind you. Jayesh Salvi started a discussion about SVG in Wave, and during that discussion he pointed us to an existing &lt;a href="http://code.google.com/p/svg-edit/"&gt;open source browser based SVG editor&lt;/a&gt; by &lt;a href="http://narendra.techfandu.org/"&gt;Narendra Sisodiya&lt;/a&gt; and &lt;a href="http://stick.gk2.sk/blog/2009/06/svg-edit-a-web-based-svg-editor/"&gt;Pavol Rusnak&lt;/a&gt;.&lt;br&gt;&lt;br&gt;&lt;img  src="/static/images/svgedit.jpg" class="selected            " align="left" alt="" style="padding-right: 20px; padding-top: 10px; padding-bottom: 10px;"&gt;That made my job reasonably easy. I chopped their editor to pieces and stripped out a lot of stuff, partially to reduce the amount of work to make it work with Wave, partially to remove features that aren't quite finished yet.&lt;br&gt;&lt;br&gt;The result is still buggy (clearing the canvas doesn't work; deletion is shaky), not as efficient as it could be (at the moment it re-sends all attributes of modified elements instead of just the changed ones, but that's easily fixed), lacks lots of features (like moving objects, saving, loading external SVG's etc.).&amp;nbsp;&lt;br&gt;&lt;br&gt;More importantly, &lt;strong&gt;since I don't have sandbox access it has not been tested with the actually Google Wave client (hint, hint; any Google people reading this?)&lt;/strong&gt;&amp;nbsp;It is possible or even likely that it won't work in the real client, but any issues should be reasonable simple to fix.&lt;br&gt;&lt;br&gt;It's been tested - somewhat - on Firefox and Safari. It is highly unlikely to work on Internet Explorer (it's possible it could work if you have an SVG plugin installed, but I doubt it). It could be made to work on IE via a shim layer to use VML instead of SVG, but that's not very high on my priority list at the moment - especially as &lt;a href="http://www.theregister.co.uk/2009/06/03/google_svg_internet_explorer/"&gt;Google looks set to introduce a suitable shim layer&lt;/a&gt;.&lt;br&gt;&lt;br&gt;You can test it now by &lt;a href="/static/wave/gadgets.html" target="_blank"&gt;going to my gadget emulator&lt;/a&gt;, and entering the filename "svg-edit.xml".&lt;br&gt;&lt;br&gt;If you want to experiment with the code on your own, get the latest version of my gadget emulator&lt;a href="http://github.com/vidarh/wave-gadget-emulator/tree/master"&gt; from the Github repository&lt;/a&gt; and the &lt;a href="http://github.com/vidarh/wave-gadget-svg-editor/tree/master"&gt;SVG editor gadget also from Github&lt;/a&gt;.&lt;br&gt;&lt;br&gt;Not that while I welcome patches / suggestions, this is a proof of concept and I'm not sure how far I'll take it - I also have not talked to Narendra or Pavol about whether it's possible or desirable to fold any of the (fairly extensive) changes I made back into the original editor. If you'd like to see this turn into something more, let me hear about it in the comments.&lt;br&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; I will be working with the SVG Edit guys to combined the two projects. Also see &lt;a href="http://thenextweb.com/2009/06/05/experience-worlds-google-wave-svg-editor-gadget/"&gt;this post at The Next Web&lt;/a&gt;&lt;br&gt;&lt;br&gt;(&lt;em&gt;And if you're with the Google Wave team and want to give me sandbox access, e-mail me at vidar@hokstad.com or vidar.hokstad@gmail.com - I promise I'll use it to make sure this gadget runs properly in the actual client ;) &lt;/em&gt;)&lt;br&gt;&lt;span style="font-family: -webkit-monospace" size="3;"&gt;&lt;span style="border-collapse: collapse; font-size: 12px; line-height: normal; white-space: pre; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px;"&gt;&lt;span style="font-family: arial" size="3;"&gt;&lt;span style="border-collapse: separate; font-size: 13px; line-height: 15px; white-space: normal; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: arial" size="3;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: arial" size="3;"&gt;&lt;/span&gt;&lt;span style="font-family: -webkit-monospace" size="3;"&gt;&lt;span style="border-collapse: collapse; font-size: 12px; line-height: normal; white-space: pre; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=nPz_wh3eudM:o0pe3h1Ve4g:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=nPz_wh3eudM:o0pe3h1Ve4g:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=nPz_wh3eudM:o0pe3h1Ve4g:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=nPz_wh3eudM:o0pe3h1Ve4g:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=nPz_wh3eudM:o0pe3h1Ve4g:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=nPz_wh3eudM:o0pe3h1Ve4g:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=nPz_wh3eudM:o0pe3h1Ve4g:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=nPz_wh3eudM:o0pe3h1Ve4g:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=nPz_wh3eudM:o0pe3h1Ve4g:iYEzUNWTmVE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=iYEzUNWTmVE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=nPz_wh3eudM:o0pe3h1Ve4g:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=nPz_wh3eudM:o0pe3h1Ve4g:Jnkt3q6G96E"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=nPz_wh3eudM:o0pe3h1Ve4g:Jnkt3q6G96E" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VidarHokstad/~4/nPz_wh3eudM" height="1" width="1"/&gt;</description>
      <category>google wave</category>
      <category>gadgets</category>
      <category> wave gadget</category>
      <category> svg</category>
      <category> svg editor</category>
      <category> hacks</category>
      <pubDate>Fri, 05 Jun 2009 07:14:17 -0400</pubDate>
      <dc:date>2009-06-05T07:14:17-04:00</dc:date>
    <feedburner:origLink>http://www.hokstad.com/svg-editor-gadget-for-google-wave.html</feedburner:origLink></item>
    <item>
      <title>Google Wave Gadget Emulator</title>
      <link>http://feedproxy.google.com/~r/VidarHokstad/~3/jyNmgOze4SA/google-wave-gadget-emulator.html</link>
      <description>&lt;img  src="http://www.hokstad.com/static/wave/samplegadgets-small.png" align="right" style="padding: 20px;" alt=""&gt;The &lt;a href="http://wave.google.com/"&gt;Google Wave&lt;/a&gt; demo contained a variety of "gadgets" - small little apps written in Javascript that interacts with Wave.&lt;br&gt;&lt;br&gt;It's one of the more interesting parts of the frontend, allowing you to customize the experience, and make the interaction with other users more structured (the pic to the right, borrowed from the &lt;a href="http://code.google.com/apis/wave/extensions/gadgets/guide.html"&gt;Google Wave gadget API guide&lt;/a&gt;&amp;nbsp;for example, shows an event attendance gadget, a chess gadget and a maps gadget.&lt;br&gt;&lt;br&gt;Cool. But since I don't have sandbox access, and even with sandbox access might like to be able to instrument and debug things in different ways than Google has prepared for, and since it seemed like a good educational exercise in figuring out the gadget API's, I decided to take matters in my own hands.&lt;br&gt;&lt;br&gt;So I wrote a Google Wave Gadget API emulation layer. Just a tiny little bit of javascript to reimplement just barely enough of the gadget API to allow some of the demo gadgets to run side by side in two iframes. It's very rough around the edge, not very cleanly written, probably full of bugs, and only tested on Safari and Firefox, but here's an example:&lt;br&gt;&lt;br&gt;&lt;img  src="/static/wave/magnets.jpg" style="display: block; " align="center" alt=""&gt;&lt;br&gt;But it's more intesting to &lt;a href="http://www.hokstad.com/static/wave/gadgets.html"&gt;play with it yourself here&lt;/a&gt;.&lt;br&gt;&lt;br&gt;If you find bugs, have comments, or want to add features to it, post in the comments here, or go over to &lt;a href="http://github.com/vidarh/wave-gadget-emulator/tree/master"&gt;Github where I've put the files you need&lt;/a&gt;. On top of the files in the Github repository you can find Gadget examples from the Gadget API guide posted above - you need to drop them somewhere on the same domain for jQuery to get hold of it.&lt;br&gt;&lt;br&gt;The Github repository is here:&amp;nbsp;&lt;a href="http://github.com/vidarh/wave-gadget-emulator/tree/master"&gt;http://github.com/vidarh/wave-gadget-emulator/tree/master&lt;/a&gt;&lt;br&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=jyNmgOze4SA:6lUcrNZAC3g:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=jyNmgOze4SA:6lUcrNZAC3g:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=jyNmgOze4SA:6lUcrNZAC3g:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=jyNmgOze4SA:6lUcrNZAC3g:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=jyNmgOze4SA:6lUcrNZAC3g:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=jyNmgOze4SA:6lUcrNZAC3g:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=jyNmgOze4SA:6lUcrNZAC3g:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=jyNmgOze4SA:6lUcrNZAC3g:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=jyNmgOze4SA:6lUcrNZAC3g:iYEzUNWTmVE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=iYEzUNWTmVE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=jyNmgOze4SA:6lUcrNZAC3g:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=jyNmgOze4SA:6lUcrNZAC3g:Jnkt3q6G96E"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=jyNmgOze4SA:6lUcrNZAC3g:Jnkt3q6G96E" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VidarHokstad/~4/jyNmgOze4SA" height="1" width="1"/&gt;</description>
      <category>google wave</category>
      <category> wave</category>
      <category> gadgets</category>
      <category> javascript</category>
      <category> emulation</category>
      <category> example</category>
      <pubDate>Mon, 01 Jun 2009 19:31:18 -0400</pubDate>
      <dc:date>2009-06-01T19:31:18-04:00</dc:date>
    <feedburner:origLink>http://www.hokstad.com/google-wave-gadget-emulator.html</feedburner:origLink></item>
    <item>
      <title>Google Wave as infrastructure</title>
      <link>http://feedproxy.google.com/~r/VidarHokstad/~3/ElG79J4CeUU/google-wave-as-infrastructure.html</link>
      <description>&lt;br&gt;&lt;h2&gt;It's new but not new&lt;/h2&gt;All of the things in the Wave demo are possible without Wave. The interesting thing about Wave is not so much the application, but the infrastructure, the protocol and the underlying concepts. Many limited collaboration apps have offered various subsets of the Wave functionality, for example, and the superficial functionality can be built using existing technology, without fancy new protocols and clients etc.&lt;br&gt;&lt;br&gt;&lt;strong&gt;But that's missing the point. Wave is interesting because the infrastructure makes it extremely open-ended.&amp;nbsp;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;A lot of people have been comparing Wave to e-mail. That's missing the point too. Wave has the potential to be as important as the Web. I'm serious. Wave is taking the web and making it interactive, embeddable, recordable, and shareable on a whole different level than what we are used to. And like most great "revolutionary" ideas it doesn't actually add all that much new:&amp;nbsp;&lt;br&gt;&lt;br&gt;When the web arrived, hypertext systems were well known (and most of them were far more advanced than early web browsers), for example. What the web gave us was two simple innovations: A simple system for letting anyone create content, and an addressing scheme and protocol that allowed the content to be distributed world wide. But that existed - sort of - too before the web, in the form of Gopher. The web was a very tiny evolutionary step in many ways, but they were "just the right ones": The web was more chaotic and unstructured and open-ended than gopher (which was more of a distributed catalog of files), and with a number of ideas that spurred people on to extend it in all kinds of weird and wonderful ways.&lt;br&gt;&lt;br&gt;Wave could be similar. We have IM. We have e-mail. We have document sharing over the web. We have the web. All of the functionality of Wave can be achieved with existing technology. You can chat with your friends. You can share content. You can run shared whiteboard apps that you could interface apps to.&lt;br&gt;&lt;br&gt;But it's not all seamlessly integrated. That is the one deceptively small evolutionary step that Wave provides, that could very well be a big game changer. Especially since Wave does it in a very simple way.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;h2&gt;It's built on XMPP&lt;/h2&gt;That means:&lt;br&gt;&lt;ul&gt;



&lt;li&gt;&lt;span&gt;It leverages a huge amount of existing infrastructure&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;It's federated by default (see below).&lt;/li&gt;
&lt;li&gt;A lot of the underlying protocol is well understood by a lot of people&lt;/li&gt;
&lt;/ul&gt;
&lt;br&gt;&lt;h2&gt;It's federated&lt;/h2&gt;Jabber / Google Talk / XMPP is powerful because anyone can set up their own server, and Google has promised the same will be the case for Google Wave - it only makes sense anyway since XMPP is built ground up to be a federated protocol, with support for server-to-server connections etc.&lt;br&gt;&lt;br&gt;Federation allows you to set up your own server, and so act as gatekeeper to information that is critical to you, and so makes Google Wave palatable as an intranet tool as much as an external tool - in fact, barring issues with how the clients are built there's no reason why an intranet user could not start a public wave (on a public server) for an open discussion and then break away a private sub-wave on the intranet wave server - all in the same session - to discuss with his/her co-workers.&amp;nbsp;&lt;br&gt;&lt;br&gt;This makes Wave a potentially pretty amazing collaboration tool for situations where you may have multiple parties with information of both public and private nature who wants to share different subsets with different parties. Systems like Basecamp allows this today (you can add other companies and users from those companies to your Basecamp setup, and control their access to your information) but it is fairly static and limited to the specific feature-set of Basecamp, while in Wave it is a feature of the infrastructure and completely orthogonal to the functionality the various users employ.&lt;br&gt;&lt;br&gt;In fact, nothing stops users from granting access to their own, internal, Wave-enabled apps, on a user by user basis as part of collaboration (or as a general service):&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;h2&gt;It's extensible&lt;/h2&gt;Imagine a booking agent (at any type of business: restaurants, airlines etc.) that answers live questions. Lots of companies do that now. But instead of just talking to you, the agent shares a booking form with you, and help you fill it in, live, while answering questions.&lt;br&gt;&lt;br&gt;Or someone at your bank walks you through mortgage deals, and shows you a mortgage calculator, fills in details to illustrate the deals they are presenting, and show you graphs of your repayment schedule in real-time.&lt;br&gt;&lt;br&gt;Because the Wave protocol allows both sides to push relatively arbitrary content, and update it realtime, you can use it to run presentations; to edit documents together; to fill in forms together that is then updated live by automated remote services.&lt;br&gt;&lt;br&gt;Consider it a sort of "remote terminal" you can run applications in. Only it's shared. And graphical. And has built in playback.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;h2&gt;It's persistent&lt;/h2&gt;The Wave server is responsible for maintaining a persistent store of the waves. Depending on your wave server there may be different policies for how long they persist, but due to the openness of the protocol, there's plenty of opportunity for archiving waves in ways that provides a record the way e-mail does. Providing search and retrieval functionality for local waves is possible, and the architecture allows searching either at "point-in-time" or building search functionality that would let you search in past states of your waves.&amp;nbsp;&lt;br&gt;&lt;br&gt;I.e. your client or your local wave server could either snapshot waves at specific times, or maintain a complete record of the wave operations and then let you find that mention of doughnuts in the kitchen that some greedy co-worker deleted seconds later.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;h2&gt;It can be "gatewayed"&lt;/h2&gt;Many of the more exciting uses of Wave allowed by the open architecture is that you can create two-way gateways for all sorts of content using it. Nothing is preventing you from building wave support into your new spreadsheet app, for example, so you can click a button to share the spreadsheet, or a graph from it, or whatever, with other people and have them help you edit it,and comment on it. Or you can share your word processor document in a phone conference and people can add their own comments. Or you could export your blog entries, and have people use Wave to add or read comments from your web page. Or Wikipedia could export every page as a wave so those obnoxiously formatted "talk" pages could instead consist of people adding comments "inline" to the actual text. Or you could turn it into an IRC client. Or Facebook could turn the walls into waves and let people read/post to their wall via wave (though given facebooks past behavior in banning people who post too many updates, perhaps not).&lt;br&gt;&lt;br&gt;Google itself has a suite of apps that could be exported as waves: Docs/Spreadsheets, Gmail, Picasa, Calendar etc. - imagine starting a wave, pulling in a document, adding your pics from Picasa, dragging in the calendar and creating an event, and turning it all into a nicely formatted event invitation e-mail that is gatewayed out via normal e-mail to your friends and family (or made available as a wave to those who use it), complete with nice pictures from the place you're inviting them too, the price list from Docs, a calendar invite etc.&lt;br&gt;&lt;br&gt;&lt;h2&gt;It's encrypted by default&lt;/h2&gt;Encryption by default makes it a lot easier sell as a collaboration tool also internally in businesses, or even in many cases as a replacement for e-mail or other channels that are insecure by default and takes conscious actions to secure.&lt;br&gt;&lt;br&gt;&lt;h2&gt;It's client independent&lt;/h2&gt;While Google obviously has a head start, and while extensions may (or may not?) be client dependent, nothing stops other parties from building Wave clients that add new capabilities. The underlying protocol is really simple - it uses XMPP for federation and layers a thing layer of maintaining shared XML documents and serializing multi-party updates to that document to all participants. How the client (or the server) interprets that document is up to the client (or the server).&amp;nbsp;&lt;br&gt;&lt;br&gt;Some ways to use this: "Load" snapshots of waves into your word processor when you've finished collaboratively editing it, and finish cleaning it up (your word processor could be a wave client); open a wave in Finder / Explorer and drag images from the wave somewhere else (or open the wave in Photoshop and pick an image to edit). All of course assuming the various app gets wave support.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=ElG79J4CeUU:DeuEUVCE_HE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=ElG79J4CeUU:DeuEUVCE_HE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=ElG79J4CeUU:DeuEUVCE_HE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=ElG79J4CeUU:DeuEUVCE_HE:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=ElG79J4CeUU:DeuEUVCE_HE:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=ElG79J4CeUU:DeuEUVCE_HE:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=ElG79J4CeUU:DeuEUVCE_HE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=ElG79J4CeUU:DeuEUVCE_HE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=ElG79J4CeUU:DeuEUVCE_HE:iYEzUNWTmVE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=iYEzUNWTmVE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=ElG79J4CeUU:DeuEUVCE_HE:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=ElG79J4CeUU:DeuEUVCE_HE:Jnkt3q6G96E"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=ElG79J4CeUU:DeuEUVCE_HE:Jnkt3q6G96E" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VidarHokstad/~4/ElG79J4CeUU" height="1" width="1"/&gt;</description>
      <category>google wave</category>
      <category> wave</category>
      <category> xmpp</category>
      <category> infrastructure</category>
      <category> opinion</category>
      <pubDate>Sat, 30 May 2009 21:44:40 -0400</pubDate>
      <dc:date>2009-05-30T21:44:40-04:00</dc:date>
    <feedburner:origLink>http://www.hokstad.com/google-wave-as-infrastructure.html</feedburner:origLink></item>
    <item>
      <title>All my known ancestors</title>
      <link>http://feedproxy.google.com/~r/VidarHokstad/~3/itXoj50TkFM/all-my-known-ancestors.html</link>
      <description>Toying with my script from the previous post... Not limiting the number of generations, and processing it with neato instead of dot (still from &lt;a href="http://www.graphviz.org/"&gt;Graphviz&lt;/a&gt;) gives this cool diagram... I haven't tried removing overlaps. I also have some changes to allow including siblings (the diagram below includes only direct ancestors). Posting it mostly because it looks neat, and it illustrates pretty well how exponential growth quickly makes family trees unwieldly. Our family database contains &lt;strong&gt;thousands&lt;/strong&gt; of people not in the diagram below - siblings of everyone there, as well as the spouses and descendants of siblings, and for the most part this stretches "only" back to the early 1700's, with a few spindly arms going back to about 1480:&lt;br&gt;&lt;br&gt;&lt;a href="/static/images/slekt/vidar-neato-40.jpg" target="_blank"&gt;&lt;img  src="/static/images/slekt/vidar-neato-10.jpg" style="padding-left: 50px" align="center" alt=""&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;(Click for a somewhat larger version -- I haven't posted a full size one as it's HUGE; maybe when I've cleaned it up a bit more)&lt;br&gt;&lt;br&gt;When I've had time to do some more cleanups I'll probably post a more recent iteration of the script I'm using.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=itXoj50TkFM:RJ9vIjlzB4c:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=itXoj50TkFM:RJ9vIjlzB4c:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=itXoj50TkFM:RJ9vIjlzB4c:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=itXoj50TkFM:RJ9vIjlzB4c:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=itXoj50TkFM:RJ9vIjlzB4c:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=itXoj50TkFM:RJ9vIjlzB4c:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=itXoj50TkFM:RJ9vIjlzB4c:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=itXoj50TkFM:RJ9vIjlzB4c:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=itXoj50TkFM:RJ9vIjlzB4c:iYEzUNWTmVE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=iYEzUNWTmVE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=itXoj50TkFM:RJ9vIjlzB4c:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=itXoj50TkFM:RJ9vIjlzB4c:Jnkt3q6G96E"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=itXoj50TkFM:RJ9vIjlzB4c:Jnkt3q6G96E" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VidarHokstad/~4/itXoj50TkFM" height="1" width="1"/&gt;</description>
      <category>genealogy</category>
      <category> family</category>
      <category> graphviz</category>
      <category> family tree</category>
      <category> hokstad</category>
      <pubDate>Thu, 28 May 2009 21:24:31 -0400</pubDate>
      <dc:date>2009-05-28T21:24:31-04:00</dc:date>
    <feedburner:origLink>http://www.hokstad.com/all-my-known-ancestors.html</feedburner:origLink></item>
    <item>
      <title>Family tree using Graphviz and Ruby</title>
      <link>http://feedproxy.google.com/~r/VidarHokstad/~3/DjuoD60SMJg/family-tree-using-graphviz-and-ruby.html</link>
      <description>My dad spent a lot of time putting together a family database, currently containing about 12000 people covering both my parents ancestors as well as tracking forward to contain a lot of living descendants. Unfortunately, since he started this over 16-17 years ago it's been managed as a custom dBase III+ app, and the code grew by accretion over at least 7 years (until my father died). Spurred on by an e-mail from a possible distant relative (who it turns out I've even met) I finally dumped the dbf files into an Sqlite database and put together a few scripts to generate diagrams from it.&lt;br&gt;&lt;br&gt;Here's an example (click to enlarge). The birth/death dates are in Norwegian format (day.month.year)&lt;br&gt;&lt;br&gt;&lt;a href="http://www.hokstad.com/static/images/slekt/olemartin.jpg" target="_blank"&gt;&lt;img  src="/static/images/slekt/olemartin-small.jpg" title="Ancestors of Ole Martin Hokstad" alt="Ancestors of Ole Martin Hokstad"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;The full SVG diagram (which is zoomable in Safari and Firefox) is&amp;nbsp;&lt;a href="http://www.hokstad.com/static/images/slekt/olemartin.svg"&gt;&lt;/a&gt;&lt;a&gt;&lt;/a&gt;&lt;a href="http://www.hokstad.com/static/images/slekt/olemartin.svg"&gt;here&lt;/a&gt;.&lt;br&gt;&lt;br&gt;This tree shows the known ancestors of Ole Martin Hokstad - the first person amongst my direct ancestors to be born to the Hokstad name (there are one or two other families where the name Hokstad was taken at different times). In our case the name stems from the Hogstad farms in Frosta, near Trondheim, Norway. The farms kept being divided as a result of children inheriting parts etc..&amp;nbsp;&lt;br&gt;At one point the farm Lille-Hogstad was bought by Ola Viktil, and one of his grandsons, Peter Magnus Hokstad Johansen combined two smaller properties to Hogstad Lille Vestre in 1854, which was then renamed Hokstad (presumably he didn't like the thought of the name Peter Magnus Hogstad Lille Vestre Johansen). His children, including my great-grandfather Ole Martin Hokstad, got the name by birth.&lt;br&gt;&lt;br&gt;The tree above doesn't show any siblings, and leaves out a few people we don't have any certain information about. I did render one of all my know ancestors as well, but it's too huge to be practical to reproduce here (about 20 times the size of the tree above).&lt;br&gt;&lt;br&gt;To produce this I put together a very quick and dirty little Ruby script:&lt;br&gt;&lt;br&gt;
&lt;pre class="ruby"&gt;require 'model'
require 'set'

id = ARGV[0].to_i

# Prevent double inclusion of a node                                                                                                                       
$memo = Set.new

def filter_node(per)
  return nil if !per
  return nil if per.firstname.strip == "?" || 
         per.lastname.strip == "?" || 
         per.maidenname.strip == "?"
  return per
end

def node (per,color)
  return false if $memo.member?(per.pk)
  $memo &amp;lt;&amp;lt; per.pk
  name = [per.firstname, per.middlename, 
                per.lastname, 
                per.maidenname]
  name = name.collect do |n| n &amp;&amp;amp; n != "" ? n : nil }.compact.join(" ")
  label = "#{name}\n#{per.birthdate} - #{per.deathdate}"
  puts "   p#{per.pk}  [ shape = box, style=\"filled\","+
          " fillcolor=\"#{color.to_s}\", label=\"#{label}\" ];"
  return true
end

def ancestors per

  father = filter_node(per.father)
  mother = filter_node(per.mother)

  pk = per.pk
  arrowhead = "normal"
  if mother and father
    merge = "m#{mother.pk}and#{father.pk}"
    if !$memo.member?(merge)
      puts " p#{merge} [ shape = point ]"
      puts " p#{merge} -&gt; p#{pk} [ arrowtail=none ]"
      arrowhead = "none"
    else
      $memo &amp;lt;&amp;lt; merge
    end
    pk = merge
  end

  if father
    if node(father,:green)
      puts "   p#{father.pk} -&gt; p#{pk} [ arrowhead=#{arrowhead} ]"
      ancestors(father)
    end
  end

  if mother
    if node(mother,:gold)
      puts "   p#{mother.pk} -&gt; p#{pk} [ arrowhead=#{arrowhead} ]"
      ancestors(mother)
    end
  end
end


def graph per
  puts "digraph ancestors {"
  node(per,:red)
  ancestors(per)
  puts "}"
end

per = Person[:id =&gt; id]
if !per
  puts "Unable to find #{id}"
  exit
end

graph(per)

&lt;/pre&gt;I'm not going to spend a lot of time going through the script, other than to point out the dependencies if you want to try this for yourself:&lt;br&gt;&lt;br&gt;You need to create a class with the methods #pk that returns a unique key suitable to be part of a&amp;nbsp;&lt;a href="http://www.graphviz.org/"&gt;&lt;span style="color: #000000; "&gt;&lt;/span&gt;&lt;/a&gt;&lt;a&gt;&lt;/a&gt;&lt;a&gt;&lt;span style="color: #000000; "&gt;&lt;/span&gt;&lt;/a&gt;&lt;a&gt;&lt;/a&gt;&lt;a&gt;Graphviz&lt;/a&gt; dot-file node name, #father and #mother that returns an equivalent object for the father and mother respectively or nil if not known, and methods #firstname, #middlename, #lastname and #maidenname respectively that returns the names as strings. Whether it comes from a database or not is irrelevant - you can load it all into memory first if you like. In my case it's all from a&amp;nbsp;&lt;a&gt;&lt;/a&gt;&lt;a&gt;&lt;/a&gt;&lt;a&gt;Sequel&lt;/a&gt; model, as you can see I retrieve a Person object for the id provided as the root of the tree at the end of the script.&amp;nbsp;&lt;br&gt;I don't think I'll put in much effort to make this a generic package, but it should be easy enough to adapt if you know some Ruby. I will probably post a couple of variations to add output of siblings and also to generate an equivalent one for descendants instead of ancestors though.&lt;br&gt;&lt;br&gt;I then use this little bash script to generate the SVG file (requires xsltproc)&lt;br&gt;&lt;br&gt;
&lt;pre class="code"&gt;#!/bin/sh

ruby ancestors.rb $1 &gt;/tmp/$1.dot
dot -Tsvg /tmp/$1.dot &gt;/tmp/$1.svg
xsltproc /opt/diagram-tools/notugly.xsl /tmp/$1.svg &gt;$2
&lt;/pre&gt;This assumes my&amp;nbsp;&lt;a href="http://github.com/vidarh/diagram-tools/tree/master"&gt;&lt;/a&gt;&lt;a&gt;&lt;/a&gt;&lt;a href="http://github.com/vidarh/diagram-tools/tree/master"&gt;diagram-tools GIT repository&lt;/a&gt; has been cloned into /opt/diagram-tools (git clone&amp;nbsp;git://github.com/vidarh/diagram-tools.git /opt/diagram-tools), to pretty up the Graphviz output.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=DjuoD60SMJg:c0YXG8KhMUU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=DjuoD60SMJg:c0YXG8KhMUU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=DjuoD60SMJg:c0YXG8KhMUU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=DjuoD60SMJg:c0YXG8KhMUU:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=DjuoD60SMJg:c0YXG8KhMUU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=DjuoD60SMJg:c0YXG8KhMUU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=DjuoD60SMJg:c0YXG8KhMUU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=DjuoD60SMJg:c0YXG8KhMUU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=DjuoD60SMJg:c0YXG8KhMUU:iYEzUNWTmVE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=iYEzUNWTmVE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=DjuoD60SMJg:c0YXG8KhMUU:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=DjuoD60SMJg:c0YXG8KhMUU:Jnkt3q6G96E"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=DjuoD60SMJg:c0YXG8KhMUU:Jnkt3q6G96E" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VidarHokstad/~4/DjuoD60SMJg" height="1" width="1"/&gt;</description>
      <category>genealogy</category>
      <category> family</category>
      <category> graphviz</category>
      <category> ruby</category>
      <category> howto</category>
      <category> family tree</category>
      <pubDate>Sat, 23 May 2009 12:04:36 -0400</pubDate>
      <dc:date>2009-05-23T12:04:36-04:00</dc:date>
    <feedburner:origLink>http://www.hokstad.com/family-tree-using-graphviz-and-ruby.html</feedburner:origLink></item>
    <item>
      <title>Making Graphviz output pretty with XSL - Updated</title>
      <link>http://feedproxy.google.com/~r/VidarHokstad/~3/kcznrZTH22Q/making-graphviz-output-pretty-with-xsl-updated.html</link>
      <description>Over a year ago I posted an &lt;a href="http://www.hokstad.com/making-graphviz-output-pretty-with-xsl.html"&gt;XSL file for prettying up &lt;/a&gt;&lt;span&gt;&lt;a&gt;Graphviz&lt;/a&gt;&lt;/span&gt;&lt;a&gt; diagrams&lt;/a&gt;.&amp;nbsp;&lt;br&gt;&lt;br&gt;I got lots of feedback, and recently I've been fixing various bugs, and I finally got around to adding support for more of the Graphviz node shapes etc.&lt;br&gt;&lt;br&gt;Here's an example of various node types and colors with the new version. Note that while rounder corners are "sort of" working, I haven't found a good way of making the gradient fill work nicely with it. The current version has been tested with Graphviz 2.20.2.&lt;br&gt;&lt;br&gt;

&lt;embed src="/static/images/notugly/may09.svg" type="image/svg+xml" pluginspage="http://www.adobe.com/svg/viewer/install/" style="width: 630px; height: 280px;"&gt;

&lt;br&gt;(Scaled down a bit to fit my layout; if you can't see it you need a browser that can embed SVG's, such as any recent Firefox or Safari)&lt;br&gt;&lt;br&gt;&lt;br&gt;The XSL file can be found with various other Graphviz related tools at my &lt;a href="http://github.com/vidarh/diagram-tools/tree/master"&gt;diagram tools repository on GitHub&lt;/a&gt;&lt;br&gt;&lt;br&gt;This is a fairly substantial set of changes, so please do let me know if you find any bugs (if so, I appreciate an example dot-file as well as the Graphviz XSL output and the "cleaned" XSL output, and the version number of the Graphviz version you're using - please try to upgrade to at least 2.20.2, though).&lt;br&gt;&lt;br&gt;&lt;strong&gt;Thanks to Jonas Tingeborn, Earl Cummings and Kevin Keraudren for various bug fixes and help debugging. Thanks to Michael Kennedy for posting&amp;nbsp;&lt;/strong&gt;&lt;a href="http://s3.digitalfort.com/posts/notugly-full.xsl"&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="color: #000000; "&gt;&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;a&gt;&lt;/a&gt;&lt;/span&gt;&lt;a&gt;&lt;strong&gt;a variation with lots of gradients&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; (I've pilfered a smallish subset for my updated version - but you can copy the rest from his version if you prefer)&lt;/strong&gt;&lt;br&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=kcznrZTH22Q:K7fKu0fNZ4k:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=kcznrZTH22Q:K7fKu0fNZ4k:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=kcznrZTH22Q:K7fKu0fNZ4k:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=kcznrZTH22Q:K7fKu0fNZ4k:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=kcznrZTH22Q:K7fKu0fNZ4k:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=kcznrZTH22Q:K7fKu0fNZ4k:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=kcznrZTH22Q:K7fKu0fNZ4k:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=kcznrZTH22Q:K7fKu0fNZ4k:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=kcznrZTH22Q:K7fKu0fNZ4k:iYEzUNWTmVE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=iYEzUNWTmVE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=kcznrZTH22Q:K7fKu0fNZ4k:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=kcznrZTH22Q:K7fKu0fNZ4k:Jnkt3q6G96E"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=kcznrZTH22Q:K7fKu0fNZ4k:Jnkt3q6G96E" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VidarHokstad/~4/kcznrZTH22Q" height="1" width="1"/&gt;</description>
      <category>graphviz</category>
      <category> diagrams</category>
      <category> diagram tools</category>
      <category> graphics</category>
      <category> xsl</category>
      <pubDate>Mon, 18 May 2009 18:54:22 -0400</pubDate>
      <dc:date>2009-05-18T18:54:22-04:00</dc:date>
    <feedburner:origLink>http://www.hokstad.com/making-graphviz-output-pretty-with-xsl-updated.html</feedburner:origLink></item>
    <item>
      <title>I love throwing out code</title>
      <link>http://feedproxy.google.com/~r/VidarHokstad/~3/nB4SJDv05jA/i-love-throwing-out-code.html</link>
      <description>... it usually means putting something cleaner and smaller back in. I'm much happier when I've cut code from an app than when I've added it - adding code is easy; removing code is like a game of &lt;a href="http://en.wikipedia.org/wiki/Jenga"&gt;Jenga&lt;/a&gt;, trying to see how much I can remove without making everything tumbling down (not that I aim to go to the brink, mind you).&lt;br&gt;&lt;br&gt;Just started thinking about that because I just ripped out lots of CSS (thanks to &lt;a href="http://www.blueprintcss.org/"&gt;Blueprint&lt;/a&gt;) and a good chunk of code from my blog - hopefully it looks nicer at least. I've also replaced my homegrown comment system with &lt;a href="http://www.disqus.com/"&gt;Disqus&lt;/a&gt;. I've kept the old comment system for now. If (when) I decide Disqus works well enough I'll migrate the old comments and tear that out too.&lt;br&gt;&lt;br&gt;If you come across something that is broken (this was a quick and dirty spur of the moment thing, sans unit tests...) please let me know.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=nB4SJDv05jA:46K219nwqVQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=nB4SJDv05jA:46K219nwqVQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=nB4SJDv05jA:46K219nwqVQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=nB4SJDv05jA:46K219nwqVQ:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=nB4SJDv05jA:46K219nwqVQ:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=nB4SJDv05jA:46K219nwqVQ:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=nB4SJDv05jA:46K219nwqVQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=nB4SJDv05jA:46K219nwqVQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=nB4SJDv05jA:46K219nwqVQ:iYEzUNWTmVE"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=iYEzUNWTmVE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=nB4SJDv05jA:46K219nwqVQ:I9og5sOYxJI"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?d=I9og5sOYxJI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/VidarHokstad?a=nB4SJDv05jA:46K219nwqVQ:Jnkt3q6G96E"&gt;&lt;img src="http://feeds.feedburner.com/~ff/VidarHokstad?i=nB4SJDv05jA:46K219nwqVQ:Jnkt3q6G96E" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/VidarHokstad/~4/nB4SJDv05jA" height="1" width="1"/&gt;</description>
      <category>meta</category>
      <category> blog</category>
      <category> disqus</category>
      <pubDate>Thu, 14 May 2009 20:24:50 -0400</pubDate>
      <dc:date>2009-05-14T20:24:50-04:00</dc:date>
    <feedburner:origLink>http://www.hokstad.com/i-love-throwing-out-code.html</feedburner:origLink></item>
    <dc:date>2009-11-05T08:05:14-05:00</dc:date>
  </channel>
</rss>
