Mothballing ZeeForge Blog

January 25, 2013

I’ve consolidated the material that was in ZeeForge back into the Zeetix sites and blog. I may relaunch ZeeForge someday (I still love the concept), but as of January 2013, it is inactive.

I’ve imported the everything, so the dates and headers have remained unchanged.


Great technology is necessary but not sufficient

January 24, 2013

Every one of the many startups I’ve worked with (and several of the major players) has had great technology. Only a handful have succeeded. Great technology is a necessary starting point. Every player in today’s technology world must have great technology. It is not nearly enough, however.

A successful startup needs a successful business model, a product, sales, legal services, accounting services, and so on. No one person can possibly do all these — a successful startup is always, therefore, a team effort.

I’m Tom Stambaugh. I love insanely great technology. I love coding. I also love succeeding. Zeetix is the corporate entity where I express these passions. This blog is one of the places where I look forward to speaking in a more first-person and informal way.

Welcome aboard!

Relaunch of

October 19, 2009

I’ve refactored and rewritten most of the site to reflect my focus on building a consulting/contracting revenue stream to sustain ZeeForge in this abysmal investment climate.

The entire site is built using Glooper, the website generator used for the Zeetix family of sites. As part of the relaunch, I added enhanced sidebar capability to Glooper. In addition, I’ve found a set of patterns for css that finally seem to work reliably and well for the sorts of multi-pane compositions that dominate the new ZeeForge look.

The new site also makes widespread use of a new (for me) approach to presenting, structuring, and handling browser forms to make it easier for users and visitors to request additional information. The new form handling capability is built around “Clacks”, a non-intrusive and relatively lightweight ZeeForge project that provides a convenient and object-oriented abstraction for browser/server exchanges. Clacks wraps XmlHttpRequest machinery in code that avoids several usability and reliability problems associated with more naive implementations.

For our new visitors, welcome to the ZeeForge blog. We encourage you to ask questions, leave comments and feedback, and visit often.

Ramping up on MoveableType

June 23, 2009

I’m in the process of refactoring ZeeForge as my portfolio, so that prospective clients can see how I work.

I’m using as a site from which I will host popular open-source services for users and visitors, including prospective clients.

The first service I’m adding is MoveableType, the famous Perl/PHP blog. I’ve been exercising it locally on my WinXP system, and over the next day or so I’ll deploy it onto the site. I’m using this entry to journal that process.

I found the initial installation on WinXP (using an apache webserver) to be relatively straightforward. I’ve had the usual collection of configuration and pre-requisite snafus, nothing too serious.

I note that the directory structure assumed by MT is a little different from my usual practice. In particular, it expects its resources to be unpacked into my standard “site_root” directory, peered with cgi-bin and public_html. Each new blog, when published, creates a directory in this site_root.

I’ve also had trouble locating a WinXP-compatible form of Image-Magick. I remember this problem from earlier perl thrashing, and I’ll get to it later.

My goal is to create a demo site (and url) where prospective clients who are interested in my ability to support blog services like moveabletype can see my work in-situ.

Refactor BuildDrawable for extensions

May 19, 2009

Every sender of ClassicBuildDrawable>>buildRightMarginFor: added an id attribute to the tag generated by the method. The new page-specific behavior needs to override this method to suppress the right margin.

Move the id attribute up to buildRightMarginFor:, then override buildRightMarginFor: in the new (special) builder.

Extend PageContainerSpecification protocol

May 19, 2009


A specific page in a Glooper site needs to be handled specially, with behavior provided by a new descendant.

Contemplated solution:

Add protocol that allows the new behavior to be supplied in a block, supplied by the descendant, that calls back to descendant code when the page is generated.


1. Create spike solution to validate that the approach works and settle on the required new method(s).
2. Add tests to GenericGlooperStructureTest to document new behavior.
3. Adjust spike solution as needed.
4. When PageContainer is working with new behavior, add code to the new site that uses it.

Catching up — Glooper history

May 14, 2009

I’ve been heads-down with Glooper since February, and it’s way better now.

It has tests (hooray), I’ve refactored it so that it will fit into the Zeetix (Hex?) world, and I’m now using it every day to update the Zeetix sites. I’ve published the first site out of the new Glooper chute — check it out at

As soon as I get a chance, I’ll add a post here describing the Glooper product/feature/assembly structure, including its test assemblies.

Glooper began as a website development tool I wrote in Smalltalk and called (for want of a better name) “SiteBuilder”. While SiteBuilder was cool and worked well enough for my needs a few years ago, it had several serious shortcomings that I needed to fix:

  1. One site at a time: SiteBuilder could only handle one site at a time. I maintain many, and many are related to each other. I needed to be able to make local changes locally (for leaves of the site hierarchy) and global changes globally (for shared nodes).
  2. Limited resource support: SiteBuilder did a poor job of handling resources like stylesheets, scripts, images, and so on that need to be present on the deployed sites. Many are shared, yet many are site-specific.
  3. Clumsy and error-prone configuration: SiteBuilder relied on reading and handling lots of outboard configuration files. Each ended up being copied to the leaves, and simple but global changes required error-prone hand-editing of each copy.

I’m sure there were more motivators, but those were the three big ones. I’ll post more entries here describing the changes I made.

More immediately, I’m now in the middle of Glooper’s next real test — an update to a site I built with its old version. I’ll be blogging my experiences here.

The site is for a real paying client (Ambiance Painting), an upscale painting company in Connecticut. The client wants to “spruce up” the site, add a blog, and include archived and current issues of a monthly newsletter distributed using ConstantContact.

Stay tuned!

Zeetix, Discworld, and Terry Pratchett

February 22, 2009

Like every similar framework, language, or environment, Zeetix needs LOTS of names. Lots of them are names for new concepts, and lots of them are names for things that are like other things but different in significant ways.

Zeetix draws on Terry Pratchett’s “Discworld” series in the same way that Python draws in Monty Python and Ruby draws on jewels and jewelry. If you haven’t read any Terry Pratchett, if you like British humor (especially if you like “Hitchhiker’s Guide”), fantasy (sort of), and satire, then you might like Terry Pratchett. Discworld is to fantasy what Hitchhiker’s Guide is to science fiction.

In addition to the novels themselves (as far as I know, all are in print and readily available), a multitude of online resources exist to inform your exploration of Discworld. I particularly like lspace.

Some immediate names that I’ll be using in Zeetix are “Glooper”, “Clacks”, and probably “Hex”. I encourage you to see “Glooper“, “Clacks“, and probably “Hex” for context.


I (Tom) did some early Zeetix development in Smalltalk (specifically, IBM Smalltalk). One early motivator was my desire to have a tool with which to build families of websites, where each website was represented as a directed graph of objects, instead of as a file hierarchy. I called this tool, for want of a better name, “SiteBuilder”. This was before RubyOnRails existed, and was mostly because I found myself frustrated with the limitations and learning curve of contemporary versions of Dreamweaver, Zope, Django, and so on.

I’m still using the Smalltalk “SiteBuilder” (on my own development PC), and I am acutely aware of the need to import it into the Zeetix framework. When I do so, it will be called “Glooper”.

I’ll write more about Glooper as I get time.


Zeetix will need to model and wrap the semantics of the internet and web. Zeetix will use “Clacks” (and variants of this theme) to name that stuff.


Underneath Zeetix is a universal virtual system. Really universal. Zeetix will use variants of “Hex” and to name related resources and assets.

Standards-compliant tool-tips

February 17, 2009

I know that everybody in the world but me already knew this, but I finally sorted out what appears to be a workable cross-browser way to do tooltips.

As it turns out, the major browsers display the contents of the “title” attribute as the tool-tip that appears on, for example, anchor tags. It turns out that IE also, and in apparent violation of the standard, uses the value of the “alt” attribute if the title attribute is missing.

For now, until I am convinced to the contrary, I’ll use the “alt” attribute of each img tag to describe the image for text-only browsers. I’ll use the “title” attribute to contain the tooltip contents (limiting it to 75 characters in deference to Firefox behavior).

Language-neutral sort block behavior

February 12, 2009

Developers frequently need to sort collections according to specific sort criteria.

A common and powerful idiom is to supply a two-argument block that, when evaluated with two elements from the collection, returns a value indicating the desired (sorted) order of the two elements. This “sortBlock” is applied to each of the elements in the collection (in some order), and the result is returned as the now-sorted collection.

So far, so good. The problem is in the semantics of how the sort block is applied, and in which order the elements of a given collection are passed to the sort block.


Smalltalk and Python use different semantics for the sort block, and apply the block in different sequences for the same initial collection.

In Smalltalk, a sortBlock is called with two elements (I’ll call them “arg1” and “arg2”), and is expected to return “true” if arg1 is to be inserted before arg2 and “false” otherwise. In Python, a sortBlock is called again called with two elements, and is expected to return -1 if arg1 is less than arg2, 0 if they are the same, and “1” if arg1 is greater than arg2.

Leaving aside, for the moment, the debate about which behavior is correct, the point is that they are different. The implication of this is that the developer is forced to think about and code for the specific language (in this case Smalltalk and Python) of a particular fragment of code.


The Zeetix solution is to encapsulate this semantic difference in the SortedCollection class itself, so that the programmer doesn’t have to think about it. The platform can, if desired, support the ability to choose whatever semantics are desired — and that choice is then automatically applied across the board, regardless of the current language binding.

Example Problem
Behavior, the (abstract) superclazz of Metaclazz and Clazz, provides a “subclazzes” method that answers a sorted collection containing the immediate subclazzes of the receiver, ordered according to their “symbol” (the name by which they are referenced in the ecology that contains them).

The Behavior.subclazzes method should answer a SortedCollection with two elements — Clazz and Metaclazz, in that order. Behavior clazz also has two subclazzes, Clazz clazz and Metaclazz clazz, in the same order.

The KernelTest.CoreTest.KernelCoreLoadsTest test case was failing testBehaviorLoads, because the SortedCollection instance returned by Behavior and BehaviorClazz was ordered incorrectly.

My inspection (in the debugger) of the failing test showed that the result was, in fact, an instance of SortedCollection and contained the correct objects. They were, however, in the wrong order. Clearly, SortedCollection was sorting incorrectly.
Read the rest of this entry »