2009-06-05 11:14 UTC Proof of concept SVG editor gadget for Google Wave

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 (hint, hint)

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 open source browser based SVG editor by Narendra Sisodiya and Pavol Rusnak.

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.

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.). 

More importantly, 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?) It is possible or even likely that it won't work in the real client, but any issues should be reasonable simple to fix.

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 Google looks set to introduce a suitable shim layer.

You can test it now by going to my gadget emulator, and entering the filename "svg-edit.xml".

If you want to experiment with the code on your own, get the latest version of my gadget emulator from the Github repository and the SVG editor gadget also from Github.

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.
UPDATE: I will be working with the SVG Edit guys to combined the two projects. Also see this post at The Next Web

(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 ;) )



2009-06-01 23:31 UTC Google Wave Gadget Emulator

The Google Wave demo contained a variety of "gadgets" - small little apps written in Javascript that interacts with Wave.

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 Google Wave gadget API guide for example, shows an event attendance gadget, a chess gadget and a maps gadget.

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.

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:


But it's more intesting to play with it yourself here.

If you find bugs, have comments, or want to add features to it, post in the comments here, or go over to Github where I've put the files you need. 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.

The Github repository is here: http://github.com/vidarh/wave-gadget-emulator/tree/master


2009-05-31 01:44 UTC Google Wave as infrastructure


It's new but not new

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.

But that's missing the point. Wave is interesting because the infrastructure makes it extremely open-ended. 

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: 

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.

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.

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.


It's built on XMPP

That means:

  • It leverages a huge amount of existing infrastructure
  • It's federated by default (see below).
  • A lot of the underlying protocol is well understood by a lot of people

It's federated

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.

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. 

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.

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):


It's extensible

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.

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.

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.

Consider it a sort of "remote terminal" you can run applications in. Only it's shared. And graphical. And has built in playback.


It's persistent

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. 

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.


It can be "gatewayed"

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).

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.

It's encrypted by default

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.

It's client independent

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). 

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.




2009-05-29 01:24 UTC All my known ancestors

Toying with my script from the previous post... Not limiting the number of generations, and processing it with neato instead of dot (still from Graphviz) 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 thousands 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:




(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)

When I've had time to do some more cleanups I'll probably post a more recent iteration of the script I'm using.


2009-05-23 16:04 UTC Family tree using Graphviz and Ruby

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.

Here's an example (click to enlarge). The birth/death dates are in Norwegian format (day.month.year)

Ancestors of Ole Martin Hokstad

The full SVG diagram (which is zoomable in Safari and Firefox) is here.

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.. 
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.

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).

To produce this I put together a very quick and dirty little Ruby script:

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 << per.pk name = [per.firstname, per.middlename, per.lastname, per.maidenname] name = name.collect do |n| n && 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} -> p#{pk} [ arrowtail=none ]" arrowhead = "none" else $memo << merge end pk = merge end

if father if node(father,:green) puts " p#{father.pk} -> p#{pk} [ arrowhead=#{arrowhead} ]" ancestors(father) end end

if mother if node(mother,:gold) puts " p#{mother.pk} -> 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 => id] if !per puts "Unable to find #{id}" exit end

graph(per)

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:

You need to create a class with the methods #pk that returns a unique key suitable to be part of a Graphviz 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 Sequel 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. 
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.

I then use this little bash script to generate the SVG file (requires xsltproc)

#!/bin/sh

ruby ancestors.rb $1 >/tmp/$1.dot dot -Tsvg /tmp/$1.dot >/tmp/$1.svg xsltproc /opt/diagram-tools/notugly.xsl /tmp/$1.svg >$2

This assumes my diagram-tools GIT repository has been cloned into /opt/diagram-tools (git clone git://github.com/vidarh/diagram-tools.git /opt/diagram-tools), to pretty up the Graphviz output.





Older Entries

  • 2009-05-18 Making Graphviz output pretty with XSL - Updated
  • 2009-05-15 I love throwing out code
  • 2009-05-14 Is it wrong to try to make the Imperial March your babys first memory?
  • 2009-05-05 Writing a (Ruby) compiler in Ruby bottom up - step 20
  • 2009-05-03 Tristan Ikemefuna Hokstad
  • 2009-04-20 Updated Graphviz tools on Github
  • 2009-04-19 The problem with compiling Ruby
  • 2009-04-16 Writing a compiler in Ruby bottom up - Milestone: It can parse itself...
  • 2009-03-25 The Home Cloud
  • 2009-03-10 Writing a compiler in Ruby bottom up - step 19
  • 2009-03-02 The Ruby Object Model - Structure and Semantics
  • 2009-02-23 Writing a compiler in Ruby bottom up - step 18
  • 2009-02-21 Writing a compiler in Ruby bottom up - step 17
  • 2009-02-19 Sliding Stats: Rack Middleware to keep an eye on your traffic
  • 2009-02-17 Writing a compiler in Ruby bottom up - step 16
  • 2009-02-14 Writing a compiler in Ruby bottom up - step 15
  • 2009-02-12 Writing a compiler in Ruby bottom up - step 14
  • 2009-02-04 Simple charts in Ruby using SVG::Graph
  • 2009-02-01 Just added a github repository for my compiler series
  • 2009-02-01 Creating Graphviz graphs from Ruby arrays
  • 2009-01-26 Writing a compiler in Ruby bottom up - step 13
  • 2009-01-19 Operations is a development concern
  • 2008-12-08 A simple Operator Precedence parser
  • 2008-10-27 Writing a compiler in Ruby bottom up - step 12
  • 2008-09-29 Writing a compiler in Ruby bottom up - step 11
  • 2008-09-21 Still alive
  • 2008-07-10 Writing a compiler in Ruby bottom up - step 10
  • 2008-06-20 Hypno trip down the fractal rug - animated sierpinski in javascript
  • 2008-06-19 Writing a compiler in Ruby bottom up - step 9
  • 2008-06-11 5 simple ways to troubleshoot using Strace
  • 2008-06-01 Writing a compiler in Ruby bottom up - step 8
  • 2008-05-29 TraceViz: Visualizing traceroute output with graphivz
  • 2008-05-28 Inversions (Iain M. Banks)
  • 2008-05-24 OpenVZ and Apache troubleshooting: PRNG still contains insufficient entropy!
  • 2008-05-22 Reducing coupling through unit tests
  • 2008-05-21 Would you like to live in the Culture?
  • 2008-05-20 Confessions of a Commodore 64 remix addict
  • 2008-05-16 Writing a compiler in Ruby bottom up - step 7
  • 2008-05-15 How to beat comment spam (for now, anyway)
  • 2008-05-13 Giant balls of typeless source files
  • 2008-05-06 A brief introduction to Semantic Dictionary Encoding
  • 2008-05-06 Unholy: Converting Ruby 1.9 bytecode to Python bytecode
  • 2008-05-03 Writing a compiler in Ruby bottom up - step 6
  • 2008-05-01 How to sell and not sell a new programming language
  • 2008-04-30 Software ICs: Reuse should not always mean inheritance or configuration
  • 2008-04-29 When your Linux / iptables firewall randomly drops connections...
  • 2008-04-29 Customizing the Ruby syntax highlighter for x86 assembler
  • 2008-04-27 Writing a compiler in Ruby bottom up - step 5
  • 2008-04-24 Where tagging falls apart
  • 2008-04-17 Writing a compiler in Ruby bottom up - step 4
  • 2008-04-16 OpenVz, /proc/user_beancounters and tcpsndbuf
  • 2008-04-14 Rebuilding the build server on every build
  • 2008-04-12 Mini reviews of 19 Ruby template engines
  • 2008-04-11 Dealing with information overload
  • 2008-04-09 LDAP braindamage
  • 2008-04-08 Strawman for a new parser generator
  • 2008-04-07 So much for giving up the OOXML fight - Demonstration in Oslo
  • 2008-04-07 Joys of virtualization
  • 2008-04-06 Ur-Scheme: A tiny self-hosting Scheme to x86 asm compiler
  • 2008-04-05 - Why am I forced to optimize when choosing my language?
  • 2008-04-05 Writing a compiler in Ruby bottom up - step 3
  • 2008-04-04 Ken Livingstone and how to handle the press
  • 2008-04-02 More OOXML folly
  • 2008-03-31 OOXML: Ashamed of Standard Norge and insulting comments from Alex Brown
  • 2008-03-31 Making Graphviz output pretty with XSL
  • 2008-03-30 Cisco and Patent Troll Tracker
  • 2008-03-29 Latest referrers using Rack and Ruby
  • 2008-03-28 The OOXML circus is making ISO increasingly irrelevant
  • 2008-03-28 Why coupling is always bad / Cohesion vs. coupling
  • 2008-03-27 Writing a compiler in Ruby bottom up - step 2/??
  • 2008-03-26 Writing a compiler in Ruby bottom up - step 1/??
  • 2008-03-24 Model-View-Controller - the beginning
  • 2008-03-24 URLs do not belong in the Views
  • 2008-03-24 Trackback / comment spammers still at it...
  • 2008-03-24 Enforcing Strict Model-View Separation in Template Engines
  • 2008-03-23 Why Rails is total overkill and why I love Rack
  • 2008-03-23 Waking up to snow in late March....
  • 2008-03-22 Rack middleware: Adding cache headers
  • 2008-03-22 Web2.0 style logo reflection with Ruby and Cairo
  • 2008-03-22 Being a recovering startup employee tired of gambling
  • 2008-03-21 Using Sequel and Ruby to import the Geonames database
  • 2008-03-21 Shotgun: The Rubinius virtual machine and some musings on compiling Ruby
  • 2008-03-21 Draw a logo with gradients with Ruby and Cairo
  • 2008-03-20 Pet peeve: Exposing file extensions on the web
  • 2008-03-20 Sequel with Sqlite caveat: Sorting on dates
  • 2008-03-20 Sequel ORM: Right level of abstraction
  • 2008-03-20 Sundown With Arthur: Remembering Arthur C. Clarke
  • 2008-03-19 Simple drawing in Ruby with Cairo
  • 2008-03-19 Rewriting content types with Rack
  • 2008-03-19 Syntax highlighting in Ruby
  • 2008-03-18 The perils of shared testing and live sites...
  • 2008-03-18 Sequel praise and Sqlite type translation problems
  • 2008-03-17 My blog, version 2
  • About me

    E-mail: vidar@hokstad.com Skype: vhokstad
    Twitter: vhokstad
    View my LinkedIn profile.

    I was born April 21st, 1975, in Oslo, Norway. Since 2000 I've been living in London, UK. I'm married and we just had our first child, Tristan Ikemefuna Hokstad.

    I'm working for Aardvark Media as Director of Technology. I'm also currently on the board of SpatialQ, a startup in the GIS space, and an advisor to Skoach, a startup doing a time management app for people with ADD.

    Twitter Updates

      follow me on Twitter