(picture)

July 31, 2002

SmartMobs

WashingtonPost article covering Howard Rheingold's SmartMobs.

In some cases, even the goal is determined collaboratively and non-hierarchically. It is the warp-speed embodiment of Gandhi's maxim, "There go my people, I must run to catch up with them for I am their leader."
Looks good. I do like Howard. This might be the book to persuade me to get a cellphone after many years of passive resistance...

ElementQueue

Here's a useful construct for Groove tool developers, especially when working with third-party ActiveX controls for UI. The ElementQueue is really easy to use, but I'll preface this with some chat about MVC and threading to give an example of where I needed it. I'm sure you'll have other applications.

In the MVC (model-view-controller) structure, your tool will receive events from the model when its dataset changes - locally (because you did something at the UI, usually) or remotely (because another member in the space triggered a data change, which was disseminated to your device). Typically, you'll install some listeners in your controller (UI gluecode) to process these events when they happen, and change the current state of the UI to reflect the new information.

When your UI is built with an ActiveX control, you can hit threading issues. This is especially important where your ActiveX control is a facade onto a single-process application (ie. the control silently loads a full application in background): I've seen this with Acrobat and MapPoint. The pipe between "controller" and "view" might need to play nice.

Groove runs a single thread for UI, and several background threads for everything else. So when Dynamics processes commands for an Engine (your Model), that's always on one of the background worker threads. The engine then fires a COM event, to which your controller code (in the UI thread) is listening. Groove proxies the event onto the UI thread for your gluecode to pick up. Then you handle the event, by talking to your user interface. Like this (JavaScript):

function PropertyList_OnPropertyChanged( sName, pValue, bRemote )
{
switch( sPropertyName )
{
case "something":
MyUIControl.DoStuff( sName, pValue );
}
}

Let's say that your UI is an ActiveX control, and it's busy right now. It won't be able to process your call to its .DoStuff() method (or whatever), and the default behaviour in these circumstances seems to be: die disgracefully. So we really want to queue the event until a later time when we know the UI has settled down.

For this, I use an "idle handler" (although you could easily use a timer instead). By registering as an idle handler, you have a function be called whenever the Groove UI thread has some spare time - this seems to be roughly every 20 milliseconds. The idle handler is a great place to perform occasional UI update, by reading from a queue of work-to-do. So let's set up an idle handler:


<SCRIPT>
var g_IdleManagerCookie = 0;

function Initialize()
{
// Register as an idle handler.
var pIdleManager = GrooveScriptFunctions.CreateNewObject( "Groove.IdleManager" );
var pIdleHandler = ScriptHostComponent.GetScriptDispatch( "[IGrooveIdleHandler]" );
g_IdleManagerCookie = pIdleManager.AddHandler( pIdleHandler );
}
function Terminate()
{
if( g_IdleManagerCookie )
{
var pIdleManager = GrooveScriptFunctions.CreateNewObject( "Groove.IdleManager" );
pIdleManager.RemoveHandler( g_IdleManagerCookie );
g_IdleManagerCookie = 0;
}
}
</SCRIPT>

<SCRIPTINTERFACE IIDName="IGrooveIdleHandler"
IID="{2ACCD3C1-9C5A-11d3-80CC-00500487878E}"
LIBID="{4253A641-5FA3-11d2-98C2-0080C7E30BA4}">
function OnIdle( nIdleCount )
{
HandleQueuedCommands();
}
</SCRIPTINTERFACE>

Now to set up an event queue, and a HandleQueuedCommands() function to dequeue work items.

Groove's ElementQueue API is just that: a FIFO queue of XML elements (children of a parent XML element; in this case, a temporary element created just to hold the queue). You can enqueue arbitrary pieces of XML, and dequeue them later. Since the payload is just XML, it's easy to wrap an event and its parameters into an element for the queue. You might want to queue many different types of command; just use elements with different names. It's not necessary to declare a formal schema for these elements, but naming them sensibly helps keep your code readable.

So, in Initialize(),


// Make a temporary element queue for handling changed records
g_pSM = GrooveScriptFunctions.CreateNewObject("Groove.StorageManager");
var pElQueue = g_pSM.CreateTemporaryElement( "urn:mynamespace.com:MyCommandQueue" );
pElQueue.SetDeleteOnRelease( true );
g_pLocalQueue = pElQueue.OpenElementQueue();

When you want to enqueue something - for example, an event called from your datamodel - just wrap it into an element and place it in the queue:


function SomeObject_OnUpdate( EventParam1, EventParam2 )
{
var pEl = g_pSM.CreateTemporaryElement( "urn:mynamespace.com:MyQueueElement" );
pEl.SetAttributeAsDouble( "Param1", EventParam1 );
pEl.SetAttributeAsDouble( "Param2", EventParam2 );
g_pLocalQueue.Enqueue( pEl );
}

Then, when the UI is idle, look at the queue and handle any commands which we see there. You'll get the best performance if you process the whole queue in the idle handler (rather than just handling one queued command at a time).


function HandleQueuedCommands()
{
if( !IsTheUIReady() ) return; // we'll just do it later!
var pEnum = g_pLocalQueue.DequeueEnum();
while( pEnum.HasMore() )
HandleQueuedCommand( pEnum.OpenNext() );
}

function HandleQueuedCommand( pElement )
{
if( pElement.OpenName()=="urn:mynamespace.com:MyQueueElement" )
{
var sParam1 = pEl.OpenAttribute( "Param1" );
var sParam2 = pEl.OpenAttribute( "Param2" );
MyActiveXControl.DoStuff( sParam1, sParam2 );
}
}

To recap:


  • Create a temporary element to hold a queue of "command" elements which we'll process when we have time
  • Register an IdleHandler to process the queue when the UI is idle (or just use a timer, if you like)
  • When events happen to your controller, wrap them up as an XML element and enqueue them
  • OnIdle, dequeue and handle any waiting commands.

Of course there are several other ways to use an element queue. The queue could be persisted, or even disseminated (on an element in a PropertyList, for example) - that could be a nice foundation for a distributed-processing application.

July 27, 2002

butterfly.net

butterfly.net is a "grid" server system for MMG. Nice. Dedicated NPC servers too. I wonder how they handle the data distribution and migration issues?

It could still all go

It could still all go horribly wrong. But I doubt it.

July 15, 2002

Non-blog

Eberhard Lutz

In the course of the last few weeks I felt that something had gone wrong with it: it began to feel like a burden to provide new content... I got bored of publishing links like: Look, Ma, a new link, found it all of my own!

Push

JD Lasica, May 1997:

We're now on the cusp of a one-to-one "narrowcasting" network where each of us is able to summon up a finely tuned menu of choices: your favorite Boston Globe sports columnist; the New York Times' op-ed page; the latest golf news; and Dave Barry's latest musings...
Isn't is strange: in the "push" bubble, all the talk was of how this changed delivery options for Big Media, but most missed the real game: in reducing the cost of publication to zero, "narrowcasting" means your daily news choices come from a million opinionated webloggers, and you can be one of them too.

July 12, 2002

David Gurteen

Another good weblog: David Gurteen. David's catalysing lots of activity around knowledge management. His newsletter is also worth subscribing to.

Mike Helfrich

Mike Helfrich, VP of "Applied Technology" at Groove (in other words, he takes some responsibility for getting people to use our stuff effectively), has a weblog! Way to go!

July 11, 2002

klogs vs. mailing lists

On the klogs mailing list, John Garside asks

What advantages do klogs have over lists such as (an
ad-free) yahoogroups and the like?
This is a surprisingly difficult question, and I'm choosing to write some rambling answers here rather than on-list because they might veer off topic (this itself is part of the answer, of course: lists tend to be topic-specific, but blogs/klogs are usually person-specific). It's somewhat easier to answer than a parallel question "klogs or newsgroups?" which might be raised.

A few dimensions of difference:


  • Categorisation. Making an effective taxonomy, at any point in time, is incredibly difficult. Maintaining an effective taxonomy over time is at least as hard. If you want to use mailing lists for knowledge logging, there's an implied setup cost in thinking a little about taxonomy before you begin, and there's always an "activity cost" in thinking about the correct place to write. On the other hand, blogs setup cost is per-person, not per-topic, and the categorisation is much more fluid. This reduces the "activation cost" in documenting your activities.
  • Purpose. Much use of mailing lists is for Q&A-type interaction, in a similar way to many effective uses of Notes/Domino and Web discussion forums. This is very different from the "k-logging" purpose of simply documenting, interrelating, and raising issues of concern. K-logs also fit extremely well with Groove shared spaces: blogging for documentation, Groove for joint action.
  • Interrelatedness. The blogging world is very fast evolving some powerful ways of linking, relating and bringing together of topics and people: RSS, blogroll lists, "trackback" (emdedded RDF referents in topics), aggregators and publishing tools. Mailing lists sometimes (depending on your mail-reader software) to a reasonable job of threading, but more often than not, even this is broken.

It's worth reiterating the fundamentals in common, too. Knowledge Management 101: "write it down". Documenting your immediate activity in a relevant place is valuable. It helps others find what you're talking about (now or later). It helps the author clarify - I've found this myself many times, that simply writing about current work is a very helpful context-switch, and forces you to continuously re-evaluate its structure and goals.

Microsoft/Groove

From the Groove Webinar, a PowerPoint presentation with some good descriptions of where Groove fits in to various modes of collaboration. This .ppt deck also includes some screenshots of existing MS/Groove technology links: the Outlook on-ramp, Word co-editing, Microsoft Project import/export, Messenger integration, and SharePoint Portal.

This last hasn't been de-geeked yet -- you can see all the portal metadata, with PROP_DAV_stuff, which means nothing to me -- but looks promising. (It's running on a server called BORG - this means nothing, but note that "Starfleet personnel are to maintain the utmost caution when encountering the Borg".)

July 10, 2002

Identities

Jon Udell has a good column about using the security features of email.

You can assert the validity and integrity of your messages, but no-one expects you to. You can automatically acquire public keys from others who sign their message, but no-one does so. Having acquired those keys you can encrypt messages to those people, but again, they don't expect you to do so.

The problem with the S/MIME suite of email security features is that they tackle problems people pay lip service to, but don't really care much about. A problem that people do care about, though, is spam. Do we care enough to assert our identities, and thus enable software to separate us from abusers who will not?

Great, thoughtful stuff. It's a pity this is such hard work!

If you'll excuse me banging on about the virtues of Groove [again]... it fixes this stuff. As many people have pointed out, Groove's solution is to create a new infrastructure, with some proprietary protocols and software -- of course in many ways the spam issue goes away if you make a walled garden. I'd like to address those things too.

Let's separate this into: transport, identity assertion, and openness.

Groove messages -- IMs and shared-space synchronisation -- are always strongly encrypted. They're also signed, meaning that you can always provably verify their authenticity. Crucially, you don't get a choice in this: it's all-crypto-all-the-time. User indifference, the biggest factor in the lousy take-up of strong crypto, is completely ignored.

Identity assertion -- the subject of Jon's piece -- is more tricky, and here I think we have a great set of solutions. In the beginning, anyone can create an identity (from scratch, with no certifier). That identity has a name, address (vcard) and some keys. Everything you do is signed and sealed with that identity's keys: your identity is always asserted, even if it's not certified. To other users you just appear as "John Doe", but anyone can authenticate your identity for their own purposes: once I know you're the real "John Doe", I can tell Groove that the real John Doe should always show me a "yes it's really him" icon authentication icon by his name. Even if the name changes, the keys remain intact. You can give John Doe an alias for your own use (say, "John from Dorking") without breaking the strong authentication.
Organisations can also certify users' identities. So my vcard says "Hugh Pyle/Groove", and this identity is certified by Groove Networks (my employer). I don't need to make any effort to authenticate other people from the same organisation: they get a "yes, it's really him" icon authentication icon because we share a certificate.
Organisations can also cross-certify. So Gavin's user-icon always shows a "yes, Gavin's employer says it's really him, and we trust Gavin's employer" icon authentication icon.

This begins to look interesting. Organisational certifiers, cross-certifiers, and full-on strong identities all the time. So we can automatically separate correspondents into several groups: members of my organisation, members of other organisations known to me, people I've authenticated myself, and don't-know-you-from-Adam.

Comms outage

Yesterday I had a complete comms outage: first the Net flaked out, then the phones went dead. The net connection came back up a couple of times during the day, but still with massive packet loss. This morning the network is back although the phones are still out.

Being held incommunicado, I learnt something about my dependency on these systems. Most of our software sucks.

My critical tasks for yesterday involved opening a VPN connection to the USA, transferring some files to a network share there, downloading a 25+mb installer, and accessing my build machine by VNC. Completely, completely impossible. The VPN connected (but died every few minutes). I spent an hour copying a half-dozen files across the network: several retries for each. VNC just wouldn't go.

July 09, 2002

Tech support

I'm seeing 60% packet loss to the first router.

"Hello, BTOpenWorld technical support. Can you tell me your ADSL phone number please?"
"0118 979 1517"
"Thank you. Can you tell me the answer to your security question?"
"What's the question?"
"Sorry, we can't tell you that...."

Doh. And it'll take up to 48 hours for an engineer to open the trouble ticket ("because, you know, Oftel and all that.")

July 08, 2002

TalOS

Taligent TalOS, aka Pink (1996):

TalOS was unique in its architecture... The end user experience revolved around a compound document-centric, multi-user networked, direct manipulation interface with infinite session undo. The principal interface theme was People, Places and Things. The networked interface represented remote users, as well as collaborative work spaces. In many ways it was more a graphic MOO than an traditional operating system.

Groupthink

January 1998, an almost unreadable archive:

Amy says, "some of the most interesting work in this area is the book Connections by Sproull and Kiesler. They found that real time chat helps more people be heard and lessons the dominance of higher-ranking participants, but also leads to disorganization and longer time to reach decisions"
...
Mr.Zoliparia says, "The 'water cooler' is one end of a spectrum of how teams work together: informal, colocated. Formal, distributed hierarchy is another end. Having just read Lipnack&Stamps "Virtual Teams" book I'm convinced that the business world is waking up to the *value* of fluid groupthink."

July 05, 2002

Dynamics, rollback and rollforward

An ugly hack has been preying on my mind since I wrote, about the tour,

If a transaction "from the past" arrives, the database will unwind, then roll forward again after applying the new transaction... To catch any "futurity", I wrap a GUID inside each event, and maintain a reasonably-sized table of already-handled events.
I knew that was ugly (and stupid and wasteful) when I wrote the code, too. There really had to be a way to ask Dynamics whether it's currently rolling back or forward, or processing commands for the first time.

There is, of course. It's in Dynamics, and I only stumbled across it this morning whilst debugging something else, so now I applied it onto the tourcode too. This improves performance, reduces the memory footprint (no need for a stupid hashtable now), reduces network traffic (no need for a GUID on the event elements), and improves reliability too. Whenever you want to track state dynamically in a Groove tool, you should know about this.

The interface to look at is IGrooveCommandContext2; this is accessible by a property on IGrooveDynamicsManager. So you can get this in Script by

	var pDynMgr = PropertyList.OpenProperty(PROPERTY_DYNAMICS_MANAGER);
var pContext = pDynMgr.CommandContext;

then look at the properties on this interface, which tell you more than you ever needed to know. The RollbackRollforward property is true if this is part of a rollback or rollforward.

Two Towers

New trailer - looks good. (via Dylan).

Meanwhile, I'd better start on the main task: hacking up satyagraha mods for the Armygame...

July 04, 2002

Audiomulch

Audiomulch (cool app, shareware) - new build available for download.

July 03, 2002

Digestive Biscuits

I'm sure this is not an economic proposition: homemade digestive biscuits. But they taste good, they're fun to make, and it's about the easiest recipe I know. Tonight we had a problem with the oatmeal, though: only porridge oats left in the cupboard, and in a fit of "can't transport this electrical stuff" we gave away the whizzing mixer thing last week. So, after ten minutes trying to push oats through a sieve...

Quantities are whatever you like. 1 = 100g or 4oz, for a good plateful.

1: oatmeal
1: wholemeal flour
1: butter
1/2: caster sugar
Mix like pastry (rub in the butter with your fingers). Add a tiny bit of cold water to help it stick together. Roll thin (3mm, 1/4"). Circles. Bake 15mins in a hottish oven (200 degrees or so) - make sure they don't go dark brown!. Cool on a wire rack. Eat.

Groove Tour: index

Recap: five pieces of not-very-deep doc.


Is this useful? Any big questions raised? Say so.

If you've not run the tour yet, it's here.

Groove Tour: UI

Finally, I think this is the home stretch. The tour has a user interface, and it's very simple, and it's HTML.

Why HTML?...

Well, if I needed something really flexible (especially for interactive work), I'd build custom UI. But the tour's display-UI requirements were: look good, and be easy to edit. The "easy to edit" might have been better served with RTF (which is well supported by Groove's TOM-based richedit control), but plugging in tables and pictures would have been harder. So, HTML.

Thus the main UI of the tour tool is just a Web browser (Groove's browser component, which is a wrapper around IE). There's a template-page on the local disk, which loads some JavaScript helpers and some CSS style. Then, at runtime,

  • the script moves into a stage;
  • code in the script's default PreInitialize handler grabs the contents of a resource attached to the current stage (usually from a CDATA section, since this is raw HTML not XML);
  • this is pre-processed (some variable substitution), and squirted into the main DIV in the webpage.

Bingo.

The "variable substitution" piece is useful: it understands a range of embedded references. These include

  • Propertynames, to be replaced with the property's value;
  • Resource names, to be replaced with the value of the named resource on the current stage element (so you effectively can do nested "#include" in the HTML, if you want);
  • Pseudo-hyperlink: references to Groove objects (tools, files in a docshare tool, etc) which turn into clickable hyperlinks to navigate you to the destination;
  • Inclusion: references to files in a Groove fileshare tool, which turn into the "thing itself" (for example, to reference .JPG or .SWF files which were loaded into the space at runtime, and which you want to appear inline at the tour's user interface).

I've used this sort of "HTML inside Groove" view in quite a few tools now. It still takes a non-trivial amount of development effort (to build the template page, script helpers etc), but if you need a clean, flexible, not-very-interactive UI it's definitely the way to go.

July 01, 2002

Structured code-containers

Following from the tour discussion, I want to ramble awhile about "structured code-containers", as I think it's an interesting perspective.

Mostly any software system (of any size) is a framework for stringing together pieces of code. The DOS/Windows filesystem and PATH is a framework for finding and launching executables (albeit a fairly uninteresting one). At another extreme, Web Services with WDSL and UDDI is a decentralised framework for having different pieces of code - hosted in different places - execute when different events happen. OO programming in general puts code into a containment structure which

  • controls "scope" via namespace (so you can see where your code lives, and manage the scope of its effects)
  • provides an event system (to pass control to different pieces of the code in a known sequence, and other forms of inter-object communication).
Where these containment structures are interpreted rather than compiled, the framework is extremely open: it's editable by an end-user. So, to take a few examples: Radio Userland (script code in an outliner); LambdaMOO (code in a multi-user object database); Lotus Notes (macro or script code attached to objects in a replicated database); Unix shell (and that #!/usr/bin/executable directive); Groove Forms (script code attached to form objects).
Groove Tour was designed to be that, too.

The core of Groove is pretty open - and very very flexible - from the same viewpoint. There's an optional "text/binary phase boundary" so you can wrap compiled code behind any COM interface, but you can also write code in script (and most Groove tools are script). The first-level container is an XML document (a tool template, typically). The next-level container is an XML database (the templates storage, or the shared-space storage, or the account storage).

So, this is another thing in common between all these interesting systems: a deliberate commingling of code and data. Storing code in a database, and being able to manipulate that same database from code.

Tour: Dynamics and EIS

Part four of the Tour: I need to finish describing dynamics (started in part three), and get moving along to talk about the user interface (a later topic).

"Dynamics" is the name for Groove's transactional synchronisation stuff. This takes care of ensuring that commands for tools' engines are disseminated to each endpoint in a shared space, and processed in the right order. The result is that when you take a static view of a shared space, you're guaranteed to see a consistent state, and that this state will tend to be the same as the state on any other endpoint.

To freeze a shared space while you look at it (enumerating over records, for example), open a transaction (for read-only or read-write access): pTelespace.OpenTransaction(). When you commit() the transaction, any changes are applied and disseminated.

Looking at a dynamic view of the shared space (by listening to sequences of events from its engines), you'll see a more complex picture: if a transaction is interrupted halfway through processing and you open a "read" transaction to look at a snapshot, the database might need to unwind. If a transaction "from the past" arrives, the database will unwind, then roll forward again after applying the new transaction.

In the case of the tour, things could become difficult to track (were I using many transactions in the processing), but, it turns out, events pretty much arrive in the expected sequence. This is because I consciously minimised the number of "wrapped" transactions; generally, everything which happens is atomic and has no dependency to past or future events. So my propertylist listeners have an easy job. To catch any "futurity", I wrap a GUID inside each event, and maintain a reasonably-sized table of already-handled events. There's something to be said for belt-and-braces defensive programming, but in this case it turns out that's just overhead; it doesn't get used.

(It likely would, if the space ever had more than two members!)

In part two, I showed a couple of snippets of the tour script (the client script lives in groove/data/ToolData/groove.net/GrooveTour, if you care to dig in further). The script is a data-file containing structured code, which runs against events (That in itself is worth further discussion, sometime...!). Now, where do these events come from? They're wrappers around COM events fired by pieces of Groove (the EIS server, the workspace, the account, the telespace, or tools).

Much of the code at the server is simply providing nice, type-safe, script wrappers around these existing event services. In the tour, part of the ease-of-use comes from choosing an appropriate level for these wrappers; and part comes from providing a "tool" context object with each event, which immediately puts you in the right place. At the server script there's also always a "chat" object which provides an interface to the chat tool. In many ways (not least for debugging), chat is the commandline.