Index: /trunk/Makefile.in
===================================================================
--- /trunk/Makefile.in	(revision 2079)
+++ /trunk/Makefile.in	(revision 2080)
@@ -35,5 +35,5 @@
 
 ifneq ($(ENABLE_GUI),)
-  TARGETS += gui lang lib instant examples 
+  TARGETS += gui lang lib builder examples 
 endif
 
Index: /trunk/builder/Makefile.in
===================================================================
--- /trunk/builder/Makefile.in	(revision 2080)
+++ /trunk/builder/Makefile.in	(revision 2080)
@@ -0,0 +1,64 @@
+
+SHELL		= @SHELL@
+
+srcdir		= @srcdir@
+prefix		= @prefix@
+exec_prefix	= @exec_prefix@
+bindir		= @bindir@
+libdir		= @libdir@
+datadir		= @datadir@
+datarootdir	= @datarootdir@
+mandir		= @mandir@
+includedir	= @includedir@
+
+pkgdatadir	= $(datadir)/$(PKG_DIR)
+pkglibdir	= $(libdir)/$(PKG_DIR)
+pkgincludedir	= $(includedir)/$(PKG_DIR)
+top_builddir	= .
+
+MKDIR_P		= @MKDIR_P@
+TCL_VERSION	= @TCL_VERSION@
+TCLSH           = $(bindir)/tclsh$(TCL_VERSION)
+INSTALL		= @INSTALL@
+
+FILES		= \
+		$(srcdir)/dragdrop.tcl \
+		$(srcdir)/filmstrip.tcl \
+		$(srcdir)/hierlist.tcl \
+		$(srcdir)/main.tcl \
+		$(srcdir)/objpath.tcl \
+		$(srcdir)/slideframes.tcl \
+		$(srcdir)/tweener.tcl
+
+IMAGEFILES	= \
+		$(srcdir)/images/drag.xbm \
+		$(srcdir)/images/dragm.xbm \
+		$(srcdir)/images/treemn.png \
+		$(srcdir)/images/treepl.png \
+		$(srcdir)/images/warn24.png \
+		$(srcdir)/images/err24.png
+
+PACKAGE_VERSION	= @PACKAGE_VERSION@
+
+version		= $(PACKAGE_VERSION)
+name		= RapptureBuilder$(version)
+
+destdir         = $(libdir)/$(name)
+
+all:
+
+install: install-pkg install-scripts
+
+install-pkg:
+	$(MKDIR_P) -m 0755 $(destdir)
+	$(INSTALL) -m 444 pkgIndex.tcl $(destdir)
+
+install-scripts: scripts
+	$(MAKE) -C scripts install
+
+clean:
+	$(RM) tool.xml
+
+distclean: clean
+	$(RM) Makefile *~
+
Index: /trunk/builder/dragdrop.tcl
===================================================================
--- /trunk/builder/dragdrop.tcl	(revision 2080)
+++ /trunk/builder/dragdrop.tcl	(revision 2080)
@@ -0,0 +1,245 @@
+# ----------------------------------------------------------------------
+#  COMPONENT: dragdrop - drag-n-drop support for widgets
+#
+#  Derived classes inherit the basic drag-n-drop support from this
+#  widget class.  Widgets can register themselves as drag-n-drop
+#  sources and also as targets.
+#
+#  Derived classes should overload the following methods:
+#
+#    dd_get_source .... examines click point and returns drag data
+#
+#    dd_scan_target ... scans target at drop point and returns 1 if
+#                         data is accepted, and 0 if rejected
+#
+#    dd_finalize ...... handles final drag-and-drop operation,
+#                         transferring data from the start widget
+#                         to the final target.  Called with "-op start"
+#                         on the starting widget, and "-op end" on the
+#                         target widget.
+#
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+package require Itcl
+
+itcl::class Rappture::Dragdrop {
+    public method dragdrop {option args}
+
+    private method _get_source {widget x y}
+    private method _do_scan {x y {option indicate}}
+    private method _do_drop {x y}
+
+    # derived classes override these methods
+    protected method dd_get_source {widget x y}
+    protected method dd_scan_target {x y data}
+    protected method dd_finalize {option args}
+
+    private variable _enabled 1      ;# set to 0 to disable drag-n-drop
+    private variable _dragwin ""     ;# widget controlling drag-n-drop cursor
+    private variable _dragowner ""   ;# mega-widget that initiated drag-n-drop
+    private variable _dragx ""       ;# drag-n-drop started at this x
+    private variable _dragy ""       ;# drag-n-drop started at this y
+    private variable _dragdata ""    ;# description of drag-n-drop source data
+    private variable _lastcursor ""  ;# cursor before start of drag-n-drop
+    private variable _lasttarget ""  ;# last target found by _do_scan
+
+    set dir [file dirname [info script]]
+    private common _dcursor "@[file join $dir images drag.xbm] [file join $dir images dragm.xbm] black white"
+}
+
+# ----------------------------------------------------------------------
+# USAGE: dragdrop protocol
+# USAGE: dragdrop enabled ?<boolean>?
+# USAGE: dragdrop source <widget>
+# USAGE: dragdrop indicate -from <w> -to <w> -x <x> -y <y> -data <data>
+# USAGE: dragdrop finalize -op <dir> -from <w> -to <w> -x <x> -y <y> -data <data>
+# USAGE: dragdrop cancel
+#
+# Derived classes use this to register component widgets as drag-n-drop
+# sources and targets.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Dragdrop::dragdrop {option args} {
+    switch -- $option {
+        protocol {
+            return "1.0"
+        }
+        enabled {
+            if {[llength $args] == 0} {
+                return $_enabled
+            } elseif {[llength $args] != 1} {
+                error "wrong # args: should be \"dragdrop enabled ?boolean?\""
+            }
+            set state [lindex $args 0]
+            set _enabled [expr {($state) ? 1 : 0}]
+            return $_enabled
+        }
+        source {
+            set widget [lindex $args 0]
+            bind $widget <ButtonPress> [itcl::code $this _get_source %W %X %Y]
+            bind $widget <B1-Motion> [itcl::code $this _do_scan %X %Y]
+            bind $widget <ButtonRelease> [itcl::code $this _do_drop %X %Y]
+        }
+        indicate {
+            array set params $args
+            return [dd_scan_target $params(-x) $params(-y) $params(-data)]
+        }
+        finalize {
+            return [eval dd_finalize drop $args]
+        }
+        cancel {
+            dd_finalize cancel
+        }
+        default {
+            error "bad option \"$option\": should be protocol, source, indicate, finalize, cancel"
+        }
+    }
+}
+
+# ----------------------------------------------------------------------
+# USAGE: _get_source <widget> <x> <y>
+#
+# Invoked when the user clicks on a widget to start a drag-n-drop
+# operation.  Saves the <x>,<y> coordinate, and waits for a _do_scan
+# call.  If the user drags the mouse a short distance away from the
+# click point, then the drag-n-drop operation begins.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Dragdrop::_get_source {widget x y} {
+    set _dragowner ""
+    set _lasttarget ""
+
+    set winx [expr {$x-[winfo rootx $widget]}]
+    set winy [expr {$y-[winfo rooty $widget]}]
+    set d [dd_get_source $widget $winx $winy]
+
+    if {"" != $d && $_enabled} {
+        set _dragwin $widget
+        set w $widget
+        while {$w != "."} {
+            if {[catch {$w dragdrop protocol}] == 0} {
+                set _dragowner $w
+                break
+            }
+            set w [winfo parent $w]
+        }
+        set _dragx $x
+        set _dragy $y
+        set _dragdata $d
+        set _lastcursor [$widget cget -cursor]
+        $widget configure -cursor $_dcursor
+    } else {
+        set _dragwin ""
+        set _dragowner ""
+        set _dragx ""
+        set _dragy ""
+        set _dragdata ""
+    }
+}
+
+# ----------------------------------------------------------------------
+# USAGE: _do_scan <x> <y> ?<operation>?
+#
+# Invoked as the user moves the mouse pointer during a drag-n-drop
+# operation.  Scans for a widget at the given <x>,<y> root window
+# coordinate that will accept the drag data.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Dragdrop::_do_scan {x y {option indicate}} {
+    if {"" != $_dragowner} {
+        set dx [expr {abs($x-$_dragx)}]
+        set dy [expr {abs($y-$_dragy)}]
+
+        # moved significantly away from click?
+        if {$dx > 3 || $dy > 3} {
+            set win [winfo containing $x $y]
+            if {"" != $win} {
+                set found 0
+                set wx [expr {$x-[winfo rootx $win]}]
+                set wy [expr {$y-[winfo rooty $win]}]
+                while {"." != $win} {
+                    # find the containing win that handles dragdrop and
+                    # accepts the given data type
+                    if {[catch {$win dragdrop $option -op end -from $_dragowner -to $win -x $wx -y $wy -data $_dragdata} result] == 0 && [string is boolean -strict $result] && $result} {
+                        if {"" != $_lasttarget && $_lasttarget != $win} {
+                            # if we had a different target, cancel it
+                            catch {$_lasttarget dragdrop cancel}
+                        }
+                        set _lasttarget $win
+                        set found 1
+
+                        # if this is a finalize operation, then send final
+                        # message to starting side
+                        if {$option == "finalize"} {
+                            catch {$_dragowner dragdrop finalize -op start -from $_dragowner -to $win -x $wx -y $wy -data $_dragdata}
+                        }
+                        break
+                    }
+                    set win [winfo parent $win]
+                }
+
+                if {!$found && "" != $_lasttarget} {
+                    # no drop target at this point? cancel any previous target
+                    catch {$_lasttarget dragdrop cancel}
+                    set _lasttarget ""
+                }
+            }
+        }
+    }
+}
+
+# ----------------------------------------------------------------------
+# USAGE: _do_drop <x> <y>
+#
+# Invoked when the user releases the mouse pointer during a drag-n-drop
+# operation.  Tries to send the drag data to the widget at the current
+# <x>,<y> root window coordinate to complete the operation.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Dragdrop::_do_drop {x y} {
+    if {"" != $_dragowner} {
+        _do_scan $x $y indicate
+        _do_scan $x $y finalize
+        $_dragwin configure -cursor $_lastcursor
+    }
+}
+
+# ----------------------------------------------------------------------
+# USAGE: dd_get_source <widget> <x> <y>
+#
+# Derived classes override this method to look at the given <widget>
+# and <x>,<y> coordinate and figure out what data value the source
+# is exporting.  Returns a string that identifies the type of the
+# data.  This string is passed along to targets via the dd_scan_target
+# method.  If the target may check the source type and reject the data.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Dragdrop::dd_get_source {widget x y} {
+    return "?"
+}
+
+# ----------------------------------------------------------------------
+# USAGE: dd_scan_target <x> <y> <data>
+#
+# Derived classes override this method to look within themselves at
+# the given <x>,<y> coordinate and decide whether or not it can
+# accept the <data> type at that location.  Returns 1 if the target
+# accepts the data, and 0 otherwise.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Dragdrop::dd_scan_target {x y data} {
+    return 0
+}
+
+# ----------------------------------------------------------------------
+# USAGE: dd_finalize drop -op start|end -from <w> -to <w> \
+#                           -x <x> -y <y> -data <data>
+# USAGE: dd_finalize cancel
+#
+# Derived classes override this method to handle the end of a drag
+# and drop operation.  The operation can be completed with a successful
+# drop of data, or cancelled.  Returns 1 if drop was successful, and
+# 0 otherwise.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Dragdrop::dd_finalize {option args} {
+    return 0
+}
Index: /trunk/builder/filmstrip.tcl
===================================================================
--- /trunk/builder/filmstrip.tcl	(revision 2080)
+++ /trunk/builder/filmstrip.tcl	(revision 2080)
@@ -0,0 +1,439 @@
+# ----------------------------------------------------------------------
+#  COMPONENT: filmstrip - palette of objects arranged horizontally
+#
+#  This widget is similar to the "film strip" view in windows.  It
+#  shows a horizontal arrangement of objects and lets you click on
+#  each one to initiate an action.
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+package require Itk
+
+option add *Filmstrip.padding 8 widgetDefault
+option add *Filmstrip.background #999999 widgetDefault
+option add *Filmstrip.troughColor #666666 widgetDefault
+option add *Filmstrip.activeBackground #d9d9d9 widgetDefault
+option add *Filmstrip.titleBackground #888888 widgetDefault
+option add *Filmstrip.titleForeground white widgetDefault
+option add *Filmstrip.font {helvetica -12} widgetDefault
+
+itcl::class Rappture::Filmstrip {
+    inherit itk::Widget Rappture::Dragdrop
+
+    itk_option define -orient orient Orient "horizontal"
+    itk_option define -length length Length 0
+    itk_option define -padding padding Padding 0
+    itk_option define -titlebackground titleBackground Background ""
+    itk_option define -titleforeground titleForeground Foreground ""
+    itk_option define -activebackground activeBackground Foreground ""
+    itk_option define -dragdropcommand dragDropCommand DragDropCommand ""
+
+    constructor {args} { # defined below }
+    public method add {name args}
+
+    protected method _hilite {state name}
+    protected method _fixLayout {args}
+    protected method _scroll {args}
+
+    # define these for drag-n-drop support of items
+    protected method dd_get_source {widget x y}
+    protected method dd_scan_target {x y data}
+    protected method dd_finalize {option args}
+
+    private variable _dispatcher ""  ;# dispatcher for !events
+    private variable _items ""       ;# list of item names
+    private variable _data           ;# maps item name => title, image, etc.
+}
+
+itk::usual Filmstrip {
+    keep -cursor -font -foreground -background
+}
+
+# ----------------------------------------------------------------------
+# CONSTRUCTOR
+# ----------------------------------------------------------------------
+itcl::body Rappture::Filmstrip::constructor {args} {
+    component hull configure -height 100
+    pack propagate $itk_component(hull) off
+
+    # create a dispatcher for events
+    Rappture::dispatcher _dispatcher
+    $_dispatcher register !layout
+    $_dispatcher dispatch $this !layout [itcl::code $this _fixLayout]
+
+    itk_component add strip {
+        canvas $itk_interior.strip -highlightthickness 0
+    } {
+        usual
+        keep -borderwidth -relief
+        ignore -highlightthickness -highlightbackground -highlightcolor
+    }
+    pack $itk_component(strip) -expand yes -fill both
+
+    # this widget exports nodes via drag-n-drop
+    dragdrop source $itk_component(strip)
+
+    itk_component add sbar {
+        scrollbar $itk_interior.sbar
+    }
+
+    eval itk_initialize $args
+}
+
+# ----------------------------------------------------------------------
+# USAGE: add <name> ?-title <string>? ?-image <handle>?
+#
+# Clients use this to add new items onto the film strip.  Each item
+# has an internal <name> that refers to it, along with an icon and
+# a title.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Filmstrip::add {name args} {
+    Rappture::getopts args params {
+        value -title ""
+        value -image ""
+    }
+    if {[llength $args] > 0} {
+        error "wrong # args: should be \"add name ?-option val -option val...?\""
+    }
+
+    set i [lsearch $_items $name]
+    if {$i >= 0} {
+        error "name \"$name\" already exists"
+    }
+    lappend _items $name
+    set _data($name-title) $params(-title)
+    set _data($name-image) $params(-image)
+    set _data($name-pos) 0
+
+    if {$itk_option(-orient) == "horizontal"} {
+        set anchor w
+        set whichsize wd
+    } else {
+        set anchor n
+        set whichsize ht
+    }
+
+    $itk_component(strip) create rectangle 0 0 0 0 \
+        -outline "" -fill "" -tags [list $name:all $name:bg]
+
+    set htmax 0
+    set sizemax 0
+    if {"" != $params(-image)} {
+        $itk_component(strip) create image 0 0 -anchor $anchor \
+            -image $params(-image) -tags [list $name:all $name:image]
+        foreach {x0 y0 x1 y1} [$itk_component(strip) bbox $name:image] break
+        set wd [expr {$x1-$x0}]
+        set ht [expr {$y1-$y0}]
+        set htmax $ht
+        set sizemax [set $whichsize]
+    }
+    if {"" != $params(-title)} {
+        $itk_component(strip) create placard 0 0 -anchor s \
+            -foreground $itk_option(-titleforeground) \
+            -background $itk_option(-titlebackground) \
+            -text $params(-title) -tags [list $name:all $name:title]
+        foreach {x0 y0 x1 y1} [$itk_component(strip) bbox $name:title] break
+        set wd [expr {$x1-$x0}]
+        set ht [expr {$y1-$y0}]
+        set htmax [expr {$htmax+$ht}]
+        set s [set $whichsize]
+        if {$s > $sizemax} {set sizemax $s}
+    }
+
+    $itk_component(strip) bind $name:all <Enter> \
+        [itcl::code $this _hilite on $name]
+    $itk_component(strip) bind $name:all <Leave> \
+        [itcl::code $this _hilite off $name]
+
+    # make sure we fix up the layout at some point
+    $_dispatcher event -idle !layout
+}
+
+# ----------------------------------------------------------------------
+# USAGE: _hilite <state> <name>
+#
+# Called automatically when the mouse pointer enters/leaves an icon
+# on the film strip.  Changes the background to highlight the option.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Filmstrip::_hilite {state name} {
+    if {$state} {
+        set bg $itk_option(-activebackground)
+    } else {
+        set bg ""
+    }
+    $itk_component(strip) itemconfigure $name:bg -fill $bg
+}
+
+# ----------------------------------------------------------------------
+# USAGE: _fixLayout ?<eventArgs>...?
+#
+# Used internally to realign all items vertically after new items
+# have been added to the strip.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Filmstrip::_fixLayout {args} {
+    if {$itk_option(-orient) == "horizontal"} {
+        # figure out the max height for overall strip
+        set xpos $itk_option(-padding)
+        set hmax 0
+        foreach name $_items {
+            foreach {x0 y0 x1 y1} [$itk_component(strip) bbox $name:image] break
+            set h1 [expr {$y1-$y0}]
+            set w [expr {$x1-$x0}]
+            foreach {x0 y0 x1 y1} [$itk_component(strip) bbox $name:title] break
+            set h2 [expr {$y1-$y0}]
+            set h [expr {$h1+$h2}]
+            if {$h > $hmax} { set hmax $h }
+
+            set _data($name-pos) $xpos
+            $itk_component(strip) coords $name:image $xpos 0
+            set xpos [expr {$xpos + $w + $itk_option(-padding)}]
+        }
+        set hmax [expr {$hmax+2*$itk_option(-padding)}]
+
+        set sbarh [winfo reqheight $itk_component(sbar)]
+        component hull configure -height [expr {$hmax+$sbarh}]
+
+        foreach name $_items {
+            foreach {x0 y0 x1 y1} [$itk_component(strip) bbox $name:image] break
+            set y0 $itk_option(-padding)
+            set y1 $hmax
+            set w [expr {$x1-$x0}]
+            $itk_component(strip) coords $name:bg $x0 $y0 $x1 $y1
+
+            foreach {x0 y0 x1 y1} [$itk_component(strip) bbox $name:title] break
+            set titleh [expr {$y1-$y0}]
+            set x [expr {$_data($name-pos) + $w/2}]
+            set y [expr {$hmax-$itk_option(-padding)}]
+            $itk_component(strip) coords $name:title $x $y
+
+            foreach {x y} [$itk_component(strip) coords $name:image] break
+            set y [expr {($hmax-$titleh)/2}]
+            $itk_component(strip) coords $name:image $x $y
+        }
+
+        # fix up the scrolling region to include all of these items
+        foreach {x0 y0 x1 y1} [$itk_component(strip) bbox all] break
+        set x1 [expr {$x1+$itk_option(-padding)}]
+        $itk_component(strip) configure -scrollregion [list 0 0 $x1 $y1]
+
+        set size [winfo pixels $itk_component(hull) $itk_option(-length)]
+        if {$size == 0} {
+            component hull configure -width [expr {$x1+$itk_option(-padding)}]
+        }
+
+    } else {
+        # figure out the max width for overall strip
+        set ypos $itk_option(-padding)
+        set wmax 0
+        foreach name $_items {
+            foreach {x0 y0 x1 y1} [$itk_component(strip) bbox $name:image] break
+            set w [expr {$x1-$x0}]
+            set ht [expr {$y1-$y0}]
+            if {$w > $wmax} { set wmax $w }
+
+            if {"" != [$itk_component(strip) find withtag $name:title]} {
+                foreach {x0 y0 x1 y1} [$itk_component(strip) bbox $name:title] break
+                set w [expr {$x1-$x0}]
+                set ht [expr {$ht+$y1-$y0}]
+                if {$w > $wmax} { set wmax $w }
+            }
+
+            set _data($name-pos) $ypos
+            $itk_component(strip) coords $name:image 0 $ypos
+            set ypos [expr {$ypos + $ht + $itk_option(-padding)}]
+        }
+        set wmax [expr {$wmax+2*$itk_option(-padding)}]
+
+        set sbarw [winfo reqwidth $itk_component(sbar)]
+        component hull configure -width [expr {$wmax+$sbarw}]
+
+        foreach name $_items {
+            foreach {x y} [$itk_component(strip) coords $name:image] break
+            set x [expr {$wmax/2}]
+            $itk_component(strip) coords $name:image $x $y
+
+            foreach {x0 y0 x1 y1} [$itk_component(strip) bbox $name:image] break
+            set imght [expr {$y1-$y0}]
+
+            if {"" != [$itk_component(strip) find withtag $name:title]} {
+                foreach {x0 y0 x1 y1} [$itk_component(strip) bbox $name:title] break
+                set titleh [expr {$y1-$y0}]
+                set x [expr {$wmax/2}]
+                set y [expr {$_data($name-pos) + $imght + $titleh}]
+                $itk_component(strip) coords $name:title $x $y
+            } else {
+                set titleh 0
+            }
+
+            set x0 $itk_option(-padding)
+            set x1 $wmax
+            set y0 $_data($name-pos)
+            set y1 [expr {$y0 + $imght + $titleh}]
+            $itk_component(strip) coords $name:bg $x0 $y0 $x1 $y1
+        }
+
+        # fix up the scrolling region to include all of these items
+        foreach {x0 y0 x1 y1} [$itk_component(strip) bbox all] break
+        set x1 [expr {$x1+$itk_option(-padding)}]
+        $itk_component(strip) configure -scrollregion [list 0 0 $x1 $y1]
+
+        set size [winfo pixels $itk_component(hull) $itk_option(-length)]
+        if {$size == 0} {
+            component hull configure -height [expr {$y1+$itk_option(-padding)}]
+        }
+    }
+}
+
+# ----------------------------------------------------------------------
+# USAGE: _scroll <arg> <arg>...
+#
+# Used internally to handle the automatic scrollbar.  If a scrollbar
+# is needed, then it is packed into view.  Otherwise, it disappears.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Filmstrip::_scroll {args} {
+    if {$itk_option(-orient) == "horizontal"} {
+        set view [$itk_component(strip) xview]
+        set side "bottom"
+        set fill "x"
+    } else {
+        set view [$itk_component(strip) yview]
+        set side "right"
+        set fill "y"
+    }
+
+    if {$view != {0 1}} {
+        pack $itk_component(sbar) -before $itk_component(strip) \
+            -side $side -fill $fill
+    } else {
+        pack forget $itk_component(sbar)
+    }
+    eval $itk_component(sbar) set $args
+}
+
+# ----------------------------------------------------------------------
+# USAGE: dd_get_source <widget> <x> <y>
+#
+# Looks at the given <widget> and <x>,<y> coordinate to figure out
+# what data value the source is exporting.  Returns a string that
+# identifies the type of the data.  This string is passed along to
+# targets via the dd_scan_target method.  If the target may check
+# the source type and reject the data.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Filmstrip::dd_get_source {widget x y} {
+    if {[string length $itk_option(-dragdropcommand)] == 0} {
+        return ""
+    }
+
+    # translate the screen x,y to the canvas x,y (may be scrolled down)
+    set x [$itk_component(strip) canvasx $x]
+    set y [$itk_component(strip) canvasy $y]
+
+    foreach id [$itk_component(strip) find overlapping $x $y $x $y] {
+        foreach tag [$itk_component(strip) gettags $id] {
+            # search for a tag like XXX:all for item XXX
+            if {[regexp {^([a-zA-Z0-9]+):all$} $tag match name]} {
+                # invoke the dragdrop command with the item name
+                # and see if it returns anything
+                if {[catch {uplevel #0 $itk_option(-dragdropcommand) $name} result]} {
+                    bgerror $result
+                } elseif {[string length $result] > 0} {
+                    return $result
+                }
+            }
+        }
+    }
+    return ""
+}
+
+# ----------------------------------------------------------------------
+# USAGE: dd_scan_target <x> <y> <data>
+#
+# Looks at the given <x>,<y> coordinate and checks to see if the
+# dragdrop <data> can be accepted at that point.  Returns 1 if so,
+# and 0 if the data is rejected.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Filmstrip::dd_scan_target {x y data} {
+}
+
+# ----------------------------------------------------------------------
+# USAGE: dd_finalize drop -op start|end -from <w> -to <w> \
+#                           -x <x> -y <y> -data <data>
+# USAGE: dd_finalize cancel
+#
+# Handles the end of a drag and drop operation.  The operation can be
+# completed with a successful drop of data, or cancelled.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Filmstrip::dd_finalize {option args} {
+}
+
+# ----------------------------------------------------------------------
+# CONFIGURATION OPTION: -orient
+# ----------------------------------------------------------------------
+itcl::configbody Rappture::Filmstrip::orient {
+    switch -- $itk_option(-orient) {
+        horizontal {
+            $itk_component(strip) configure \
+                -xscrollcommand [itcl::code $this _scroll]
+            $itk_component(sbar) configure -orient horizontal \
+                -command [list $itk_component(strip) xview]
+            pack $itk_component(strip) -side top
+
+            set size [winfo pixels $itk_component(hull) $itk_option(-length)]
+            if {$size > 0} {
+                component hull configure -width $size
+            }
+        }
+        vertical {
+            $itk_component(strip) configure \
+                -yscrollcommand [itcl::code $this _scroll]
+            $itk_component(sbar) configure -orient vertical \
+                -command [list $itk_component(strip) yview]
+            pack $itk_component(strip) -side left
+
+            set size [winfo pixels $itk_component(hull) $itk_option(-length)]
+            if {$size > 0} {
+                component hull configure -height $size
+            }
+        }
+        default {
+            error "bad value \"$itk_option(-orient)\": should be horizontal, vertical"
+        }
+    }
+    $_dispatcher event -idle !layout
+}
+
+# ----------------------------------------------------------------------
+# CONFIGURATION OPTION: -length
+# ----------------------------------------------------------------------
+itcl::configbody Rappture::Filmstrip::length {
+    set size [winfo pixels $itk_component(hull) $itk_option(-length)]
+    if {$size > 0} {
+        if {$itk_option(-orient) == "horizontal"} {
+            component hull configure -width $size
+        } else {
+            component hull configure -height $size
+        }
+    } else {
+        $_dispatcher event -idle !layout
+    }
+}
+
+# ----------------------------------------------------------------------
+# CONFIGURATION OPTION: -titlebackground, -titleforeground
+# ----------------------------------------------------------------------
+itcl::configbody Rappture::Filmstrip::titlebackground {
+    foreach name $_items {
+        $itk_component(strip) itemconfigure $name:title \
+            -background $itk_option(-titlebackground)
+    }
+}
+itcl::configbody Rappture::Filmstrip::titleforeground {
+    foreach name $_items {
+        $itk_component(strip) itemconfigure $name:title \
+            -foreground $itk_option(-titleforeground)
+    }
+}
Index: /trunk/builder/hierlist.tcl
===================================================================
--- /trunk/builder/hierlist.tcl	(revision 2080)
+++ /trunk/builder/hierlist.tcl	(revision 2080)
@@ -0,0 +1,536 @@
+# ----------------------------------------------------------------------
+#  COMPONENT: hierlist - hierarchical list of elements
+#
+#  This widget is similar to the BLT hierbox or treeview, but it
+#  allows for embedded windows at each node.
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+package require Itk
+package require BLT
+
+option add *Hierlist.width 2i widgetDefault
+option add *Hierlist.height 3i widgetDefault
+option add *Hierlist.indent 20 widgetDefault
+option add *Hierlist.icon {treepl treemn} widgetDefault
+option add *Hierlist.selectBackground cyan widgetDefault
+option add *Hierlist.dropLineColor blue widgetDefault
+option add *Hierlist.font {helvetica -12} widgetDefault
+
+itcl::class Rappture::Hierlist {
+    inherit itk::Widget Rappture::Dragdrop
+
+    itk_option define -indent indent Indent 10
+    itk_option define -padding padding Padding 4
+    itk_option define -icon icon Icon ""
+    itk_option define -font font Font ""
+    itk_option define -title title Title "%type: %id"
+    itk_option define -selectbackground selectBackground Foreground ""
+    itk_option define -droplinecolor dropLineColor Foreground ""
+
+    constructor {args} { # defined below }
+    destructor { # defined below }
+
+    public method tree {option args}
+    public method select {what {how "-notify"}}
+    public method curselection {args}
+    public method toggle {what}
+
+    public method xview {args} { eval $itk_component(area) xview $args }
+    public method yview {args} { eval $itk_component(area) yview $args }
+
+    protected method _redraw {args}
+    protected method _redrawChildren {node indent ypos}
+    protected method _edit {option node field args}
+
+    # define these for drag-n-drop support of items
+    protected method dd_get_source {widget x y}
+    protected method dd_scan_target {x y data}
+    protected method dd_finalize {option args}
+
+    private variable _dispatcher ""  ;# dispatcher for !events
+    private variable _tree ""        ;# BLT tree object for node data
+    private variable _current ""     ;# current selected node
+    private variable _droppos ""     ;# node index for dragdrop target pos
+    private variable _imh            ;# open/close images
+}
+
+itk::usual Hierlist {
+    keep -cursor -font -foreground -background
+}
+
+# ----------------------------------------------------------------------
+# CONSTRUCTOR
+# ----------------------------------------------------------------------
+itcl::body Rappture::Hierlist::constructor {args} {
+    itk_option add hull.width hull.height
+    pack propagate $itk_component(hull) off
+
+    # create a dispatcher for events
+    Rappture::dispatcher _dispatcher
+    $_dispatcher register !redraw
+    $_dispatcher dispatch $this !redraw [itcl::code $this _redraw]
+
+    # create a root node
+    set _tree [blt::tree create]
+    $_tree set 0 terminal yes  ;# so you can't drop at the top level
+
+    itk_component add area {
+        canvas $itk_interior.area -highlightthickness 0
+    } {
+        usual
+        ignore -borderwidth -relief
+        ignore -highlightthickness -highlightbackground -highlightcolor
+        keep -xscrollcommand -yscrollcommand
+    }
+    pack $itk_component(area) -expand yes -fill both
+
+    # this widget exports nodes via drag-n-drop
+    dragdrop source $itk_component(area)
+
+    set _imh(open) [image create photo]
+    set _imh(close) [image create photo]
+
+    eval itk_initialize $args
+}
+
+# ----------------------------------------------------------------------
+# DESTRUCTOR
+# ----------------------------------------------------------------------
+itcl::body Rappture::Hierlist::destructor {} {
+    foreach name [array names _imh] {
+        image delete $_imh($name)
+    }
+    blt::tree destroy $_tree
+}
+
+# ----------------------------------------------------------------------
+# USAGE: tree insert <node> <pos> ?<field1> <val1> <field2> <val2> ...?
+# USAGE: tree delete ?<node> <node> ...?
+# USAGE: tree get <node> <field>
+# USAGE: tree set <node> <field> <value>
+# USAGE: tree path <node> ?<pattern>?
+# USAGE: tree children <node>
+#
+# Clients use this to manipulate items in the tree being displayed
+# within the widget.  Each <node> is an integer node number in the
+# underlying BLT tree object.  The root node is node 0.  Each node
+# has a series of <field>'s with values.  The fields are used for the
+# -title of each node, and the "terminal" field controls whether or
+# not a node can have children added.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Hierlist::tree {option args} {
+    switch -- $option {
+        insert {
+            set node [lindex $args 0]
+            set pos [lindex $args 1]
+            if {$pos == "end"} {set pos [llength [$_tree children $node]]}
+            set args [lrange $args 2 end]
+            set newnode [$_tree insert $node -at $pos -data [eval list open yes terminal yes dragdrop yes $args]]
+
+            # make sure we fix up the layout at some point
+            $_dispatcher event -idle !redraw
+
+            return $newnode
+        }
+        delete {
+            if {$args == "all"} {
+                $_tree delete 0
+            } else {
+                foreach node $args {
+                    $_tree delete $node
+                }
+            }
+
+            # make sure we fix up the layout at some point
+            $_dispatcher event -idle !redraw
+        }
+        get {
+            return [eval $_tree get $args]
+        }
+        set {
+            # changed an option -- may be %type or %id -- update display
+            $_dispatcher event -idle !redraw
+
+            return [eval $_tree set $args]
+        }
+        path {
+            if {[llength $args] < 1 || [llength $args] > 2} {
+                error "wrong # args: should be \"tree path node ?pattern?\""
+            }
+            set node [lindex $args 0]
+            set pattern [lindex $args 1]
+            if {$pattern == ""} { set pattern %id }
+
+            set path ""
+            while {$node > 0} {
+                catch {unset info}
+                foreach {name val} [$_tree get $node] {
+                    set info(%$name) $val
+                    set info(%lc:$name) [string tolower $val]
+                    set info(%uc:$name) [string toupper $val]
+                }
+                set name [string map [array get info] $pattern]
+                set path "$name.$path"
+                set node [$_tree parent $node]
+            }
+            return [string trimright $path .]
+        }
+        children {
+            set node [lindex $args 0]
+            return [$_tree children $node]
+        }
+        default {
+            error "bad option \"$option\": should be insert, delete, get, set, path, children"
+        }
+    }
+}
+
+# ----------------------------------------------------------------------
+# USAGE: select <what> ?-notify|-silent?
+#
+# Called when you click on an item to select it.  Highlights the item
+# and returns information about it for the curselection.  This normally
+# triggers a <<Selection>> event on the widget, but that is suppressed
+# if the -silent option is given.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Hierlist::select {what {how "-notify"}} {
+    set c $itk_component(area)
+    if {$what == "none"} {
+        set what ""
+    }
+    set same [string equal $what $_current]
+
+    if {"" != $_current} {
+        # clear any current selection
+        $c itemconfigure item:$_current-bg -fill ""
+        set _current ""
+    }
+
+    if {"" != $what} {
+        $c itemconfigure item:$what-bg -fill $itk_option(-selectbackground)
+        set _current $what
+    }
+
+    if {!$same && ![string equal $how "-silent"]} {
+        # selection changed? then tell clients
+        event generate $itk_component(hull) <<Selection>>
+    }
+}
+
+# ----------------------------------------------------------------------
+# USAGE: curselection
+# USAGE: curselection -path <string>
+# USAGE: curselection -field <name>
+#
+# Returns information about the current selection.  Returns "" if
+# there is no selection.  If "-field <name>" is specified, then it
+# returns the value of that field for the current selection.  If
+# the "-path <string>" is specified, then it returns the path to
+# the current node, using <string> as a pattern for each node name
+# and filling in any %field items for each node.  With no extra args,
+# it returns the node number from the underlying BLT tree.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Hierlist::curselection {args} {
+    if {"" == $_current} {
+        return ""
+    }
+
+    if {[llength $args] == 0} {
+        return $_current
+
+    } elseif {[llength $args] == 2} {
+        switch -- [lindex $args 0] {
+            -path {
+                set pattern [lindex $args 1]
+                return [tree path $_current $pattern]
+            }
+            -field {
+                return [$_tree get $_current [lindex $args 1]]
+            }
+            default {
+                error "bad option \"[lindex $args 0]\": should be -field, -path"
+            }
+        }
+    } else {
+        error "wrong # args: should be \"curselection ?-path str? ?-field name?\""
+    }
+}
+
+# ----------------------------------------------------------------------
+# USAGE: toggle <what>
+#
+# Called when you click on an item to select it.  Highlights the item
+# and returns information about it for the curselection.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Hierlist::toggle {what} {
+    set flipped [expr {![$_tree get $what open]}]
+    $_tree set $what open $flipped
+    $_dispatcher event -idle !redraw
+}
+
+# ----------------------------------------------------------------------
+# USAGE: _redraw ?<eventArgs>...?
+#
+# Used internally to redraw all items in the hierarchy after the
+# tree has changed somehow.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Hierlist::_redraw {args} {
+    set c $itk_component(area)
+    $c delete all
+
+    set lineht [font metrics $itk_option(-font) -linespace]
+    set ypos [expr {0.5*$lineht + $itk_option(-padding)}]
+    _redrawChildren 0 0 ypos
+
+    foreach {x0 y0 x1 y1} [$c bbox text] break
+    $c configure -scrollregion [list 0 0 [expr {$x1+10}] [expr {$y1+10}]]
+
+    # did a selected node get folded up when the parent closed?
+    if {"" == [$c find withtag selected]} {
+        select none
+    }
+}
+
+# ----------------------------------------------------------------------
+# USAGE: _redrawChildren <node> <indent> <yposVar>
+#
+# Used internally to redraw all items in the hierarchy after the
+# tree has changed somehow.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Hierlist::_redrawChildren {node indent yposVar} {
+    set c $itk_component(area)
+    upvar $yposVar ypos
+
+    set xmid [expr {$indent + $itk_option(-indent)/2}]
+    set xtxt [expr {$indent + $itk_option(-indent)}]
+    set lineht [font metrics $itk_option(-font) -linespace]
+
+    foreach n [$_tree children $node] {
+        # background rectangle for selection highlight
+        set tlist [list item:$n item:$n-bg]
+        if {[string equal $n $_current]} {
+            set bg $itk_option(-selectbackground)
+            lappend tlist selected
+        } else {
+            set bg ""
+        }
+        $c create rect 0 [expr {$ypos-0.5*$lineht-1}] 1000 [expr {$ypos+0.5*$lineht+1}] -outline "" -fill $bg -tags $tlist
+
+        $c bind item:$n <ButtonRelease> [itcl::code $this select $n]
+
+        # +/- button for expanding the hierarchy
+        if {![$_tree get $n terminal]} {
+            if {[$_tree get $n open]} {
+                set imh $_imh(open)
+            } else {
+                set imh $_imh(close)
+            }
+            $c create image $xmid $ypos -anchor c -image $imh -tags plus:$n
+            $c bind plus:$n <ButtonPress> [itcl::code $this toggle $n]
+        }
+
+        # label for this node 
+        catch {unset data}
+        array set data [$_tree get $n]
+        set xpos $xtxt
+
+        set subs(%type) ""
+        set subs(%id) ""
+        foreach {name val} [$_tree get $n] {
+            set subs(%$name) $val
+            set subs(%lc:$name) [string tolower $val]
+            set subs(%uc:$name) [string toupper $val]
+        }
+
+        set str [string map [array get subs] $itk_option(-title)]
+        $c create text $xpos $ypos -anchor w -text $str -font $itk_option(-font) -tags [list text item:$n item:$n-text]
+
+        set ypos [expr {$ypos+$lineht+$itk_option(-padding)}]
+
+        # indent and draw all children
+        if {![$_tree get $n terminal] && [$_tree get $n open]} {
+            # if this node has children, draw them here
+            _redrawChildren $n $xtxt ypos
+        }
+    }
+}
+
+# ----------------------------------------------------------------------
+# USAGE: dd_get_source <widget> <x> <y>
+#
+# Looks at the given <widget> and <x>,<y> coordinate to figure out
+# what data value the source is exporting.  Returns a string that
+# identifies the type of the data.  This string is passed along to
+# targets via the dd_scan_target method.  If the target may check
+# the source type and reject the data.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Hierlist::dd_get_source {widget x y} {
+    set data ""
+    foreach id [$itk_component(area) find overlapping $x $y $x $y] {
+        foreach tag [$itk_component(area) gettags $id] {
+            # search for a tag like item:NNN and make sure it's selected
+            if {[regexp {^item:([0-9]+)$} $tag match node]
+                  && $node == $_current} {
+
+                # some nodes have drag-n-drop turned off
+                if {[$_tree get $node dragdrop]} {
+                    set data [list node:$node [$_tree get $node]]
+                }
+                break
+            }
+        }
+    }
+    # return drag-n-drop data, if we found it
+    return $data
+}
+
+# ----------------------------------------------------------------------
+# USAGE: dd_scan_target <x> <y> <data>
+#
+# Looks at the given <x>,<y> coordinate and checks to see if the
+# dragdrop <data> can be accepted at that point.  Returns 1 if so,
+# and 0 if the data is rejected.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Hierlist::dd_scan_target {x y data} {
+    set c $itk_component(area)
+    set _droppos ""  ;# assume no place to drop
+
+    switch -glob -- $data {
+        node:* {
+            # convert from screen coords to canvas coords (for scrollbars)
+            set x [$c canvasx $x]
+            set y [$c canvasy $y]
+
+            # search a little above the hot-spot
+            set y [expr {$y-5}]
+
+            foreach id [$c find overlapping $x $y $x $y] {
+                foreach tag [$c gettags $id] {
+                    if {[regexp {^item:([0-9]+)$} $tag match node]} {
+                        # draw the dropline beneath the item found
+                        if {"" == [$c find withtag dropline]} {
+                            $c create line 0 0 0 0 \
+                                -fill $itk_option(-droplinecolor) -tags dropline
+                        }
+
+                        foreach {x0 y0 x1 y1} [$c bbox item:$node-bg] break
+                        if {![$_tree get $node terminal]} {
+                            # drop on a node with children
+                            if {$y > $y0 + 0.6*($y1-$y0)} {
+                                # drop near the bottom -- insert as first child
+                                set _droppos "$node -at 0"
+                                set d [$_tree depth $node]
+                                set x0 [expr {($d+1)*$itk_option(-indent)}]
+                                $c coords dropline $x0 $y1 $x1 $y1
+                            } else {
+                                # drop on top -- insert as last child
+                                set x0 [expr {$x0+1}]
+                                set x1 [expr {[winfo width $c]-1}]
+                                $c coords dropline $x0 $y0 $x1 $y0 $x1 $y1 $x0 $y1 $x0 $y0
+                                set last [llength [$_tree children $node]]
+                                set _droppos "$node -at $last"
+                            }
+                        } else {
+                            set pnode [$_tree parent $node]
+                            if {![$_tree get $pnode terminal]} {
+                                set pos [expr {[$_tree position $node]+1}]
+                                set _droppos "$pnode -at $pos"
+                                set d [$_tree depth $node]
+                                set x0 [expr {$d*$itk_option(-indent)}]
+                                $c coords dropline $x0 $y1 $x1 $y1
+                            }
+                        }
+
+                        break
+                    }
+                }
+            }
+            if {"" != $_droppos} {
+                return 1
+            }
+            $c coords dropline -1 -1 -1 -1
+            return 0
+        }
+    }
+    return 0
+}
+
+# ----------------------------------------------------------------------
+# USAGE: dd_finalize drop -op start|end -from <w> -to <w> \
+#                           -x <x> -y <y> -data <data>
+# USAGE: dd_finalize cancel
+#
+# Handles the end of a drag and drop operation.  The operation can be
+# completed with a successful drop of data, or cancelled.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Hierlist::dd_finalize {option args} {
+    $itk_component(area) delete dropline
+
+    if {$option == "drop" && "" != $_droppos} {
+        array set params $args
+        switch -glob -- $params(-data) {
+            node:* {
+                if {$params(-op) == "end"
+                      && [string equal $params(-from) $params(-to)]} {
+
+                    regexp {node:([0-9]+)} $params(-data) match node
+                    eval $_tree move $node $_droppos
+                    event generate $itk_component(hull) <<SelectionPath>>
+                } else {
+                    set dlist [list open yes terminal yes dragdrop yes]
+                    eval lappend dlist [lrange $params(-data) 1 end]
+                    eval $_tree insert $_droppos -data [list $dlist]
+                }
+                # make sure the parent is open so we can see this node
+                set parent [lindex $_droppos 0]
+                if {![$_tree get $parent open]} {
+                    $_tree set $parent open 1
+                }
+
+                $_dispatcher event -idle !redraw
+                return 1
+            }
+        }
+        return 0
+    }
+}
+
+# ----------------------------------------------------------------------
+# CONFIGURATION OPTION: -icon
+# ----------------------------------------------------------------------
+itcl::configbody Rappture::Hierlist::icon {
+    set imh0 [lindex $itk_option(-icon) 0]
+    set imh1 [lindex $itk_option(-icon) 1]
+    if {$imh1 == ""} { set imh1 $imh0 }
+
+    set imh0 [Rappture::icon $imh0]
+    if {$imh0 == ""} {
+        $_imh(open) configure -width 1 -height 1
+        $_imh(open) blank
+    } else {
+        $_imh(open) configure -width [image width $imh0] -height [image height $imh0]
+        $_imh(open) copy $imh0
+    }
+
+    set imh1 [Rappture::icon $imh1]
+    if {$imh1 == ""} {
+        $_imh(close) configure -width 1 -height 1
+        $_imh(close) blank
+    } else {
+        $_imh(close) configure -width [image width $imh1] -height [image height $imh1]
+        $_imh(close) copy $imh1
+    }
+}
+
+# ----------------------------------------------------------------------
+# CONFIGURATION OPTION: -selectbackground
+# ----------------------------------------------------------------------
+itcl::configbody Rappture::Hierlist::selectbackground {
+    $itk_component(area) itemconfigure select \
+        -background $itk_option(-selectbackground)
+}
Index: /trunk/builder/images/drag.xbm
===================================================================
--- /trunk/builder/images/drag.xbm	(revision 2080)
+++ /trunk/builder/images/drag.xbm	(revision 2080)
@@ -0,0 +1,11 @@
+#define drag_width 24
+#define drag_height 24
+#define drag_x_hot 9
+#define drag_y_hot 2
+static unsigned char drag_bits[] = {
+   0xe0, 0xff, 0x07, 0x20, 0x00, 0x04, 0x20, 0x06, 0x04, 0x20, 0x09, 0x04,
+   0x20, 0x09, 0x04, 0xe0, 0xf9, 0x07, 0x00, 0x09, 0x00, 0x00, 0x39, 0x00,
+   0x00, 0xc9, 0x01, 0x00, 0x49, 0x06, 0x00, 0x49, 0x0a, 0x78, 0x49, 0x12,
+   0x88, 0x01, 0x12, 0x08, 0x01, 0x10, 0x10, 0x01, 0x10, 0x20, 0x01, 0x10,
+   0x20, 0x00, 0x10, 0x20, 0x00, 0x10, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08,
+   0x80, 0x00, 0x08, 0x80, 0x00, 0x04, 0x00, 0x01, 0x04, 0x00, 0xff, 0x07};
Index: /trunk/builder/images/dragm.xbm
===================================================================
--- /trunk/builder/images/dragm.xbm	(revision 2080)
+++ /trunk/builder/images/dragm.xbm	(revision 2080)
@@ -0,0 +1,9 @@
+#define dragm_width 24
+#define dragm_height 24
+static unsigned char dragm_bits[] = {
+   0xe0, 0xff, 0x07, 0xe0, 0xff, 0x07, 0xe0, 0xff, 0x07, 0xe0, 0xff, 0x07,
+   0xe0, 0xff, 0x07, 0xe0, 0xff, 0x07, 0x00, 0x0f, 0x00, 0x00, 0x3f, 0x00,
+   0x00, 0xff, 0x01, 0x00, 0xff, 0x07, 0x00, 0xff, 0x0f, 0x78, 0xff, 0x1f,
+   0xf8, 0xff, 0x1f, 0xf8, 0xff, 0x1f, 0xf0, 0xff, 0x1f, 0xe0, 0xff, 0x1f,
+   0xe0, 0xff, 0x1f, 0xe0, 0xff, 0x1f, 0xc0, 0xff, 0x0f, 0xc0, 0xff, 0x0f,
+   0x80, 0xff, 0x0f, 0x80, 0xff, 0x07, 0x00, 0xff, 0x07, 0x00, 0xff, 0x07};
Index: /trunk/builder/irappture.in
===================================================================
--- /trunk/builder/irappture.in	(revision 2080)
+++ /trunk/builder/irappture.in	(revision 2080)
@@ -0,0 +1,25 @@
+#!/bin/sh
+# ----------------------------------------------------------------------
+#  RAPPTURE
+#
+#  This is the main script that most people use to invoke the
+#  Instant Rappture GUI builder.  It sets environment variables so
+#  that the builder script will work properly for the current
+#  installation.
+#
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+libdir=@libdir@
+TCL_VERSION=@TCL_VERSION@
+
+. ${bindir}/rappture.env
+exec ${bindir}/wish${TCL_VERSION} ${libdir}/instant/main.tcl $*
Index: /trunk/builder/main.tcl
===================================================================
--- /trunk/builder/main.tcl	(revision 2080)
+++ /trunk/builder/main.tcl	(revision 2080)
@@ -0,0 +1,1283 @@
+# ----------------------------------------------------------------------
+#  USER INTERFACE BUILDER
+#
+#  This program allows the user to create a tool.xml file, or reload
+#  and edit an existing tool.xml.  It also produces some skeleton
+#  code for the main program that queries inputs and saves outputs.
+#
+#  RUN AS FOLLOWS:
+#    wish main.tcl ?-tool <toolfile>?
+#
+#  If the <toolfile> is not specified, it defaults to "tool.xml" in
+#  the current working directory.
+#
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+package require Itcl
+package require Rappture
+package require RapptureGUI
+package require Img
+
+option add *Tooltip.background white
+option add *Editor.background white
+option add *Gauge.textBackground white
+option add *TemperatureGauge.textBackground white
+option add *Switch.textBackground white
+option add *Progress.barColor #ffffcc
+option add *Balloon.titleBackground #6666cc
+option add *Balloon.titleForeground white
+option add *Balloon*Label.font -*-helvetica-medium-r-normal-*-12-*
+option add *Balloon*Radiobutton.font -*-helvetica-medium-r-normal-*-12-*
+option add *Balloon*Checkbutton.font -*-helvetica-medium-r-normal-*-12-*
+option add *BugReport*banner*foreground white
+option add *BugReport*banner*background #a9a9a9
+option add *BugReport*banner*highlightBackground #a9a9a9
+option add *BugReport*banner*font -*-helvetica-bold-r-normal-*-18-*
+option add *Filmstrip.background #aaaaaa
+option add *previewButtonBackground #4a758c
+option add *previewButtonActiveBackground #a3c3cc
+option add *previewButtonForeground white
+option add *previewButtonIcon arrow-up-white
+option add *build*cntls*background #cccccc
+option add *build*cntls*highlightBackground #cccccc
+option add *build*cntls*font {helvetica -12}
+option add *build*cntls*Button.borderWidth 1
+option add *build*cntls*Button.relief flat
+option add *build*cntls*Button.overRelief raised
+option add *build*cntls*Button.padX 2
+option add *build*cntls*Editor.background white
+option add *options*Entry.background white
+option add *options*Text.background white
+option add *options*Text.font {Helvetica -12}
+option add *options*Button.font {Helvetica -10}
+option add *options*Button.padX 2
+option add *options*Button.padY 2
+option add *options.errs*Background black
+option add *options.errs*highlightBackground black
+option add *options.errs*Foreground white
+option add *options.errs*Button.relief flat
+option add *options.errs*Button.padX 1
+option add *options.errs*Button.padY 1
+option add *saveas*toolv*Label.font {Helvetica -12}
+option add *saveas*toolv*Button.font {Helvetica -12}
+option add *saveas*toolv*Button.borderWidth 1
+option add *saveas*toolv*Button.padX 2
+option add *saveas*toolv*Button.padY 2
+option add *saveas*progv*Label.font {Helvetica -12}
+option add *saveas*progv*Button.font {Helvetica -12}
+option add *saveas*progv*Button.borderWidth 1
+option add *saveas*progv*Button.padX 2
+option add *saveas*progv*Button.padY 2
+option add *saveas*progl*Label.font {Helvetica -12}
+option add *saveas*progl*Combobox.textBackground #d9d9d9
+option add *saveas*progl*Combobox.borderWidth 1
+
+switch $tcl_platform(platform) {
+    unix - windows {
+        event add <<PopupMenu>> <ButtonPress-3>
+    }
+    macintosh {
+        event add <<PopupMenu>> <Control-ButtonPress-1>
+    }
+}
+
+wm protocol . WM_DELETE_WINDOW main_exit
+wm title . "Instant Rappture"
+
+# install a better bug handler
+Rappture::bugreport::install
+# fix the "grab" command to support a stack of grab windows
+Rappture::grab::init
+
+#
+# Process command line args to get the names of files to load...
+#
+Rappture::getopts argv params {
+    value -tool ""
+}
+
+# load type and object definitions
+set dir [file dirname [info script]]
+set auto_path [linsert $auto_path 0 $dir]
+
+Rappture::icon foo  ;# force loading of this module
+lappend Rappture::icon::iconpath [file join $dir images]
+
+# ----------------------------------------------------------------------
+#  HACK ALERT!  Make it so the Analyzer can't possibly enable its
+#    simulate button in "preview" mode, or else the user might
+#    actually launch a simulation.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Analyzer::_simState {state args} {
+    if {"" != $itk_option(-simcontrolbackground)} {
+        set simcbg $itk_option(-simcontrolbackground)
+    } else {
+        set simcbg $itk_option(-background)
+    }
+    $itk_interior.simol configure \
+        -background $itk_option(-simcontroloutline)
+    configure -simcontrolcolor $simcbg
+
+    $itk_component(simulate) configure -state disabled
+}
+
+# ----------------------------------------------------------------------
+# USAGE: main_palette_source <type>
+#
+# Returns drag-n-drop data for the object <type>.  This data can be
+# dragged between the filmstrip object palettes and the hierlist of
+# nodes for the current tool.
+# ----------------------------------------------------------------------
+set ValueId 0
+proc main_palette_source {type} {
+    global ValueId
+    if {[catch {Rappture::objects::get $type -attributes} attrs]} {
+        return ""
+    }
+    set term [Rappture::objects::get $type -terminal]
+    set vname "value[incr ValueId]"
+    set type [string totitle $type]
+    return [list node: id $vname type $type terminal $term attributes ""]
+}
+
+# ----------------------------------------------------------------------
+# USAGE: main_open ?-new|-file|filename?
+#
+# Handles the Open... operation, which opens a tool.xml file and
+# loads the contents.  If there are any pending changes, the user
+# is prompted to save the changes before continuing with the open.
+# ----------------------------------------------------------------------
+proc main_open {{what "-new"}} {
+    global ToolXml LastToolXmlFile LastToolXmlLoaded ValueId
+
+    if {![main_options_save -clear]} {
+        return
+    }
+    main_generate_xml
+
+    if {[string length $LastToolXmlLoaded] > 0 && ![string equal [$ToolXml xml] $LastToolXmlLoaded]} {
+        set choice [tk_messageBox -icon warning -type yesno -title "iRappture: Save Changes?" -message "Changes to the current tool haven't been saved.\n\nSave changes?"]
+        if {$choice == "yes" && ![main_saveas]} {
+            return
+        }
+    }
+
+    if {$what == "-new"} {
+        set xmlobj [Rappture::LibraryObj ::#auto "<?xml version=\"1.0\"?><run><tool/></run>"]
+    } else {
+        if {$what == "-file"} {
+            set fname [tk_getOpenFile -title "iRappture: Open Tool" -initialfile "tool.xml" -defaultextension .xml -filetypes { {{XML files} .xml} {{All files} *} }]
+        } else {
+            set fname $what
+        }
+
+        if {"" == $fname} {
+            return
+        }
+
+        # save the current file name in the "Save As..." dialog for later
+        set LastToolXmlFile $fname
+        .saveas.opts.toolv.file configure -text $fname
+        main_saveas update
+
+        if {[catch {Rappture::library $fname} xmlobj]} {
+            tk_messageBox -icon error -title "iRappture: Error" -message "Error loading tool description: $xmlobj"
+            return
+        }
+    }
+
+    # plug in the new tool definition
+    set LastToolXmlLoaded [$xmlobj xml]
+    set ValueId 0
+
+    # clear the tree and load the new data
+    set win [.func.build.options.panes pane 0]
+    $win.scrl.skel tree delete all
+    pack forget .func.build.options.errs
+
+    set alist [main_open_import_attrs $xmlobj tool]
+    $win.scrl.skel tree insert 0 end \
+        type "Tool" terminal yes dragdrop no attributes $alist
+
+    # all the Input section
+    set n [$win.scrl.skel tree insert 0 end \
+        type "Input" terminal no dragdrop no]
+    main_open_children $win.scrl.skel $xmlobj $n
+
+    # all the Output section
+    set n [$win.scrl.skel tree insert 0 end \
+        type "Output" terminal no dragdrop no]
+    main_open_children $win.scrl.skel $xmlobj $n
+}
+
+# ----------------------------------------------------------------------
+# USAGE: main_open_children <hierlist> <xmlobj> <node>
+#
+# Called by main_open to insert children in the <xml> at the specified
+# <node> into the given <hierlist> widget.  The children must be
+# recognized object types.
+# ----------------------------------------------------------------------
+proc main_open_children {hierlist xmlobj node} {
+    global ValueId
+
+    set path [$hierlist tree path $node "%lc:type(%id)"]
+    regsub -all {\(%id\)} $path "" path
+
+    foreach elem [$xmlobj children $path] {
+        set type [$xmlobj element -as type $path.$elem]
+
+        # make sure that this is a recognized object type
+        if {[catch {Rappture::objects::get $type -image} result] == 0
+              && [string length $result] > 0} {
+
+            # get info about this object
+            set id [$xmlobj element -as id $path.$elem]
+            set term [Rappture::objects::get $type -terminal]
+            set alist [main_open_import_attrs $xmlobj $path.$elem]
+
+            # add it into the tree
+            set newnode [$hierlist tree insert $node end \
+                type [string totitle $type] id $id terminal $term \
+                attributes $alist]
+
+            # find the highest auto-generated node and start from there
+            if {[regexp {^value([0-9]+)$} $id match num]} {
+                if {$num > $ValueId} {
+                    set ValueId $num
+                }
+            }
+
+            if {!$term} {
+                # if it can have children, then add any children
+                main_open_children $hierlist $xmlobj $newnode
+            }
+        }
+    }
+}
+
+# ----------------------------------------------------------------------
+# USAGE: main_open_import_attrs <xml> <path>
+#
+# Called by main_open_children to import attributes from the place
+# <path> in the <xml> object.
+# ----------------------------------------------------------------------
+proc main_open_import_attrs {xmlobj path} {
+    set alist ""
+    set type [$xmlobj element -as type $path]
+
+    if {[catch {Rappture::objects::get $type -attributes} attr] == 0} {
+        # scan through and ingest all known attributes
+        foreach rec $attr {
+            set name [lindex $rec 0]
+            catch {unset info}
+            array set info [lrange $rec 1 end]
+
+            set atype [lindex [split $info(-type) :] 0]
+            set proc "Attr[string totitle $atype]::import"
+            if {[catch {$proc $xmlobj $path.$info(-path)} result]} {
+                puts "ERROR: $result"
+                puts "  skipping $name attribute of $path"
+            } else {
+                lappend alist $name $result
+            }
+        }
+    }
+    return $alist
+}
+
+# ----------------------------------------------------------------------
+# USAGE: main_errors
+#
+# Checks the values of all objects in the tree to look for errors
+# before previewing and saving.  If any errors are found, the user
+# is prompted to look at them, and they can be popped up in a viewer
+# above the object tree.
+# ----------------------------------------------------------------------
+proc main_errors {} {
+    global ErrList ErrListPos
+
+    set ErrList ""
+    set ErrListPos 0
+    set ErrFocusAttr ""
+    pack forget .func.build.options.errs
+
+    set counter 0
+    set win [.func.build.options.panes pane 0]
+    set hlist $win.scrl.skel
+    set nodelist [$hlist tree children 0]
+    while {[llength $nodelist] > 0} {
+        set node [lindex $nodelist 0]
+        set nodelist [lrange $nodelist 1 end]
+
+        # add children into the node traversal list
+        set cnodes [$hlist tree children $node]
+        if {[llength $cnodes] > 0} {
+            set nodelist [eval linsert [list $nodelist] 0 $cnodes]
+        }
+
+        set type [string tolower [$hlist tree get $node type]]
+
+        if {[catch {Rappture::objects::get $type -attributes} attrdef]
+             || [catch {$hlist tree get $node attributes} attrlist]} {
+            # can't find any attributes for this node or node type
+            continue
+        }
+        array set ainfo $attrlist
+
+        foreach rec $attrdef {
+            set name [lindex $rec 0]
+            if {![info exists ainfo($name)]} {
+                set ainfo($name) ""
+            }
+        }
+        set debug [list -node $node -counter [incr counter]]
+
+        # perform all checks for this attribute type and append to ErrList
+        eval lappend ErrList [Rappture::objects::check $type \
+            [array get ainfo] $debug]
+    }
+
+    if {[llength $ErrList] > 0} {
+        # arrange errors in order of severity
+        set ErrList [lsort -decreasing -command main_errors_cmp $ErrList]
+
+        # count the errors and warnings
+        set nerrs 0
+        set nwarn 0
+        set nother 0
+        foreach rec $ErrList {
+            switch -- [lindex $rec 0] {
+                error   { incr nerrs }
+                warning { incr nwarn }
+                default { incr nother }
+            }
+        }
+
+        set phrases ""
+        if {$nerrs == 1} {
+            lappend phrases "1 error"
+        } elseif {$nerrs > 1} {
+            lappend phrases "$nerrs errors"
+        }
+        if {$nwarn == 1} {
+            lappend phrases "1 warning"
+        } elseif {$nwarn > 1} {
+            lappend phrases "$nwarn warnings"
+        }
+        if {$nother == 1} {
+            lappend phrases "1 other suggestion"
+        } elseif {$nother > 1} {
+            lappend phrases "$nother suggestions"
+        }
+        switch -- [llength $phrases] {
+            1 { set phrases [lindex $phrases 0] }
+            2 { set phrases [join $phrases " and "] }
+            3 { set phrases [join $phrases "%"]
+                regsub "%" $phrases ", " phrases
+                regsub "%" $phrases ", and " phrases
+            }
+        }
+
+        if {$nerrs+$nwarn+$nother == 1} {
+            set thereis "There is"
+            set problem "this problem"
+        } else {
+            set thereis "There are"
+            set problem "these problems"
+        }
+
+        set choice [tk_messageBox -icon error -type yesno -title "iRappture: Problems with your tool definition" -message "$thereis $phrases for your current tool definition.  Examine and resolve $problem?"]
+        if {$choice == "yes"} {
+            return 1
+        } else {
+            return 0
+        }
+    }
+    return 0
+}
+
+# ----------------------------------------------------------------------
+# USAGE: main_errors_nav index|next|prev
+#
+# Navigates through the error messages generated by the last call
+# to main_errors, putting up the next message in the sequence.
+# ----------------------------------------------------------------------
+proc main_errors_nav {where} {
+    global ErrList ErrListPos ErrFocusAttr
+
+    if {![main_options_save]} {
+        return
+    }
+
+    if {$where == "next"} {
+        incr ErrListPos
+    } elseif {$where == "prev"} {
+        incr ErrListPos -1
+    } elseif {[string is integer -strict $where]} {
+        set ErrListPos $where
+    } else {
+        error "bad option \"$where\": should be next or prev"
+    }
+
+    if {$ErrListPos < 0} {
+        set ErrListPos [expr {[llength $ErrList]-1}]
+    } elseif {$ErrListPos >= [llength $ErrList]} {
+        set ErrListPos 0
+    }
+
+    set err [lindex $ErrList $ErrListPos]
+    set class [string totitle [lindex $err 0]]
+    set mesg [lindex $err 1]
+    array set debug [lindex $err 2]
+
+    .func.build.options.errs.info configure -text "$class: $mesg"
+
+    if {$class == "Error"} {
+        .func.build.options.errs.exclaim config -image [Rappture::icon err24]
+    } else {
+        .func.build.options.errs.exclaim config -image [Rappture::icon warn24]
+    }
+
+    set win [.func.build.options.panes pane 0]
+    set ErrFocusAttr $debug(-attribute)
+    $win.scrl.skel select none -silent  ;# force a reload of options
+    $win.scrl.skel select $debug(-node) ;# so we can highlight ErrFocusAttr
+
+    .func.build.options.errs.nav.prev configure \
+        -state [expr {($ErrListPos == 0) ? "disabled" : "normal"}]
+    .func.build.options.errs.nav.next configure \
+        -state [expr {($ErrListPos >= [llength $ErrList]-1) ? "disabled" : "normal"}]
+}
+
+# ----------------------------------------------------------------------
+# USAGE: main_errors_cmp <err1> <err2>
+#
+# Used to compare two error records when sorting the main ErrList.
+# Each record should have the following form:
+#
+#   error "this describes the error" {-node n -counter c -attribute a}
+#
+# Errors appear at the top, followed by warnings and suggestions.
+# Each record has a counter value, which determines its position in
+# the tree.  Serious errors near the top of the tree are shown first.
+# ----------------------------------------------------------------------
+proc main_errors_cmp {err1 err2} {
+    array set severity {
+        suggestion 0
+        warning 1
+        error 2
+    }
+
+    set eclass1 [lindex $err1 0]
+    array set einfo1 [lindex $err1 2]
+
+    set eclass2 [lindex $err2 0]
+    array set einfo2 [lindex $err2 2]
+
+    if {$severity($eclass1) > $severity($eclass2)} {
+        return 1
+    } elseif {$severity($eclass1) < $severity($eclass2)} {
+        return -1
+    }
+    if {$einfo1(-counter) > $einfo2(-counter)} {
+        return -1  ;# higher counters are further down in tree
+    } elseif {$einfo1(-counter) < $einfo2(-counter)} {
+        return 1   ;# put lower counters near the top
+    }
+    return 0
+}
+
+# ----------------------------------------------------------------------
+# USAGE: main_generate_xml
+#
+# Builds an XML representation of the current contents of the tool
+# defintion tree.  Usually called just before previewing or saving
+# the tool to build a fresh XML representation with all changes.
+# Returns 1 if the XML was successfully generated, and 0 if something
+# went wrong.
+# ----------------------------------------------------------------------
+proc main_generate_xml {} {
+    global ToolXml
+
+    # save any outstanding changes from the current options panel
+    if {![main_options_save]} {
+        return 0
+    }
+
+    # create a fresh XML object
+    if {"" != $ToolXml} {
+        itcl::delete object $ToolXml
+    }
+    set ToolXml [Rappture::LibraryObj ::#auto "<?xml version=\"1.0\"?><run><tool/></run>"]
+
+    set win [.func.build.options.panes pane 0]
+    set hlist $win.scrl.skel
+    set nodelist [$hlist tree children 0]
+    while {[llength $nodelist] > 0} {
+        set node [lindex $nodelist 0]
+        set nodelist [lrange $nodelist 1 end]
+
+        # add children into the node traversal list
+        set cnodes [$hlist tree children $node]
+        if {[llength $cnodes] > 0} {
+            set nodelist [eval linsert [list $nodelist] 0 $cnodes]
+        }
+
+        set path [$hlist tree path $node "%lc:type(%id)"]
+        regsub -all {\(%id\)} $path "" path
+        set type [string tolower [$hlist tree get $node type]]
+
+        if {[catch {Rappture::objects::get $type -attributes} attrdef]
+             || [catch {$hlist tree get $node attributes} attrlist]} {
+            # can't find any attributes for this node or node type
+            continue
+        }
+        array set ainfo $attrlist
+
+        foreach rec $attrdef {
+            set name [lindex $rec 0]
+            if {![info exists ainfo($name)]} {
+                continue
+            }
+            array set info [lrange $rec 1 end]
+            set atype [lindex [split $info(-type) :] 0]
+            set proc "Attr[string totitle $atype]::export"
+            if {[catch {$proc $ToolXml $path.$info(-path) $ainfo($name)} result]} {
+                puts "ERROR: $result"
+                puts "  skipping $name attribute of $path"
+            }
+        }
+    }
+    return 1
+}
+
+# ----------------------------------------------------------------------
+# USAGE: main_saveas start|cancel|finish|update|gettoolfile|getprogfile
+#
+# Handles the Save As... operation, which saves the current tool
+# information into a tool.xml file.  Prompts the user to determine
+# the save file, and then saves the data--unless the user cancels.
+# ----------------------------------------------------------------------
+proc main_saveas {{option "start"}} {
+    global SaveAs ToolXml LastToolXmlFile LastToolXmlLoaded
+
+    switch -- $option {
+        start {
+            if {![main_options_save -clear]} {
+                return
+            }
+            # generate now to catch any errors
+            main_generate_xml
+
+            # make the saveas dialog big enough and center it on the main win
+            set w 400
+            set ho [winfo reqheight .saveas.opts]
+            set hc [winfo reqheight .saveas.cntls]
+            set h [expr {$ho+$hc+40}]
+            set x0 [winfo rootx .]
+            set y0 [winfo rooty .]
+            set wmain [winfo width .]
+            set hmain [winfo height .]
+            set x0 [expr {$x0+($wmain-$w)/2}]
+            set y0 [expr {$y0+($hmain-$h)/2}]
+
+            wm geometry .saveas ${w}x${h}+${x0}+${y0}
+            wm deiconify .saveas
+            raise .saveas
+            grab set .saveas
+
+            # wait for the user to save/cancel and return 1/0
+            vwait SaveAs(status)
+            return [string equal $SaveAs(status) "ok"]
+        }
+
+        cancel {
+            grab release .saveas
+            wm withdraw .saveas
+            after idle [list set SaveAs(status) "cancelled"]
+        }
+
+        finish {
+            grab release .saveas
+            wm withdraw .saveas
+            set status "ok"
+
+            set tfile [.saveas.opts.toolv.file cget -text]
+            set pfile [.saveas.opts.progv.file cget -text]
+
+            if {$SaveAs(tool) && ![string equal "select a file" $tfile]} {
+                # generate again now that we know the file name to get
+                # relative file paths for things like <note>'s
+                set LastToolXmlFile $tfile
+                main_generate_xml
+
+                set cmds {
+                    set fid [open $tfile w]
+                    puts $fid "<?xml version=\"1.0\"?>"
+                    puts -nonewline $fid [$ToolXml xml]
+                    close $fid
+                }
+                if {[catch $cmds result]} {
+                    tk_messageBox -icon error -title "iRappture: Error" -message "Error saving tool description: $result"
+                    set status "error"
+                } else {
+                    set LastToolXmlLoaded [$ToolXml xml]
+                }
+            }
+
+            if {$SaveAs(prog) && ![string equal "select a file" $pfile]} {
+                tk_messageBox -icon error -title "iRappture: Error" -message "Generating script file is not yet implemented"
+            }
+
+            after idle [list set SaveAs(status) $status]
+        }
+
+        update {
+            set havefile 0
+            set tfile [.saveas.opts.toolv.file cget -text]
+            if {$SaveAs(tool) && ![string equal $tfile "select a file"]} {
+                .saveas.opts.toolv.file configure -fg black
+                set havefile 1
+            } else {
+                .saveas.opts.toolv.file configure -fg gray60
+            }
+
+            set pfile [.saveas.opts.progv.file cget -text]
+            if {$SaveAs(prog) && ![string equal $pfile "select a file"]} {
+                .saveas.opts.progv.file configure -fg black
+                set havefile 1
+            } else {
+                .saveas.opts.progv.file configure -fg gray60
+            }
+
+            if {$havefile} {
+                .saveas.cntls.save configure -state normal
+            } else {
+                .saveas.cntls.save configure -state disabled
+            }
+        }
+
+        gettoolfile {
+            set fname [tk_getSaveFile -title "iRappture: Save Tool" -parent .saveas -initialfile "tool.xml" -defaultextension .xml -filetypes { {{XML files} .xml} {{All files} *} }]
+
+            if {"" != $fname} {
+                .saveas.opts.toolv.file configure -text $fname
+                set SaveAs(tool) 1
+                main_saveas update
+            }
+        }
+
+        getprogfile {
+            set ext .tcl
+            set fname [tk_getSaveFile -title "iRappture: Save Program Skeleton" -parent .saveas -initialfile "wrapper$ext" -defaultextension $ext -filetypes {
+    {{C programs} .c}
+    {{C++ programs} .cpp}
+    {{F77 programs} .f}
+    {{MATLAB scripts} .m}
+    {{Perl scripts} .pl}
+    {{Python scripts} .py}
+    {{Tcl scripts} .tcl}
+    {{Ruby scripts} .ruby}
+    {{All files} *}
+}]
+
+            if {"" != $fname} {
+                .saveas.opts.progv.file configure -text $fname
+                set SaveAs(prog) 1
+                main_saveas update
+            }
+        }
+
+        default {
+            error "bad option \"$option\": should be start, cancel, finish, gettoolfile, getprogfile"
+        }
+    }
+
+}
+
+# ----------------------------------------------------------------------
+# USAGE: main_exit
+#
+# Handles the Save As... operation, which saves the current tool
+# information into a tool.xml file.  Prompts the user to determine
+# the save file, and then saves the data--unless the user cancels.
+# ----------------------------------------------------------------------
+proc main_exit {} {
+    global ToolXml LastToolXmlLoaded
+
+    if {![main_options_save -clear]} {
+        return
+    }
+    main_generate_xml
+
+    if {![string equal [$ToolXml xml] $LastToolXmlLoaded]} {
+        set choice [tk_messageBox -icon warning -type yesno -title "iRappture: Save Changes?" -message "Changes to the current tool haven't been saved.\n\nSave changes?"]
+        if {$choice == "yes" && ![main_saveas]} {
+            return
+        }
+    }
+    exit
+}
+
+# ----------------------------------------------------------------------
+# USAGE: main_preview
+#
+# Handles the "Preview" tab.  Whenever a preview is needed, this
+# function clears the current contents of the preview window and
+# builds a new set of input controls based on the current XML.
+# ----------------------------------------------------------------------
+proc main_preview {} {
+    global ToolXml ToolPreview
+
+    # while we're checking for errors, put up a striped pattern over
+    # the preview area
+    set w [winfo width .func.preview]
+    set h [winfo height .func.preview]
+    place .func.preview.stripes -x 0 -y 0 -width $w -height $h
+    raise .func.preview.stripes
+
+    # freshen up the ToolXml
+    if {![main_generate_xml]} {
+        # something went wrong while saving the xml
+        # pull up the build tab, so we can see the error
+        .func select [.func index -name "Build"]
+        return
+    }
+
+    if {[main_errors]} {
+        .func select [.func index -name "Build"]
+        pack .func.build.options.errs -before .func.build.options.panes \
+            -pady {10 0} -fill x
+        main_errors_nav 0
+        return
+    }
+
+    # clear all current widgets in the preview window
+    place forget .func.preview.stripes
+    set win .func.preview
+    $win.pager delete 0 end
+
+    if {"" != $ToolPreview} {
+        itcl::delete object $ToolPreview
+        set ToolPreview ""
+    }
+    set ToolPreview [Rappture::Tool ::#auto $ToolXml [pwd]]
+
+    # add new widgets based on the phases
+    set phases [$ToolXml children -type phase input]
+    if {[llength $phases] > 0} {
+        set plist ""
+        foreach name $phases {
+            lappend plist input.$name
+        }
+        set phases $plist
+    } else {
+        set phases input
+    }
+
+    if {[llength $phases] == 1} {
+        $win.pager configure -arrangement side-by-side
+    } else {
+        $win.pager configure -arrangement pages
+    }
+
+    foreach comp $phases {
+        if {"" == [$ToolXml element $comp]} {
+            # empty element? then skip it
+            continue
+        }
+        set title [$ToolXml get $comp.about.label]
+        if {$title == ""} {
+            set title "Input #auto"
+        }
+        $win.pager insert end -name $comp -title $title
+
+        #
+        # Build the page of input controls for this phase.
+        #
+        set f [$win.pager page $comp]
+        Rappture::Page $f.cntls $ToolPreview $comp
+        pack $f.cntls -expand yes -fill both
+    }
+
+    # add an analyzer for output widgets
+    set simtxt [$ToolXml get tool.action.label]
+    if {"" == $simtxt} {
+        set simtxt "Simulate"
+    }
+    $win.pager insert end -name analyzer -title $simtxt
+    set f [$win.pager page analyzer]
+    # note: simcontrol on but disabled due to _simState code above
+    Rappture::Analyzer $f.analyze $ToolPreview -simcontrol on
+    pack $f.analyze -expand yes -fill both
+
+    # copy the ToolXml object and pass to analyzer to show outputs
+    set synthrun [Rappture::LibraryObj ::#auto "<?xml version=\"1.0\"?><run/>"]
+    $synthrun copy "" from $ToolXml ""
+    $f.analyze load $synthrun
+    $f.analyze configure -notebookpage analyze
+
+    # turn off download options and clear button
+    $f.analyze component download configure -state disabled
+    $f.analyze component resultset component clear configure -state disabled
+    # remove the "---" and "Download..." options from the result selector
+    $f.analyze component resultselector choices delete end
+    $f.analyze component resultselector choices delete end
+}
+
+# ----------------------------------------------------------------------
+# MAIN WINDOW
+# ----------------------------------------------------------------------
+wm geometry . 700x600
+
+# ----------------------------------------------------------------------
+# MAIN WINDOW
+# ----------------------------------------------------------------------
+wm geometry . 600x500
+Rappture::Postern .postern
+pack .postern -side bottom -fill x
+
+blt::tabset .func -borderwidth 0 -relief flat -side top -tearoff 0 \
+    -highlightthickness 0
+pack .func -expand yes -fill both
+
+# ----------------------------------------------------------------------
+# BUILD AREA
+# ----------------------------------------------------------------------
+frame .func.build
+.func insert end "Build" -window .func.build -fill both
+
+frame .func.build.cntls
+pack .func.build.cntls -fill x
+button .func.build.cntls.new -text "New..." -command {main_open -new}
+pack .func.build.cntls.new -side left -padx 2 -pady 4
+button .func.build.cntls.open -text "Open..." -command {main_open -file}
+pack .func.build.cntls.open -side left -padx 2 -pady 4
+button .func.build.cntls.save -text "Save As..." -command main_saveas
+pack .func.build.cntls.save -side left -padx 2 -pady 4
+
+frame .func.build.side
+pack .func.build.side -side left -fill y -pady 10
+label .func.build.side.l -text "Object Types:"
+pack .func.build.side.l -side top -anchor w
+
+Rappture::Slideframes .func.build.side.palettes -animstartcommand {
+    # turn scrollbars off during animation
+    for {set i 0} {$i < [.func.build.side.palettes size]} {incr i} {
+        set win [.func.build.side.palettes page @$i]
+        $win.scrl configure -yscrollmode off
+    }
+} -animendcommand {
+    # turn scrollbars back on when animation is over
+    for {set i 0} {$i < [.func.build.side.palettes size]} {incr i} {
+        set win [.func.build.side.palettes page @$i]
+        $win.scrl configure -yscrollmode auto
+    }
+}
+pack .func.build.side.palettes -expand yes -fill both
+
+set plist [Rappture::objects::palettes]
+set plist [linsert $plist 0 "All"]
+
+set pnum 0
+foreach ptitle $plist {
+    set win [.func.build.side.palettes insert end $ptitle]
+
+    Rappture::Scroller $win.scrl -xscrollmode off -yscrollmode auto
+    pack $win.scrl -expand yes -fill both
+    set iwin [$win.scrl contents frame]
+    Rappture::Filmstrip $iwin.strip -orient vertical \
+        -dragdropcommand main_palette_source
+    pack $iwin.strip -expand yes -fill both
+
+    foreach name [Rappture::objects::get] {
+        set imh [Rappture::objects::get $name -image]
+        if {"" == $imh} {
+            continue
+        }
+        set plist [Rappture::objects::get $name -palettes]
+        if {$ptitle == "All" || [lsearch $plist $ptitle] >= 0} {
+            $iwin.strip add $name -image $imh
+        }
+    }
+}
+
+# ----------------------------------------------------------------------
+#  OPTIONS AREA
+# ----------------------------------------------------------------------
+frame .func.build.options
+pack .func.build.options -expand yes -fill both -padx 10
+
+frame .func.build.options.errs
+frame .func.build.options.errs.nav
+pack .func.build.options.errs.nav -side bottom -fill x -padx 2 -pady 2
+button .func.build.options.errs.nav.next -text "Next >" -command {main_errors_nav next}
+pack .func.build.options.errs.nav.next -side right
+button .func.build.options.errs.nav.prev -text "< Prev" -command {main_errors_nav prev}
+pack .func.build.options.errs.nav.prev -side right -padx 4
+
+button .func.build.options.errs.x -bitmap [Rappture::icon dismiss] \
+    -command {pack forget .func.build.options.errs}
+pack .func.build.options.errs.x -side right -anchor n -padx 4 -pady 8
+label .func.build.options.errs.exclaim -image [Rappture::icon err24]
+pack .func.build.options.errs.exclaim -side left -anchor nw -padx 4 -pady 4
+label .func.build.options.errs.info -text "" -anchor nw -justify left
+pack .func.build.options.errs.info -side left -expand yes -fill both -pady {6 0}
+bind .func.build.options.errs.info <Configure> {.func.build.options.errs.info configure -wraplength [expr {%w-4}]}
+
+Rappture::Panes .func.build.options.panes -orientation vertical
+pack .func.build.options.panes -expand yes -fill both -padx 10
+.func.build.options.panes insert end -fraction 0.5
+
+set win [.func.build.options.panes pane 0]
+label $win.heading -text "Tool Interface:"
+pack $win.heading -anchor w -pady {12 0}
+Rappture::Scroller $win.scrl -xscrollmode auto -yscrollmode auto
+pack $win.scrl -expand yes -fill both
+
+Rappture::Hierlist $win.scrl.skel
+$win.scrl contents $win.scrl.skel
+
+bind $win.scrl.skel <<Selection>> main_options_load
+bind $win.scrl.skel <<SelectionPath>> main_options_rename
+
+set win [.func.build.options.panes pane 1]
+Rappture::Scroller $win.vals -xscrollmode none -yscrollmode auto
+pack $win.vals -expand yes -fill both
+
+# ----------------------------------------------------------------------
+# USAGE: main_options_load
+#
+# Invoked whenever the selection changes in the tree of all known
+# objects.  Gets the current selection and pops up controls to edit
+# the attributes.
+# ----------------------------------------------------------------------
+set OptionsPanelNode ""
+
+proc main_options_load {} {
+    global OptionsPanelNode OptionsPanelObjs ErrFocusAttr
+
+    set win [.func.build.options.panes pane 0]
+    set hlist $win.scrl.skel
+
+    if {![main_options_save -clear]} {
+        # something is wrong with the previous edits
+        # show the last node as the current selection and fix the error
+        if {"" != $OptionsPanelNode} {
+            $hlist select $OptionsPanelNode -silent
+        }
+        return
+    }
+
+    # figure out the current selection
+    set node [$hlist curselection]
+    set type [$hlist curselection -field type]
+    set path [$hlist curselection -path "%lc:type(%id)"]
+    regsub -all {\(%id\)} $path "" path
+
+    # set the value column to expand
+    set win [.func.build.options.panes pane 1]
+    set frame [$win.vals contents frame]
+    grid columnconfigure $frame 1 -weight 1
+
+    # create new widgets for each object attribute
+    if {"" != $type && [lsearch {Inputs Outputs} $type] < 0
+          && [catch {Rappture::objects::get $type -attributes} attr] == 0} {
+
+        frame $frame.cntls -borderwidth 4 -relief flat
+        grid $frame.cntls -row 0 -column 0 -columnspan 2 -sticky nsew
+
+        if {![string equal $type "Tool"]} {
+            # can't let people delete the tool info
+            button $frame.cntls.del -text "Delete" -command main_options_delete
+            pack $frame.cntls.del -side right
+        }
+
+        button $frame.cntls.help -text "Help" -command main_options_help
+        pack $frame.cntls.help -side right
+
+        # put this in last so it gets squeezed out
+        Rappture::ObjPath $frame.cntls.path -label "Object" -pathtext $path \
+            -renamecommand main_options_rename
+        pack $frame.cntls.path -side left -expand yes -fill both
+
+        if {[string equal $type "Tool"]} {
+            # if this is a tool, then lose the rename button
+            pack forget [$frame.cntls.path component button]
+        }
+
+        array set ainfo [$hlist curselection -field attributes]
+
+        set wnum 1
+        foreach rec $attr {
+            catch {unset info}
+            set name [lindex $rec 0]
+            array set info [lrange $rec 1 end]
+
+            set atype [split $info(-type) :]
+            set atname [lindex $atype 0]
+            set atname "Attr[string totitle $atname]"
+            set atargs ""
+            foreach term [split [lindex $atype 1] ,] {
+                set key [lindex [split $term =] 0]
+                set val [lindex [split $term =] 1]
+                if {$key == "validate"} {
+                    set val "validate_$val"
+                }
+                lappend atargs -$key $val
+            }
+
+            set win [frame $frame.val$wnum]
+            if {[catch {eval $atname ::#auto $win $atargs} obj]} {
+                puts stderr "attribute editor failed: $obj"
+                destroy $win
+                continue
+            }
+            if {[info exists ainfo($name)]} {
+                $obj load $ainfo($name)
+            }
+            set OptionsPanelObjs($name) $obj
+
+            # no title? then use the attribute name as a title
+            if {[string length $info(-title)] == 0} {
+                set info(-title) [string totitle $name]
+            }
+            label $frame.l$wnum -text "$info(-title):"
+            grid $frame.l$wnum -row $wnum -column 0 -sticky e -padx 4 -pady 4
+            grid $win -row $wnum -column 1 -sticky nsew -pady 4
+            grid rowconfigure $frame $wnum -weight [expr {$info(-expand)? 1:0}]
+
+            # if an error was found at this attribute, set focus there
+            if {[string equal $name $ErrFocusAttr]} {
+                $obj edit
+                set ErrFocusAttr ""
+            }
+
+            incr wnum
+        }
+    }
+
+    # save this so we know later what node we're editing
+    set OptionsPanelNode $node
+}
+
+# ----------------------------------------------------------------------
+# USAGE: main_options_rename ?<name>?
+#
+# Used to change the id of the current selection to the given <name>.
+# ----------------------------------------------------------------------
+proc main_options_rename {args} {
+    set win [.func.build.options.panes pane 0]
+    set hlist $win.scrl.skel
+    set node [$hlist curselection]
+
+    if {[llength $args] > 0} {
+        $hlist tree set $node id [lindex $args 0]
+    }
+
+    # get the updated path for this element and show in ObjPath widget
+    set path [$hlist curselection -path "%lc:type(%id)"]
+    regsub -all {\(%id\)} $path "" path
+
+    set win [.func.build.options.panes pane 1]
+    set frame [$win.vals contents frame]
+    $frame.cntls.path configure -pathtext $path
+}
+
+# ----------------------------------------------------------------------
+# USAGE: main_options_save ?-clear?
+#
+# Scans through all attribute widgets on the panel showing the current
+# object and tells each one to save its value.  Returns 1 if successful,
+# or 0 if errors are encountered.  Any errors are indicated by a popup
+# cue under the widget with the bad value.
+# ----------------------------------------------------------------------
+proc main_options_save {{op -keep}} {
+    global OptionsPanelNode OptionsPanelObjs
+    set win [.func.build.options.panes pane 0]
+
+    if {$OptionsPanelNode != "" && [catch {$win.scrl.skel tree get $OptionsPanelNode attributes} attrlist] == 0} {
+        array set ainfo $attrlist
+
+        # transfer values from the panel to the ainfo array
+        foreach name [array names OptionsPanelObjs] {
+            set obj $OptionsPanelObjs($name)
+            if {![$obj save ainfo($name)]} {
+                return 0
+            }
+        }
+
+        # save current settings back in the tree
+        $win.scrl.skel tree set $OptionsPanelNode attributes [array get ainfo]
+    }
+
+    if {$op == "-clear"} {
+        foreach name [array names OptionsPanelObjs] {
+            itcl::delete object $OptionsPanelObjs($name)
+        }
+        catch {unset OptionsPanelObjs}
+
+        set win [.func.build.options.panes pane 1]
+        set frame [$win.vals contents frame]
+        foreach win [winfo children $frame] {
+            destroy $win
+        }
+    }
+    return 1
+}
+
+# ----------------------------------------------------------------------
+# USAGE: main_options_help
+#
+# Handles the "Help" button for an object.  Pops up a help page
+# explaining the object.
+# ----------------------------------------------------------------------
+proc main_options_help {} {
+    # delete the node from the tree
+    set win [.func.build.options.panes pane 0]
+    set hlist $win.scrl.skel
+    set node [$hlist curselection]
+    set type [$hlist curselection -field type]
+    if {"" != $node} {
+        # look for a -help option for this node type
+        set url [Rappture::objects::get $type -help]
+        if {"" != $url} {
+            Rappture::filexfer::webpage $url
+
+            set win [.func.build.options.panes pane 1]
+            set frame [$win.vals contents frame]
+            Rappture::Tooltip::cue $frame.cntls.help "Popping up a web page with additional help information.  Making sure your web browser is not blocking pop-ups."
+            after 2000 [list catch {Rappture::Tooltip::cue hide}]
+        }
+    }
+}
+
+# ----------------------------------------------------------------------
+# USAGE: main_options_delete
+#
+# Handles the "Delete" button for an object.  Deletes the object and
+# all of its children from the tree.
+# ----------------------------------------------------------------------
+proc main_options_delete {} {
+    global OptionsPanelNode OptionsPanelObjs
+
+    # delete the node from the tree
+    set win [.func.build.options.panes pane 0]
+    set hlist $win.scrl.skel
+    set node [$hlist curselection]
+    if {"" != $node} {
+        # clear the current panel without saving
+        foreach name [array names OptionsPanelObjs] {
+            itcl::delete object $OptionsPanelObjs($name)
+        }
+        catch {unset OptionsPanelObjs}
+
+        set win [.func.build.options.panes pane 1]
+        set frame [$win.vals contents frame]
+        foreach win [winfo children $frame] {
+            destroy $win
+        }
+
+        # now delete the node itself
+        $hlist tree delete $node
+    }
+}
+
+# ----------------------------------------------------------------------
+#  PREVIEW PANEL
+# ----------------------------------------------------------------------
+frame .func.preview
+.func insert end "Preview" -window .func.preview -fill both
+Rappture::Pager .func.preview.pager
+pack .func.preview.pager -expand yes -fill both
+
+bind .func.preview.pager <Map> main_preview
+
+# use this frame to cover preview before it appears
+blt::tile::frame .func.preview.stripes -tile [Rappture::icon diag]
+
+# ----------------------------------------------------------------------
+#  SAVE AS DIALOG
+# ----------------------------------------------------------------------
+toplevel .saveas
+pack propagate .saveas off
+wm title .saveas "iRappture: Save As..."
+wm withdraw .saveas
+wm protocol .saveas WM_DELETE_WINDOW {.saveas.cntls.cancel invoke}
+
+frame .saveas.cntls
+pack .saveas.cntls -side bottom -fill x -padx 4 -pady 4
+button .saveas.cntls.cancel -text "Cancel" -underline 0 \
+    -command {main_saveas cancel}
+pack .saveas.cntls.cancel -side right -padx 4 -pady 4
+button .saveas.cntls.save -text "Save" -underline 0 -default active \
+    -command {main_saveas finish} -state disabled
+pack .saveas.cntls.save -side right -padx 4 -pady 4
+
+frame .saveas.opts
+pack .saveas.opts -expand yes -fill both -padx 10 -pady 10
+label .saveas.opts.l -text "What do you want to save?"
+pack .saveas.opts.l -side top -anchor w
+
+checkbutton .saveas.opts.tool -text "Tool definition file" -variable SaveAs(tool) -command {main_saveas update}
+pack .saveas.opts.tool -side top -anchor w -pady {10 0}
+frame .saveas.opts.toolv
+pack .saveas.opts.toolv -anchor w
+label .saveas.opts.toolv.filel -text "File:" -width 12 -anchor e
+pack .saveas.opts.toolv.filel -side left
+button .saveas.opts.toolv.getfile -text "Choose..." -command {main_saveas gettoolfile}
+pack .saveas.opts.toolv.getfile -side right
+label .saveas.opts.toolv.file -text "select a file" -anchor e -fg gray60
+pack .saveas.opts.toolv.file -side left -expand yes -fill x
+.saveas.opts.tool select
+
+checkbutton .saveas.opts.prog -text "Skeleton program" -variable SaveAs(prog) -command {main_saveas update}
+pack .saveas.opts.prog -side top -anchor w -pady {10 0}
+frame .saveas.opts.progv
+pack .saveas.opts.progv -anchor w
+label .saveas.opts.progv.filel -text "File:" -width 12 -anchor e
+pack .saveas.opts.progv.filel -side left
+button .saveas.opts.progv.getfile -text "Choose..." -command {main_saveas getprogfile}
+pack .saveas.opts.progv.getfile -side right
+label .saveas.opts.progv.file -text "select a file" -anchor e -fg gray60
+pack .saveas.opts.progv.file -side left -expand yes -fill x
+frame .saveas.opts.progl
+pack .saveas.opts.progl -anchor w
+label .saveas.opts.progl.l -text "Language:" -width 12 -anchor e
+pack .saveas.opts.progl.l -side left
+Rappture::Combobox .saveas.opts.progl.val -width 20 -editable no
+pack .saveas.opts.progl.val -side left -pady {4 0}
+.saveas.opts.progl.val choices insert end \
+    .c    "C programs" \
+    .cpp  "C++ programs" \
+    .f    "F77 programs" \
+    .m    "MATLAB scripts" \
+    .pl   "Perl scripts" \
+    .py   "Python scripts" \
+    .tcl  "Tcl scripts" \
+    .ruby "Ruby scripts"
+.saveas.opts.progl.val value "Python scripts"
+
+# ----------------------------------------------------------------------
+#  Open the given XML file or create a new one
+# ----------------------------------------------------------------------
+set ToolXml ""
+set LastToolXmlLoaded ""
+set LastToolXmlFile ""
+set ToolPreview ""
+set ErrFocusAttr ""
+
+if {"" != $params(-tool)} {
+    if {![file exists $params(-tool)]} {
+        puts stderr "can't find tool \"$params(-tool)\""
+        exit 1
+    }
+    main_open $params(-tool)
+} else {
+    main_open -new
+}
Index: /trunk/builder/objects.tcl
===================================================================
--- /trunk/builder/objects.tcl	(revision 2080)
+++ /trunk/builder/objects.tcl	(revision 2080)
@@ -0,0 +1,455 @@
+# ----------------------------------------------------------------------
+#  COMPONENT: objects
+#
+#  This file contains routines to parse object data from files in
+#  the "objects" directory.  Each file defines a Rappture object and
+#  all information needed to specify the object in a tool.xml file.
+#
+#    object NAME ?-extends BASE? {
+#        attr NAME -title XX -type TYPE -path PATH
+#        check attr { code... }
+#        palettes NAME NAME ...
+#        help URL
+#        terminal yes|no
+#        ...
+#    }
+#
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+package require Itcl
+
+namespace eval Rappture { # forward declaration }
+namespace eval Rappture::objects {
+    #
+    # Set up a safe interpreter for loading object defn files...
+    #
+    variable objParser [interp create -safe]
+    foreach cmd [$objParser eval {info commands}] {
+	$objParser hide $cmd
+    }
+    $objParser alias object Rappture::objects::parse_object
+    $objParser alias unknown Rappture::objects::parse_obj_unknown
+    proc ::Rappture::objects::parse_obj_unknown {args} {
+        error "bad option \"[lindex $args 0]\": should be object"
+    }
+
+    #
+    # Set up a safe interpreter for loading object attributes...
+    #
+    variable attrParser [interp create -safe]
+    foreach cmd [$attrParser eval {info commands}] {
+	$attrParser hide $cmd
+    }
+    $attrParser alias attr Rappture::objects::parse_attr
+    $attrParser alias check Rappture::objects::parse_check
+    $attrParser alias help Rappture::objects::parse_help
+    $attrParser alias palettes Rappture::objects::parse_palettes
+    $attrParser alias terminal Rappture::objects::parse_terminal
+    $attrParser alias unknown Rappture::objects::parse_attr_unknown
+    proc ::Rappture::objects::parse_attr_unknown {args} {
+        error "bad option \"[lindex $args 0]\": should be attr, check, help, palettes, terminal"
+    }
+
+    # this variable will hold ObjDef object as it is being built
+    variable currObjDef ""
+
+    # this variable will hold the name of the object file being parsed
+    variable currFile ""
+}
+
+# ----------------------------------------------------------------------
+# USAGE: Rappture::objects::load ?<filePattern> <filePattern> ...?
+#
+# Clients call this to load object definitions from all files that
+# match the given set of file patterns.  These may be specific
+# file names or patterns of the form "dir/*.rp".  Each object is
+# loaded and Rappture::ObjDef objects are created as a side effect
+# to represent them.  Object types can be queried by calling
+# Rappture::objects::get.
+# ----------------------------------------------------------------------
+proc Rappture::objects::load {args} {
+    variable objParser
+    variable objDefs
+    variable currFile
+
+    # scan through all matching files and load their definitions
+    foreach pattern $args {
+        foreach fname [glob -nocomplain $pattern] {
+            set currFile $fname
+            set fid [open $fname r]
+            set info [read $fid]
+            close $fid
+
+            if {[catch {$objParser eval $info} err] != 0} {
+                error $err "\n    (while loading object definition from file \"$fname\")"
+            }
+        }
+    }
+
+    # look at all inheritance relationships and make sure they're satisfied
+    foreach name [array names objDefs] {
+        set ilist [$objDefs($name) cget -inherit]
+        set newilist ""
+        foreach obj $ilist {
+            if {[string index $obj 0] == "@"} {
+                set tname [string range $obj 1 end]
+                if {[info exists objDefs($tname)]} {
+                    lappend newilist $objDefs($tname)
+                } else {
+                    set errs($tname) 1
+                }
+            }
+            $objDefs($name) configure -inherit $newilist
+        }
+    }
+
+    if {[array size errs] > 0} {
+        error "missing definition for base class: [join [lsort [array names errs]] {, }]"
+    }
+}
+
+# ----------------------------------------------------------------------
+# USAGE: Rappture::objects::get ?<name>? ?-what?
+#
+# Returns information about the known Rappture object types.
+# With no args, it returns a list of object class names.  With a
+# specified <name>, it returns all information for that object in
+# a key/value format:
+#
+#   -image xxx -palettes {xx xx xx} -attributes {{...} {...} ...}
+#   -help URL -terminal bool
+#
+# Otherwise, the -what indicates which specific value should be
+# returned.
+# ----------------------------------------------------------------------
+proc Rappture::objects::get {{name ""} {what ""}} {
+    variable objDefs
+
+    if {"" == $name} {
+        return [array names objDefs]
+    }
+
+    set name [string tolower $name]  ;# doesn't matter: Tool or tool
+    set info(-image) [$objDefs($name) cget -image]
+    set info(-help) [$objDefs($name) cget -help]
+    set info(-palettes) [$objDefs($name) cget -palettes]
+    set info(-terminal) [$objDefs($name) cget -terminal]
+
+    set rlist ""
+    set olist $objDefs($name)
+    while {[llength $olist] > 0} {
+        set obj [lindex $olist 0]
+        if {![info exists gotparents($obj)]} {
+            set pos 0
+            foreach baseobj [$obj cget -inherit] {
+                set olist [linsert $olist $pos $baseobj]
+                incr pos
+            }
+            set gotparents($obj) 1
+        }
+
+        set obj [lindex $olist 0]
+        set olist [lrange $olist 1 end]
+
+        foreach aname [$obj get] {
+            lappend rlist [$obj get $aname]
+        }
+    }
+    set info(-attributes) $rlist
+
+    if {"" == $what} {
+        return [array get info]
+    } elseif {[info exists info($what)]} {
+        return $info($what)
+    }
+    error "bad option \"$what\": should be [join [lsort [array names info]] {, }]"
+}
+
+# ----------------------------------------------------------------------
+# USAGE: Rappture::objects::palettes
+#
+# Returns a list of unique palette names from all known types.
+# ----------------------------------------------------------------------
+proc Rappture::objects::palettes {} {
+    variable objDefs
+
+    foreach name [array names objDefs] {
+        foreach pname [$objDefs($name) cget -palettes] {
+            set unique($pname) 1
+        }
+    }
+    return [lsort -dictionary [array names unique]]
+}
+
+# ----------------------------------------------------------------------
+# USAGE: Rappture::objects::check <type> {<key> <val>...} <debugInfo>
+#
+# Checks the definition for an object of the given <type> to see if
+# there are any errors in the values.  The attribute values are
+# specified as a key/value list.  Returns a list of the form:
+#   error "something went wrong"
+#   warning "might check this"
+# ----------------------------------------------------------------------
+proc Rappture::objects::check {type attrinfo debug} {
+    variable objDefs
+
+    set type [string tolower $type]  ;# doesn't matter: Tool or tool
+
+    if {[info exists objDefs($type)]} {
+        return [$objDefs($type) check $attrinfo $debug]
+    }
+    return ""
+}
+
+# ----------------------------------------------------------------------
+# PARSER:  Rappture::objects::parse_object
+#
+# Used internally to parse the definition of a Rappture object type:
+#
+#   object <name> ?-extends <type>? {
+#     attr <name> <args>...
+#     attr <name> <args>...
+#     ...
+#   }
+#
+# Builds an object in currObjDef and then registers the completed
+# object in the objDefs array.
+# ----------------------------------------------------------------------
+proc Rappture::objects::parse_object {args} {
+    variable currObjDef
+    variable currFile
+    variable objDefs
+    variable attrParser
+
+    set name [lindex $args 0]
+    set args [lrange $args 1 end]
+
+    set ilist ""
+    while {1} {
+        set first [lindex $args 0]
+        if {[string index $first 0] != "-"} {
+            break
+        }
+        if {"-extends" == $first} {
+            set base [lindex $args 1]
+            set args [lrange $args 2 end]
+            lappend ilist @$base
+        } else {
+            error "bad option \"$first\": should be -extends"
+        }
+    }
+
+    if {[llength $args] != 1} {
+        error "wrong # args: should be \"object name ?-extends base? {...definition...}\""
+    }
+    set body [lindex $args end]
+
+    # create an object definition and add attributes to it
+    set currObjDef [Rappture::objects::ObjDef ::#auto -inherit $ilist]
+    set cmds {
+        # parse attribute definitions
+        $attrParser eval $body
+
+        # look for an image for this object
+        set rootf [file rootname $currFile]
+        foreach ext {png jpg gif} {
+            if {[file readable $rootf.$ext]} {
+                set imh [image create photo -file $rootf.$ext]
+                $currObjDef configure -image $imh
+                break
+            }
+        }
+    }
+
+    if {[catch $cmds err] != 0} {
+        itcl::delete object $currObjDef
+        set currObjDef ""
+        error $err "\n    (while loading object definition for \"$name\")"
+    }
+
+    set objDefs($name) $currObjDef
+    set currObjDef ""
+}
+
+# ----------------------------------------------------------------------
+# PARSER:  Rappture::objects::parse_attr
+#
+# Used internally to parse the definition of an attribute within a
+# Rappture object definition:
+#
+#   attr <name> -title <string> -type <string> -path <string>
+#
+# Adds an attribute definition to the object in currObjDef.
+# ----------------------------------------------------------------------
+proc Rappture::objects::parse_attr {args} {
+    variable currObjDef
+
+    set name [lindex $args 0]
+    eval $currObjDef add attr $name [lrange $args 1 end]
+}
+
+# ----------------------------------------------------------------------
+# PARSER:  Rappture::objects::parse_check
+#
+# Used internally to register a bit of code that's used to check the
+# integrity of a value.
+#
+#   check attr { code... }
+#
+# The code assumes that attribute values are stored in an attr(...)
+# array.  It checks the values and returns errors in the following
+# format:
+#   error "something went wrong" {-node 2 -counter 7 -attr label}
+#   warning "watch out for this" {-node 8 -counter 1 -attr description}
+# ----------------------------------------------------------------------
+proc Rappture::objects::parse_check {attr code} {
+    variable currObjDef
+    $currObjDef add check $attr $code
+}
+
+# ----------------------------------------------------------------------
+# PARSER:  Rappture::objects::parse_help
+#
+# Used internally to parse the definition of the help page URL for a
+# Rappture object definition:
+#
+#   help <url>
+#
+# Keeps the <url> around so it can be displayed later in a "Help"
+# button on the attribute editor.
+# ----------------------------------------------------------------------
+proc Rappture::objects::parse_help {url} {
+    variable currObjDef
+    if {![regexp {^https?://} $url]} {
+        error "bad value \"$url\": should be a URL for the help page"
+    }
+    $currObjDef configure -help $url
+}
+
+# ----------------------------------------------------------------------
+# PARSER:  Rappture::objects::parse_palettes
+#
+# Used internally to parse the definition of the palettes for a
+# Rappture object definition:
+#
+#   palettes <name> <name> ...
+#
+# Adds the list of palettes to the object definition.  This determines
+# what palettes of controls will contain this object.
+# ----------------------------------------------------------------------
+proc Rappture::objects::parse_palettes {args} {
+    variable currObjDef
+    $currObjDef configure -palettes $args
+}
+
+# ----------------------------------------------------------------------
+# PARSER:  Rappture::objects::parse_terminal
+#
+# Used internally to parse the "terminal" setting within a Rappture
+# object definition:
+#
+#   terminal yes|no
+#
+# Sets the Boolean value, which determines whether or not this object
+# can have other objects embedded within it.  If it is "terminal",
+# an object is a leaf node.
+# ----------------------------------------------------------------------
+proc Rappture::objects::parse_terminal {val} {
+    variable currObjDef
+    if {![string is boolean -strict $val]} {
+        error "bad value \"$val\": should be boolean"
+    }
+    $currObjDef configure -terminal $val
+}
+
+# ----------------------------------------------------------------------
+#  CLASS: ObjDef
+# ----------------------------------------------------------------------
+itcl::class Rappture::objects::ObjDef {
+    public variable inherit ""
+    public variable image ""
+    public variable help ""
+    public variable terminal "yes"
+    public variable palettes ""
+
+    constructor {args} {
+        set _checks(num) 0
+        eval configure $args
+    }
+
+    public method add {what name args} {
+        switch -- $what {
+            attr {
+                if {[info exists _attr2def($name)]} {
+                    error "attribute \"$name\" already defined"
+                }
+                set obj [Rappture::objects::ObjAttr #auto]
+                if {[catch {eval $obj configure $args} err] != 0} {
+                    itcl::delete object $obj
+                    error $err
+                }
+                lappend _attrs $name
+                set _attr2def($name) $obj
+            }
+            check {
+                set n [incr _checks(num)]
+                set _checks($n-attr) $name
+                set _checks($n-code) [lindex $args 0]
+            }
+        }
+    }
+
+    public method get {{name ""}} {
+        if {"" == $name} {
+            return $_attrs
+        } elseif {[info exists _attr2def($name)]} {
+            set rlist $name
+            foreach opt [$_attr2def($name) configure] {
+                lappend rlist [lindex $opt 0] [lindex $opt 2]
+            }
+            return $rlist
+        }
+    }
+
+    # call this to check the integrity of all values
+    public method check {data debug} {
+        set rlist ""
+        array set attr $data
+        for {set n 1} {$n <= $_checks(num)} {incr n} {
+            set status [catch $_checks($n-code) result]
+            if {$status != 0 && $status != 2} {
+                puts stderr "ERROR DURING VALUE CHECK:\n$result"
+            } elseif {[llength $result] > 0} {
+                set class [lindex $result 0]
+                set mesg [lindex $result 1]
+                set dinfo $debug
+                lappend dinfo -attribute $_checks($n-attr)
+                lappend rlist [list $class $mesg $dinfo]
+            }
+        }
+        return $rlist
+    }
+
+    private variable _attrs ""  ;# list of attr names in order
+    private variable _attr2def  ;# maps attr name => ObjAttr object
+    private variable _checks    ;# bits of code used for checks
+}
+
+# ----------------------------------------------------------------------
+#  CLASS: ObjAttr
+# ----------------------------------------------------------------------
+itcl::class Rappture::objects::ObjAttr {
+    public variable title ""
+    public variable type ""
+    public variable path ""
+    public variable expand "no"
+
+    constructor {args} {
+        eval configure $args
+    }
+}
Index: /trunk/builder/objects/base.rp
===================================================================
--- /trunk/builder/objects/base.rp	(revision 2080)
+++ /trunk/builder/objects/base.rp	(revision 2080)
@@ -0,0 +1,5 @@
+object base {
+    attr label -type string -path about.label
+    attr description -type string:lines=3 -expand yes -path about.description
+    attr enable -title "Enable" -type string:validate=enable -path about.enable
+}
Index: /trunk/builder/objects/boolean.rp
===================================================================
--- /trunk/builder/objects/boolean.rp	(revision 2080)
+++ /trunk/builder/objects/boolean.rp	(revision 2080)
@@ -0,0 +1,19 @@
+object boolean -extends base {
+    palettes "Inputs"
+    help http://rappture.org/wiki/rp_xml_ele_boolean
+    attr default -title "Default Value" -type boolean -path default
+
+    check label {
+        if {[string length [string trim $attr(label)]] == 0} {
+            return [list warning "Should set a label that describes this value."]
+        }
+    }
+    check description {
+        set desc [string trim $attr(description)]
+        if {[string length $desc] == 0} {
+            return [list warning "Should include a description of what this value represents, typical settings, etc."]
+        } elseif {[string equal $desc $attr(label)]} {
+            return [list warning "Description should be different from the label and give additional information about the value."]
+        }
+    }
+}
Index: /trunk/builder/objects/curve.rp
===================================================================
--- /trunk/builder/objects/curve.rp	(revision 2080)
+++ /trunk/builder/objects/curve.rp	(revision 2080)
@@ -0,0 +1,47 @@
+object curve -extends base {
+    palettes "Outputs"
+    help http://rappture.org/wiki/rp_xml_ele_curve
+    attr group -title "Plotting Group" -type string -path about.group
+    attr xlabel -title "X-axis Label" -type string -path xaxis.label
+    attr xdesc  -title "X-axis Description" -type string -path xaxis.description
+    attr xunits -title "X-axis Units" -type units -path xaxis.units
+    attr ylabel -title "Y-axis Label" -type string -path yaxis.label
+    attr ydesc  -title "Y-axis Description" -type string -path yaxis.description
+    attr yunits -title "Y-axis Units" -type units -path yaxis.units
+
+    check label {
+        if {[string length [string trim $attr(label)]] == 0} {
+            return [list warning "Should set a label that describes this value."]
+        }
+    }
+    check description {
+        set desc [string trim $attr(description)]
+        if {[string length $desc] == 0} {
+            return [list warning "Should include a description of what this value represents, typical settings, etc."]
+        } elseif {[string equal $desc $attr(label)]} {
+            return [list warning "Description should be different from the label and give additional information about the value."]
+        }
+    }
+
+    check xlabel {
+        if {[string length [string trim $attr(xlabel)]] == 0} {
+            return [list warning "Should set a label that describes the x-axis of this plot."]
+        }
+    }
+    check xdesc {
+        if {[string length [string trim $attr(xdesc)]] == 0} {
+            return [list warning "Should include a description of what the x-axis represents, physical meaning, expected range, etc."]
+        }
+    }
+
+    check ylabel {
+        if {[string length [string trim $attr(ylabel)]] == 0} {
+            return [list warning "Should set a label that describes the y-axis of this plot."]
+        }
+    }
+    check ydesc {
+        if {[string length [string trim $attr(ydesc)]] == 0} {
+            return [list warning "Should include a description of what the y-axis represents, physical meaning, expected range, etc."]
+        }
+    }
+}
Index: /trunk/builder/objects/group.rp
===================================================================
--- /trunk/builder/objects/group.rp	(revision 2080)
+++ /trunk/builder/objects/group.rp	(revision 2080)
@@ -0,0 +1,5 @@
+object group -extends base {
+    palettes "Grouping"
+    help http://rappture.org/wiki/rp_xml_ele_group
+    terminal no
+}
Index: /trunk/builder/objects/histogram.rp
===================================================================
--- /trunk/builder/objects/histogram.rp	(revision 2080)
+++ /trunk/builder/objects/histogram.rp	(revision 2080)
@@ -0,0 +1,46 @@
+object histogram -extends base {
+    palettes "Outputs"
+    help http://rappture.org/wiki/rp_xml_ele_histogram
+    attr xlabel -title "X-axis Label" -type string -path xaxis.label
+    attr xdesc  -title "X-axis Description" -type string -path xaxis.description
+    attr xunits -title "X-axis Units" -type units -path xaxis.units
+    attr ylabel -title "Y-axis Label" -type string -path yaxis.label
+    attr ydesc  -title "Y-axis Description" -type string -path yaxis.description
+    attr yunits -title "Y-axis Units" -type units -path yaxis.units
+
+    check label {
+        if {[string length [string trim $attr(label)]] == 0} {
+            return [list warning "Should set a label that describes this value."]
+        }
+    }
+    check description {
+        set desc [string trim $attr(description)]
+        if {[string length $desc] == 0} {
+            return [list warning "Should include a description of what this value represents, typical settings, etc."]
+        } elseif {[string equal $desc $attr(label)]} {
+            return [list warning "Description should be different from the label and give additional information about the value."]
+        }
+    }
+
+    check xlabel {
+        if {[string length [string trim $attr(xlabel)]] == 0} {
+            return [list warning "Should set a label that describes the x-axis of this plot."]
+        }
+    }
+    check xdesc {
+        if {[string length [string trim $attr(xdesc)]] == 0} {
+            return [list warning "Should include a description of what the x-axis represents, physical meaning, expected range, etc."]
+        }
+    }
+
+    check ylabel {
+        if {[string length [string trim $attr(ylabel)]] == 0} {
+            return [list warning "Should set a label that describes the y-axis of this plot."]
+        }
+    }
+    check ydesc {
+        if {[string length [string trim $attr(ydesc)]] == 0} {
+            return [list warning "Should include a description of what the y-axis represents, physical meaning, expected range, etc."]
+        }
+    }
+}
Index: /trunk/builder/objects/integer.rp
===================================================================
--- /trunk/builder/objects/integer.rp	(revision 2080)
+++ /trunk/builder/objects/integer.rp	(revision 2080)
@@ -0,0 +1,39 @@
+object integer -extends base {
+    palettes "Inputs"
+    help http://rappture.org/wiki/rp_xml_ele_integer
+    attr default -title "Default Value" -type string:validate=int -path default
+    attr min -title "Minimum Value" -type string:validate=int -path min
+    attr max -title "Maximum Value" -type string:validate=int -path max
+
+    check label {
+        if {[string length [string trim $attr(label)]] == 0} {
+            return [list warning "Should set a label that describes this value."]
+        }
+    }
+    check description {
+        set desc [string trim $attr(description)]
+        if {[string length $desc] == 0} {
+            return [list warning "Should include a description of what this value represents, typical settings, etc."]
+        } elseif {[string equal $desc $attr(label)]} {
+            return [list warning "Description should be different from the label and give additional information about the value."]
+        }
+    }
+
+    check default {
+        if {[string length [string trim $attr(default)]] == 0} {
+            return [list error "Must have a default value for this integer."]
+        }
+        if {"" != $attr(min) && $attr(default) < $attr(min)} {
+            return [list error "Default value is less than the minimum that you've specified for this value."]
+        }
+        if {"" != $attr(max) && $attr(default) > $attr(max)} {
+            return [list error "Default value is greater than the maximum that you've specified for this value."]
+        }
+    }
+
+    check min {
+        if {"" != $attr(min) && "" != $attr(max) && $attr(min) >= $attr(max)} {
+            return [list error "Minimum value should be less than the maximum.  If you don't want to see a min/max range, you can clear out either or both values."]
+        }
+    }
+}
Index: /trunk/builder/objects/note.rp
===================================================================
--- /trunk/builder/objects/note.rp	(revision 2080)
+++ /trunk/builder/objects/note.rp	(revision 2080)
@@ -0,0 +1,13 @@
+object note {
+    palettes "Documentation"
+    help http://rappture.org/wiki/rp_xml_ele_note
+    attr contents -title "HTML File" -type file -path contents
+
+    check contents {
+        set fname [string trim $attr(contents)]
+        if {[string length $fname] == 0
+              || [string equal $fname "select a file"]} {
+            return [list warning "Should set an HTML file with the contents of the note, or else delete the element."]
+        }
+    }
+}
Index: /trunk/builder/objects/number.rp
===================================================================
--- /trunk/builder/objects/number.rp	(revision 2080)
+++ /trunk/builder/objects/number.rp	(revision 2080)
@@ -0,0 +1,78 @@
+object number -extends base {
+    palettes "Inputs"
+    help http://rappture.org/wiki/rp_xml_ele_number
+    attr default -title "Default Value" -type string:validate=number -path default
+    attr units -title "Units of Measurement" -type units -path units
+    attr min -title "Minimum Value" -type string:validate=number -path min
+    attr max -title "Maximum Value" -type string:validate=number -path max
+    attr color -title "Color" -type color -path color
+
+    check label {
+        if {[string length [string trim $attr(label)]] == 0} {
+            return [list warning "Should set a label that describes this value"]
+        }
+    }
+    check description {
+        set desc [string trim $attr(description)]
+        if {[string length $desc] == 0} {
+            return [list warning "Should include a description of what this value represents, typical settings, etc."]
+        } elseif {[string equal $desc $attr(label)]} {
+            return [list warning "Description should be different from the label and give additional information about the value."]
+        }
+    }
+
+    check default {
+        if {[string length [string trim $attr(default)]] == 0} {
+            return [list error "Must have a default value for this number."]
+        }
+        if {"" != $attr(units)} {
+            set base [Rappture::Units::System::for $attr(units)]
+            if {[validate_number_parse $attr(default) num units]
+               && "" != $units
+               && ![string equal [Rappture::Units::System::for $units] $base]} {
+                return [list error "Units for default value don't match the expected units for this value"]
+            }
+
+            set dval [Rappture::Units::convert $attr(default) -context $attr(units) -to $attr(units) -units off]
+
+            if {[validate_number_parse $attr(min) num units]
+                 && [catch {Rappture::Units::convert $attr(min) -context $attr(units) -to $attr(units) -units off} min] == 0
+                 && $dval < $min} {
+                return [list error "Default value is less than the minimum that you've specified for this value."]
+            }
+
+            if {[validate_number_parse $attr(max) num units]
+                 && [catch {Rappture::Units::convert $attr(max) -context $attr(units) -to $attr(units) -units off} max] == 0
+                 && $dval > $max} {
+                return [list error "Default value is greater than the maximum that you've specified for this value."]
+            }
+        }
+    }
+
+    check min {
+        if {"" != $attr(units)} {
+            set base [Rappture::Units::System::for $attr(units)]
+            if {[validate_number_parse $attr(min) num units]
+               && "" != $units
+               && ![string equal [Rappture::Units::System::for $units] $base]} {
+                return [list error "Units for minimum value don't match the expected units for this value"]
+            }
+        }
+        if {[catch {Rappture::Units::convert $attr(min) -context $attr(units) -to $attr(units) -units off} min] == 0
+              && [catch {Rappture::Units::convert $attr(max) -context $attr(units) -to $attr(units) -units off} max] == 0
+              && $min >= $max} {
+            return [list error "Minimum value should be less than the maximum.  If you don't want to see a min/max range, you can clear out either or both values."]
+        }
+    }
+
+    check max {
+        if {"" != $attr(units)} {
+            set base [Rappture::Units::System::for $attr(units)]
+            if {[validate_number_parse $attr(max) num units]
+               && "" != $units
+               && ![string equal [Rappture::Units::System::for $units] $base]} {
+                return [list error "Units for maximum value don't match the expected units for this value"]
+            }
+        }
+    }
+}
Index: /trunk/builder/objects/phase.rp
===================================================================
--- /trunk/builder/objects/phase.rp	(revision 2080)
+++ /trunk/builder/objects/phase.rp	(revision 2080)
@@ -0,0 +1,5 @@
+object phase -extends base {
+    palettes "Grouping"
+    help http://rappture.org/wiki/rp_xml_ele_phase
+    terminal no
+}
Index: /trunk/builder/objects/string.rp
===================================================================
--- /trunk/builder/objects/string.rp	(revision 2080)
+++ /trunk/builder/objects/string.rp	(revision 2080)
@@ -0,0 +1,7 @@
+object string -extends base {
+    palettes "Inputs"
+    help http://rappture.org/wiki/rp_xml_ele_string
+    attr default -title "Default Value" -type string -path default
+    attr size -title "Size" -type string:validate=size -path size
+    attr hints -title "Hint String" -type string -path about.hints
+}
Index: /trunk/builder/objects/tool.rp
===================================================================
--- /trunk/builder/objects/tool.rp	(revision 2080)
+++ /trunk/builder/objects/tool.rp	(revision 2080)
@@ -0,0 +1,32 @@
+object tool {
+    help http://rappture.org/wiki/rappture_xml_elements
+
+    attr title -type string -path title
+    attr description -type string:lines=6 -expand yes -path about
+    attr command -type string -path command
+
+    check title {
+        if {[string length [string trim $attr(title)]] == 0} {
+            return [list warning "You should include a title that describes your tool.  This usually appears on the opening screen when the tool starts up."]
+        }
+    }
+
+    check description {
+        if {[string length [string trim $attr(description)]] == 0} {
+            return [list warning "You should include a brief description of your tool.  This usually appears on the opening screen when the tool starts up."]
+        }
+    }
+
+    check command {
+        set cmd [string trim $attr(command)]
+        if {[string length $cmd] == 0} {
+            return [list error "Must set the command associated with the underlying tool that will be invoked to handle the simulation."]
+        }
+        if {![regexp @tool $cmd]} {
+            return [list warning "The command string usually contains @tool, which represents the directory containing the tool.xml file.  The program is usually located relative to this directory.  Avoid hard-coded directory paths."]
+        }
+        if {![regexp @driver $cmd]} {
+            return [list warning "The command should contain the argument @driver, which represents the driver input file generated by Rappture."]
+        }
+    }
+}
Index: /trunk/builder/objpath.tcl
===================================================================
--- /trunk/builder/objpath.tcl	(revision 2080)
+++ /trunk/builder/objpath.tcl	(revision 2080)
@@ -0,0 +1,301 @@
+# ----------------------------------------------------------------------
+#  COMPONENT: objpath - show object path and copy/rename
+#
+#  This widget is used within the header above the object options
+#  panel.  It shows the object name, but includes a button for things
+#  like "rename" to change the object ID, and "copy" to copy the
+#  path and paste into another widget.
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+package require Itk
+
+option add *ObjPath.selectBackground cyan widgetDefault
+option add *ObjPath.pathFont {helvetica -12} widgetDefault
+
+itcl::class Rappture::ObjPath {
+    inherit itk::Widget
+
+    itk_option define -label label Label ""
+    itk_option define -pathtext pathText PathText ""
+    itk_option define -selectbackground selectBackground Foreground ""
+    itk_option define -renamecommand renameCommand RenameCommand ""
+
+    constructor {args} { # defined below }
+
+    protected method _redraw {args}
+    protected method _resize {args}
+    protected method _hilite {op}
+    protected method _copy {}
+    protected method _edit {option args}
+
+    private variable _dispatcher ""  ;# dispatcher for !events
+}
+
+itk::usual ObjPath {
+    keep -cursor -font -foreground -background
+}
+
+# ----------------------------------------------------------------------
+# CONSTRUCTOR
+# ----------------------------------------------------------------------
+itcl::body Rappture::ObjPath::constructor {args} {
+    # create a dispatcher for events
+    Rappture::dispatcher _dispatcher
+    $_dispatcher register !redraw
+    $_dispatcher dispatch $this !redraw [itcl::code $this _redraw]
+
+    itk_component add size {
+        frame $itk_interior.size -width 20
+    }
+    pack propagate $itk_component(size) no
+    pack $itk_component(size) -side left -expand yes -fill both
+
+    itk_component add path {
+        text $itk_component(size).path -width 1 -height 1 \
+            -borderwidth 0 -highlightthickness 0
+    } {
+        usual
+        rename -font -pathfont pathFont Font
+        ignore -highlightthickness -highlightbackground -highlightcolor
+    }
+    pack $itk_component(path) -expand yes -fill both
+
+    # bind to <Expose> instead of <Configure> so we get events even after
+    # we've reached the maximum width size, so we can scale down smaller
+    bind $itk_component(path) <Expose> [itcl::code $this _resize]
+    bindtags $itk_component(path) [list $itk_component(path) [winfo toplevel $itk_component(path)] all]
+
+    # binding so when you click on the path, it becomes highlighted
+    $itk_component(path) tag bind path <ButtonPress> [itcl::code $this _hilite toggle]
+
+    # add the button for Rename/Copy
+    itk_component add button {
+        button $itk_interior.btn -width 6 -text "Rename" \
+            -command [itcl::code $this _edit start]
+    } {
+        usual
+        ignore -font -borderwidth -relief
+    }
+    pack $itk_component(button) -side left
+
+    # create a pop-up editor to handle "rename" operations
+    itk_component add editor {
+        Rappture::Editor $itk_interior.editor \
+            -activatecommand [itcl::code $this _edit activate] \
+            -validatecommand [itcl::code $this _edit validate] \
+            -applycommand [itcl::code $this _edit apply]
+    }
+
+    bind $itk_component(editor) <Unmap> [itcl::code $this _edit revert]
+
+    eval itk_initialize $args
+}
+
+# ----------------------------------------------------------------------
+# USAGE: _redraw ?<eventArgs>...?
+#
+# Used internally to redraw all items on the path name display.  This
+# gets invoked after the widget is packed to wrap the path name
+# properly whenever the width changes.
+# ----------------------------------------------------------------------
+itcl::body Rappture::ObjPath::_redraw {args} {
+    set fn $itk_option(-pathfont)
+    $itk_component(path) delete 1.0 end
+
+    set label $itk_option(-label)
+    if {"" != $label && ![string match *: $label]} {
+        append label ":"
+    }
+    $itk_component(path) insert end $label
+    $itk_component(path) insert end "  "
+    $itk_component(path) insert end $itk_option(-pathtext) path
+
+    _resize
+}
+
+# ----------------------------------------------------------------------
+# USAGE: _resize ?<eventArgs>...?
+#
+# Used internally to update the height of the path part of this widget
+# whenever it changes size.  If the path gets squeezed, it wraps onto
+# multiple lines.  This routine figures out how many lines to display.
+# ----------------------------------------------------------------------
+itcl::body Rappture::ObjPath::_resize {args} {
+    set fn $itk_option(-pathfont)
+
+    # figure out how much width is available for the path
+    set whull [winfo width $itk_component(hull)]
+    set wbtn [winfo width $itk_component(button)]
+    set wpath [expr {$whull-$wbtn-10}]
+
+    # if the path were on 1 line, how much width would we need?
+    # if it fits on 1 line, then pack it differently
+    set str [$itk_component(path) get 1.0 end]
+    set w [font measure $fn $str]
+    if {$w < $wpath} {
+        $itk_component(size) configure -width [expr {$w+4}]
+        pack $itk_component(size) -expand no -fill x
+    } else {
+        $itk_component(size) configure -width 1
+        pack $itk_component(size) -expand yes -fill both
+    }
+
+    # figure out how many lines we need for the height
+    set lspace [font metrics $fn -linespace]
+    set bbox [$itk_component(path) bbox end-1char]
+    if {"" != $bbox} {
+        # Find the position of the last char and figure out how tall to be.
+        foreach {x0 y0 w h} $bbox break
+        set ht [expr {round(ceil(($y0+$h-2)/double($lspace)))}]
+        $itk_component(path) configure -height $ht
+    } else {
+        # Dang! bbox won't work because the last char is off screen.
+        # Figure out the char in the bottom-right corner and then
+        # guess how many lines are off screen below that.
+        set w [expr {[winfo width $itk_component(path)]-4}]
+        set h [expr {[winfo height $itk_component(path)]-4}]
+        set index [$itk_component(path) index @$w,$h]
+        set cnum [lindex [split $index .] 1]
+        set end [lindex [split [$itk_component(path) index end-1char] .] 1]
+        set frac [expr {1 + double($end-$cnum)/$end}]
+
+        set ht [expr {$frac*[winfo height $itk_component(path)]}]
+        set ht [expr {round(ceil($ht/$lspace))}]
+        $itk_component(path) configure -height $ht
+    }
+    $itk_component(size) configure -height [expr {$ht*$lspace+4}]
+}
+
+# ----------------------------------------------------------------------
+# USAGE: _hilite set|clear
+#
+# Invoked whenever you click on the path name to highlight the path
+# and change to "copy" mode for the path.
+# ----------------------------------------------------------------------
+itcl::body Rappture::ObjPath::_hilite {op} {
+    switch -- $op {
+        set {
+            $itk_component(path) tag configure path \
+                -background $itk_option(-selectbackground) \
+                -borderwidth 1 -relief raised
+            $itk_component(button) configure -text "Copy" \
+                -command [itcl::code $this _copy]
+        }
+        clear {
+            $itk_component(path) tag configure path \
+                -background "" -borderwidth 0
+            $itk_component(button) configure -text "Rename" \
+                -command [itcl::code $this _edit start]
+        }
+        toggle {
+            if {"" != [$itk_component(path) tag cget path -background]} {
+                _hilite clear
+            } else {
+                _hilite set
+            }
+        }
+        default {
+            error "bad option \"$op\": should be set, clear, toggle"
+        }
+    }
+}
+
+# ----------------------------------------------------------------------
+# USAGE: _copy
+#
+# Handles the operation of the "Copy" button.  Copies the current
+# path text to the clipboard so it can be pasted into other widgets.
+# ----------------------------------------------------------------------
+itcl::body Rappture::ObjPath::_copy {} {
+    clipboard clear
+    clipboard append -type STRING -- $itk_option(-pathtext)
+    _hilite clear
+}
+
+# ----------------------------------------------------------------------
+# USAGE: _edit activate
+# USAGE: _edit validate <value>
+# USAGE: _edit apply <value>
+# USAGE: _edit revert
+#
+# Used internally to handle the pop-up editor that edits part of
+# the title string for a node.  The "start" operation is called when
+# the user clicks on the "rename" button.  This brings up an editor
+# for the id anme, allowing the user to change the name.  The
+# "activate" operation is called by the editor to figure out where
+# it should pop up.  The "validate" operation is called to check the
+# new value and make sure that it is okay.  The "apply" operation
+# applies the new name to the node.  The "revert" operation puts
+# the original value back into the display when the user presses Esc.
+# ----------------------------------------------------------------------
+itcl::body Rappture::ObjPath::_edit {option args} {
+    switch -- $option {
+        start {
+            if {[regexp -indices {[a-zA-Z]+\([a-zA-Z0-9_]+\)$} $itk_option(-pathtext) match]} {
+                foreach {s0 s1} $match break
+                $itk_component(path) delete 1.0 end
+                $itk_component(path) insert 1.0 [string range $itk_option(-pathtext) $s0 end]
+                $itk_component(editor) activate
+            }
+        }
+        activate {
+            if {[regexp -indices {([a-zA-Z]+)\(([a-zA-Z0-9_]+)\)$} $itk_option(-pathtext) match type id]} {
+                foreach {t0 t1} $type break
+                foreach {s0 s1} $id break
+                set str [string range $itk_option(-pathtext) $s0 $s1]
+
+                set s0 [expr {$s0-$t0}]  ;# set relative to start of tail string
+                set s1 [expr {$s1-$t0}]
+
+                # get bbox for first and last char in "(id)" part
+                foreach {x0 y0 w h} [$itk_component(path) bbox 1.$s0] break
+                foreach {x1 y0 w h} [$itk_component(path) bbox 1.$s1] break
+                set x1 [expr {$x1+$w}]
+                set y1 [expr {$y0+$h}]
+
+                # compute overall x0,y0 and width/height for this area
+                set w [expr {$x1-$x0}]
+                set h [expr {$y1-$y0}]
+                set x0 [expr {[winfo rootx $itk_component(path)]+$x0}]
+                set y0 [expr {[winfo rooty $itk_component(path)]+$y0}]
+
+                return [list text $str x $x0 y [expr {$y0-2}] w $w h $h]
+            }
+        }
+        validate {
+            set val [lindex $args 0]
+            if {![regexp {^[a-zA-Z0-9_]+$} $val]} {
+                bell
+                return 0
+            }
+            return 1
+        }
+        apply {
+            set val [lindex $args 0]
+            if {[string length $itk_option(-renamecommand)] > 0} {
+                uplevel #0 $itk_option(-renamecommand) [list $val]
+            }
+        }
+        revert {
+            _redraw
+        }
+        default {
+            error "bad option \"$option\": should be start, activate, validate, apply, revert"
+        }
+    }
+}
+
+# ----------------------------------------------------------------------
+# CONFIGURATION OPTION: -label, -pathtext
+# ----------------------------------------------------------------------
+itcl::configbody Rappture::ObjPath::label {
+    $_dispatcher event -idle !redraw
+}
+itcl::configbody Rappture::ObjPath::pathtext {
+    $_dispatcher event -idle !redraw
+}
Index: /trunk/builder/pkgIndex.tcl.in
===================================================================
--- /trunk/builder/pkgIndex.tcl.in	(revision 2080)
+++ /trunk/builder/pkgIndex.tcl.in	(revision 2080)
@@ -0,0 +1,12 @@
+
+package ifneeded RapptureBuilder @PACKAGE_VERSION@ [format {
+    set dir [file normalize "%s"]
+    set version @PACKAGE_VERSION@
+    lappend auto_path [file join $dir scripts]
+    namespace eval RapptureBuilder {
+	variable version $version
+	variable library $dir
+    }
+    package provide RapptureBuilder $version
+} $dir]
+
Index: /trunk/builder/slideframes.tcl
===================================================================
--- /trunk/builder/slideframes.tcl	(revision 2080)
+++ /trunk/builder/slideframes.tcl	(revision 2080)
@@ -0,0 +1,369 @@
+# ----------------------------------------------------------------------
+#  COMPONENT: slideframes - collection of frames with headings
+#
+#  This widget is similar to a tabbed notebook, but instead of having
+#  tabs on the side, it has headings inline with the content.  Clicking
+#  on a heading brings up the frame beneath the heading.  Only one
+#  frame can be packed at a time.
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+package require Itk
+
+option add *Slideframes.width 0 widgetDefault
+option add *Slideframes.height 0 widgetDefault
+option add *Slideframes.headingBackground gray widgetDefault
+option add *Slideframes.headingForeground black widgetDefault
+option add *Slideframes.headingBorderWidth 2 widgetDefault
+option add *Slideframes.headingRelief raised widgetDefault
+
+itcl::class Rappture::Slideframes {
+    inherit itk::Widget
+
+    itk_option define -width width Width 0
+    itk_option define -height height Height 0
+    itk_option define -animstartcommand animStartCommand AnimStartCommand ""
+    itk_option define -animendcommand animEndCommand AnimEndCommand ""
+
+    constructor {args} { # defined below }
+    destructor { # defined below }
+
+    public method insert {pos args}
+    public method delete {args}
+    public method index {name}
+    public method page {name}
+    public method current {args}
+    public method size {} { return [llength $_pages] }
+
+    private method _fixSize {}
+    private method _fixLayout {args}
+
+    private variable _count 0       ;# counter for unique names
+    private variable _pages ""      ;# list of page frames
+    private variable _name2num      ;# maps name => id num for heading/page
+    private variable _current ""    ;# page currently shown
+    private variable _tweener ""    ;# tweener object for animations
+}
+
+itk::usual Slideframes {
+    keep -cursor -font
+    keep -headingbackground -headingforeground
+    keep -headingborderwidth -headingrelief
+}
+
+# ----------------------------------------------------------------------
+# CONSTRUCTOR
+# ----------------------------------------------------------------------
+itcl::body Rappture::Slideframes::constructor {args} {
+    itk_option add hull.width hull.height
+    pack propagate $itk_component(hull) no
+
+    bind $itk_component(hull) <Configure> [itcl::code $this _fixLayout]
+
+    set _tweener [Rappture::Tweener #auto]
+
+    eval itk_initialize $args
+}
+
+# ----------------------------------------------------------------------
+# DESTRUCTOR
+# ----------------------------------------------------------------------
+itcl::body Rappture::Slideframes::destructor {} {
+    itcl::delete object $_tweener
+}
+
+# ----------------------------------------------------------------------
+# USAGE: insert <pos> ?<name> <name>...?
+#
+# Used to insert one or more pages in the list of sliding frames.
+# Each page is identified by its <name>.  Returns the widget name
+# for each page created.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Slideframes::insert {pos args} {
+    set rlist ""
+    foreach name $args {
+        if {[lsearch $_pages $name] >= 0} {
+            error "page \"$name\" already exists"
+        }
+        set id [incr _count]
+
+        set hname "heading$id"
+        itk_component add $hname {
+            button $itk_interior.$hname -text $name -highlightthickness 0 \
+                -anchor w -command [itcl::code $this current $name]
+        } {
+            usual
+            rename -background -headingbackground headingBackground Background
+            rename -foreground -headingforeground headingForeground Foreground
+            rename -borderwidth -headingborderwidth headingBorderWidth BorderWidth
+            rename -relief -headingrelief headingRelief Relief
+            ignore -highlightthickness
+        }
+
+        set pname "page$id"
+        itk_component add $pname {
+            frame $itk_interior.$pname
+        }
+        bind $itk_component($pname) <Configure> [itcl::code $this _fixSize]
+
+        if {[llength $_pages] == 0} {
+            # select first page by default
+            after idle [list catch [list $this current $name]]
+        }
+        set _pages [linsert $_pages $pos $name]
+        set _name2num($name) $id
+
+        lappend rlist $itk_component($pname)
+    }
+
+    return $rlist
+}
+
+# ----------------------------------------------------------------------
+# USAGE: delete -all
+# USAGE: delete ?<name> <name>...?
+#
+# Used to delete one or more pages from the notebook.  With the -all
+# flag, it deletes all pages.  Otherwise, it deletes each page
+# by name.  You can also delete a page by using an index of the
+# form "@n".
+# ----------------------------------------------------------------------
+itcl::body Rappture::Slideframes::delete {args} {
+    if {$args == "-all"} {
+        set args $_pages
+    }
+    foreach name $args {
+        set i [index $name]
+        set pname [lindex $_pages $i]
+        if {$pname != ""} {
+            set _pages [lreplace $_pages $i $i]
+            set id $_name2num($pname)
+            destroy $itk_component(heading$id) $itk_component(page$id)
+            unset _name2num($pname)
+        }
+    }
+}
+
+# ----------------------------------------------------------------------
+# USAGE: index <name>|@n
+#
+# Used to convert a page <name> to its corresponding integer index.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Slideframes::index {name} {
+    set i [lsearch $_pages $name]
+    if {$i >= 0} {
+        return $i
+    }
+    if {[regexp {^@([0-9]+)$} $name match i]} {
+        return $i
+    }
+    error "bad page name \"$name\": should be @int or one of [join [lsort $_pages] {, }]"
+}
+
+# ----------------------------------------------------------------------
+# USAGE: page <name>|@n
+#
+# Used to convert a page <name> to its corresponding frame.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Slideframes::page {name} {
+    set i [index $name]
+    set name [lindex $_pages $i]
+    set id $_name2num($name)
+    return $itk_component(page$id)
+}
+
+# ----------------------------------------------------------------------
+# USAGE: current ?<name>?
+#
+# Used to query/set the current page in the notebook.  With no args,
+# it returns the name of the current page.  Otherwise, it sets the
+# current page.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Slideframes::current {args} {
+    switch -- [llength $args] {
+        0 {
+            return $_current
+        }
+        1 {
+            set name [lindex $args 0]
+            set index [lsearch -exact $_pages $name]
+            if {$index < 0} {
+                error "can't find page \"$name\""
+            }
+
+            set prev $_current
+            set _current [lindex $_pages $index]
+
+            if {$prev != $_current} {
+                $_tweener configure -from 0 -to 1 -duration 50 -steps 10 \
+                    -command [itcl::code $this _fixLayout $_current $prev %v] \
+                    -finalize [itcl::code $this _fixLayout end]
+            } else {
+                _fixLayout
+            }
+        }
+        default {
+            error "wrong # args: should be \"current ?name?\""
+        }
+    }
+}
+
+# ----------------------------------------------------------------------
+# USAGE: _fixSize
+#
+# Used to handle the requested size for this widget.  If -width or
+# -height is 0, then the size is computed based on the requested
+# sizes of internal pages.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Slideframes::_fixSize {} {
+    if {"0" == $itk_option(-width)} {
+        set wd 0
+        foreach pname $_pages {
+            set id $_name2num($pname)
+            set w [winfo reqwidth $itk_component(page$id)]
+            if {$w > $wd} { set wd $w }
+        }
+        component hull configure -width $wd
+    } else {
+        component hull configure -width $itk_option(-width)
+    }
+
+    if {"0" == $itk_option(-height)} {
+        set headht 0
+        set pageht 0
+        foreach pname $_pages {
+            set id $_name2num($pname)
+            set h [winfo reqheight $itk_component(heading$id)]
+            set headht [expr {$headht + $h}]
+
+            set h [winfo reqheight $itk_component(page$id)]
+            if {$h > $pageht} { set pageht $h }
+        }
+        component hull configure -height [expr {$headht+$pageht}]
+    } else {
+        component hull configure -height $itk_option(-height)
+    }
+}
+
+# ----------------------------------------------------------------------
+# USAGE: _fixLayout ?<toName>? ?<fromName>? ?<frac>?
+#
+# Updates the layout of pages within this widget.  With no args, it
+# updates the layout based on the current page.  This is good for
+# resize operations.  The extra args let us animate from the layout
+# with one ID to the layout with another according to a fraction
+# <frac> from 0 to 1.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Slideframes::_fixLayout {args} {
+    set atend 0
+    if {$args == "end"} {
+        set atend 1
+        set args ""
+    }
+
+    set toName $_current
+    set fromName ""
+    set frac 1
+    if {[llength $args] >= 1} { set toName [lindex $args 0] }
+    if {[llength $args] >= 2} { set fromName [lindex $args 1] }
+    if {[llength $args] >= 3} { set frac [lindex $args 2] }
+    if {[llength $args] > 3} {
+        error "wrong # args: should be \"_fixLayout ?id? ?previd? ?frac?\""
+    }
+
+    if {$frac == 0 && [string length $itk_option(-animstartcommand)] > 0} {
+        if {[catch [list uplevel #0 $itk_option(-animstartcommand)] err]} {
+            bgerror $err
+        }
+    }
+
+    set fromid ""
+    if {[info exists _name2num($fromName)]} {
+        set fromid $_name2num($fromName)
+    }
+
+    set toid ""
+    if {[info exists _name2num($toName)]} {
+        set toid $_name2num($toName)
+    }
+
+    set w [winfo width $itk_component(hull)]
+    set h [winfo height $itk_component(hull)]
+
+    # figure out the overall size of title buttons and space left over
+    set titlemax 0
+    foreach pname $_pages {
+        set id $_name2num($pname)
+        set titleh [winfo reqheight $itk_component(heading$id)]
+        set titlemax [expr {$titlemax + $titleh}]
+    }
+
+    set extra [expr {$h - $titlemax}]
+    if {$extra < 0} { set extra 0 }
+
+    if {$toid != ""} {
+        set pageht1 [winfo reqheight $itk_component(page$toid)]
+    } else {
+        set pageht1 0
+    }
+    if {$fromid != ""} {
+        set pageht2 [winfo reqheight $itk_component(page$fromid)]
+    } else {
+        set pageht2 0
+    }
+    set pageht [expr {$frac*$pageht1 + (1-$frac)*$pageht2}]
+    if {$pageht < $extra} {
+        set extra $pageht
+    }
+
+    # scan through all buttons and place them, along with the pages beneath
+    set ypos 0
+    foreach pname $_pages {
+        set id $_name2num($pname)
+        set titleh [winfo reqheight $itk_component(heading$id)]
+
+        # place the heading button
+        place $itk_component(heading$id) -x 0 -y $ypos -anchor nw \
+            -width $w -height $titleh
+        set ypos [expr {$ypos + $titleh}]
+
+        set pageht [winfo reqheight $itk_component(page$id)]
+        if {$id == $fromid || $id == $toid} {
+            if {$id == $toid} {
+                set ht [expr {round($extra * $frac)}]
+            } else {
+                set ht [expr {round($extra * (1-$frac))}]
+            }
+            if {$ht > $pageht} { set ht $pageht }
+            if {$ht > 0} {
+                place $itk_component(page$id) -x 0 -y $ypos -anchor nw \
+                    -width $w -height $ht
+                set ypos [expr {$ypos + $ht}]
+            } else {
+                place forget $itk_component(page$id)
+            }
+        } else {
+            place forget $itk_component(page$id)
+        }
+    }
+
+    if {$atend && [string length $itk_option(-animendcommand)] > 0} {
+        if {[catch [list uplevel #0 $itk_option(-animendcommand)] err]} {
+            bgerror $err
+        }
+    }
+}
+
+# ----------------------------------------------------------------------
+# OPTION: -width, -height
+# ----------------------------------------------------------------------
+itcl::configbody Rappture::Slideframes::width {
+    _fixSize
+}
+itcl::configbody Rappture::Slideframes::height {
+    _fixSize
+}
Index: /trunk/builder/tweener.tcl
===================================================================
--- /trunk/builder/tweener.tcl	(revision 2080)
+++ /trunk/builder/tweener.tcl	(revision 2080)
@@ -0,0 +1,117 @@
+# ----------------------------------------------------------------------
+#  COMPONENT: tweener - used for animating smooth movements
+#
+#  Each Tweener executes a command repeatedly through a series of
+#  values from one extreme to another.  For example, the command may
+#  change the size of a rectangle, and the values may go from 10 to
+#  200.  The Tweener will make that happen over a specified interval
+#  of time.  The animation can be stopped or changed at any point,
+#  and if the Tweener is destroyed, the action is cancelled.
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+package require Itcl
+
+namespace eval Rappture { # forward declaration }
+
+itcl::class Rappture::Tweener {
+    public variable from 0        ;# value goes from this...
+    public variable to   1        ;# ...to this
+    public variable duration 500  ;# during this time interval
+    public variable steps 10      ;# with this many steps
+    public variable command ""    ;# gets executed with %v for value
+    public variable finalize ""   ;# gets executed at the end to finish up
+
+    constructor {args} { eval configure $args }
+    destructor { # defined below }
+
+    public method go {{how "-resume"}}
+    public method stop {}
+
+    private method _next {}
+
+    private variable _nstep 0      ;# current step number
+    private variable _afterid ""   ;# pending after event
+}
+										
+# ----------------------------------------------------------------------
+# DESTRUCTOR
+# ----------------------------------------------------------------------
+itcl::body Rappture::Tweener::destructor {} {
+    stop
+}
+
+# ----------------------------------------------------------------------
+# USAGE: go ?-resume|-restart?
+#
+# Causes the current animation to start running, either where it
+# left off (-resume) or fromt the beginning (-restart).
+# ----------------------------------------------------------------------
+itcl::body Rappture::Tweener::go {{how -resume}} {
+    switch -- $how {
+        -resume {
+            # leave _nstep alone
+        }
+        -restart {
+            set _nstep 0
+        }
+        default {
+            error "bad option \"$how\": should be -restart or -resume"
+        }
+    }
+    stop
+    set _afterid [after idle [itcl::code $this _next]]
+}
+
+# ----------------------------------------------------------------------
+# USAGE: stop
+#
+# Causes the animation to stop by cancelling any pending after event.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Tweener::stop {} {
+    if {"" != $_afterid} {
+	after cancel $_afterid
+        set _afterid ""
+    }
+}
+
+# ----------------------------------------------------------------------
+# USAGE: _next
+#
+# Used internally to advance the animation.  Executes the -command
+# option with the current value substituted in place of any %v values.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Tweener::_next {} {
+    set value [expr {($to-$from)/double($steps)*$_nstep + $from}]
+    set cmd $command
+    regsub -all %v $cmd $value cmd
+    if {[catch {uplevel #0 $cmd} result]} {
+        bgerror $result "\n    (while managing tweener $this)"
+    }
+
+    if {[incr _nstep] <= $steps} {
+        set delay [expr {round($duration/double($steps))}]
+        set _afterid [after $delay [itcl::code $this _next]]
+    } elseif {[string length $finalize] > 0} {
+        set cmd $finalize
+        regsub -all %v $cmd $value cmd
+        if {[catch {uplevel #0 $cmd} result]} {
+            bgerror $result "\n    (while finalizing tweener $this)"
+        }
+    }
+}
+
+# ----------------------------------------------------------------------
+# CONFIGURATION OPTION: -command
+# ----------------------------------------------------------------------
+itcl::configbody Rappture::Tweener::command {
+    if {[string length $command] == 0} {
+        stop
+    } else {
+        go -restart
+    }
+}
Index: /trunk/builder/types/boolean.tcl
===================================================================
--- /trunk/builder/types/boolean.tcl	(revision 2080)
+++ /trunk/builder/types/boolean.tcl	(revision 2080)
@@ -0,0 +1,74 @@
+# ----------------------------------------------------------------------
+#  EDITOR: boolean attribute values
+#
+#  Used within the Instant Rappture builder to edit boolean values.
+#
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+itcl::class AttrBoolean {
+    constructor {win args} {
+        Rappture::getopts args params {
+        }
+
+        Rappture::Combobox $win.val -width 10 -editable no
+        pack $win.val -side left
+        $win.val choices insert end 1 "True" 0 "False"
+        set _win $win
+    }
+
+    public method check {} {
+        set val [$_win.val translate [$_win.val value]]
+        if {![string is boolean -strict $val]} {
+            return [list error "Bad value \"$val\": should be Boolean"]
+        }
+        return ""
+    }
+
+    public method load {val} {
+        if {![string is boolean -strict $val] || $val} {
+            $_win.val value "True"
+        } else {
+            $_win.val value "False"
+        }
+    }
+
+    public method save {var} {
+        upvar $var value
+        set str [$_win.val translate [$_win.val value]]
+        if {[string is boolean -strict $str] && $str} {
+            set value "yes"
+        } else {
+            set value "no"
+        }
+        return 1
+    }
+
+    public method edit {} {
+        focus $_win.val
+    }
+
+    public proc import {xmlobj path} {
+        set val [$xmlobj get $path]
+        if {[string is boolean -strict $val] && $val} {
+            set val "yes"
+        } else {
+            set val "no"
+        }
+        return $val
+    }
+
+    public proc export {xmlobj path value} {
+        if {$value} {
+            $xmlobj put $path "yes"
+        } else {
+            $xmlobj put $path "no"
+        }
+    }
+
+    private variable _win ""       ;# containing frame
+}
Index: /trunk/builder/types/color.tcl
===================================================================
--- /trunk/builder/types/color.tcl	(revision 2080)
+++ /trunk/builder/types/color.tcl	(revision 2080)
@@ -0,0 +1,97 @@
+# ----------------------------------------------------------------------
+#  EDITOR: color attribute values
+#
+#  Used within the Instant Rappture builder to edit color values.
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+itcl::class AttrColor {
+    constructor {win args} {
+        Rappture::getopts args params {
+        }
+        set _icon [image create photo -width 20 -height 20]
+
+        label $win.sample -image $_icon
+        pack $win.sample -side left
+        button $win.change -text "Choose..." -command [itcl::code $this choose]
+        pack $win.change -side left
+        _redraw ""
+
+        set _win $win
+    }
+    destructor {
+        image delete $_icon
+    }
+
+    public method load {val} {
+        _redraw $val
+    }
+
+    public method check {} {
+        if {"" != $_color && [catch {winfo rgb . $_color} err]} {
+            return [list error "Bad value \"$_color\": should be color name or #RRGGBB"]
+        }
+    }
+
+    public method save {var} {
+        upvar $var value
+
+        set err [lindex [check] 1]
+        if {[string length $err] > 0} {
+            Rappture::Tooltip::cue $_win $err
+            return 0
+        }
+
+        set value $_color
+        return 1
+    }
+
+    public method edit {} {
+        focus $_win.change
+    }
+
+    public proc import {xmlobj path} {
+        # trivial import -- just return info as-is from XML
+        return [$xmlobj get $path]
+    }
+
+    public proc export {xmlobj path value} {
+        # trivial export -- just save info as-is into XML
+        if {[string length $value] > 0} {
+            $xmlobj put $path $value
+        }
+    }
+
+    public method choose {} {
+        if {"" != $_color} {
+            _redraw [tk_chooseColor -title "iRappture: Choose Color" -initialcolor $_color]
+        } else {
+            _redraw [tk_chooseColor -title "iRappture: Choose Color"]
+        }
+    }
+
+    private method _redraw {color} {
+        set _color $color
+        set w [image width $_icon]
+        set h [image width $_icon]
+        $_icon put white -to 0 0 $w $h
+        $_icon put black -to 0 0 $w 1
+        $_icon put black -to 0 0 1 $h
+        $_icon put black -to [expr {$w-1}] 0 $w $h
+        $_icon put black -to 0 [expr {$h-1}] $w $h
+
+        if {"" != $color} {
+            $_icon put $color -to 4 4 [expr {$w-4}] [expr {$h-4}]
+        } else {
+            $_icon copy [Rappture::icon diag] -to 4 4 [expr {$w-4}] [expr {$h-4}]
+        }
+    }
+
+    private variable _win ""       ;# containing frame
+    private variable _icon ""      ;# image for color sample
+    private variable _color ""     ;# name of color sample
+}
Index: /trunk/builder/types/file.tcl
===================================================================
--- /trunk/builder/types/file.tcl	(revision 2080)
+++ /trunk/builder/types/file.tcl	(revision 2080)
@@ -0,0 +1,117 @@
+# ----------------------------------------------------------------------
+#  EDITOR: file attribute values
+#
+#  Used within the Instant Rappture builder to set file paths.
+#  Rappture tries to avoid files, but it's okay for things like the
+#  <note> element, which points to documentation.
+#
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+itcl::class AttrFile {
+    constructor {win args} {
+        Rappture::getopts args params {
+        }
+        label $win.file -text "select a file" -width 10 -anchor e -fg gray60
+        pack $win.file -side left
+        button $win.getfile -text "Choose..." -command [itcl::code $this _getfile]
+        pack $win.getfile -side left
+
+        set _win $win
+    }
+
+    public method load {val} {
+        if {[string length $val] > 0} {
+            $_win.file configure -text $val -foreground black
+
+            # if the file name is long, then set up to clip and show the tail
+            set w [expr {[winfo width $_win]-[winfo width $_win.getfile]}]
+            set fn [$_win.file cget -font]
+            if {[font measure $fn $val] > $w} {
+                $_win.file configure -width 10
+                pack $_win.file -expand yes -fill x
+            } else {
+                $_win.file configure -width 0
+                pack $_win.file -expand no
+            }
+        }
+    }
+
+    public method check {} {
+        set fname [$_win.file cget -text]
+        if {"" != $fname && ![string equal $fname "select a file"]
+              && ![regexp {^file://(.+)} $fname]} {
+            return [list error "Bad value \"$fname\": should be file://filename"]
+        }
+    }
+
+    public method save {var} {
+        upvar $var value
+
+        set err [lindex [check] 1]
+        if {[string length $err] > 0} {
+            Rappture::Tooltip::cue $_win $err
+            return 0
+        }
+
+        set value [$_win.file cget -text]
+        if {[string equal $value "select a file"]} {
+            set value ""
+        }
+        return 1
+    }
+
+    public method edit {} {
+        focus $_win.getfile
+    }
+
+    public proc import {xmlobj path} {
+        # trivial import -- just return info as-is from XML
+        return [$xmlobj get $path]
+    }
+
+    public proc export {xmlobj path value} {
+        global LastToolXmlFile
+
+        # save a relative path to this file
+        if {[regexp {^file://(.+)} $value match fname]} {
+            if {[file pathtype $fname] == "absolute"} {
+                set dir [file dirname $LastToolXmlFile]
+                if {[string match $dir/* $fname]} {
+                    set len [string length "$dir/"]
+                    set value [string range $fname $len end]
+                } elseif {"" != $LastToolXmlFile} {
+                    error "Can't find file \"$fname\" relative to tool.xml file.  All items for a tool should be bundled together in the same directory, so they can be easily relocated later."
+                }
+            }
+        }
+
+        if {[string length $value] > 0} {
+            $xmlobj put $path $value
+        }
+    }
+
+    protected method _getfile {} {
+        set fname [tk_getOpenFile -title "iRappture: Select HTML File" -defaultextension .html -filetypes { {{HTML files} {.html .htm}} {{All files} *} }]
+        if {"" != $fname} {
+            $_win.file configure -text "file://$fname" -foreground black
+
+            # if the file name is long, then set up to clip and show the tail
+            set w [expr {[winfo width $_win]-[winfo width $_win.getfile]}]
+            set fn [$_win.file cget -font]
+            if {[font measure $fn $fname] > $w} {
+                $_win.file configure -width 10
+                pack $_win.file -expand yes -fill x
+            } else {
+                $_win.file configure -width 0
+                pack $_win.file -expand no
+            }
+        }
+    }
+
+    private variable _win ""       ;# containing frame
+}
Index: /trunk/builder/types/string.tcl
===================================================================
--- /trunk/builder/types/string.tcl	(revision 2080)
+++ /trunk/builder/types/string.tcl	(revision 2080)
@@ -0,0 +1,102 @@
+# ----------------------------------------------------------------------
+#  EDITOR: string attribute values
+#
+#  Used within the Instant Rappture builder to edit string values.
+#  Strings can have the following additional options:
+#
+#    -lines N ......... height of editor (default is 1 line)
+#    -validate type ... validation routine applied to string values
+#
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+itcl::class AttrString {
+    constructor {win args} {
+        Rappture::getopts args params {
+            value -lines 1
+            value -validate ""
+        }
+
+        if {$params(-lines) > 1} {
+            Rappture::Scroller $win.scrl -xscrollmode none -yscrollmode auto
+            pack $win.scrl -expand yes -fill both
+            text $win.scrl.text -width 10 -height $params(-lines) -wrap word
+            $win.scrl contents $win.scrl.text
+        } else {
+            entry $win.str
+            pack $win.str -fill x
+        }
+        set _win $win
+        set _validate $params(-validate)
+    }
+
+    public method load {val} {
+        if {[winfo exists $_win.str]} {
+            $_win.str delete 0 end
+            $_win.str insert end $val
+        } else {
+            $_win.scrl.text delete 1.0 end
+            $_win.scrl.text insert end $val
+        }
+    }
+
+    public method check {} {
+        if {[string length $_validate] > 0} {
+            if {[winfo exists $_win.str]} {
+                set str [$_win.str get]
+            } else {
+                set str [$_win.scrl.text get 1.0 end-1char]
+            }
+            if {[catch {uplevel #0 $_validate [list $str]} result]} {
+                return [list error "Bad value: $result"]
+            }
+        }
+    }
+
+    public method save {var} {
+        upvar $var value
+
+        set err [lindex [check] 1]
+        if {[string length $err] > 0} {
+            Rappture::Tooltip::cue $_win $err
+            return 0
+        }
+
+        if {[winfo exists $_win.str]} {
+            set value [$_win.str get]
+        } else {
+            set value [$_win.scrl.text get 1.0 end-1char]
+        }
+        return 1
+    }
+
+    public method edit {} {
+        if {[winfo exists $_win.str]} {
+            focus $_win.str
+            $_win.str selection from 0
+            $_win.str selection to end
+        } else {
+            focus $_win.scrl.text
+            $_win.scrl.text tag add sel 1.0 end
+        }
+    }
+
+    public proc import {xmlobj path} {
+        # trivial import -- just return info as-is from XML
+        return [$xmlobj get $path]
+    }
+
+    public proc export {xmlobj path value} {
+        # trivial export -- just save info as-is into XML
+        if {[string length $value] > 0} {
+            $xmlobj put $path $value
+        }
+    }
+
+    private variable _win ""       ;# containing frame
+    private variable _validate ""  ;# validation command for checking values
+}
Index: /trunk/builder/types/units.tcl
===================================================================
--- /trunk/builder/types/units.tcl	(revision 2080)
+++ /trunk/builder/types/units.tcl	(revision 2080)
@@ -0,0 +1,119 @@
+# ----------------------------------------------------------------------
+#  EDITOR: units attribute values
+#
+#  Used within the Instant Rappture builder to edit units for numbers.
+#
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+itcl::class AttrUnits {
+    constructor {win args} {
+        Rappture::getopts args params {
+        }
+
+        Rappture::Combobox $win.val -width 10 -editable yes
+        pack $win.val -side left
+        $win.val choices insert end \
+          m   "Length Units" \
+          m   "  m - meters" \
+          in  "  in - inches" \
+          ft  "  ft - feet" \
+          yd  "  yd - yards" \
+          mi  "  mi - miles" \
+          s   "Time Units" \
+          s   "  s - seconds" \
+          min "  min - minutes" \
+          h   "  h - hours" \
+          d   "  d - days" \
+          Hz  "  Hz - Hertz" \
+          K   "Temperature Units" \
+          K   "  K - Kelvin" \
+          F   "  F - Fahrenheit" \
+          C   "  C - Celcius" \
+          eV  "Energy Units" \
+          eV  "  eV - electron Volts" \
+          J   "  J - Joules" \
+          V   "  V - volts" \
+          m3  "Volume Units" \
+          m3  "  cubic meter" \
+          gal "  gal - US gallon" \
+          L   "  L - liter" \
+          deg "Angle Units" \
+          deg "  deg - degrees" \
+          rad "  rad - radians" \
+          g   "Mass Units" \
+          g   "  g - grams" \
+          N   "Force Units" \
+          N   "  N - Newtons" \
+          Pa  "Pressure Units" \
+          Pa  "  Pa - Pascals" \
+          atm "  atm - atmospheres" \
+          pis "  psi - pounds per square inch" \
+          T   "Magnetic Units" \
+          T   "  T - Teslas" \
+          G   "  G - Gauss"
+
+        set _win $win
+    }
+
+    public method check {} {
+        set val [$_win.val translate [$_win.val value]]
+        if {"" != $val} {
+            return ""
+        }
+        set val [$_win.val value]
+        if {"" != [Rappture::Units::description $val]} {
+            return ""
+        }
+        return [list error "Bad value \"$val\": should be valid system of units"]
+    }
+
+    public method load {val} {
+        set newval [$_win.val translate $val]
+        if {"" != $newval} {
+            $_win.val value $newval
+        } else {
+            $_win.val value $val
+        }
+    }
+
+    public method save {var} {
+        upvar $var value
+
+        set err [lindex [check] 1]
+        if {[string length $err] > 0} {
+            Rappture::Tooltip::cue $_win $err
+            return 0
+        }
+
+        set val [$_win.val value]
+        set newval [$_win.val translate $val]
+        if {"" != $newval} {
+            set value $newval
+        } else {
+            set value $val
+        }
+        return 1
+    }
+
+    public method edit {} {
+        focus $_win.val
+        $_win.val component entry selection from 0
+        $_win.val component entry selection to end
+    }
+
+    public proc import {xmlobj path} {
+        set val [$xmlobj get $path]
+        return $val
+    }
+
+    public proc export {xmlobj path value} {
+        $xmlobj put $path $value
+    }
+
+    private variable _win ""       ;# containing frame
+}
Index: /trunk/builder/validations/enable.tcl
===================================================================
--- /trunk/builder/validations/enable.tcl	(revision 2080)
+++ /trunk/builder/validations/enable.tcl	(revision 2080)
@@ -0,0 +1,17 @@
+# ----------------------------------------------------------------------
+#  VALIDATION: enable
+#
+#  Handles the type:validate=enable setting for an object attribute.
+#  Checks the given string to see if it is a valid Rappture <enable>
+#  settings.  Returns an error if something is wrong.
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+proc validate_enable {str} {
+    # punt for now
+    return "ok"
+}
Index: /trunk/builder/validations/int.tcl
===================================================================
--- /trunk/builder/validations/int.tcl	(revision 2080)
+++ /trunk/builder/validations/int.tcl	(revision 2080)
@@ -0,0 +1,18 @@
+# ----------------------------------------------------------------------
+#  VALIDATION: int
+#
+#  Handles the string:validate=int setting for an object attribute.
+#  Checks the given string to see if it is an integer value.  Returns
+#  an error if something is wrong.
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+proc validate_int {str} {
+    if {![string is integer $str]} {
+        error "bad value \"$str\": should be an integer"
+    }
+}
Index: /trunk/builder/validations/number.tcl
===================================================================
--- /trunk/builder/validations/number.tcl	(revision 2080)
+++ /trunk/builder/validations/number.tcl	(revision 2080)
@@ -0,0 +1,31 @@
+# ----------------------------------------------------------------------
+#  VALIDATION: number
+#
+#  Handles the type:validate=number setting for an object attribute.
+#  Checks the given string to see if it is a valid Rappture "number"
+#  value.  Returns an error if something is wrong.
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+proc validate_number_parse {str numvar unitsvar} {
+    upvar $numvar num
+    upvar $unitsvar units
+    return [regexp {^([-+]?(?:[0-9]+\.|\.)?[0-9]+(?:[eE][-+]?[0-9]+)?)( *(?:[a-zA-Z]+[0-9]*)+(?:\/(?:[a-zA-Z]+[0-9]*)+)*)*$} $str match num units]
+}
+
+proc validate_number {str} {
+    if {"" == $str} {
+        # empty string is okay
+        return "ok"
+    } elseif {[validate_number_parse $str num units]} {
+        if {"" != $units && "" == [Rappture::Units::description $units]} {
+            error "units \"$units\" not recognized"
+        }
+        return "ok"
+    }
+    error "should be a real number with units"
+}
Index: /trunk/builder/validations/size.tcl
===================================================================
--- /trunk/builder/validations/size.tcl	(revision 2080)
+++ /trunk/builder/validations/size.tcl	(revision 2080)
@@ -0,0 +1,23 @@
+# ----------------------------------------------------------------------
+#  VALIDATION: size
+#
+#  Handles the string:validate=size setting for an object attribute.
+#  Checks the given string to see if it is a valid size for a <string>
+#  object.  Returns an error if something is wrong.
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+proc validate_size {str} {
+    switch -regexp -- $str {
+        ^$ - ^[0-9]+$ - ^[0-9]+x[0-9]+$ - binary {
+            return "ok"
+        }
+        default {
+            error "bad size \"$str\": should be WW or WWxHH or binary"
+        }
+    }
+}
Index: /trunk/configure
===================================================================
--- /trunk/configure	(revision 2079)
+++ /trunk/configure	(revision 2080)
@@ -1,13 +1,11 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.68 for Rappture 1.1.
+# Generated by GNU Autoconf 2.64 for Rappture 1.1.
 #
 # Report bugs to <rappture@nanohub.org>.
 #
-#
 # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
-# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software
 # Foundation, Inc.
-#
 #
 # This configure script is free software; the Free Software Foundation
@@ -92,5 +90,4 @@
 
 # Find who we are.  Look in the path if we contain no directory separator.
-as_myself=
 case $0 in #((
   *[\\/]* ) as_myself=$0 ;;
@@ -218,16 +215,9 @@
 	# neutralization value for shells without unset; and this also
 	# works around shells that cannot unset nonexistent variables.
-	# Preserve -v and -x to the replacement shell.
 	BASH_ENV=/dev/null
 	ENV=/dev/null
 	(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
 	export CONFIG_SHELL
-	case $- in # ((((
-	  *v*x* | *x*v* ) as_opts=-vx ;;
-	  *v* ) as_opts=-v ;;
-	  *x* ) as_opts=-x ;;
-	  * ) as_opts= ;;
-	esac
-	exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}
+	exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
 fi
 
@@ -328,5 +318,5 @@
     done
     test -z "$as_dirs" || eval "mkdir $as_dirs"
-  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+  } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir"
 
 
@@ -368,17 +358,17 @@
 
 
-# as_fn_error STATUS ERROR [LINENO LOG_FD]
-# ----------------------------------------
+# as_fn_error ERROR [LINENO LOG_FD]
+# ---------------------------------
 # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
 # provided, also output the error to LOG_FD, referencing LINENO. Then exit the
-# script with STATUS, using 1 if that was 0.
+# script with status $?, using 1 if that was 0.
 as_fn_error ()
 {
-  as_status=$1; test $as_status -eq 0 && as_status=1
-  if test "$4"; then
-    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
-  fi
-  $as_echo "$as_me: error: $2" >&2
+  as_status=$?; test $as_status -eq 0 && as_status=1
+  if test "$3"; then
+    as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3
+  fi
+  $as_echo "$as_me: error: $1" >&2
   as_fn_exit $as_status
 } # as_fn_error
@@ -538,9 +528,8 @@
 
 
-test -n "$DJDIR" || exec 7<&0 </dev/null
-exec 6>&1
+exec 7<&0 </dev/null 6>&1
 
 # Name of the host.
-# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
 # so uname gets run too.
 ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
@@ -865,7 +854,6 @@
 
   case $ac_option in
-  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
-  *=)   ac_optarg= ;;
-  *)    ac_optarg=yes ;;
+  *=*)	ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *)	ac_optarg=yes ;;
   esac
 
@@ -912,5 +900,5 @@
     # Reject names that are not valid shell variable names.
     expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      as_fn_error $? "invalid feature name: $ac_useropt"
+      as_fn_error "invalid feature name: $ac_useropt"
     ac_useropt_orig=$ac_useropt
     ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
@@ -938,5 +926,5 @@
     # Reject names that are not valid shell variable names.
     expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      as_fn_error $? "invalid feature name: $ac_useropt"
+      as_fn_error "invalid feature name: $ac_useropt"
     ac_useropt_orig=$ac_useropt
     ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
@@ -1142,5 +1130,5 @@
     # Reject names that are not valid shell variable names.
     expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      as_fn_error $? "invalid package name: $ac_useropt"
+      as_fn_error "invalid package name: $ac_useropt"
     ac_useropt_orig=$ac_useropt
     ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
@@ -1158,5 +1146,5 @@
     # Reject names that are not valid shell variable names.
     expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      as_fn_error $? "invalid package name: $ac_useropt"
+      as_fn_error "invalid package name: $ac_useropt"
     ac_useropt_orig=$ac_useropt
     ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
@@ -1188,6 +1176,6 @@
     x_libraries=$ac_optarg ;;
 
-  -*) as_fn_error $? "unrecognized option: \`$ac_option'
-Try \`$0 --help' for more information"
+  -*) as_fn_error "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information."
     ;;
 
@@ -1197,5 +1185,5 @@
     case $ac_envvar in #(
       '' | [0-9]* | *[!_$as_cr_alnum]* )
-      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+      as_fn_error "invalid variable name: \`$ac_envvar'" ;;
     esac
     eval $ac_envvar=\$ac_optarg
@@ -1207,5 +1195,5 @@
     expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
       $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
-    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+    : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
     ;;
 
@@ -1215,5 +1203,5 @@
 if test -n "$ac_prev"; then
   ac_option=--`echo $ac_prev | sed 's/_/-/g'`
-  as_fn_error $? "missing argument to $ac_option"
+  as_fn_error "missing argument to $ac_option"
 fi
 
@@ -1221,5 +1209,5 @@
   case $enable_option_checking in
     no) ;;
-    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+    fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;;
     *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
   esac
@@ -1244,5 +1232,5 @@
     NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
   esac
-  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+  as_fn_error "expected an absolute directory name for --$ac_var: $ac_val"
 done
 
@@ -1258,6 +1246,6 @@
   if test "x$build_alias" = x; then
     cross_compiling=maybe
-    $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
-    If a cross compiler is detected then cross compile mode will be used" >&2
+    $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used." >&2
   elif test "x$build_alias" != "x$host_alias"; then
     cross_compiling=yes
@@ -1274,7 +1262,7 @@
 ac_ls_di=`ls -di .` &&
 ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
-  as_fn_error $? "working directory cannot be determined"
+  as_fn_error "working directory cannot be determined"
 test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
-  as_fn_error $? "pwd does not report name of working directory"
+  as_fn_error "pwd does not report name of working directory"
 
 
@@ -1315,9 +1303,9 @@
 if test ! -r "$srcdir/$ac_unique_file"; then
   test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
-  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+  as_fn_error "cannot find sources ($ac_unique_file) in $srcdir"
 fi
 ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
 ac_abs_confdir=`(
-	cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+	cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg"
 	pwd)`
 # When building in place, set srcdir=.
@@ -1359,5 +1347,5 @@
       --help=recursive    display the short help of all the included packages
   -V, --version           display version information and exit
-  -q, --quiet, --silent   do not print \`checking ...' messages
+  -q, --quiet, --silent   do not print \`checking...' messages
       --cache-file=FILE   cache test results in FILE [disabled]
   -C, --config-cache      alias for \`--cache-file=config.cache'
@@ -1443,5 +1431,5 @@
               nonstandard directory <lib dir>
   LIBS        libraries to pass to the linker, e.g. -l<library>
-  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+  CPPFLAGS    C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
               you have headers in a nonstandard directory <include dir>
   CXX         C++ compiler command
@@ -1519,7 +1507,7 @@
   cat <<\_ACEOF
 Rappture configure 1.1
-generated by GNU Autoconf 2.68
-
-Copyright (C) 2010 Free Software Foundation, Inc.
+generated by GNU Autoconf 2.64
+
+Copyright (C) 2009 Free Software Foundation, Inc.
 This configure script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it.
@@ -1565,6 +1553,6 @@
 	ac_retval=1
 fi
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-  as_fn_set_status $ac_retval
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  return $ac_retval
 
 } # ac_fn_c_try_compile
@@ -1603,6 +1591,6 @@
 	ac_retval=1
 fi
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-  as_fn_set_status $ac_retval
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  return $ac_retval
 
 } # ac_fn_cxx_try_compile
@@ -1641,6 +1629,6 @@
 	ac_retval=1
 fi
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-  as_fn_set_status $ac_retval
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  return $ac_retval
 
 } # ac_fn_f77_try_compile
@@ -1667,5 +1655,5 @@
   fi
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } > conftest.i && {
+  test $ac_status = 0; } >/dev/null && {
 	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
 	 test ! -s conftest.err
@@ -1678,6 +1666,6 @@
     ac_retval=1
 fi
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-  as_fn_set_status $ac_retval
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  return $ac_retval
 
 } # ac_fn_c_try_cpp
@@ -1720,6 +1708,6 @@
 fi
   rm -rf conftest.dSYM conftest_ipa8_conftest.oo
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-  as_fn_set_status $ac_retval
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  return $ac_retval
 
 } # ac_fn_c_try_run
@@ -1766,6 +1754,6 @@
   # left behind by Apple's compiler.  We do this before executing the actions.
   rm -rf conftest.dSYM conftest_ipa8_conftest.oo
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-  as_fn_set_status $ac_retval
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  return $ac_retval
 
 } # ac_fn_c_try_link
@@ -1779,5 +1767,5 @@
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
 $as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
   $as_echo_n "(cached) " >&6
 else
@@ -1834,5 +1822,5 @@
 	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
 $as_echo "$ac_res" >&6; }
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
 
 } # ac_fn_c_check_func
@@ -1879,6 +1867,6 @@
   # left behind by Apple's compiler.  We do this before executing the actions.
   rm -rf conftest.dSYM conftest_ipa8_conftest.oo
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-  as_fn_set_status $ac_retval
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  return $ac_retval
 
 } # ac_fn_cxx_try_link
@@ -1892,5 +1880,5 @@
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
 $as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
   $as_echo_n "(cached) " >&6
 else
@@ -1947,5 +1935,5 @@
 	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
 $as_echo "$ac_res" >&6; }
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
 
 } # ac_fn_cxx_check_func
@@ -1972,5 +1960,5 @@
   fi
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } > conftest.i && {
+  test $ac_status = 0; } >/dev/null && {
 	 test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
 	 test ! -s conftest.err
@@ -1983,6 +1971,6 @@
     ac_retval=1
 fi
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-  as_fn_set_status $ac_retval
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  return $ac_retval
 
 } # ac_fn_cxx_try_cpp
@@ -1996,8 +1984,8 @@
 {
   as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  if eval \${$3+:} false; then :
+  if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
 $as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
   $as_echo_n "(cached) " >&6
 fi
@@ -2035,5 +2023,5 @@
   ac_header_preproc=no
 fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
 $as_echo "$ac_header_preproc" >&6; }
@@ -2058,7 +2046,9 @@
     { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
-( $as_echo "## ----------------------------------- ##
+( cat <<\_ASBOX
+## ----------------------------------- ##
 ## Report this to rappture@nanohub.org ##
-## ----------------------------------- ##"
+## ----------------------------------- ##
+_ASBOX
      ) | sed "s/^/$as_me: WARNING:     /" >&2
     ;;
@@ -2066,5 +2056,5 @@
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
 $as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
   $as_echo_n "(cached) " >&6
 else
@@ -2075,5 +2065,5 @@
 $as_echo "$ac_res" >&6; }
 fi
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
 
 } # ac_fn_cxx_check_header_mongrel
@@ -2088,5 +2078,5 @@
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
 $as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
   $as_echo_n "(cached) " >&6
 else
@@ -2106,5 +2096,5 @@
 	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
 $as_echo "$ac_res" >&6; }
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
 
 } # ac_fn_cxx_check_header_compile
@@ -2147,6 +2137,6 @@
 fi
   rm -rf conftest.dSYM conftest_ipa8_conftest.oo
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-  as_fn_set_status $ac_retval
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  return $ac_retval
 
 } # ac_fn_cxx_try_run
@@ -2325,6 +2315,6 @@
 
   fi
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-  as_fn_set_status $ac_retval
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+  return $ac_retval
 
 } # ac_fn_cxx_compute_int
@@ -2334,5 +2324,5 @@
 
 It was created by Rappture $as_me 1.1, which was
-generated by GNU Autoconf 2.68.  Invocation command line was
+generated by GNU Autoconf 2.64.  Invocation command line was
 
   $ $0 $@
@@ -2444,7 +2434,9 @@
     echo
 
-    $as_echo "## ---------------- ##
+    cat <<\_ASBOX
+## ---------------- ##
 ## Cache variables. ##
-## ---------------- ##"
+## ---------------- ##
+_ASBOX
     echo
     # The following way of writing the cache mishandles newlines in values,
@@ -2480,7 +2472,9 @@
     echo
 
-    $as_echo "## ----------------- ##
+    cat <<\_ASBOX
+## ----------------- ##
 ## Output variables. ##
-## ----------------- ##"
+## ----------------- ##
+_ASBOX
     echo
     for ac_var in $ac_subst_vars
@@ -2495,7 +2489,9 @@
 
     if test -n "$ac_subst_files"; then
-      $as_echo "## ------------------- ##
+      cat <<\_ASBOX
+## ------------------- ##
 ## File substitutions. ##
-## ------------------- ##"
+## ------------------- ##
+_ASBOX
       echo
       for ac_var in $ac_subst_files
@@ -2511,7 +2507,9 @@
 
     if test -s confdefs.h; then
-      $as_echo "## ----------- ##
+      cat <<\_ASBOX
+## ----------- ##
 ## confdefs.h. ##
-## ----------- ##"
+## ----------- ##
+_ASBOX
       echo
       cat confdefs.h
@@ -2568,10 +2566,5 @@
 ac_site_file2=NONE
 if test -n "$CONFIG_SITE"; then
-  # We do not want a PATH search for config.site.
-  case $CONFIG_SITE in #((
-    -*)  ac_site_file1=./$CONFIG_SITE;;
-    */*) ac_site_file1=$CONFIG_SITE;;
-    *)   ac_site_file1=./$CONFIG_SITE;;
-  esac
+  ac_site_file1=$CONFIG_SITE
 elif test "x$prefix" != xNONE; then
   ac_site_file1=$prefix/share/config.site
@@ -2584,20 +2577,16 @@
 do
   test "x$ac_site_file" = xNONE && continue
-  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+  if test -r "$ac_site_file"; then
     { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
 $as_echo "$as_me: loading site script $ac_site_file" >&6;}
     sed 's/^/| /' "$ac_site_file" >&5
-    . "$ac_site_file" \
-      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "failed to load site script $ac_site_file
-See \`config.log' for more details" "$LINENO" 5; }
+    . "$ac_site_file"
   fi
 done
 
 if test -r "$cache_file"; then
-  # Some versions of bash will fail to source /dev/null (special files
-  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
-  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special
+  # files actually), so we avoid doing that.
+  if test -f "$cache_file"; then
     { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
 $as_echo "$as_me: loading cache $cache_file" >&6;}
@@ -2668,5 +2657,5 @@
   { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
-  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+  as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
 fi
 ## -------------------- ##
@@ -2683,20 +2672,14 @@
 ac_aux_dir=
 for ac_dir in cf "$srcdir"/cf; do
-  if test -f "$ac_dir/install-sh"; then
-    ac_aux_dir=$ac_dir
-    ac_install_sh="$ac_aux_dir/install-sh -c"
-    break
-  elif test -f "$ac_dir/install.sh"; then
-    ac_aux_dir=$ac_dir
-    ac_install_sh="$ac_aux_dir/install.sh -c"
-    break
-  elif test -f "$ac_dir/shtool"; then
-    ac_aux_dir=$ac_dir
-    ac_install_sh="$ac_aux_dir/shtool install -c"
-    break
-  fi
+  for ac_t in install-sh install.sh shtool; do
+    if test -f "$ac_dir/$ac_t"; then
+      ac_aux_dir=$ac_dir
+      ac_install_sh="$ac_aux_dir/$ac_t -c"
+      break 2
+    fi
+  done
 done
 if test -z "$ac_aux_dir"; then
-  as_fn_error $? "cannot find install-sh, install.sh, or shtool in cf \"$srcdir\"/cf" "$LINENO" 5
+  as_fn_error "cannot find install-sh, install.sh, or shtool in cf \"$srcdir\"/cf" "$LINENO" 5
 fi
 
@@ -2751,5 +2734,5 @@
 $as_echo_n "checking for a BSD-compatible install... " >&6; }
 if test -z "$INSTALL"; then
-if ${ac_cv_path_install+:} false; then :
+if test "${ac_cv_path_install+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -2833,5 +2816,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_RANLIB+:} false; then :
+if test "${ac_cv_prog_RANLIB+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -2873,5 +2856,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -2934,5 +2917,5 @@
 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
 if test -z "$MKDIR_P"; then
-  if ${ac_cv_path_mkdir+:} false; then :
+  if test "${ac_cv_path_mkdir+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -2959,5 +2942,4 @@
 fi
 
-  test -d ./--version && rmdir ./--version
   if test "${ac_cv_path_mkdir+set}" = set; then
     MKDIR_P="$ac_cv_path_mkdir -p"
@@ -2967,4 +2949,5 @@
     # break other packages using the cache if that directory is
     # removed, or if the value is a relative name.
+    test -d ./--version && rmdir ./--version
     MKDIR_P="$ac_install_sh -d"
   fi
@@ -2977,5 +2960,5 @@
 set x ${MAKE-make}
 ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
-if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then :
   $as_echo_n "(cached) " >&6
 else
@@ -2985,5 +2968,5 @@
 	@echo '@@@%%%=$(MAKE)=@@@%%%'
 _ACEOF
-# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
 case `${MAKE-make} -f conftest.make 2>/dev/null` in
   *@@@%%%=?*=@@@%%%*)
@@ -3016,5 +2999,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
+if test "${ac_cv_prog_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -3056,5 +3039,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -3109,5 +3092,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
+if test "${ac_cv_prog_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -3149,5 +3132,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
+if test "${ac_cv_prog_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -3208,5 +3191,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
+if test "${ac_cv_prog_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -3252,5 +3235,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -3306,6 +3289,6 @@
 test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "no acceptable C compiler found in \$PATH
-See \`config.log' for more details" "$LINENO" 5; }
+as_fn_error "no acceptable C compiler found in \$PATH
+See \`config.log' for more details." "$LINENO" 5; }
 
 # Provide some information about the compiler.
@@ -3328,6 +3311,6 @@
          10q' conftest.err >conftest.er1
     cat conftest.er1 >&5
-  fi
-  rm -f conftest.er1 conftest.err
+    rm -f conftest.er1 conftest.err
+  fi
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }
@@ -3336,8 +3319,10 @@
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-
+#include <stdio.h>
 int
 main ()
 {
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
 
   ;
@@ -3346,10 +3331,10 @@
 _ACEOF
 ac_clean_files_save=$ac_clean_files
-ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out conftest.out"
 # Try to create an executable without -o first, disregard a.out.
 # It will help us diagnose broken compilers, and finding out an intuition
 # of exeext.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
-$as_echo_n "checking whether the C compiler works... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
 ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
 
@@ -3413,26 +3398,60 @@
   ac_file=''
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
 if test -z "$ac_file"; then :
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-$as_echo "$as_me: failed program was:" >&5
+  $as_echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "C compiler cannot create executables
-See \`config.log' for more details" "$LINENO" 5; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+{ as_fn_set_status 77
+as_fn_error "C compiler cannot create executables
+See \`config.log' for more details." "$LINENO" 5; }; }
+fi
+ac_exeext=$ac_cv_exeext
+
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+  if { ac_try='./$ac_file'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." "$LINENO" 5; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
-$as_echo_n "checking for C compiler default output file name... " >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
-$as_echo "$ac_file" >&6; }
-ac_exeext=$ac_cv_exeext
-
-rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out conftest.out
 ac_clean_files=$ac_clean_files_save
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
 $as_echo_n "checking for suffix of executables... " >&6; }
@@ -3464,8 +3483,8 @@
   { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot compute suffix of executables: cannot compile and link
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-rm -f conftest conftest$ac_cv_exeext
+as_fn_error "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." "$LINENO" 5; }
+fi
+rm -f conftest$ac_cv_exeext
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
 $as_echo "$ac_cv_exeext" >&6; }
@@ -3474,66 +3493,7 @@
 EXEEXT=$ac_cv_exeext
 ac_exeext=$EXEEXT
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <stdio.h>
-int
-main ()
-{
-FILE *f = fopen ("conftest.out", "w");
- return ferror (f) || fclose (f) != 0;
-
-  ;
-  return 0;
-}
-_ACEOF
-ac_clean_files="$ac_clean_files conftest.out"
-# Check that the compiler produces executables we can run.  If not, either
-# the compiler is broken, or we cross compile.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
-$as_echo_n "checking whether we are cross compiling... " >&6; }
-if test "$cross_compiling" != yes; then
-  { { ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_link") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }
-  if { ac_try='./conftest$ac_cv_exeext'
-  { { case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then
-    cross_compiling=no
-  else
-    if test "$cross_compiling" = maybe; then
-	cross_compiling=yes
-    else
-	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot run C compiled programs.
-If you meant to cross compile, use \`--host'.
-See \`config.log' for more details" "$LINENO" 5; }
-    fi
-  fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
-$as_echo "$cross_compiling" >&6; }
-
-rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
-ac_clean_files=$ac_clean_files_save
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
 $as_echo_n "checking for suffix of object files... " >&6; }
-if ${ac_cv_objext+:} false; then :
+if test "${ac_cv_objext+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -3575,6 +3535,6 @@
 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot compute suffix of object files: cannot compile
-See \`config.log' for more details" "$LINENO" 5; }
+as_fn_error "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." "$LINENO" 5; }
 fi
 rm -f conftest.$ac_cv_objext conftest.$ac_ext
@@ -3586,5 +3546,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
-if ${ac_cv_c_compiler_gnu+:} false; then :
+if test "${ac_cv_c_compiler_gnu+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -3623,5 +3583,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
 $as_echo_n "checking whether $CC accepts -g... " >&6; }
-if ${ac_cv_prog_cc_g+:} false; then :
+if test "${ac_cv_prog_cc_g+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -3701,5 +3661,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
-if ${ac_cv_prog_cc_c89+:} false; then :
+if test "${ac_cv_prog_cc_c89+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -3812,5 +3772,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CXX+:} false; then :
+if test "${ac_cv_prog_CXX+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -3856,5 +3816,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CXX+:} false; then :
+if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -3926,6 +3886,6 @@
          10q' conftest.err >conftest.er1
     cat conftest.er1 >&5
-  fi
-  rm -f conftest.er1 conftest.err
+    rm -f conftest.er1 conftest.err
+  fi
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }
@@ -3934,5 +3894,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
-if ${ac_cv_cxx_compiler_gnu+:} false; then :
+if test "${ac_cv_cxx_compiler_gnu+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -3971,5 +3931,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
 $as_echo_n "checking whether $CXX accepts -g... " >&6; }
-if ${ac_cv_prog_cxx_g+:} false; then :
+if test "${ac_cv_prog_cxx_g+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -4065,5 +4025,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_F77+:} false; then :
+if test "${ac_cv_prog_F77+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -4109,5 +4069,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_F77+:} false; then :
+if test "${ac_cv_prog_ac_ct_F77+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -4178,6 +4138,6 @@
          10q' conftest.err >conftest.er1
     cat conftest.er1 >&5
-  fi
-  rm -f conftest.er1 conftest.err
+    rm -f conftest.er1 conftest.err
+  fi
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }
@@ -4191,5 +4151,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU Fortran 77 compiler" >&5
 $as_echo_n "checking whether we are using the GNU Fortran 77 compiler... " >&6; }
-if ${ac_cv_f77_compiler_gnu+:} false; then :
+if test "${ac_cv_f77_compiler_gnu+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -4219,5 +4179,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $F77 accepts -g" >&5
 $as_echo_n "checking whether $F77 accepts -g... " >&6; }
-if ${ac_cv_prog_f77_g+:} false; then :
+if test "${ac_cv_prog_f77_g+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -4286,5 +4246,5 @@
 fi
 if test -z "$CPP"; then
-  if ${ac_cv_prog_CPP+:} false; then :
+  if test "${ac_cv_prog_CPP+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -4316,5 +4276,5 @@
 continue
 fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
 
   # OK, works on sane cases.  Now check whether nonexistent headers
@@ -4332,9 +4292,9 @@
 break
 fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
 
 done
 # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.i conftest.err conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
 if $ac_preproc_ok; then :
   break
@@ -4375,5 +4335,5 @@
 continue
 fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
 
   # OK, works on sane cases.  Now check whether nonexistent headers
@@ -4391,9 +4351,9 @@
 break
 fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
 
 done
 # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.i conftest.err conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
 if $ac_preproc_ok; then :
 
@@ -4401,6 +4361,6 @@
   { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
-See \`config.log' for more details" "$LINENO" 5; }
+as_fn_error "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." "$LINENO" 5; }
 fi
 
@@ -4414,5 +4374,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
 $as_echo_n "checking for grep that handles long lines and -e... " >&6; }
-if ${ac_cv_path_GREP+:} false; then :
+if test "${ac_cv_path_GREP+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -4463,5 +4423,5 @@
 IFS=$as_save_IFS
   if test -z "$ac_cv_path_GREP"; then
-    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+    as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
   fi
 else
@@ -4477,5 +4437,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
 $as_echo_n "checking for egrep... " >&6; }
-if ${ac_cv_path_EGREP+:} false; then :
+if test "${ac_cv_path_EGREP+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -4529,5 +4489,5 @@
 IFS=$as_save_IFS
   if test -z "$ac_cv_path_EGREP"; then
-    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+    as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
   fi
 else
@@ -4544,5 +4504,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
 $as_echo_n "checking for ANSI C header files... " >&6; }
-if ${ac_cv_header_stdc+:} false; then :
+if test "${ac_cv_header_stdc+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -4655,8 +4615,8 @@
 
 ac_fn_c_check_func "$LINENO" "atol" "ac_cv_func_atol"
-if test "x$ac_cv_func_atol" = xyes; then :
-
-else
-  as_fn_error $? "oops! no atol ?!?" "$LINENO" 5
+if test "x$ac_cv_func_atol" = x""yes; then :
+
+else
+  as_fn_error "oops! no atol ?!?" "$LINENO" 5
 fi
 
@@ -4673,5 +4633,5 @@
 do :
   ac_fn_cxx_check_func "$LINENO" "sysinfo" "ac_cv_func_sysinfo"
-if test "x$ac_cv_func_sysinfo" = xyes; then :
+if test "x$ac_cv_func_sysinfo" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_SYSINFO 1
@@ -4689,5 +4649,5 @@
 $as_echo_n "checking how to run the C++ preprocessor... " >&6; }
 if test -z "$CXXCPP"; then
-  if ${ac_cv_prog_CXXCPP+:} false; then :
+  if test "${ac_cv_prog_CXXCPP+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -4719,5 +4679,5 @@
 continue
 fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
 
   # OK, works on sane cases.  Now check whether nonexistent headers
@@ -4735,9 +4695,9 @@
 break
 fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
 
 done
 # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.i conftest.err conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
 if $ac_preproc_ok; then :
   break
@@ -4778,5 +4738,5 @@
 continue
 fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
 
   # OK, works on sane cases.  Now check whether nonexistent headers
@@ -4794,9 +4754,9 @@
 break
 fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
 
 done
 # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.i conftest.err conftest.$ac_ext
+rm -f conftest.err conftest.$ac_ext
 if $ac_preproc_ok; then :
 
@@ -4804,6 +4764,6 @@
   { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check
-See \`config.log' for more details" "$LINENO" 5; }
+as_fn_error "C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details." "$LINENO" 5; }
 fi
 
@@ -4822,5 +4782,6 @@
 ac_fn_cxx_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
 "
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+eval as_val=\$$as_ac_Header
+   if test "x$as_val" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
@@ -4835,5 +4796,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "sys/sysinfo.h" "ac_cv_header_sys_sysinfo_h" "$ac_includes_default"
-if test "x$ac_cv_header_sys_sysinfo_h" = xyes; then :
+if test "x$ac_cv_header_sys_sysinfo_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_SYS_SYSINFO_H 1
@@ -4847,5 +4808,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lm" >&5
 $as_echo_n "checking for main in -lm... " >&6; }
-if ${ac_cv_lib_m_main+:} false; then :
+if test "${ac_cv_lib_m_main+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -4875,5 +4836,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_main" >&5
 $as_echo "$ac_cv_lib_m_main" >&6; }
-if test "x$ac_cv_lib_m_main" = xyes; then :
+if test "x$ac_cv_lib_m_main" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_LIBM 1
@@ -4883,10 +4844,10 @@
 
 else
-  as_fn_error $? "librappture requires libm" "$LINENO" 5
+  as_fn_error "librappture requires libm" "$LINENO" 5
 fi
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lstdc++" >&5
 $as_echo_n "checking for main in -lstdc++... " >&6; }
-if ${ac_cv_lib_stdcpp_main+:} false; then :
+if test "${ac_cv_lib_stdcpp_main+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -4916,5 +4877,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_stdcpp_main" >&5
 $as_echo "$ac_cv_lib_stdcpp_main" >&6; }
-if test "x$ac_cv_lib_stdcpp_main" = xyes; then :
+if test "x$ac_cv_lib_stdcpp_main" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_LIBSTDC__ 1
@@ -4924,5 +4885,5 @@
 
 else
-  as_fn_error $? "librappture requires libstdc++" "$LINENO" 5
+  as_fn_error "librappture requires libstdc++" "$LINENO" 5
 fi
 
@@ -4930,5 +4891,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "algorithm" "ac_cv_header_algorithm" "$ac_includes_default"
-if test "x$ac_cv_header_algorithm" = xyes; then :
+if test "x$ac_cv_header_algorithm" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_ALGORITHM 1
@@ -4945,5 +4906,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "cctype" "ac_cv_header_cctype" "$ac_includes_default"
-if test "x$ac_cv_header_cctype" = xyes; then :
+if test "x$ac_cv_header_cctype" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_CCTYPE 1
@@ -4960,5 +4921,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "cfloat" "ac_cv_header_cfloat" "$ac_includes_default"
-if test "x$ac_cv_header_cfloat" = xyes; then :
+if test "x$ac_cv_header_cfloat" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_CFLOAT 1
@@ -4975,5 +4936,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "cmath" "ac_cv_header_cmath" "$ac_includes_default"
-if test "x$ac_cv_header_cmath" = xyes; then :
+if test "x$ac_cv_header_cmath" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_CMATH 1
@@ -4990,5 +4951,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "cstdio" "ac_cv_header_cstdio" "$ac_includes_default"
-if test "x$ac_cv_header_cstdio" = xyes; then :
+if test "x$ac_cv_header_cstdio" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_CSTDIO 1
@@ -5005,5 +4966,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "cstdlib" "ac_cv_header_cstdlib" "$ac_includes_default"
-if test "x$ac_cv_header_cstdlib" = xyes; then :
+if test "x$ac_cv_header_cstdlib" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_CSTDLIB 1
@@ -5020,5 +4981,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "cstring" "ac_cv_header_cstring" "$ac_includes_default"
-if test "x$ac_cv_header_cstring" = xyes; then :
+if test "x$ac_cv_header_cstring" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_CSTRING 1
@@ -5035,5 +4996,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "fstream" "ac_cv_header_fstream" "$ac_includes_default"
-if test "x$ac_cv_header_fstream" = xyes; then :
+if test "x$ac_cv_header_fstream" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_FSTREAM 1
@@ -5050,5 +5011,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "list" "ac_cv_header_list" "$ac_includes_default"
-if test "x$ac_cv_header_list" = xyes; then :
+if test "x$ac_cv_header_list" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_LIST 1
@@ -5065,5 +5026,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "iostream" "ac_cv_header_iostream" "$ac_includes_default"
-if test "x$ac_cv_header_iostream" = xyes; then :
+if test "x$ac_cv_header_iostream" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_IOSTREAM 1
@@ -5080,5 +5041,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "iterator" "ac_cv_header_iterator" "$ac_includes_default"
-if test "x$ac_cv_header_iterator" = xyes; then :
+if test "x$ac_cv_header_iterator" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_ITERATOR 1
@@ -5095,5 +5056,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "sstream" "ac_cv_header_sstream" "$ac_includes_default"
-if test "x$ac_cv_header_sstream" = xyes; then :
+if test "x$ac_cv_header_sstream" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_SSTREAM 1
@@ -5110,5 +5071,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "stack" "ac_cv_header_stack" "$ac_includes_default"
-if test "x$ac_cv_header_stack" = xyes; then :
+if test "x$ac_cv_header_stack" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_STACK 1
@@ -5125,5 +5086,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "string" "ac_cv_header_string" "$ac_includes_default"
-if test "x$ac_cv_header_string" = xyes; then :
+if test "x$ac_cv_header_string" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_STRING 1
@@ -5140,5 +5101,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "vector" "ac_cv_header_vector" "$ac_includes_default"
-if test "x$ac_cv_header_vector" = xyes; then :
+if test "x$ac_cv_header_vector" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_VECTOR 1
@@ -5156,5 +5117,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "assert.h" "ac_cv_header_assert_h" "$ac_includes_default"
-if test "x$ac_cv_header_assert_h" = xyes; then :
+if test "x$ac_cv_header_assert_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_ASSERT_H 1
@@ -5171,5 +5132,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "ctype.h" "ac_cv_header_ctype_h" "$ac_includes_default"
-if test "x$ac_cv_header_ctype_h" = xyes; then :
+if test "x$ac_cv_header_ctype_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_CTYPE_H 1
@@ -5186,5 +5147,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "errno.h" "ac_cv_header_errno_h" "$ac_includes_default"
-if test "x$ac_cv_header_errno_h" = xyes; then :
+if test "x$ac_cv_header_errno_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_ERRNO_H 1
@@ -5201,5 +5162,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "limits.h" "ac_cv_header_limits_h" "$ac_includes_default"
-if test "x$ac_cv_header_limits_h" = xyes; then :
+if test "x$ac_cv_header_limits_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_LIMITS_H 1
@@ -5216,5 +5177,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "string.h" "ac_cv_header_string_h" "$ac_includes_default"
-if test "x$ac_cv_header_string_h" = xyes; then :
+if test "x$ac_cv_header_string_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_STRING_H 1
@@ -5231,5 +5192,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default"
-if test "x$ac_cv_header_stdlib_h" = xyes; then :
+if test "x$ac_cv_header_stdlib_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_STDLIB_H 1
@@ -5246,5 +5207,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "stddef.h" "ac_cv_header_stddef_h" "$ac_includes_default"
-if test "x$ac_cv_header_stddef_h" = xyes; then :
+if test "x$ac_cv_header_stddef_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_STDDEF_H 1
@@ -5261,5 +5222,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "float.h" "ac_cv_header_float_h" "$ac_includes_default"
-if test "x$ac_cv_header_float_h" = xyes; then :
+if test "x$ac_cv_header_float_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_FLOAT_H 1
@@ -5276,5 +5237,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "math.h" "ac_cv_header_math_h" "$ac_includes_default"
-if test "x$ac_cv_header_math_h" = xyes; then :
+if test "x$ac_cv_header_math_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_MATH_H 1
@@ -5291,5 +5252,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "malloc.h" "ac_cv_header_malloc_h" "$ac_includes_default"
-if test "x$ac_cv_header_malloc_h" = xyes; then :
+if test "x$ac_cv_header_malloc_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_MALLOC_H 1
@@ -5306,5 +5267,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "memory.h" "ac_cv_header_memory_h" "$ac_includes_default"
-if test "x$ac_cv_header_memory_h" = xyes; then :
+if test "x$ac_cv_header_memory_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_MEMORY_H 1
@@ -5321,5 +5282,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default"
-if test "x$ac_cv_header_unistd_h" = xyes; then :
+if test "x$ac_cv_header_unistd_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_UNISTD_H 1
@@ -5337,5 +5298,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "inttypes.h" "ac_cv_header_inttypes_h" "$ac_includes_default"
-if test "x$ac_cv_header_inttypes_h" = xyes; then :
+if test "x$ac_cv_header_inttypes_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_INTTYPES_H 1
@@ -5398,5 +5359,5 @@
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking system version" >&5
 $as_echo_n "checking system version... " >&6; }
-if ${tcl_cv_sys_version+:} false; then :
+if test "${tcl_cv_sys_version+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -5434,5 +5395,5 @@
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
 $as_echo_n "checking for dlopen in -ldl... " >&6; }
-if ${ac_cv_lib_dl_dlopen+:} false; then :
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -5468,5 +5429,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
 $as_echo "$ac_cv_lib_dl_dlopen" >&6; }
-if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+if test "x$ac_cv_lib_dl_dlopen" = x""yes; then :
   have_dl=yes
 else
@@ -5502,5 +5463,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_AR+:} false; then :
+if test "${ac_cv_prog_AR+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -5536,5 +5497,5 @@
 
     if test "${AR}" = "" ; then
-	as_fn_error $? "Required archive tool 'ar' not found on PATH." "$LINENO" 5
+	as_fn_error "Required archive tool 'ar' not found on PATH." "$LINENO" 5
     fi
     STLIB_LD='${AR} cr'
@@ -5627,5 +5588,5 @@
 	    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gettimeofday in -lbsd" >&5
 $as_echo_n "checking for gettimeofday in -lbsd... " >&6; }
-if ${ac_cv_lib_bsd_gettimeofday+:} false; then :
+if test "${ac_cv_lib_bsd_gettimeofday+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -5661,5 +5622,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_gettimeofday" >&5
 $as_echo "$ac_cv_lib_bsd_gettimeofday" >&6; }
-if test "x$ac_cv_lib_bsd_gettimeofday" = xyes; then :
+if test "x$ac_cv_lib_bsd_gettimeofday" = x""yes; then :
   libbsd=yes
 else
@@ -5688,5 +5649,5 @@
 	    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa in -lbind" >&5
 $as_echo_n "checking for inet_ntoa in -lbind... " >&6; }
-if ${ac_cv_lib_bind_inet_ntoa+:} false; then :
+if test "${ac_cv_lib_bind_inet_ntoa+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -5722,5 +5683,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bind_inet_ntoa" >&5
 $as_echo "$ac_cv_lib_bind_inet_ntoa" >&6; }
-if test "x$ac_cv_lib_bind_inet_ntoa" = xyes; then :
+if test "x$ac_cv_lib_bind_inet_ntoa" = x""yes; then :
   LIBS="$LIBS -lbind -lsocket"
 fi
@@ -5773,5 +5734,5 @@
 	    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
 $as_echo_n "checking for shl_load in -ldld... " >&6; }
-if ${ac_cv_lib_dld_shl_load+:} false; then :
+if test "${ac_cv_lib_dld_shl_load+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -5807,5 +5768,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
 $as_echo "$ac_cv_lib_dld_shl_load" >&6; }
-if test "x$ac_cv_lib_dld_shl_load" = xyes; then :
+if test "x$ac_cv_lib_dld_shl_load" = x""yes; then :
   tcl_ok=yes
 else
@@ -5862,5 +5823,5 @@
 	    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
 $as_echo_n "checking for shl_load in -ldld... " >&6; }
-if ${ac_cv_lib_dld_shl_load+:} false; then :
+if test "${ac_cv_lib_dld_shl_load+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -5896,5 +5857,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
 $as_echo "$ac_cv_lib_dld_shl_load" >&6; }
-if test "x$ac_cv_lib_dld_shl_load" = xyes; then :
+if test "x$ac_cv_lib_dld_shl_load" = x""yes; then :
   tcl_ok=yes
 else
@@ -6005,5 +5966,5 @@
 	    else
 		ac_fn_cxx_check_header_mongrel "$LINENO" "dld.h" "ac_cv_header_dld_h" "$ac_includes_default"
-if test "x$ac_cv_header_dld_h" = xyes; then :
+if test "x$ac_cv_header_dld_h" = x""yes; then :
 
 		    SHLIB_LD="ld -shared"
@@ -6022,5 +5983,5 @@
 		{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -m64 flag" >&5
 $as_echo_n "checking if compiler accepts -m64 flag... " >&6; }
-if ${tcl_cv_cc_m64+:} false; then :
+if test "${tcl_cv_cc_m64+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -6086,5 +6047,5 @@
 	    else
 		ac_fn_cxx_check_header_mongrel "$LINENO" "dld.h" "ac_cv_header_dld_h" "$ac_includes_default"
-if test "x$ac_cv_header_dld_h" = xyes; then :
+if test "x$ac_cv_header_dld_h" = x""yes; then :
 
 		    SHLIB_LD="ld -shared"
@@ -6137,5 +6098,5 @@
 	    # Not available on all versions:  check for include file.
 	    ac_fn_cxx_check_header_mongrel "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default"
-if test "x$ac_cv_header_dlfcn_h" = xyes; then :
+if test "x$ac_cv_header_dlfcn_h" = x""yes; then :
 
 		# NetBSD/SPARC needs -fPIC, -fpic will not do.
@@ -6150,5 +6111,5 @@
 		{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ELF" >&5
 $as_echo_n "checking for ELF... " >&6; }
-if ${tcl_cv_ld_elf+:} false; then :
+if test "${tcl_cv_ld_elf+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -6232,5 +6193,5 @@
 		{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ELF" >&5
 $as_echo_n "checking for ELF... " >&6; }
-if ${tcl_cv_ld_elf+:} false; then :
+if test "${tcl_cv_ld_elf+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -6310,5 +6271,5 @@
 			{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -arch ppc64 flag" >&5
 $as_echo_n "checking if compiler accepts -arch ppc64 flag... " >&6; }
-if ${tcl_cv_cc_arch_ppc64+:} false; then :
+if test "${tcl_cv_cc_arch_ppc64+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -6345,5 +6306,5 @@
 			{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler accepts -arch x86_64 flag" >&5
 $as_echo_n "checking if compiler accepts -arch x86_64 flag... " >&6; }
-if ${tcl_cv_cc_arch_x86_64+:} false; then :
+if test "${tcl_cv_cc_arch_x86_64+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -6390,5 +6351,5 @@
 	    { $as_echo "$as_me:${as_lineno-$LINENO}: checking if ld accepts -single_module flag" >&5
 $as_echo_n "checking if ld accepts -single_module flag... " >&6; }
-if ${tcl_cv_ld_single_module+:} false; then :
+if test "${tcl_cv_ld_single_module+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -6432,5 +6393,5 @@
 	    { $as_echo "$as_me:${as_lineno-$LINENO}: checking if ld accepts -search_paths_first flag" >&5
 $as_echo_n "checking if ld accepts -search_paths_first flag... " >&6; }
-if ${tcl_cv_ld_search_paths_first+:} false; then :
+if test "${tcl_cv_ld_search_paths_first+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -6482,5 +6443,5 @@
 		{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CoreFoundation.framework" >&5
 $as_echo_n "checking for CoreFoundation.framework... " >&6; }
-if ${tcl_cv_lib_corefoundation+:} false; then :
+if test "${tcl_cv_lib_corefoundation+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -6528,5 +6489,5 @@
 		    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit CoreFoundation" >&5
 $as_echo_n "checking for 64-bit CoreFoundation... " >&6; }
-if ${tcl_cv_lib_corefoundation_64+:} false; then :
+if test "${tcl_cv_lib_corefoundation_64+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -6853,5 +6814,5 @@
 	    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld accepts -Bexport flag" >&5
 $as_echo_n "checking for ld accepts -Bexport flag... " >&6; }
-if ${tcl_cv_ld_Bexport+:} false; then :
+if test "${tcl_cv_ld_Bexport+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -6919,5 +6880,5 @@
 	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking sys/exec.h" >&5
 $as_echo_n "checking sys/exec.h... " >&6; }
-if ${tcl_cv_sysexec_h+:} false; then :
+if test "${tcl_cv_sysexec_h+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -6960,5 +6921,5 @@
 	    { $as_echo "$as_me:${as_lineno-$LINENO}: checking a.out.h" >&5
 $as_echo_n "checking a.out.h... " >&6; }
-if ${tcl_cv_aout_h+:} false; then :
+if test "${tcl_cv_aout_h+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -7001,5 +6962,5 @@
 		{ $as_echo "$as_me:${as_lineno-$LINENO}: checking sys/exec_aout.h" >&5
 $as_echo_n "checking sys/exec_aout.h... " >&6; }
-if ${tcl_cv_sysexecaout_h+:} false; then :
+if test "${tcl_cv_sysexecaout_h+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -7180,5 +7141,5 @@
 done
 if test "x${make_command}" = "x" ; then
-  as_fn_error $? "Requires GNU make. You can specify a version with \$MAKE" "$LINENO" 5
+  as_fn_error "Requires GNU make. You can specify a version with \$MAKE" "$LINENO" 5
 fi
 MAKE=${make_command}
@@ -7229,5 +7190,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_TCLSH+:} false; then :
+if test "${ac_cv_path_TCLSH+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -7271,5 +7232,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_TCLSH+:} false; then :
+if test "${ac_cv_path_TCLSH+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -7310,5 +7271,5 @@
   fi
   if test "x${TCLSH}" = "x" ; then
-    as_fn_error $? "can't find tclsh" "$LINENO" 5
+    as_fn_error "can't find tclsh" "$LINENO" 5
   fi
 fi
@@ -7379,5 +7340,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_MATLAB+:} false; then :
+if test "${ac_cv_path_MATLAB+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -7420,5 +7381,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_MATLAB+:} false; then :
+if test "${ac_cv_path_MATLAB+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -7471,5 +7432,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_MEX+:} false; then :
+if test "${ac_cv_path_MEX+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -7511,5 +7472,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_MEXEXT+:} false; then :
+if test "${ac_cv_path_MEXEXT+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -7562,5 +7523,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_MCC+:} false; then :
+if test "${ac_cv_path_MCC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -7632,5 +7593,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_OCTAVE+:} false; then :
+if test "${ac_cv_path_OCTAVE+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -7672,5 +7633,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_MKOCTFILE+:} false; then :
+if test "${ac_cv_path_MKOCTFILE+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -7742,5 +7703,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_octave2+:} false; then :
+if test "${ac_cv_path_octave2+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -7782,5 +7743,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_mkoctfile2+:} false; then :
+if test "${ac_cv_path_mkoctfile2+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -7849,5 +7810,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_octave3+:} false; then :
+if test "${ac_cv_path_octave3+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -7889,5 +7850,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_mkoctfile3+:} false; then :
+if test "${ac_cv_path_mkoctfile3+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -7975,5 +7936,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PERL+:} false; then :
+if test "${ac_cv_path_PERL+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -8017,5 +7978,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PERL+:} false; then :
+if test "${ac_cv_path_PERL+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -8111,5 +8072,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PYTHON+:} false; then :
+if test "${ac_cv_path_PYTHON+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -8152,5 +8113,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PYTHON+:} false; then :
+if test "${ac_cv_path_PYTHON+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -8236,5 +8197,5 @@
 do :
   ac_fn_cxx_check_header_mongrel "$LINENO" "Python.h" "ac_cv_header_Python_h" "$ac_includes_default"
-if test "x$ac_cv_header_Python_h" = xyes; then :
+if test "x$ac_cv_header_Python_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_PYTHON_H 1
@@ -8284,5 +8245,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_RUBY+:} false; then :
+if test "${ac_cv_path_RUBY+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -8325,5 +8286,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_RUBY+:} false; then :
+if test "${ac_cv_path_RUBY+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -8371,5 +8332,5 @@
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
 $as_echo_n "checking for a sed that does not truncate output... " >&6; }
-if ${ac_cv_path_SED+:} false; then :
+if test "${ac_cv_path_SED+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -8426,5 +8387,5 @@
 IFS=$as_save_IFS
   if test -z "$ac_cv_path_SED"; then
-    as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+    as_fn_error "no acceptable sed could be found in \$PATH" "$LINENO" 5
   fi
 else
@@ -8464,5 +8425,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_AWK+:} false; then :
+if test "${ac_cv_prog_AWK+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -8703,5 +8664,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_JAVA+:} false; then :
+if test "${ac_cv_path_JAVA+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -8743,5 +8704,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_JAVAC+:} false; then :
+if test "${ac_cv_path_JAVAC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -8783,5 +8744,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_JAVAH+:} false; then :
+if test "${ac_cv_path_JAVAH+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -8824,5 +8785,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_JAVA+:} false; then :
+if test "${ac_cv_path_JAVA+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -8865,5 +8826,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_JAVAC+:} false; then :
+if test "${ac_cv_path_JAVAC+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -8906,5 +8867,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_JAVAH+:} false; then :
+if test "${ac_cv_path_JAVAH+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -9043,5 +9004,5 @@
  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
 $as_echo_n "checking whether byte ordering is bigendian... " >&6; }
-if ${ac_cv_c_bigendian+:} false; then :
+if test "${ac_cv_c_bigendian+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -9261,5 +9222,5 @@
      ;; #(
    *)
-     as_fn_error $? "unknown endianness
+     as_fn_error "unknown endianness
  presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;;
  esac
@@ -9271,5 +9232,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5
 $as_echo_n "checking size of int... " >&6; }
-if ${ac_cv_sizeof_int+:} false; then :
+if test "${ac_cv_sizeof_int+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -9280,6 +9241,7 @@
      { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "cannot compute sizeof (int)
-See \`config.log' for more details" "$LINENO" 5; }
+{ as_fn_set_status 77
+as_fn_error "cannot compute sizeof (int)
+See \`config.log' for more details." "$LINENO" 5; }; }
    else
      ac_cv_sizeof_int=0
@@ -9304,5 +9266,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5
 $as_echo_n "checking size of long... " >&6; }
-if ${ac_cv_sizeof_long+:} false; then :
+if test "${ac_cv_sizeof_long+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -9313,6 +9275,7 @@
      { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "cannot compute sizeof (long)
-See \`config.log' for more details" "$LINENO" 5; }
+{ as_fn_set_status 77
+as_fn_error "cannot compute sizeof (long)
+See \`config.log' for more details." "$LINENO" 5; }; }
    else
      ac_cv_sizeof_long=0
@@ -9337,5 +9300,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5
 $as_echo_n "checking size of long long... " >&6; }
-if ${ac_cv_sizeof_long_long+:} false; then :
+if test "${ac_cv_sizeof_long_long+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -9346,6 +9309,7 @@
      { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "cannot compute sizeof (long long)
-See \`config.log' for more details" "$LINENO" 5; }
+{ as_fn_set_status 77
+as_fn_error "cannot compute sizeof (long long)
+See \`config.log' for more details." "$LINENO" 5; }; }
    else
      ac_cv_sizeof_long_long=0
@@ -9370,5 +9334,5 @@
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5
 $as_echo_n "checking size of void *... " >&6; }
-if ${ac_cv_sizeof_void_p+:} false; then :
+if test "${ac_cv_sizeof_void_p+set}" = set; then :
   $as_echo_n "(cached) " >&6
 else
@@ -9379,6 +9343,7 @@
      { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "cannot compute sizeof (void *)
-See \`config.log' for more details" "$LINENO" 5; }
+{ as_fn_set_status 77
+as_fn_error "cannot compute sizeof (void *)
+See \`config.log' for more details." "$LINENO" 5; }; }
    else
      ac_cv_sizeof_void_p=0
@@ -9478,5 +9443,5 @@
 
 "
-if test "x$ac_cv_header_ffmpeg_avcodec_h" = xyes; then :
+if test "x$ac_cv_header_ffmpeg_avcodec_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_FFMPEG_AVCODEC_H 1
@@ -9496,5 +9461,5 @@
 
 "
-if test "x$ac_cv_header_libavcodec_avcodec_h" = xyes; then :
+if test "x$ac_cv_header_libavcodec_avcodec_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_LIBAVCODEC_AVCODEC_H 1
@@ -9514,5 +9479,5 @@
 
 "
-if test "x$ac_cv_header_ffmpeg_avformat_h" = xyes; then :
+if test "x$ac_cv_header_ffmpeg_avformat_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_FFMPEG_AVFORMAT_H 1
@@ -9532,5 +9497,5 @@
 
 "
-if test "x$ac_cv_header_libavformat_avformat_h" = xyes; then :
+if test "x$ac_cv_header_libavformat_avformat_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_LIBAVFORMAT_AVFORMAT_H 1
@@ -9550,5 +9515,5 @@
 
 "
-if test "x$ac_cv_header_ffmpeg_avutil_h" = xyes; then :
+if test "x$ac_cv_header_ffmpeg_avutil_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_FFMPEG_AVUTIL_H 1
@@ -9568,5 +9533,5 @@
 
 "
-if test "x$ac_cv_header_libavutil_avutil_h" = xyes; then :
+if test "x$ac_cv_header_libavutil_avutil_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_LIBAVUTIL_AVUTIL_H 1
@@ -9586,5 +9551,5 @@
 
 "
-if test "x$ac_cv_header_ffmpeg_swscale_h" = xyes; then :
+if test "x$ac_cv_header_ffmpeg_swscale_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_FFMPEG_SWSCALE_H 1
@@ -9604,5 +9569,5 @@
 
 "
-if test "x$ac_cv_header_libswscale_swscale_h" = xyes; then :
+if test "x$ac_cv_header_libswscale_swscale_h" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_LIBSWSCALE_SWSCALE_H 1
@@ -9634,5 +9599,5 @@
 do :
   ac_fn_cxx_check_func "$LINENO" "img_convert" "ac_cv_func_img_convert"
-if test "x$ac_cv_func_img_convert" = xyes; then :
+if test "x$ac_cv_func_img_convert" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_IMG_CONVERT 1
@@ -9645,5 +9610,5 @@
 do :
   ac_fn_cxx_check_func "$LINENO" "sws_scale" "ac_cv_func_sws_scale"
-if test "x$ac_cv_func_sws_scale" = xyes; then :
+if test "x$ac_cv_func_sws_scale" = x""yes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_SWS_SCALE 1
@@ -9661,5 +9626,5 @@
 
 
-ac_config_files="$ac_config_files Makefile packages/Makefile src/Makefile src/core/Makefile src/core2/Makefile src/objects/Makefile src/objects/RpHash.h gui/Makefile gui/apps/Makefile gui/apps/about gui/apps/encodedata gui/apps/rappture gui/apps/rappture-csh.env gui/apps/rappture.env gui/apps/rappture.use gui/apps/rerun gui/apps/simsim gui/apps/xmldiff gui/pkgIndex.tcl gui/scripts/Makefile instant/Makefile instant/irappture lang/Makefile lang/java/Makefile lang/java/rappture/Makefile lang/perl/Makefile lang/perl/Makefile.PL lang/python/Makefile lang/python/setup.py lang/matlab/Makefile lang/octave/Makefile lang/octave/octave2/Makefile lang/octave/octave3/Makefile lang/ruby/Makefile lang/ruby/build.rb lang/tcl/Makefile lang/tcl/pkgIndex.tcl lang/tcl/src/Makefile lang/tcl/scripts/Makefile lang/tcl/tests/Makefile lib/Makefile examples/3D/Makefile examples/Makefile examples/app-fermi/2.0/Makefile examples/app-fermi/Makefile examples/app-fermi/cee/Makefile examples/app-fermi/fortran/Makefile examples/app-fermi/java/Makefile examples/app-fermi/matlab/Makefile examples/app-fermi/matlab/compiled/Makefile examples/app-fermi/matlab/uncompiled/Makefile examples/app-fermi/octave/2/Makefile examples/app-fermi/octave/3/Makefile examples/app-fermi/octave/Makefile examples/app-fermi/perl/Makefile examples/app-fermi/python/Makefile examples/app-fermi/ruby/Makefile examples/app-fermi/tcl/Makefile examples/app-fermi/wrapper/Makefile examples/app-fermi/wrapper/cee/Makefile examples/app-fermi/wrapper/perl/Makefile examples/app-fermi/wrapper/python/Makefile examples/app-fermi/wrapper/tcl/Makefile examples/c-example/Makefile examples/canvas/Makefile examples/demo.bash examples/flow/Makefile examples/flow/demo1/Makefile examples/flow/demo2/Makefile examples/flow/demo3/Makefile examples/graph/Makefile examples/objects/Makefile examples/objects/axis/Makefile examples/objects/contour/Makefile examples/objects/curve/Makefile examples/objects/dxWriter/Makefile examples/objects/floatBuffer/Makefile examples/objects/histogram/Makefile examples/objects/library/Makefile examples/objects/number/Makefile examples/objects/path/Makefile examples/objects/plot/Makefile examples/objects/scatter/Makefile examples/objects/string/Makefile examples/objects/tree/Makefile examples/objects/xmlparser/Makefile examples/zoo/Makefile examples/zoo/binary/Makefile examples/zoo/boolean/Makefile examples/zoo/choice/Makefile examples/zoo/cloud/Makefile examples/zoo/cloud/matlab/Makefile examples/zoo/curve/Makefile examples/zoo/enable/Makefile examples/zoo/field/Makefile examples/zoo/group/Makefile examples/zoo/image/Makefile examples/zoo/image/docs/Makefile examples/zoo/image/examples/Makefile examples/zoo/integer/Makefile examples/zoo/integer2/Makefile examples/zoo/loader/Makefile examples/zoo/loader/examples/Makefile examples/zoo/loadrun/Makefile examples/zoo/log/Makefile examples/zoo/note/Makefile examples/zoo/note/docs/Makefile examples/zoo/number/Makefile examples/zoo/number2/Makefile examples/zoo/parallelepiped/Makefile examples/zoo/periodicelement/Makefile examples/zoo/phase/Makefile examples/zoo/sequence/Makefile examples/zoo/sequence/examples/Makefile examples/zoo/string/Makefile examples/zoo/structure/Makefile examples/zoo/structure/examples/Makefile examples/zoo/table/Makefile examples/zoo/unirect2d/Makefile oldtest/Makefile oldtest/src/Makefile"
+ac_config_files="$ac_config_files Makefile packages/Makefile src/Makefile src/core/Makefile src/core2/Makefile src/objects/Makefile src/objects/RpHash.h gui/Makefile gui/apps/Makefile gui/apps/about gui/apps/encodedata gui/apps/rappture gui/apps/rappture-csh.env gui/apps/rappture.env gui/apps/rappture.use gui/apps/rerun gui/apps/simsim gui/apps/xmldiff gui/pkgIndex.tcl gui/scripts/Makefile builder/Makefile builder/pkgIndex.tcl tester/Makefile tester/pkgIndex.tcl lang/Makefile lang/java/Makefile lang/java/rappture/Makefile lang/perl/Makefile lang/perl/Makefile.PL lang/python/Makefile lang/python/setup.py lang/matlab/Makefile lang/octave/Makefile lang/octave/octave2/Makefile lang/octave/octave3/Makefile lang/ruby/Makefile lang/ruby/build.rb lang/tcl/Makefile lang/tcl/pkgIndex.tcl lang/tcl/src/Makefile lang/tcl/scripts/Makefile lang/tcl/tests/Makefile lib/Makefile examples/3D/Makefile examples/Makefile examples/app-fermi/2.0/Makefile examples/app-fermi/Makefile examples/app-fermi/cee/Makefile examples/app-fermi/fortran/Makefile examples/app-fermi/java/Makefile examples/app-fermi/matlab/Makefile examples/app-fermi/matlab/compiled/Makefile examples/app-fermi/matlab/uncompiled/Makefile examples/app-fermi/octave/2/Makefile examples/app-fermi/octave/3/Makefile examples/app-fermi/octave/Makefile examples/app-fermi/perl/Makefile examples/app-fermi/python/Makefile examples/app-fermi/ruby/Makefile examples/app-fermi/tcl/Makefile examples/app-fermi/wrapper/Makefile examples/app-fermi/wrapper/cee/Makefile examples/app-fermi/wrapper/perl/Makefile examples/app-fermi/wrapper/python/Makefile examples/app-fermi/wrapper/tcl/Makefile examples/c-example/Makefile examples/canvas/Makefile examples/demo.bash examples/flow/Makefile examples/flow/demo1/Makefile examples/flow/demo2/Makefile examples/flow/demo3/Makefile examples/graph/Makefile examples/objects/Makefile examples/objects/axis/Makefile examples/objects/contour/Makefile examples/objects/curve/Makefile examples/objects/dxWriter/Makefile examples/objects/floatBuffer/Makefile examples/objects/histogram/Makefile examples/objects/library/Makefile examples/objects/number/Makefile examples/objects/path/Makefile examples/objects/plot/Makefile examples/objects/scatter/Makefile examples/objects/string/Makefile examples/objects/tree/Makefile examples/objects/xmlparser/Makefile examples/zoo/Makefile examples/zoo/binary/Makefile examples/zoo/boolean/Makefile examples/zoo/choice/Makefile examples/zoo/cloud/Makefile examples/zoo/cloud/matlab/Makefile examples/zoo/curve/Makefile examples/zoo/enable/Makefile examples/zoo/field/Makefile examples/zoo/group/Makefile examples/zoo/image/Makefile examples/zoo/image/docs/Makefile examples/zoo/image/examples/Makefile examples/zoo/integer/Makefile examples/zoo/integer2/Makefile examples/zoo/loader/Makefile examples/zoo/loader/examples/Makefile examples/zoo/loadrun/Makefile examples/zoo/log/Makefile examples/zoo/note/Makefile examples/zoo/note/docs/Makefile examples/zoo/number/Makefile examples/zoo/number2/Makefile examples/zoo/parallelepiped/Makefile examples/zoo/periodicelement/Makefile examples/zoo/phase/Makefile examples/zoo/sequence/Makefile examples/zoo/sequence/examples/Makefile examples/zoo/string/Makefile examples/zoo/structure/Makefile examples/zoo/structure/examples/Makefile examples/zoo/table/Makefile examples/zoo/unirect2d/Makefile oldtest/Makefile oldtest/src/Makefile"
 
 cat >confcache <<\_ACEOF
@@ -9727,19 +9692,8 @@
 if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
   if test -w "$cache_file"; then
-    if test "x$cache_file" != "x/dev/null"; then
+    test "x$cache_file" != "x/dev/null" &&
       { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
 $as_echo "$as_me: updating cache $cache_file" >&6;}
-      if test ! -f "$cache_file" || test -h "$cache_file"; then
-	cat confcache >"$cache_file"
-      else
-        case $cache_file in #(
-        */* | ?:*)
-	  mv -f confcache "$cache_file"$$ &&
-	  mv -f "$cache_file"$$ "$cache_file" ;; #(
-        *)
-	  mv -f confcache "$cache_file" ;;
-	esac
-      fi
-    fi
+    cat confcache >$cache_file
   else
     { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
@@ -9757,5 +9711,4 @@
 ac_libobjs=
 ac_ltlibobjs=
-U=
 for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
   # 1. Remove the extension, and $U if already installed.
@@ -9774,5 +9727,5 @@
 
 
-: "${CONFIG_STATUS=./config.status}"
+: ${CONFIG_STATUS=./config.status}
 ac_write_fail=0
 ac_clean_files_save=$ac_clean_files
@@ -9875,5 +9828,4 @@
 
 # Find who we are.  Look in the path if we contain no directory separator.
-as_myself=
 case $0 in #((
   *[\\/]* ) as_myself=$0 ;;
@@ -9921,17 +9873,17 @@
 
 
-# as_fn_error STATUS ERROR [LINENO LOG_FD]
-# ----------------------------------------
+# as_fn_error ERROR [LINENO LOG_FD]
+# ---------------------------------
 # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
 # provided, also output the error to LOG_FD, referencing LINENO. Then exit the
-# script with STATUS, using 1 if that was 0.
+# script with status $?, using 1 if that was 0.
 as_fn_error ()
 {
-  as_status=$1; test $as_status -eq 0 && as_status=1
-  if test "$4"; then
-    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
-  fi
-  $as_echo "$as_me: error: $2" >&2
+  as_status=$?; test $as_status -eq 0 && as_status=1
+  if test "$3"; then
+    as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3
+  fi
+  $as_echo "$as_me: error: $1" >&2
   as_fn_exit $as_status
 } # as_fn_error
@@ -10129,5 +10081,5 @@
     done
     test -z "$as_dirs" || eval "mkdir $as_dirs"
-  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+  } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir"
 
 
@@ -10183,5 +10135,5 @@
 ac_log="
 This file was extended by Rappture $as_me 1.1, which was
-generated by GNU Autoconf 2.68.  Invocation command line was
+generated by GNU Autoconf 2.64.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -10222,5 +10174,4 @@
   -h, --help       print this help, then exit
   -V, --version    print version number and configuration settings, then exit
-      --config     print configuration, then exit
   -q, --quiet, --silent
                    do not print progress messages
@@ -10242,11 +10193,10 @@
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
 Rappture config.status 1.1
-configured by $0, generated by GNU Autoconf 2.68,
-  with options \\"\$ac_cs_config\\"
-
-Copyright (C) 2010 Free Software Foundation, Inc.
+configured by $0, generated by GNU Autoconf 2.64,
+  with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2009 Free Software Foundation, Inc.
 This config.status script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it."
@@ -10266,12 +10216,7 @@
 do
   case $1 in
-  --*=?*)
+  --*=*)
     ac_option=`expr "X$1" : 'X\([^=]*\)='`
     ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
-    ac_shift=:
-    ;;
-  --*=)
-    ac_option=`expr "X$1" : 'X\([^=]*\)='`
-    ac_optarg=
     ac_shift=:
     ;;
@@ -10289,6 +10234,4 @@
   --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
     $as_echo "$ac_cs_version"; exit ;;
-  --config | --confi | --conf | --con | --co | --c )
-    $as_echo "$ac_cs_config"; exit ;;
   --debug | --debu | --deb | --de | --d | -d )
     debug=: ;;
@@ -10297,5 +10240,4 @@
     case $ac_optarg in
     *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
-    '') as_fn_error $? "missing file argument" ;;
     esac
     as_fn_append CONFIG_FILES " '$ac_optarg'"
@@ -10310,5 +10252,5 @@
   --he | --h)
     # Conflict between --help and --header
-    as_fn_error $? "ambiguous option: \`$1'
+    as_fn_error "ambiguous option: \`$1'
 Try \`$0 --help' for more information.";;
   --help | --hel | -h )
@@ -10319,5 +10261,5 @@
 
   # This is an error.
-  -*) as_fn_error $? "unrecognized option: \`$1'
+  -*) as_fn_error "unrecognized option: \`$1'
 Try \`$0 --help' for more information." ;;
 
@@ -10389,6 +10331,8 @@
     "gui/pkgIndex.tcl") CONFIG_FILES="$CONFIG_FILES gui/pkgIndex.tcl" ;;
     "gui/scripts/Makefile") CONFIG_FILES="$CONFIG_FILES gui/scripts/Makefile" ;;
-    "instant/Makefile") CONFIG_FILES="$CONFIG_FILES instant/Makefile" ;;
-    "instant/irappture") CONFIG_FILES="$CONFIG_FILES instant/irappture" ;;
+    "builder/Makefile") CONFIG_FILES="$CONFIG_FILES builder/Makefile" ;;
+    "builder/pkgIndex.tcl") CONFIG_FILES="$CONFIG_FILES builder/pkgIndex.tcl" ;;
+    "tester/Makefile") CONFIG_FILES="$CONFIG_FILES tester/Makefile" ;;
+    "tester/pkgIndex.tcl") CONFIG_FILES="$CONFIG_FILES tester/pkgIndex.tcl" ;;
     "lang/Makefile") CONFIG_FILES="$CONFIG_FILES lang/Makefile" ;;
     "lang/java/Makefile") CONFIG_FILES="$CONFIG_FILES lang/java/Makefile" ;;
@@ -10491,5 +10435,5 @@
     "oldtest/src/Makefile") CONFIG_FILES="$CONFIG_FILES oldtest/src/Makefile" ;;
 
-  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+  *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
   esac
 done
@@ -10513,8 +10457,7 @@
 $debug ||
 {
-  tmp= ac_tmp=
+  tmp=
   trap 'exit_status=$?
-  : "${ac_tmp:=$tmp}"
-  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+  { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
 ' 0
   trap 'as_fn_exit 1' 1 2 13 15
@@ -10524,11 +10467,10 @@
 {
   tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
-  test -d "$tmp"
+  test -n "$tmp" && test -d "$tmp"
 }  ||
 {
   tmp=./conf$$-$RANDOM
   (umask 077 && mkdir "$tmp")
-} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
-ac_tmp=$tmp
+} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5
 
 # Set up the scripts for CONFIG_FILES section.
@@ -10547,10 +10489,10 @@
 ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
 if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
-  ac_cs_awk_cr='\\r'
+  ac_cs_awk_cr='\r'
 else
   ac_cs_awk_cr=$ac_cr
 fi
 
-echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+echo 'BEGIN {' >"$tmp/subs1.awk" &&
 _ACEOF
 
@@ -10561,10 +10503,10 @@
   echo "_ACEOF"
 } >conf$$subs.sh ||
-  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
-ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+  as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'`
 ac_delim='%!_!# '
 for ac_last_try in false false false false false :; do
   . ./conf$$subs.sh ||
-    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+    as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
 
   ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
@@ -10572,5 +10514,5 @@
     break
   elif $ac_last_try; then
-    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+    as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
   else
     ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
@@ -10580,5 +10522,5 @@
 
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+cat >>"\$tmp/subs1.awk" <<\\_ACAWK &&
 _ACEOF
 sed -n '
@@ -10594,5 +10536,5 @@
 :nl
 h
-s/\(.\{148\}\)..*/\1/
+s/\(.\{148\}\).*/\1/
 t more1
 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
@@ -10608,5 +10550,5 @@
 :delim
 h
-s/\(.\{148\}\)..*/\1/
+s/\(.\{148\}\).*/\1/
 t more2
 s/["\\]/\\&/g; s/^/"/; s/$/"/
@@ -10628,5 +10570,5 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 _ACAWK
-cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+cat >>"\$tmp/subs1.awk" <<_ACAWK &&
   for (key in S) S_is_set[key] = 1
   FS = ""
@@ -10660,27 +10602,19 @@
 else
   cat
-fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
-  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
-_ACEOF
-
-# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
-# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \
+  || as_fn_error "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
 # trailing colons and then remove the whole line if VPATH becomes empty
 # (actually we leave an empty line to preserve line numbers).
 if test "x$srcdir" = x.; then
-  ac_vpsub='/^[	 ]*VPATH[	 ]*=[	 ]*/{
-h
-s///
-s/^/:/
-s/[	 ]*$/:/
-s/:\$(srcdir):/:/g
-s/:\${srcdir}:/:/g
-s/:@srcdir@:/:/g
-s/^:*//
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=/{
+s/:*\$(srcdir):*/:/
+s/:*\${srcdir}:*/:/
+s/:*@srcdir@:*/:/
+s/^\([^=]*=[	 ]*\):*/\1/
 s/:*$//
-x
-s/\(=[	 ]*\).*/\1/
-G
-s/\n//
 s/^[^=]*=[	 ]*$//
 }'
@@ -10694,5 +10628,5 @@
 # This happens for instance with `./config.status Makefile'.
 if test -n "$CONFIG_HEADERS"; then
-cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+cat >"$tmp/defines.awk" <<\_ACAWK ||
 BEGIN {
 _ACEOF
@@ -10706,9 +10640,9 @@
 ac_delim='%!_!# '
 for ac_last_try in false false :; do
-  ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
-  if test -z "$ac_tt"; then
+  ac_t=`sed -n "/$ac_delim/p" confdefs.h`
+  if test -z "$ac_t"; then
     break
   elif $ac_last_try; then
-    as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+    as_fn_error "could not make $CONFIG_HEADERS" "$LINENO" 5
   else
     ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
@@ -10795,5 +10729,5 @@
 _ACEOF
 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-  as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+  as_fn_error "could not setup config headers machinery" "$LINENO" 5
 fi # test -n "$CONFIG_HEADERS"
 
@@ -10808,5 +10742,5 @@
   case $ac_mode$ac_tag in
   :[FHL]*:*);;
-  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+  :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;;
   :[FH]-) ac_tag=-:-;;
   :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
@@ -10827,5 +10761,5 @@
     do
       case $ac_f in
-      -) ac_f="$ac_tmp/stdin";;
+      -) ac_f="$tmp/stdin";;
       *) # Look for the file first in the build tree, then in the source tree
 	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
@@ -10836,5 +10770,5 @@
 	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
 	   esac ||
-	   as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+	   as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;;
       esac
       case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
@@ -10862,6 +10796,6 @@
 
     case $ac_tag in
-    *:-:* | *:-) cat >"$ac_tmp/stdin" \
-      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+    *:-:* | *:-) cat >"$tmp/stdin" \
+      || as_fn_error "could not create $ac_file" "$LINENO" 5 ;;
     esac
     ;;
@@ -10999,22 +10933,21 @@
 $ac_datarootdir_hack
 "
-eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
-  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \
+  || as_fn_error "could not create $ac_file" "$LINENO" 5
 
 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
-  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
-  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' \
-      "$ac_tmp/out"`; test -z "$ac_out"; } &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
   { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
-which seems to be undefined.  Please make sure it is defined" >&5
+which seems to be undefined.  Please make sure it is defined." >&5
 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
-which seems to be undefined.  Please make sure it is defined" >&2;}
-
-  rm -f "$ac_tmp/stdin"
+which seems to be undefined.  Please make sure it is defined." >&2;}
+
+  rm -f "$tmp/stdin"
   case $ac_file in
-  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
-  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+  -) cat "$tmp/out" && rm -f "$tmp/out";;
+  *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";;
   esac \
-  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+  || as_fn_error "could not create $ac_file" "$LINENO" 5
  ;;
   :H)
@@ -11025,19 +10958,19 @@
     {
       $as_echo "/* $configure_input  */" \
-      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
-    } >"$ac_tmp/config.h" \
-      || as_fn_error $? "could not create $ac_file" "$LINENO" 5
-    if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+      && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs"
+    } >"$tmp/config.h" \
+      || as_fn_error "could not create $ac_file" "$LINENO" 5
+    if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then
       { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
 $as_echo "$as_me: $ac_file is unchanged" >&6;}
     else
       rm -f "$ac_file"
-      mv "$ac_tmp/config.h" "$ac_file" \
-	|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
+      mv "$tmp/config.h" "$ac_file" \
+	|| as_fn_error "could not create $ac_file" "$LINENO" 5
     fi
   else
     $as_echo "/* $configure_input  */" \
-      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
-      || as_fn_error $? "could not create -" "$LINENO" 5
+      && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \
+      || as_fn_error "could not create -" "$LINENO" 5
   fi
  ;;
@@ -11054,5 +10987,5 @@
 
 test $ac_write_fail = 0 ||
-  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+  as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5
 
 
@@ -11075,5 +11008,5 @@
   # Use ||, not &&, to avoid exiting from the if with $? = 1, which
   # would make configure fail if this is the last instruction.
-  $ac_cs_success || as_fn_exit 1
+  $ac_cs_success || as_fn_exit $?
 fi
 
@@ -11216,5 +11149,5 @@
       eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \
 	   --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" ||
-	as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5
+	as_fn_error "$ac_sub_configure failed for $ac_dir" "$LINENO" 5
     fi
 
Index: /trunk/configure.in
===================================================================
--- /trunk/configure.in	(revision 2079)
+++ /trunk/configure.in	(revision 2080)
@@ -723,6 +723,8 @@
     gui/pkgIndex.tcl
     gui/scripts/Makefile
-    instant/Makefile
-    instant/irappture
+    builder/Makefile
+    builder/pkgIndex.tcl
+    tester/Makefile
+    tester/pkgIndex.tcl
     lang/Makefile
     lang/java/Makefile
Index: /trunk/gui/apps/Makefile.in
===================================================================
--- /trunk/gui/apps/Makefile.in	(revision 2079)
+++ /trunk/gui/apps/Makefile.in	(revision 2080)
@@ -22,5 +22,5 @@
 SCRIPTS	= \
 		encodedata \
-		$(srcdir)/driver \
+		$(srcdir)/launcher.tcl \
 		$(srcdir)/grabdata \
 		$(srcdir)/nanovis-test \
Index: unk/gui/apps/driver
===================================================================
--- /trunk/gui/apps/driver	(revision 2079)
+++ 	(revision )
@@ -1,351 +1,0 @@
-#!/bin/sh
-# ----------------------------------------------------------------------
-#  USER INTERFACE DRIVER
-#
-#  This driver program loads a tool description from a tool.xml file,
-#  and produces a user interface automatically to drive an application.
-#  The user can set up input, click and button to launch a tool, and
-#  browse through output.
-#
-#  RUN AS FOLLOWS:
-#    driver ?-tool <toolfile>?
-#
-#  If the <toolfile> is not specified, it defaults to "tool.xml" in
-#  the current working directory.
-#
-# ======================================================================
-#  AUTHOR:  Michael McLennan, Purdue University
-#  Copyright (c) 2004-2005  Purdue Research Foundation
-#
-#  See the file "license.terms" for information on usage and
-#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
-# ======================================================================
-#\
-exec wish "$0" $*
-# ----------------------------------------------------------------------
-# wish executes everything from here on...
-
-package require Itcl
-package require Rappture
-package require RapptureGUI
-
-option add *MainWin.mode desktop startupFile
-option add *MainWin.borderWidth 0 startupFile
-option add *MainWin.anchor fill startupFile
-
-# "web site" look
-option add *MainWin.bgScript {
-    rectangle 0 0 200 <h> -outline "" -fill #5880BB
-    rectangle 200 0 300 <h> -outline "" -fill #425F8B
-    rectangle 300 0 <w> <h> -outline "" -fill #324565
-} startupFile
-
-# "clean" look
-option add *MainWin.bgScript "" startupFile
-option add *MainWin.bgColor white startupFile
-option add *Tooltip.background white
-option add *Editor.background white
-option add *Gauge.textBackground white
-option add *TemperatureGauge.textBackground white
-option add *Switch.textBackground white
-option add *Progress.barColor #ffffcc
-option add *Balloon.titleBackground #6666cc
-option add *Balloon.titleForeground white
-option add *Balloon*Label.font -*-helvetica-medium-r-normal-*-12-*
-option add *Balloon*Radiobutton.font -*-helvetica-medium-r-normal-*-12-*
-option add *Balloon*Checkbutton.font -*-helvetica-medium-r-normal-*-12-*
-option add *ResultSet.controlbarBackground #6666cc
-option add *ResultSet.controlbarForeground white
-option add *ResultSet.activeControlBackground #ccccff
-option add *ResultSet.activeControlForeground black
-option add *Radiodial.length 3i
-option add *BugReport*banner*foreground white
-option add *BugReport*banner*background #a9a9a9
-option add *BugReport*banner*highlightBackground #a9a9a9
-option add *BugReport*banner*font -*-helvetica-bold-r-normal-*-18-*
-option add *hubcntls*Button.padX 0 widgetDefault
-option add *hubcntls*Button.padY 0 widgetDefault
-option add *hubcntls*Button.relief flat widgetDefault
-option add *hubcntls*Button.overRelief raised widgetDefault
-option add *hubcntls*Button.borderWidth 1 widgetDefault
-option add *hubcntls*Button.font \
-    -*-helvetica-medium-r-normal-*-8-* widgetDefault
-
-switch $tcl_platform(platform) {
-    unix - windows {
-        event add <<PopupMenu>> <ButtonPress-3>
-    }
-    macintosh {
-        event add <<PopupMenu>> <Control-ButtonPress-1>
-    }
-}
-
-# install a better bug handler
-Rappture::bugreport::install
-# fix the "grab" command to support a stack of grab windows
-Rappture::grab::init
-
-#
-# Process command line args to get the names of files to load...
-#
-Rappture::getopts argv params {
-    value -tool tool.xml
-    list  -load ""
-    value -nosim 0
-}
-
-set loadobjs {}
-foreach runfile $params(-load) {
-    if {![file exists $runfile]} {
-        puts stderr "can't find run: \"$runfile\""
-        exit 1
-    }
-    set status [catch {Rappture::library $runfile} result]
-    lappend loadobjs $result
-}
-
-# open the XML file containing the tool parameters
-if {![file exists $params(-tool)]} {
-    # check to see if the user specified any run.xml files to load.
-    # if so, we can use that as the tool.xml. if we can find where
-    # the original application was installed using the xml tag
-    # tool.version.application.directory(top), the user can
-    # run new simulations, otherwise they can only revisualize the
-    # run.xml files they are loading.
-    set pseudotool ""
-    if {0 == [llength $loadobjs]} {
-        puts stderr "can't find tool \"$params(-tool)\""
-        exit 1
-    }
-    # search the loadfiles for the install location
-    # we could just use run.xml files as tool.xml, but
-    # if there are loaders or notes, they will still need
-    # examples/ and docs/ dirs from the install location
-    foreach runobj $loadobjs {
-        set tdir [$runobj get tool.version.application.directory(tool)]
-        if {[file isdirectory $tdir] && \
-            [file exists $tdir/tool.xml]} {
-            set pseudotool $tdir/tool.xml
-            break
-        }
-    }
-    if {![file exists $pseudotool]} {
-        # we didn't find a tool.xml file,
-        # use info from a runfile to build gui
-        # disable simulation, because no tool.xml
-        set pseudotool [lindex $params(-load) 0]
-        array set params [list -nosim true]
-    }
-    if {![file exists $pseudotool]} {
-        puts stderr "can't find tool \"$params(-tool)\""
-        exit 1
-    }
-    array set params [list -tool $pseudotool]
-}
-
-set xmlobj [Rappture::library $params(-tool)]
-
-set installdir [file dirname $params(-tool)]
-if {"." == $installdir} {
-    set installdir [pwd]
-}
-
-set tool [Rappture::Tool ::#auto $xmlobj $installdir]
-
-# ----------------------------------------------------------------------
-# CHECK JOB FAILURE REPORTING
-#
-# If this tool might fail when it launches jobs (i.e., Rappture
-# can't check some inputs, such as strings), then disable the
-# automatic ticket submission for job failures
-# ----------------------------------------------------------------------
-set val [$tool xml get tool.reportJobFailures]
-if { "" != $val} {
-    if {[catch {Rappture::bugreport::shouldReport jobfailures $val} result]} {
-        puts stderr "WARNING for reportJobFailures: $result"
-    }
-}
-
-# ----------------------------------------------------------------------
-# LOAD RESOURCE SETTINGS
-#
-# Try to load the $SESSIONDIR/resources file, which contains
-# middleware settings, such as the application name and the
-# filexfer settings.
-# ----------------------------------------------------------------------
-Rappture::resources::load
-
-# ----------------------------------------------------------------------
-# INITIALIZE THE DESKTOP CONNECTION
-#
-# If there's a SESSION ID, then this must be running within the
-# nanoHUB.  Try to initialize the server handling the desktop
-# connection.
-# ----------------------------------------------------------------------
-Rappture::filexfer::init
-
-# ----------------------------------------------------------------------
-# MAIN WINDOW
-# ----------------------------------------------------------------------
-wm withdraw .
-Rappture::MainWin .main -borderwidth 0
-.main configure -title [$tool xml get tool.title]
-wm withdraw .main
-
-# if the FULLSCREEN variable is set, then nanoHUB wants us to go full screen
-if {[info exists env(FULLSCREEN)]} {
-    .main configure -mode web
-}
-
-#
-# The main window has a pager that acts as a notebook for the
-# various parts.  This notebook as at least two pages--an input
-# page and an output (analysis) page.  If there are <phase>'s
-# for input, then there are more pages in the notebook.
-#
-set win [.main component app]
-Rappture::Postern $win.postern
-pack $win.postern -side bottom -fill x
-
-Rappture::Pager $win.pager
-pack $win.pager -expand yes -fill both
-
-#
-# Add a place for about/questions in the breadcrumbs area of this pager.
-#
-set app [$tool xml get tool.id]
-set url [Rappture::Tool::resources -huburl]
-if {"" != $url && "" != $app} {
-    set f [$win.pager component breadcrumbarea]
-    frame $f.hubcntls
-    pack $f.hubcntls -side right -padx 4
-    label $f.hubcntls.icon -image [Rappture::icon ask] -highlightthickness 0
-    pack $f.hubcntls.icon -side left
-    button $f.hubcntls.about -text "About this tool" \
-        -command [list Rappture::filexfer::webpage "$url/tools/$app"]
-    pack $f.hubcntls.about -side top -anchor w
-    button $f.hubcntls.questions -text Questions? \
-        -command [list Rappture::filexfer::webpage "$url/resources/$app/questions"]
-    pack $f.hubcntls.questions -side top -anchor w
-}
-
-#
-# Load up the components in the various phases of input.
-#
-set phases [$tool xml children -type phase input]
-if {[llength $phases] > 0} {
-    set plist ""
-    foreach name $phases {
-        lappend plist input.$name
-    }
-    set phases $plist
-} else {
-    set phases input
-}
-
-foreach comp $phases {
-    set title [$tool xml get $comp.about.label]
-    if {$title == ""} {
-        set title "Input #auto"
-    }
-    $win.pager insert end -name $comp -title $title
-
-    #
-    # Build the page of input controls for this phase.
-    #
-    set f [$win.pager page $comp]
-    Rappture::Page $f.cntls $tool $comp
-    pack $f.cntls -expand yes -fill both
-}
-
-# let components (loaders) in the newly created pages settle
-update
-
-# ----------------------------------------------------------------------
-# OUTPUT AREA
-# ----------------------------------------------------------------------
-
-# adjust the title of the page here.
-# to adjust the button text, look in analyzer.tcl
-set simtxt [$xmlobj get tool.action.label]
-if {"" == $simtxt} {
-    set simtxt "Simulate"
-}
-$win.pager insert end -name analyzer -title $simtxt
-set f [$win.pager page analyzer]
-$win.pager page analyzer -command [subst {
-    if { !$params(-nosim) } {
-        $win.pager busy yes
-        update
-        $f.analyze simulate -ifneeded
-        $win.pager busy no
-    }
-}]
-
-Rappture::Analyzer $f.analyze $tool -simcontrol auto -notebookpage about
-pack $f.analyze -expand yes -fill both
-
-$tool notify add analyzer * [list $f.analyze reset]
-
-# ----------------------------------------------------------------------
-# Finalize the arrangement
-# ----------------------------------------------------------------------
-if {[llength [$win.pager page]] == 2} {
-    set style [$xmlobj get tool.layout]
-    set screenw [winfo screenwidth .]
-
-    update idletasks
-    set w0 [winfo reqwidth [$win.pager page @0]]
-    set w1 [winfo reqwidth [$win.pager page @1]]
-
-    if { $style != "wizard" } {
-	# If only two windows and they're small enough, put them up
-	# side-by-side
-	if {$w0+$w1 < $screenw } {
-	    $win.pager configure -arrangement side-by-side
-	    $f.analyze configure -holdwindow [$win.pager page @0]
-	}
-    }
-    set type [$tool xml get tool.control]
-    if {$type == ""} {
-	set type [$tool xml get tool.control.type]
-    }
-    set arrangement [$win.pager cget -arrangement]
-    if { $type == "" } {
-        if { $arrangement != "side-by-side" } { 
-           set type auto
-        }
-    }
-    if { $arrangement != "side-by-side" && 
-	    ($type == "manual" || $type == "auto" || $style == "wizard") } {
-	# in "auto" mode, we don't need a simulate button
-	$f.analyze configure -simcontrol off
-    } else {
-	# not in "auto" mode but side-by-side, we always need the button
-	$f.analyze configure -simcontrol on
-    }
-} elseif {[llength [$win.pager page]] > 2} {
-    # We have phases, so we shouldn't allow the "Simulate" button.
-    # If it pops up, there are two ways to push simulate and duplicate
-    # links for "About" and "Questions?".
-    $f.analyze configure -simcontrol off
-}
-
-# load previous xml runfiles
-if {0 != [llength $params(-load)]} {
-    foreach runobj $loadobjs {
-        # this doesn't seem to work with loaders
-        # loaders seem to get their value after this point
-        # may need to tell loader elements to update its value
-        $tool load $runobj
-        $f.analyze load $runobj
-    }
-    # don't need simulate button if we cannot simulate
-    if {$params(-nosim)} {
-        $f.analyze configure -simcontrol off
-    }
-    $f.analyze configure -notebookpage analyze
-    $win.pager current analyzer
-}
-
-wm deiconify .main
Index: /trunk/gui/apps/launcher.tcl
===================================================================
--- /trunk/gui/apps/launcher.tcl	(revision 2080)
+++ /trunk/gui/apps/launcher.tcl	(revision 2080)
@@ -0,0 +1,114 @@
+#!/bin/sh
+# ----------------------------------------------------------------------
+#  RAPPTURE LAUNCHER
+#
+#  This script is invoked by the "rappture" command.  It parses
+#  various input options and selects the proper main program to
+#  run depending on the function (build tool, run tool, tester, etc.).
+#
+#  RUN AS FOLLOWS:
+#    rappture ?-run? ?-tool <toolfile>?
+#    rappture -builder ?-tool <toolfile>?
+#    rappture -tester ?-tool <toolfile>? ?-testdir <directory>?
+#
+#  The default option is "-run", which brings up the GUI used to
+#  run the tool.  If the <toolfile> is not specified, it defaults
+#  to "tool.xml" in the current working directory.
+#
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2011  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+package require RapptureGUI
+set guidir $RapptureGUI::library
+
+package require RapptureBuilder
+set blddir $RapptureBuilder::library
+
+package require RapptureTester
+set testdir $RapptureTester::library
+
+set mainscript [file join $guidir scripts main.tcl]
+set alist ""
+set toolxml ""
+
+# scan through the arguments and look for the function
+while {[llength $argv] > 0} {
+    set opt [lindex $argv 0]
+    set argv [lrange $argv 1 end]
+
+    if {[string index $opt 0] == "-"} {
+        switch -- $opt {
+            -run {
+                set mainscript [file join $guidir scripts main.tcl]
+            }
+            -builder {
+                set mainscript [file join $blddir scripts main.tcl]
+            }
+            -tester {
+                set mainscript [file join $testdir scripts main.tcl]
+            }
+            -tool {
+                set toolxml [lindex $argv 0]
+                set argv [lrange $argv 1 end]
+                if {![file exists $toolxml]} {
+                    puts stderr "file not found: $toolxml"
+                    exit 1
+                }
+                lappend alist -tool $toolxml
+            }
+            -testdir - -nosim {
+                lappend alist $opt [lindex $argv 0]
+                set argv [lrange $argv 1 end]
+            }
+            -load {
+                lappend alist $opt
+                while {1} {
+                    set val [lindex $argv 0]
+                    if {[string index $val 0] != "-"} {
+                        break
+                    }
+                    lappend alist $val
+                    set argv [lrange $argv 1 end]
+                }
+            }
+            default {
+                puts stderr "usage:"
+                puts stderr "  rappture ?-run? ?-tool toolFile? ?-nosim 0/1? ?-load file file ...?"
+                puts stderr "  rappture -builder ?-tool toolFile?"
+                puts stderr "  rappture -tester ?-tool toolFile? ?-testdir directory?"
+                exit 1
+            }
+        }
+    }
+}
+
+# if we didn't find a tool.xml file, then look for one here
+if {$toolxml eq ""} {
+    if {![file exists tool.xml]} {
+        puts stderr "rappture: can't find tool definition file \"tool.xml\""
+        puts stderr "  Use the -tool option to specify the location of this file."
+        exit 1
+    }
+    set alist [linsert $alist 0 -tool tool.xml]
+}
+
+# invoke the main program with the args
+set bindir [file dirname [info nameofexecutable]]
+set prog ""
+foreach name {wish wish8.5 wish8.4} {
+    if {[file executable [file join $bindir $prog]]} {
+        set prog [file join $bindir $name]
+        break
+    }
+}
+
+if {$prog eq ""} {
+    puts stderr "rappture: can't find wish program in $bindir"
+}
+
+#eval exec [list $prog $mainscript] $alist
+puts "RUNNING: exec $prog $mainscript $alist"
Index: /trunk/gui/apps/rappture.in
===================================================================
--- /trunk/gui/apps/rappture.in	(revision 2079)
+++ /trunk/gui/apps/rappture.in	(revision 2080)
@@ -9,5 +9,5 @@
 # ======================================================================
 #  AUTHOR:  Michael McLennan, Purdue University
-#  Copyright (c) 2004-2007  Purdue Research Foundation
+#  Copyright (c) 2004-2011  Purdue Research Foundation
 #
 #  See the file "license.terms" for information on usage and
@@ -16,3 +16,3 @@
 dir=`dirname $0`
 . $dir/rappture.env
-exec $dir/driver $*
+exec $dir/launcher.tcl $*
Index: /trunk/gui/scripts/main.tcl
===================================================================
--- /trunk/gui/scripts/main.tcl	(revision 2080)
+++ /trunk/gui/scripts/main.tcl	(revision 2080)
@@ -0,0 +1,346 @@
+#!/bin/sh
+# ----------------------------------------------------------------------
+#  USER INTERFACE DRIVER
+#
+#  This driver program loads a tool description from a tool.xml file,
+#  and produces a user interface automatically to drive an application.
+#  The user can set up input, click and button to launch a tool, and
+#  browse through output.
+#
+#  RUN AS FOLLOWS:
+#    wish main.tcl ?-tool <toolfile>?
+#
+#  If the <toolfile> is not specified, it defaults to "tool.xml" in
+#  the current working directory.
+#
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2011  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+package require Itcl
+package require Rappture
+package require RapptureGUI
+
+option add *MainWin.mode desktop startupFile
+option add *MainWin.borderWidth 0 startupFile
+option add *MainWin.anchor fill startupFile
+
+# "web site" look
+option add *MainWin.bgScript {
+    rectangle 0 0 200 <h> -outline "" -fill #5880BB
+    rectangle 200 0 300 <h> -outline "" -fill #425F8B
+    rectangle 300 0 <w> <h> -outline "" -fill #324565
+} startupFile
+
+# "clean" look
+option add *MainWin.bgScript "" startupFile
+option add *MainWin.bgColor white startupFile
+option add *Tooltip.background white
+option add *Editor.background white
+option add *Gauge.textBackground white
+option add *TemperatureGauge.textBackground white
+option add *Switch.textBackground white
+option add *Progress.barColor #ffffcc
+option add *Balloon.titleBackground #6666cc
+option add *Balloon.titleForeground white
+option add *Balloon*Label.font -*-helvetica-medium-r-normal-*-12-*
+option add *Balloon*Radiobutton.font -*-helvetica-medium-r-normal-*-12-*
+option add *Balloon*Checkbutton.font -*-helvetica-medium-r-normal-*-12-*
+option add *ResultSet.controlbarBackground #6666cc
+option add *ResultSet.controlbarForeground white
+option add *ResultSet.activeControlBackground #ccccff
+option add *ResultSet.activeControlForeground black
+option add *Radiodial.length 3i
+option add *BugReport*banner*foreground white
+option add *BugReport*banner*background #a9a9a9
+option add *BugReport*banner*highlightBackground #a9a9a9
+option add *BugReport*banner*font -*-helvetica-bold-r-normal-*-18-*
+option add *hubcntls*Button.padX 0 widgetDefault
+option add *hubcntls*Button.padY 0 widgetDefault
+option add *hubcntls*Button.relief flat widgetDefault
+option add *hubcntls*Button.overRelief raised widgetDefault
+option add *hubcntls*Button.borderWidth 1 widgetDefault
+option add *hubcntls*Button.font \
+    -*-helvetica-medium-r-normal-*-8-* widgetDefault
+
+switch $tcl_platform(platform) {
+    unix - windows {
+        event add <<PopupMenu>> <ButtonPress-3>
+    }
+    macintosh {
+        event add <<PopupMenu>> <Control-ButtonPress-1>
+    }
+}
+
+# install a better bug handler
+Rappture::bugreport::install
+# fix the "grab" command to support a stack of grab windows
+Rappture::grab::init
+
+#
+# Process command line args to get the names of files to load...
+#
+Rappture::getopts argv params {
+    value -tool tool.xml
+    list  -load ""
+    value -nosim 0
+}
+
+set loadobjs {}
+foreach runfile $params(-load) {
+    if {![file exists $runfile]} {
+        puts stderr "can't find run: \"$runfile\""
+        exit 1
+    }
+    set status [catch {Rappture::library $runfile} result]
+    lappend loadobjs $result
+}
+
+# open the XML file containing the tool parameters
+if {![file exists $params(-tool)]} {
+    # check to see if the user specified any run.xml files to load.
+    # if so, we can use that as the tool.xml. if we can find where
+    # the original application was installed using the xml tag
+    # tool.version.application.directory(top), the user can
+    # run new simulations, otherwise they can only revisualize the
+    # run.xml files they are loading.
+    set pseudotool ""
+    if {0 == [llength $loadobjs]} {
+        puts stderr "can't find tool \"$params(-tool)\""
+        exit 1
+    }
+    # search the loadfiles for the install location
+    # we could just use run.xml files as tool.xml, but
+    # if there are loaders or notes, they will still need
+    # examples/ and docs/ dirs from the install location
+    foreach runobj $loadobjs {
+        set tdir [$runobj get tool.version.application.directory(tool)]
+        if {[file isdirectory $tdir] && \
+            [file exists $tdir/tool.xml]} {
+            set pseudotool $tdir/tool.xml
+            break
+        }
+    }
+    if {![file exists $pseudotool]} {
+        # we didn't find a tool.xml file,
+        # use info from a runfile to build gui
+        # disable simulation, because no tool.xml
+        set pseudotool [lindex $params(-load) 0]
+        array set params [list -nosim true]
+    }
+    if {![file exists $pseudotool]} {
+        puts stderr "can't find tool \"$params(-tool)\""
+        exit 1
+    }
+    array set params [list -tool $pseudotool]
+}
+
+set xmlobj [Rappture::library $params(-tool)]
+
+set installdir [file dirname $params(-tool)]
+if {"." == $installdir} {
+    set installdir [pwd]
+}
+
+set tool [Rappture::Tool ::#auto $xmlobj $installdir]
+
+# ----------------------------------------------------------------------
+# CHECK JOB FAILURE REPORTING
+#
+# If this tool might fail when it launches jobs (i.e., Rappture
+# can't check some inputs, such as strings), then disable the
+# automatic ticket submission for job failures
+# ----------------------------------------------------------------------
+set val [$tool xml get tool.reportJobFailures]
+if { "" != $val} {
+    if {[catch {Rappture::bugreport::shouldReport jobfailures $val} result]} {
+        puts stderr "WARNING for reportJobFailures: $result"
+    }
+}
+
+# ----------------------------------------------------------------------
+# LOAD RESOURCE SETTINGS
+#
+# Try to load the $SESSIONDIR/resources file, which contains
+# middleware settings, such as the application name and the
+# filexfer settings.
+# ----------------------------------------------------------------------
+Rappture::resources::load
+
+# ----------------------------------------------------------------------
+# INITIALIZE THE DESKTOP CONNECTION
+#
+# If there's a SESSION ID, then this must be running within the
+# nanoHUB.  Try to initialize the server handling the desktop
+# connection.
+# ----------------------------------------------------------------------
+Rappture::filexfer::init
+
+# ----------------------------------------------------------------------
+# MAIN WINDOW
+# ----------------------------------------------------------------------
+wm withdraw .
+Rappture::MainWin .main -borderwidth 0
+.main configure -title [$tool xml get tool.title]
+wm withdraw .main
+
+# if the FULLSCREEN variable is set, then nanoHUB wants us to go full screen
+if {[info exists env(FULLSCREEN)]} {
+    .main configure -mode web
+}
+
+#
+# The main window has a pager that acts as a notebook for the
+# various parts.  This notebook as at least two pages--an input
+# page and an output (analysis) page.  If there are <phase>'s
+# for input, then there are more pages in the notebook.
+#
+set win [.main component app]
+Rappture::Postern $win.postern
+pack $win.postern -side bottom -fill x
+
+Rappture::Pager $win.pager
+pack $win.pager -expand yes -fill both
+
+#
+# Add a place for about/questions in the breadcrumbs area of this pager.
+#
+set app [$tool xml get tool.id]
+set url [Rappture::Tool::resources -huburl]
+if {"" != $url && "" != $app} {
+    set f [$win.pager component breadcrumbarea]
+    frame $f.hubcntls
+    pack $f.hubcntls -side right -padx 4
+    label $f.hubcntls.icon -image [Rappture::icon ask] -highlightthickness 0
+    pack $f.hubcntls.icon -side left
+    button $f.hubcntls.about -text "About this tool" \
+        -command [list Rappture::filexfer::webpage "$url/tools/$app"]
+    pack $f.hubcntls.about -side top -anchor w
+    button $f.hubcntls.questions -text Questions? \
+        -command [list Rappture::filexfer::webpage "$url/resources/$app/questions"]
+    pack $f.hubcntls.questions -side top -anchor w
+}
+
+#
+# Load up the components in the various phases of input.
+#
+set phases [$tool xml children -type phase input]
+if {[llength $phases] > 0} {
+    set plist ""
+    foreach name $phases {
+        lappend plist input.$name
+    }
+    set phases $plist
+} else {
+    set phases input
+}
+
+foreach comp $phases {
+    set title [$tool xml get $comp.about.label]
+    if {$title == ""} {
+        set title "Input #auto"
+    }
+    $win.pager insert end -name $comp -title $title
+
+    #
+    # Build the page of input controls for this phase.
+    #
+    set f [$win.pager page $comp]
+    Rappture::Page $f.cntls $tool $comp
+    pack $f.cntls -expand yes -fill both
+}
+
+# let components (loaders) in the newly created pages settle
+update
+
+# ----------------------------------------------------------------------
+# OUTPUT AREA
+# ----------------------------------------------------------------------
+
+# adjust the title of the page here.
+# to adjust the button text, look in analyzer.tcl
+set simtxt [$xmlobj get tool.action.label]
+if {"" == $simtxt} {
+    set simtxt "Simulate"
+}
+$win.pager insert end -name analyzer -title $simtxt
+set f [$win.pager page analyzer]
+$win.pager page analyzer -command [subst {
+    if { !$params(-nosim) } {
+        $win.pager busy yes
+        update
+        $f.analyze simulate -ifneeded
+        $win.pager busy no
+    }
+}]
+
+Rappture::Analyzer $f.analyze $tool -simcontrol auto -notebookpage about
+pack $f.analyze -expand yes -fill both
+
+$tool notify add analyzer * [list $f.analyze reset]
+
+# ----------------------------------------------------------------------
+# Finalize the arrangement
+# ----------------------------------------------------------------------
+if {[llength [$win.pager page]] == 2} {
+    set style [$xmlobj get tool.layout]
+    set screenw [winfo screenwidth .]
+
+    update idletasks
+    set w0 [winfo reqwidth [$win.pager page @0]]
+    set w1 [winfo reqwidth [$win.pager page @1]]
+
+    if { $style != "wizard" } {
+	# If only two windows and they're small enough, put them up
+	# side-by-side
+	if {$w0+$w1 < $screenw } {
+	    $win.pager configure -arrangement side-by-side
+	    $f.analyze configure -holdwindow [$win.pager page @0]
+	}
+    }
+    set type [$tool xml get tool.control]
+    if {$type == ""} {
+	set type [$tool xml get tool.control.type]
+    }
+    set arrangement [$win.pager cget -arrangement]
+    if { $type == "" } {
+        if { $arrangement != "side-by-side" } { 
+           set type auto
+        }
+    }
+    if { $arrangement != "side-by-side" && 
+	    ($type == "manual" || $type == "auto" || $style == "wizard") } {
+	# in "auto" mode, we don't need a simulate button
+	$f.analyze configure -simcontrol off
+    } else {
+	# not in "auto" mode but side-by-side, we always need the button
+	$f.analyze configure -simcontrol on
+    }
+} elseif {[llength [$win.pager page]] > 2} {
+    # We have phases, so we shouldn't allow the "Simulate" button.
+    # If it pops up, there are two ways to push simulate and duplicate
+    # links for "About" and "Questions?".
+    $f.analyze configure -simcontrol off
+}
+
+# load previous xml runfiles
+if {0 != [llength $params(-load)]} {
+    foreach runobj $loadobjs {
+        # this doesn't seem to work with loaders
+        # loaders seem to get their value after this point
+        # may need to tell loader elements to update its value
+        $tool load $runobj
+        $f.analyze load $runobj
+    }
+    # don't need simulate button if we cannot simulate
+    if {$params(-nosim)} {
+        $f.analyze configure -simcontrol off
+    }
+    $f.analyze configure -notebookpage analyze
+    $win.pager current analyzer
+}
+
+wm deiconify .main
Index: /trunk/lang/tcl/scripts/Makefile.in
===================================================================
--- /trunk/lang/tcl/scripts/Makefile.in	(revision 2079)
+++ /trunk/lang/tcl/scripts/Makefile.in	(revision 2080)
@@ -41,10 +41,37 @@
 		$(srcdir)/exec.tcl \
 		$(srcdir)/library.tcl \
+		$(srcdir)/objects.tcl \
+		$(srcdir)/objects/base.rp \
 		$(srcdir)/result.tcl \
 		$(srcdir)/units.tcl
 
+OBJECTS		= \
+		boolean \
+		choice \
+		curve \
+		group \
+		histogram \
+		integer \
+		note \
+		number \
+		phase \
+		string
+
+TYPEFILES	= \
+		$(srcdir)/types/boolean.tcl \
+		$(srcdir)/types/color.tcl \
+		$(srcdir)/types/file.tcl \
+		$(srcdir)/types/string.tcl \
+		$(srcdir)/types/units.tcl
+
+VALIDATEFILES	= \
+		$(srcdir)/validations/enable.tcl \
+		$(srcdir)/validations/int.tcl \
+		$(srcdir)/validations/number.tcl \
+		$(srcdir)/validations/size.tcl
+
 all: tclIndex
 
-tclIndex: $(FILES)
+tclIndex: install-objects install-types install-validations $(FILES)
 	$(TCLSH) $(srcdir)/../tclconfig/mkindex.tcl --srcdir $(srcdir) \
 		--outfile tclIndex
@@ -57,4 +84,28 @@
 	$(INSTALL) -m 0444 tclIndex $(destdir)
 
+install-objects:
+	$(MKDIR_P) -m 0755 $(destdir)/objects
+	for i in $(OBJECTS); do \
+	    echo "Installing object definition: $$i" ; \
+	    $(MKDIR_P) -m 0755 $(destdir)/objects/$$i ; \
+	    for j in $(srcdir)/objects/$$i/*; do \
+		$(INSTALL) -m 0444 $$j $(destdir)/objects/$$i ; \
+	    done
+	done
+
+install-types: $(TYPEFILES)
+	$(MKDIR_P) -m 0755 $(destdir)/types
+	@for i in $(TYPEFILES); do \
+	    echo "Installing $$i" ; \
+	    $(INSTALL) -m 555 $$i $(destdir)/types ; \
+	done
+
+install-validations: $(VALIDATEFILES)
+	$(MKDIR_P) -m 0755 $(destdir)/validations
+	@for i in $(VALIDATEFILES); do \
+	    echo "Installing $$i" ; \
+	    $(INSTALL) -m 555 $$i $(destdir)/validations ; \
+	done
+
 clean: 
 	$(RM) tclIndex
Index: /trunk/lang/tcl/scripts/library.tcl
===================================================================
--- /trunk/lang/tcl/scripts/library.tcl	(revision 2079)
+++ /trunk/lang/tcl/scripts/library.tcl	(revision 2080)
@@ -16,4 +16,10 @@
 namespace eval Rappture {
     variable stdlib ""
+}
+
+# automatically load all Rappture object types
+if {[catch {Rappture::objects::init} err]} {
+    puts stderr "Error loading object definitions:\n$err"
+    exit 1
 }
 
Index: /trunk/lang/tcl/scripts/objects.tcl
===================================================================
--- /trunk/lang/tcl/scripts/objects.tcl	(revision 2080)
+++ /trunk/lang/tcl/scripts/objects.tcl	(revision 2080)
@@ -0,0 +1,488 @@
+# ----------------------------------------------------------------------
+#  COMPONENT: objects
+#
+#  This file contains routines to parse object data from files in
+#  the "objects" directory.  Each file defines a Rappture object and
+#  all information needed to specify the object in a tool.xml file.
+#
+#    object NAME ?-extends BASE? {
+#        attr NAME -title XX -type TYPE -path PATH
+#        check attr { code... }
+#        palettes NAME NAME ...
+#        help URL
+#        terminal yes|no
+#        ...
+#    }
+#
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2011  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+package require Itcl
+
+namespace eval Rappture { # forward declaration }
+namespace eval Rappture::objects {
+    # location of system object info
+    variable installdir [file dirname [file normalize [info script]]]
+
+    #
+    # Set up a safe interpreter for loading object defn files...
+    #
+    variable objParser [interp create -safe]
+    foreach cmd [$objParser eval {info commands}] {
+	$objParser hide $cmd
+    }
+    $objParser alias object Rappture::objects::parse_object
+    $objParser alias unknown Rappture::objects::parse_obj_unknown
+    proc ::Rappture::objects::parse_obj_unknown {args} {
+        error "bad option \"[lindex $args 0]\": should be object"
+    }
+
+    #
+    # Set up a safe interpreter for loading object attributes...
+    #
+    variable attrParser [interp create -safe]
+    foreach cmd [$attrParser eval {info commands}] {
+	$attrParser hide $cmd
+    }
+    $attrParser alias attr Rappture::objects::parse_attr
+    $attrParser alias check Rappture::objects::parse_check
+    $attrParser alias help Rappture::objects::parse_help
+    $attrParser alias palettes Rappture::objects::parse_palettes
+    $attrParser alias terminal Rappture::objects::parse_terminal
+    $attrParser alias unknown Rappture::objects::parse_attr_unknown
+    proc ::Rappture::objects::parse_attr_unknown {args} {
+        error "bad option \"[lindex $args 0]\": should be attr, check, help, palettes, terminal"
+    }
+
+    # this variable will hold ObjDef object as it is being built
+    variable currObjDef ""
+
+    # this variable will hold the name of the object file being parsed
+    variable currFile ""
+}
+
+# ----------------------------------------------------------------------
+# USAGE: Rappture::objects::init
+#
+# Called at the beginning of a Rappture program to initialize the
+# object system.  Loads all object definitions in the "objects"
+# directory found at the system location.  Object types can be
+# queried by calling Rappture::objects::get.
+# ----------------------------------------------------------------------
+proc Rappture::objects::init {} {
+    variable installdir
+
+    # load supporting type definitions
+    foreach fname [glob [file join $installdir types *.tcl]] {
+        source $fname
+    }
+
+    # load supporting validation procs
+    foreach fname [glob [file join $installdir validations *.tcl]] {
+        source $fname
+    }
+
+    # load the base class
+    Rappture::objects::load [file join $installdir objects base.rp]
+
+    # load any other classes found
+    foreach dir [glob -nocomplain -types d [file join $installdir objects *]] {
+        Rappture::objects::load [file join $dir *.rp]
+    }
+}
+
+# ----------------------------------------------------------------------
+# USAGE: Rappture::objects::load ?<filePattern> <filePattern> ...?
+#
+# Clients call this to load object definitions from all files that
+# match the given set of file patterns.  These may be specific
+# file names or patterns of the form "dir/*.rp".  Each object is
+# loaded and Rappture::ObjDef objects are created as a side effect
+# to represent them.  Object types can be queried by calling
+# Rappture::objects::get.
+# ----------------------------------------------------------------------
+proc Rappture::objects::load {args} {
+    variable objParser
+    variable objDefs
+    variable currFile
+
+    # scan through all matching files and load their definitions
+    foreach pattern $args {
+        foreach fname [glob -nocomplain $pattern] {
+            set currFile $fname
+            set fid [open $fname r]
+            set info [read $fid]
+            close $fid
+
+            if {[catch {$objParser eval $info} err] != 0} {
+                error $err "\n    (while loading object definition from file \"$fname\")"
+            }
+        }
+    }
+
+    # look at all inheritance relationships and make sure they're satisfied
+    foreach name [array names objDefs] {
+        set ilist [$objDefs($name) cget -inherit]
+        set newilist ""
+        foreach obj $ilist {
+            if {[string index $obj 0] == "@"} {
+                set tname [string range $obj 1 end]
+                if {[info exists objDefs($tname)]} {
+                    lappend newilist $objDefs($tname)
+                } else {
+                    set errs($tname) 1
+                }
+            }
+            $objDefs($name) configure -inherit $newilist
+        }
+    }
+
+    if {[array size errs] > 0} {
+        error "missing definition for base class: [join [lsort [array names errs]] {, }]"
+    }
+}
+
+# ----------------------------------------------------------------------
+# USAGE: Rappture::objects::get ?<name>? ?-what?
+#
+# Returns information about the known Rappture object types.
+# With no args, it returns a list of object class names.  With a
+# specified <name>, it returns all information for that object in
+# a key/value format:
+#
+#   -image xxx -palettes {xx xx xx} -attributes {{...} {...} ...}
+#   -help URL -terminal bool
+#
+# Otherwise, the -what indicates which specific value should be
+# returned.
+# ----------------------------------------------------------------------
+proc Rappture::objects::get {{name ""} {what ""}} {
+    variable objDefs
+
+    if {"" == $name} {
+        return [array names objDefs]
+    }
+
+    set name [string tolower $name]  ;# doesn't matter: Tool or tool
+    set info(-image) [$objDefs($name) cget -image]
+    set info(-help) [$objDefs($name) cget -help]
+    set info(-palettes) [$objDefs($name) cget -palettes]
+    set info(-terminal) [$objDefs($name) cget -terminal]
+
+    set rlist ""
+    set olist $objDefs($name)
+    while {[llength $olist] > 0} {
+        set obj [lindex $olist 0]
+        if {![info exists gotparents($obj)]} {
+            set pos 0
+            foreach baseobj [$obj cget -inherit] {
+                set olist [linsert $olist $pos $baseobj]
+                incr pos
+            }
+            set gotparents($obj) 1
+        }
+
+        set obj [lindex $olist 0]
+        set olist [lrange $olist 1 end]
+
+        foreach aname [$obj get] {
+            lappend rlist [$obj get $aname]
+        }
+    }
+    set info(-attributes) $rlist
+
+    if {"" == $what} {
+        return [array get info]
+    } elseif {[info exists info($what)]} {
+        return $info($what)
+    }
+    error "bad option \"$what\": should be [join [lsort [array names info]] {, }]"
+}
+
+# ----------------------------------------------------------------------
+# USAGE: Rappture::objects::palettes
+#
+# Returns a list of unique palette names from all known types.
+# ----------------------------------------------------------------------
+proc Rappture::objects::palettes {} {
+    variable objDefs
+
+    foreach name [array names objDefs] {
+        foreach pname [$objDefs($name) cget -palettes] {
+            set unique($pname) 1
+        }
+    }
+    return [lsort -dictionary [array names unique]]
+}
+
+# ----------------------------------------------------------------------
+# USAGE: Rappture::objects::check <type> {<key> <val>...} <debugInfo>
+#
+# Checks the definition for an object of the given <type> to see if
+# there are any errors in the values.  The attribute values are
+# specified as a key/value list.  Returns a list of the form:
+#   error "something went wrong"
+#   warning "might check this"
+# ----------------------------------------------------------------------
+proc Rappture::objects::check {type attrinfo debug} {
+    variable objDefs
+
+    set type [string tolower $type]  ;# doesn't matter: Tool or tool
+
+    if {[info exists objDefs($type)]} {
+        return [$objDefs($type) check $attrinfo $debug]
+    }
+    return ""
+}
+
+# ----------------------------------------------------------------------
+# PARSER:  Rappture::objects::parse_object
+#
+# Used internally to parse the definition of a Rappture object type:
+#
+#   object <name> ?-extends <type>? {
+#     attr <name> <args>...
+#     attr <name> <args>...
+#     ...
+#   }
+#
+# Builds an object in currObjDef and then registers the completed
+# object in the objDefs array.
+# ----------------------------------------------------------------------
+proc Rappture::objects::parse_object {args} {
+    variable currObjDef
+    variable currFile
+    variable objDefs
+    variable attrParser
+
+    set name [lindex $args 0]
+    set args [lrange $args 1 end]
+
+    set ilist ""
+    while {1} {
+        set first [lindex $args 0]
+        if {[string index $first 0] != "-"} {
+            break
+        }
+        if {"-extends" == $first} {
+            set base [lindex $args 1]
+            set args [lrange $args 2 end]
+            lappend ilist @$base
+        } else {
+            error "bad option \"$first\": should be -extends"
+        }
+    }
+
+    if {[llength $args] != 1} {
+        error "wrong # args: should be \"object name ?-extends base? {...definition...}\""
+    }
+    set body [lindex $args end]
+
+    # create an object definition and add attributes to it
+    set currObjDef [Rappture::objects::ObjDef ::#auto -inherit $ilist]
+    set cmds {
+        # parse attribute definitions
+        $attrParser eval $body
+
+        # look for an image for this object
+        set rootf [file rootname $currFile]
+        foreach ext {png jpg gif} {
+            if {[file readable $rootf.$ext]} {
+                set imh [image create photo -file $rootf.$ext]
+                $currObjDef configure -image $imh
+                break
+            }
+        }
+    }
+
+    if {[catch $cmds err] != 0} {
+        itcl::delete object $currObjDef
+        set currObjDef ""
+        error $err "\n    (while loading object definition for \"$name\")"
+    }
+
+    set objDefs($name) $currObjDef
+    set currObjDef ""
+}
+
+# ----------------------------------------------------------------------
+# PARSER:  Rappture::objects::parse_attr
+#
+# Used internally to parse the definition of an attribute within a
+# Rappture object definition:
+#
+#   attr <name> -title <string> -type <string> -path <string>
+#
+# Adds an attribute definition to the object in currObjDef.
+# ----------------------------------------------------------------------
+proc Rappture::objects::parse_attr {args} {
+    variable currObjDef
+
+    set name [lindex $args 0]
+    eval $currObjDef add attr $name [lrange $args 1 end]
+}
+
+# ----------------------------------------------------------------------
+# PARSER:  Rappture::objects::parse_check
+#
+# Used internally to register a bit of code that's used to check the
+# integrity of a value.
+#
+#   check attr { code... }
+#
+# The code assumes that attribute values are stored in an attr(...)
+# array.  It checks the values and returns errors in the following
+# format:
+#   error "something went wrong" {-node 2 -counter 7 -attr label}
+#   warning "watch out for this" {-node 8 -counter 1 -attr description}
+# ----------------------------------------------------------------------
+proc Rappture::objects::parse_check {attr code} {
+    variable currObjDef
+    $currObjDef add check $attr $code
+}
+
+# ----------------------------------------------------------------------
+# PARSER:  Rappture::objects::parse_help
+#
+# Used internally to parse the definition of the help page URL for a
+# Rappture object definition:
+#
+#   help <url>
+#
+# Keeps the <url> around so it can be displayed later in a "Help"
+# button on the attribute editor.
+# ----------------------------------------------------------------------
+proc Rappture::objects::parse_help {url} {
+    variable currObjDef
+    if {![regexp {^https?://} $url]} {
+        error "bad value \"$url\": should be a URL for the help page"
+    }
+    $currObjDef configure -help $url
+}
+
+# ----------------------------------------------------------------------
+# PARSER:  Rappture::objects::parse_palettes
+#
+# Used internally to parse the definition of the palettes for a
+# Rappture object definition:
+#
+#   palettes <name> <name> ...
+#
+# Adds the list of palettes to the object definition.  This determines
+# what palettes of controls will contain this object.
+# ----------------------------------------------------------------------
+proc Rappture::objects::parse_palettes {args} {
+    variable currObjDef
+    $currObjDef configure -palettes $args
+}
+
+# ----------------------------------------------------------------------
+# PARSER:  Rappture::objects::parse_terminal
+#
+# Used internally to parse the "terminal" setting within a Rappture
+# object definition:
+#
+#   terminal yes|no
+#
+# Sets the Boolean value, which determines whether or not this object
+# can have other objects embedded within it.  If it is "terminal",
+# an object is a leaf node.
+# ----------------------------------------------------------------------
+proc Rappture::objects::parse_terminal {val} {
+    variable currObjDef
+    if {![string is boolean -strict $val]} {
+        error "bad value \"$val\": should be boolean"
+    }
+    $currObjDef configure -terminal $val
+}
+
+# ----------------------------------------------------------------------
+#  CLASS: ObjDef
+# ----------------------------------------------------------------------
+itcl::class Rappture::objects::ObjDef {
+    public variable inherit ""
+    public variable image ""
+    public variable help ""
+    public variable terminal "yes"
+    public variable palettes ""
+
+    constructor {args} {
+        set _checks(num) 0
+        eval configure $args
+    }
+
+    public method add {what name args} {
+        switch -- $what {
+            attr {
+                if {[info exists _attr2def($name)]} {
+                    error "attribute \"$name\" already defined"
+                }
+                set obj [Rappture::objects::ObjAttr #auto]
+                if {[catch {eval $obj configure $args} err] != 0} {
+                    itcl::delete object $obj
+                    error $err
+                }
+                lappend _attrs $name
+                set _attr2def($name) $obj
+            }
+            check {
+                set n [incr _checks(num)]
+                set _checks($n-attr) $name
+                set _checks($n-code) [lindex $args 0]
+            }
+        }
+    }
+
+    public method get {{name ""}} {
+        if {"" == $name} {
+            return $_attrs
+        } elseif {[info exists _attr2def($name)]} {
+            set rlist $name
+            foreach opt [$_attr2def($name) configure] {
+                lappend rlist [lindex $opt 0] [lindex $opt 2]
+            }
+            return $rlist
+        }
+    }
+
+    # call this to check the integrity of all values
+    public method check {data debug} {
+        set rlist ""
+        array set attr $data
+        for {set n 1} {$n <= $_checks(num)} {incr n} {
+            set status [catch $_checks($n-code) result]
+            if {$status != 0 && $status != 2} {
+                puts stderr "ERROR DURING VALUE CHECK:\n$result"
+            } elseif {[llength $result] > 0} {
+                set class [lindex $result 0]
+                set mesg [lindex $result 1]
+                set dinfo $debug
+                lappend dinfo -attribute $_checks($n-attr)
+                lappend rlist [list $class $mesg $dinfo]
+            }
+        }
+        return $rlist
+    }
+
+    private variable _attrs ""  ;# list of attr names in order
+    private variable _attr2def  ;# maps attr name => ObjAttr object
+    private variable _checks    ;# bits of code used for checks
+}
+
+# ----------------------------------------------------------------------
+#  CLASS: ObjAttr
+# ----------------------------------------------------------------------
+itcl::class Rappture::objects::ObjAttr {
+    public variable title ""
+    public variable type ""
+    public variable path ""
+    public variable expand "no"
+
+    constructor {args} {
+        eval configure $args
+    }
+}
Index: /trunk/lang/tcl/scripts/objects/base.rp
===================================================================
--- /trunk/lang/tcl/scripts/objects/base.rp	(revision 2080)
+++ /trunk/lang/tcl/scripts/objects/base.rp	(revision 2080)
@@ -0,0 +1,5 @@
+object base {
+    attr label -type string -path about.label
+    attr description -type string:lines=3 -expand yes -path about.description
+    attr enable -title "Enable" -type string:validate=enable -path about.enable
+}
Index: /trunk/lang/tcl/scripts/objects/boolean/boolean.rp
===================================================================
--- /trunk/lang/tcl/scripts/objects/boolean/boolean.rp	(revision 2080)
+++ /trunk/lang/tcl/scripts/objects/boolean/boolean.rp	(revision 2080)
@@ -0,0 +1,19 @@
+object boolean -extends base {
+    palettes "Inputs"
+    help http://rappture.org/wiki/rp_xml_ele_boolean
+    attr default -title "Default Value" -type boolean -path default
+
+    check label {
+        if {[string length [string trim $attr(label)]] == 0} {
+            return [list warning "Should set a label that describes this value."]
+        }
+    }
+    check description {
+        set desc [string trim $attr(description)]
+        if {[string length $desc] == 0} {
+            return [list warning "Should include a description of what this value represents, typical settings, etc."]
+        } elseif {[string equal $desc $attr(label)]} {
+            return [list warning "Description should be different from the label and give additional information about the value."]
+        }
+    }
+}
Index: /trunk/lang/tcl/scripts/objects/curve/curve.rp
===================================================================
--- /trunk/lang/tcl/scripts/objects/curve/curve.rp	(revision 2080)
+++ /trunk/lang/tcl/scripts/objects/curve/curve.rp	(revision 2080)
@@ -0,0 +1,47 @@
+object curve -extends base {
+    palettes "Outputs"
+    help http://rappture.org/wiki/rp_xml_ele_curve
+    attr group -title "Plotting Group" -type string -path about.group
+    attr xlabel -title "X-axis Label" -type string -path xaxis.label
+    attr xdesc  -title "X-axis Description" -type string -path xaxis.description
+    attr xunits -title "X-axis Units" -type units -path xaxis.units
+    attr ylabel -title "Y-axis Label" -type string -path yaxis.label
+    attr ydesc  -title "Y-axis Description" -type string -path yaxis.description
+    attr yunits -title "Y-axis Units" -type units -path yaxis.units
+
+    check label {
+        if {[string length [string trim $attr(label)]] == 0} {
+            return [list warning "Should set a label that describes this value."]
+        }
+    }
+    check description {
+        set desc [string trim $attr(description)]
+        if {[string length $desc] == 0} {
+            return [list warning "Should include a description of what this value represents, typical settings, etc."]
+        } elseif {[string equal $desc $attr(label)]} {
+            return [list warning "Description should be different from the label and give additional information about the value."]
+        }
+    }
+
+    check xlabel {
+        if {[string length [string trim $attr(xlabel)]] == 0} {
+            return [list warning "Should set a label that describes the x-axis of this plot."]
+        }
+    }
+    check xdesc {
+        if {[string length [string trim $attr(xdesc)]] == 0} {
+            return [list warning "Should include a description of what the x-axis represents, physical meaning, expected range, etc."]
+        }
+    }
+
+    check ylabel {
+        if {[string length [string trim $attr(ylabel)]] == 0} {
+            return [list warning "Should set a label that describes the y-axis of this plot."]
+        }
+    }
+    check ydesc {
+        if {[string length [string trim $attr(ydesc)]] == 0} {
+            return [list warning "Should include a description of what the y-axis represents, physical meaning, expected range, etc."]
+        }
+    }
+}
Index: /trunk/lang/tcl/scripts/objects/group/group.rp
===================================================================
--- /trunk/lang/tcl/scripts/objects/group/group.rp	(revision 2080)
+++ /trunk/lang/tcl/scripts/objects/group/group.rp	(revision 2080)
@@ -0,0 +1,5 @@
+object group -extends base {
+    palettes "Grouping"
+    help http://rappture.org/wiki/rp_xml_ele_group
+    terminal no
+}
Index: /trunk/lang/tcl/scripts/objects/histogram/histogram.rp
===================================================================
--- /trunk/lang/tcl/scripts/objects/histogram/histogram.rp	(revision 2080)
+++ /trunk/lang/tcl/scripts/objects/histogram/histogram.rp	(revision 2080)
@@ -0,0 +1,46 @@
+object histogram -extends base {
+    palettes "Outputs"
+    help http://rappture.org/wiki/rp_xml_ele_histogram
+    attr xlabel -title "X-axis Label" -type string -path xaxis.label
+    attr xdesc  -title "X-axis Description" -type string -path xaxis.description
+    attr xunits -title "X-axis Units" -type units -path xaxis.units
+    attr ylabel -title "Y-axis Label" -type string -path yaxis.label
+    attr ydesc  -title "Y-axis Description" -type string -path yaxis.description
+    attr yunits -title "Y-axis Units" -type units -path yaxis.units
+
+    check label {
+        if {[string length [string trim $attr(label)]] == 0} {
+            return [list warning "Should set a label that describes this value."]
+        }
+    }
+    check description {
+        set desc [string trim $attr(description)]
+        if {[string length $desc] == 0} {
+            return [list warning "Should include a description of what this value represents, typical settings, etc."]
+        } elseif {[string equal $desc $attr(label)]} {
+            return [list warning "Description should be different from the label and give additional information about the value."]
+        }
+    }
+
+    check xlabel {
+        if {[string length [string trim $attr(xlabel)]] == 0} {
+            return [list warning "Should set a label that describes the x-axis of this plot."]
+        }
+    }
+    check xdesc {
+        if {[string length [string trim $attr(xdesc)]] == 0} {
+            return [list warning "Should include a description of what the x-axis represents, physical meaning, expected range, etc."]
+        }
+    }
+
+    check ylabel {
+        if {[string length [string trim $attr(ylabel)]] == 0} {
+            return [list warning "Should set a label that describes the y-axis of this plot."]
+        }
+    }
+    check ydesc {
+        if {[string length [string trim $attr(ydesc)]] == 0} {
+            return [list warning "Should include a description of what the y-axis represents, physical meaning, expected range, etc."]
+        }
+    }
+}
Index: /trunk/lang/tcl/scripts/objects/integer/integer.rp
===================================================================
--- /trunk/lang/tcl/scripts/objects/integer/integer.rp	(revision 2080)
+++ /trunk/lang/tcl/scripts/objects/integer/integer.rp	(revision 2080)
@@ -0,0 +1,39 @@
+object integer -extends base {
+    palettes "Inputs"
+    help http://rappture.org/wiki/rp_xml_ele_integer
+    attr default -title "Default Value" -type string:validate=int -path default
+    attr min -title "Minimum Value" -type string:validate=int -path min
+    attr max -title "Maximum Value" -type string:validate=int -path max
+
+    check label {
+        if {[string length [string trim $attr(label)]] == 0} {
+            return [list warning "Should set a label that describes this value."]
+        }
+    }
+    check description {
+        set desc [string trim $attr(description)]
+        if {[string length $desc] == 0} {
+            return [list warning "Should include a description of what this value represents, typical settings, etc."]
+        } elseif {[string equal $desc $attr(label)]} {
+            return [list warning "Description should be different from the label and give additional information about the value."]
+        }
+    }
+
+    check default {
+        if {[string length [string trim $attr(default)]] == 0} {
+            return [list error "Must have a default value for this integer."]
+        }
+        if {"" != $attr(min) && $attr(default) < $attr(min)} {
+            return [list error "Default value is less than the minimum that you've specified for this value."]
+        }
+        if {"" != $attr(max) && $attr(default) > $attr(max)} {
+            return [list error "Default value is greater than the maximum that you've specified for this value."]
+        }
+    }
+
+    check min {
+        if {"" != $attr(min) && "" != $attr(max) && $attr(min) >= $attr(max)} {
+            return [list error "Minimum value should be less than the maximum.  If you don't want to see a min/max range, you can clear out either or both values."]
+        }
+    }
+}
Index: /trunk/lang/tcl/scripts/objects/note/note.rp
===================================================================
--- /trunk/lang/tcl/scripts/objects/note/note.rp	(revision 2080)
+++ /trunk/lang/tcl/scripts/objects/note/note.rp	(revision 2080)
@@ -0,0 +1,13 @@
+object note {
+    palettes "Documentation"
+    help http://rappture.org/wiki/rp_xml_ele_note
+    attr contents -title "HTML File" -type file -path contents
+
+    check contents {
+        set fname [string trim $attr(contents)]
+        if {[string length $fname] == 0
+              || [string equal $fname "select a file"]} {
+            return [list warning "Should set an HTML file with the contents of the note, or else delete the element."]
+        }
+    }
+}
Index: /trunk/lang/tcl/scripts/objects/number/number.rp
===================================================================
--- /trunk/lang/tcl/scripts/objects/number/number.rp	(revision 2080)
+++ /trunk/lang/tcl/scripts/objects/number/number.rp	(revision 2080)
@@ -0,0 +1,78 @@
+object number -extends base {
+    palettes "Inputs"
+    help http://rappture.org/wiki/rp_xml_ele_number
+    attr default -title "Default Value" -type string:validate=number -path default
+    attr units -title "Units of Measurement" -type units -path units
+    attr min -title "Minimum Value" -type string:validate=number -path min
+    attr max -title "Maximum Value" -type string:validate=number -path max
+    attr color -title "Color" -type color -path color
+
+    check label {
+        if {[string length [string trim $attr(label)]] == 0} {
+            return [list warning "Should set a label that describes this value"]
+        }
+    }
+    check description {
+        set desc [string trim $attr(description)]
+        if {[string length $desc] == 0} {
+            return [list warning "Should include a description of what this value represents, typical settings, etc."]
+        } elseif {[string equal $desc $attr(label)]} {
+            return [list warning "Description should be different from the label and give additional information about the value."]
+        }
+    }
+
+    check default {
+        if {[string length [string trim $attr(default)]] == 0} {
+            return [list error "Must have a default value for this number."]
+        }
+        if {"" != $attr(units)} {
+            set base [Rappture::Units::System::for $attr(units)]
+            if {[validate_number_parse $attr(default) num units]
+               && "" != $units
+               && ![string equal [Rappture::Units::System::for $units] $base]} {
+                return [list error "Units for default value don't match the expected units for this value"]
+            }
+
+            set dval [Rappture::Units::convert $attr(default) -context $attr(units) -to $attr(units) -units off]
+
+            if {[validate_number_parse $attr(min) num units]
+                 && [catch {Rappture::Units::convert $attr(min) -context $attr(units) -to $attr(units) -units off} min] == 0
+                 && $dval < $min} {
+                return [list error "Default value is less than the minimum that you've specified for this value."]
+            }
+
+            if {[validate_number_parse $attr(max) num units]
+                 && [catch {Rappture::Units::convert $attr(max) -context $attr(units) -to $attr(units) -units off} max] == 0
+                 && $dval > $max} {
+                return [list error "Default value is greater than the maximum that you've specified for this value."]
+            }
+        }
+    }
+
+    check min {
+        if {"" != $attr(units)} {
+            set base [Rappture::Units::System::for $attr(units)]
+            if {[validate_number_parse $attr(min) num units]
+               && "" != $units
+               && ![string equal [Rappture::Units::System::for $units] $base]} {
+                return [list error "Units for minimum value don't match the expected units for this value"]
+            }
+        }
+        if {[catch {Rappture::Units::convert $attr(min) -context $attr(units) -to $attr(units) -units off} min] == 0
+              && [catch {Rappture::Units::convert $attr(max) -context $attr(units) -to $attr(units) -units off} max] == 0
+              && $min >= $max} {
+            return [list error "Minimum value should be less than the maximum.  If you don't want to see a min/max range, you can clear out either or both values."]
+        }
+    }
+
+    check max {
+        if {"" != $attr(units)} {
+            set base [Rappture::Units::System::for $attr(units)]
+            if {[validate_number_parse $attr(max) num units]
+               && "" != $units
+               && ![string equal [Rappture::Units::System::for $units] $base]} {
+                return [list error "Units for maximum value don't match the expected units for this value"]
+            }
+        }
+    }
+}
Index: /trunk/lang/tcl/scripts/objects/phase/phase.rp
===================================================================
--- /trunk/lang/tcl/scripts/objects/phase/phase.rp	(revision 2080)
+++ /trunk/lang/tcl/scripts/objects/phase/phase.rp	(revision 2080)
@@ -0,0 +1,5 @@
+object phase -extends base {
+    palettes "Grouping"
+    help http://rappture.org/wiki/rp_xml_ele_phase
+    terminal no
+}
Index: /trunk/lang/tcl/scripts/objects/string/string.rp
===================================================================
--- /trunk/lang/tcl/scripts/objects/string/string.rp	(revision 2080)
+++ /trunk/lang/tcl/scripts/objects/string/string.rp	(revision 2080)
@@ -0,0 +1,7 @@
+object string -extends base {
+    palettes "Inputs"
+    help http://rappture.org/wiki/rp_xml_ele_string
+    attr default -title "Default Value" -type string -path default
+    attr size -title "Size" -type string:validate=size -path size
+    attr hints -title "Hint String" -type string -path about.hints
+}
Index: /trunk/lang/tcl/scripts/types/boolean.tcl
===================================================================
--- /trunk/lang/tcl/scripts/types/boolean.tcl	(revision 2080)
+++ /trunk/lang/tcl/scripts/types/boolean.tcl	(revision 2080)
@@ -0,0 +1,74 @@
+# ----------------------------------------------------------------------
+#  EDITOR: boolean attribute values
+#
+#  Used within the Instant Rappture builder to edit boolean values.
+#
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+itcl::class AttrBoolean {
+    constructor {win args} {
+        Rappture::getopts args params {
+        }
+
+        Rappture::Combobox $win.val -width 10 -editable no
+        pack $win.val -side left
+        $win.val choices insert end 1 "True" 0 "False"
+        set _win $win
+    }
+
+    public method check {} {
+        set val [$_win.val translate [$_win.val value]]
+        if {![string is boolean -strict $val]} {
+            return [list error "Bad value \"$val\": should be Boolean"]
+        }
+        return ""
+    }
+
+    public method load {val} {
+        if {![string is boolean -strict $val] || $val} {
+            $_win.val value "True"
+        } else {
+            $_win.val value "False"
+        }
+    }
+
+    public method save {var} {
+        upvar $var value
+        set str [$_win.val translate [$_win.val value]]
+        if {[string is boolean -strict $str] && $str} {
+            set value "yes"
+        } else {
+            set value "no"
+        }
+        return 1
+    }
+
+    public method edit {} {
+        focus $_win.val
+    }
+
+    public proc import {xmlobj path} {
+        set val [$xmlobj get $path]
+        if {[string is boolean -strict $val] && $val} {
+            set val "yes"
+        } else {
+            set val "no"
+        }
+        return $val
+    }
+
+    public proc export {xmlobj path value} {
+        if {$value} {
+            $xmlobj put $path "yes"
+        } else {
+            $xmlobj put $path "no"
+        }
+    }
+
+    private variable _win ""       ;# containing frame
+}
Index: /trunk/lang/tcl/scripts/types/color.tcl
===================================================================
--- /trunk/lang/tcl/scripts/types/color.tcl	(revision 2080)
+++ /trunk/lang/tcl/scripts/types/color.tcl	(revision 2080)
@@ -0,0 +1,97 @@
+# ----------------------------------------------------------------------
+#  EDITOR: color attribute values
+#
+#  Used within the Instant Rappture builder to edit color values.
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+itcl::class AttrColor {
+    constructor {win args} {
+        Rappture::getopts args params {
+        }
+        set _icon [image create photo -width 20 -height 20]
+
+        label $win.sample -image $_icon
+        pack $win.sample -side left
+        button $win.change -text "Choose..." -command [itcl::code $this choose]
+        pack $win.change -side left
+        _redraw ""
+
+        set _win $win
+    }
+    destructor {
+        image delete $_icon
+    }
+
+    public method load {val} {
+        _redraw $val
+    }
+
+    public method check {} {
+        if {"" != $_color && [catch {winfo rgb . $_color} err]} {
+            return [list error "Bad value \"$_color\": should be color name or #RRGGBB"]
+        }
+    }
+
+    public method save {var} {
+        upvar $var value
+
+        set err [lindex [check] 1]
+        if {[string length $err] > 0} {
+            Rappture::Tooltip::cue $_win $err
+            return 0
+        }
+
+        set value $_color
+        return 1
+    }
+
+    public method edit {} {
+        focus $_win.change
+    }
+
+    public proc import {xmlobj path} {
+        # trivial import -- just return info as-is from XML
+        return [$xmlobj get $path]
+    }
+
+    public proc export {xmlobj path value} {
+        # trivial export -- just save info as-is into XML
+        if {[string length $value] > 0} {
+            $xmlobj put $path $value
+        }
+    }
+
+    public method choose {} {
+        if {"" != $_color} {
+            _redraw [tk_chooseColor -title "iRappture: Choose Color" -initialcolor $_color]
+        } else {
+            _redraw [tk_chooseColor -title "iRappture: Choose Color"]
+        }
+    }
+
+    private method _redraw {color} {
+        set _color $color
+        set w [image width $_icon]
+        set h [image width $_icon]
+        $_icon put white -to 0 0 $w $h
+        $_icon put black -to 0 0 $w 1
+        $_icon put black -to 0 0 1 $h
+        $_icon put black -to [expr {$w-1}] 0 $w $h
+        $_icon put black -to 0 [expr {$h-1}] $w $h
+
+        if {"" != $color} {
+            $_icon put $color -to 4 4 [expr {$w-4}] [expr {$h-4}]
+        } else {
+            $_icon copy [Rappture::icon diag] -to 4 4 [expr {$w-4}] [expr {$h-4}]
+        }
+    }
+
+    private variable _win ""       ;# containing frame
+    private variable _icon ""      ;# image for color sample
+    private variable _color ""     ;# name of color sample
+}
Index: /trunk/lang/tcl/scripts/types/file.tcl
===================================================================
--- /trunk/lang/tcl/scripts/types/file.tcl	(revision 2080)
+++ /trunk/lang/tcl/scripts/types/file.tcl	(revision 2080)
@@ -0,0 +1,117 @@
+# ----------------------------------------------------------------------
+#  EDITOR: file attribute values
+#
+#  Used within the Instant Rappture builder to set file paths.
+#  Rappture tries to avoid files, but it's okay for things like the
+#  <note> element, which points to documentation.
+#
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+itcl::class AttrFile {
+    constructor {win args} {
+        Rappture::getopts args params {
+        }
+        label $win.file -text "select a file" -width 10 -anchor e -fg gray60
+        pack $win.file -side left
+        button $win.getfile -text "Choose..." -command [itcl::code $this _getfile]
+        pack $win.getfile -side left
+
+        set _win $win
+    }
+
+    public method load {val} {
+        if {[string length $val] > 0} {
+            $_win.file configure -text $val -foreground black
+
+            # if the file name is long, then set up to clip and show the tail
+            set w [expr {[winfo width $_win]-[winfo width $_win.getfile]}]
+            set fn [$_win.file cget -font]
+            if {[font measure $fn $val] > $w} {
+                $_win.file configure -width 10
+                pack $_win.file -expand yes -fill x
+            } else {
+                $_win.file configure -width 0
+                pack $_win.file -expand no
+            }
+        }
+    }
+
+    public method check {} {
+        set fname [$_win.file cget -text]
+        if {"" != $fname && ![string equal $fname "select a file"]
+              && ![regexp {^file://(.+)} $fname]} {
+            return [list error "Bad value \"$fname\": should be file://filename"]
+        }
+    }
+
+    public method save {var} {
+        upvar $var value
+
+        set err [lindex [check] 1]
+        if {[string length $err] > 0} {
+            Rappture::Tooltip::cue $_win $err
+            return 0
+        }
+
+        set value [$_win.file cget -text]
+        if {[string equal $value "select a file"]} {
+            set value ""
+        }
+        return 1
+    }
+
+    public method edit {} {
+        focus $_win.getfile
+    }
+
+    public proc import {xmlobj path} {
+        # trivial import -- just return info as-is from XML
+        return [$xmlobj get $path]
+    }
+
+    public proc export {xmlobj path value} {
+        global LastToolXmlFile
+
+        # save a relative path to this file
+        if {[regexp {^file://(.+)} $value match fname]} {
+            if {[file pathtype $fname] == "absolute"} {
+                set dir [file dirname $LastToolXmlFile]
+                if {[string match $dir/* $fname]} {
+                    set len [string length "$dir/"]
+                    set value [string range $fname $len end]
+                } elseif {"" != $LastToolXmlFile} {
+                    error "Can't find file \"$fname\" relative to tool.xml file.  All items for a tool should be bundled together in the same directory, so they can be easily relocated later."
+                }
+            }
+        }
+
+        if {[string length $value] > 0} {
+            $xmlobj put $path $value
+        }
+    }
+
+    protected method _getfile {} {
+        set fname [tk_getOpenFile -title "iRappture: Select HTML File" -defaultextension .html -filetypes { {{HTML files} {.html .htm}} {{All files} *} }]
+        if {"" != $fname} {
+            $_win.file configure -text "file://$fname" -foreground black
+
+            # if the file name is long, then set up to clip and show the tail
+            set w [expr {[winfo width $_win]-[winfo width $_win.getfile]}]
+            set fn [$_win.file cget -font]
+            if {[font measure $fn $fname] > $w} {
+                $_win.file configure -width 10
+                pack $_win.file -expand yes -fill x
+            } else {
+                $_win.file configure -width 0
+                pack $_win.file -expand no
+            }
+        }
+    }
+
+    private variable _win ""       ;# containing frame
+}
Index: /trunk/lang/tcl/scripts/types/string.tcl
===================================================================
--- /trunk/lang/tcl/scripts/types/string.tcl	(revision 2080)
+++ /trunk/lang/tcl/scripts/types/string.tcl	(revision 2080)
@@ -0,0 +1,102 @@
+# ----------------------------------------------------------------------
+#  EDITOR: string attribute values
+#
+#  Used within the Instant Rappture builder to edit string values.
+#  Strings can have the following additional options:
+#
+#    -lines N ......... height of editor (default is 1 line)
+#    -validate type ... validation routine applied to string values
+#
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+itcl::class AttrString {
+    constructor {win args} {
+        Rappture::getopts args params {
+            value -lines 1
+            value -validate ""
+        }
+
+        if {$params(-lines) > 1} {
+            Rappture::Scroller $win.scrl -xscrollmode none -yscrollmode auto
+            pack $win.scrl -expand yes -fill both
+            text $win.scrl.text -width 10 -height $params(-lines) -wrap word
+            $win.scrl contents $win.scrl.text
+        } else {
+            entry $win.str
+            pack $win.str -fill x
+        }
+        set _win $win
+        set _validate $params(-validate)
+    }
+
+    public method load {val} {
+        if {[winfo exists $_win.str]} {
+            $_win.str delete 0 end
+            $_win.str insert end $val
+        } else {
+            $_win.scrl.text delete 1.0 end
+            $_win.scrl.text insert end $val
+        }
+    }
+
+    public method check {} {
+        if {[string length $_validate] > 0} {
+            if {[winfo exists $_win.str]} {
+                set str [$_win.str get]
+            } else {
+                set str [$_win.scrl.text get 1.0 end-1char]
+            }
+            if {[catch {uplevel #0 $_validate [list $str]} result]} {
+                return [list error "Bad value: $result"]
+            }
+        }
+    }
+
+    public method save {var} {
+        upvar $var value
+
+        set err [lindex [check] 1]
+        if {[string length $err] > 0} {
+            Rappture::Tooltip::cue $_win $err
+            return 0
+        }
+
+        if {[winfo exists $_win.str]} {
+            set value [$_win.str get]
+        } else {
+            set value [$_win.scrl.text get 1.0 end-1char]
+        }
+        return 1
+    }
+
+    public method edit {} {
+        if {[winfo exists $_win.str]} {
+            focus $_win.str
+            $_win.str selection from 0
+            $_win.str selection to end
+        } else {
+            focus $_win.scrl.text
+            $_win.scrl.text tag add sel 1.0 end
+        }
+    }
+
+    public proc import {xmlobj path} {
+        # trivial import -- just return info as-is from XML
+        return [$xmlobj get $path]
+    }
+
+    public proc export {xmlobj path value} {
+        # trivial export -- just save info as-is into XML
+        if {[string length $value] > 0} {
+            $xmlobj put $path $value
+        }
+    }
+
+    private variable _win ""       ;# containing frame
+    private variable _validate ""  ;# validation command for checking values
+}
Index: /trunk/lang/tcl/scripts/types/units.tcl
===================================================================
--- /trunk/lang/tcl/scripts/types/units.tcl	(revision 2080)
+++ /trunk/lang/tcl/scripts/types/units.tcl	(revision 2080)
@@ -0,0 +1,119 @@
+# ----------------------------------------------------------------------
+#  EDITOR: units attribute values
+#
+#  Used within the Instant Rappture builder to edit units for numbers.
+#
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+itcl::class AttrUnits {
+    constructor {win args} {
+        Rappture::getopts args params {
+        }
+
+        Rappture::Combobox $win.val -width 10 -editable yes
+        pack $win.val -side left
+        $win.val choices insert end \
+          m   "Length Units" \
+          m   "  m - meters" \
+          in  "  in - inches" \
+          ft  "  ft - feet" \
+          yd  "  yd - yards" \
+          mi  "  mi - miles" \
+          s   "Time Units" \
+          s   "  s - seconds" \
+          min "  min - minutes" \
+          h   "  h - hours" \
+          d   "  d - days" \
+          Hz  "  Hz - Hertz" \
+          K   "Temperature Units" \
+          K   "  K - Kelvin" \
+          F   "  F - Fahrenheit" \
+          C   "  C - Celcius" \
+          eV  "Energy Units" \
+          eV  "  eV - electron Volts" \
+          J   "  J - Joules" \
+          V   "  V - volts" \
+          m3  "Volume Units" \
+          m3  "  cubic meter" \
+          gal "  gal - US gallon" \
+          L   "  L - liter" \
+          deg "Angle Units" \
+          deg "  deg - degrees" \
+          rad "  rad - radians" \
+          g   "Mass Units" \
+          g   "  g - grams" \
+          N   "Force Units" \
+          N   "  N - Newtons" \
+          Pa  "Pressure Units" \
+          Pa  "  Pa - Pascals" \
+          atm "  atm - atmospheres" \
+          pis "  psi - pounds per square inch" \
+          T   "Magnetic Units" \
+          T   "  T - Teslas" \
+          G   "  G - Gauss"
+
+        set _win $win
+    }
+
+    public method check {} {
+        set val [$_win.val translate [$_win.val value]]
+        if {"" != $val} {
+            return ""
+        }
+        set val [$_win.val value]
+        if {"" != [Rappture::Units::description $val]} {
+            return ""
+        }
+        return [list error "Bad value \"$val\": should be valid system of units"]
+    }
+
+    public method load {val} {
+        set newval [$_win.val translate $val]
+        if {"" != $newval} {
+            $_win.val value $newval
+        } else {
+            $_win.val value $val
+        }
+    }
+
+    public method save {var} {
+        upvar $var value
+
+        set err [lindex [check] 1]
+        if {[string length $err] > 0} {
+            Rappture::Tooltip::cue $_win $err
+            return 0
+        }
+
+        set val [$_win.val value]
+        set newval [$_win.val translate $val]
+        if {"" != $newval} {
+            set value $newval
+        } else {
+            set value $val
+        }
+        return 1
+    }
+
+    public method edit {} {
+        focus $_win.val
+        $_win.val component entry selection from 0
+        $_win.val component entry selection to end
+    }
+
+    public proc import {xmlobj path} {
+        set val [$xmlobj get $path]
+        return $val
+    }
+
+    public proc export {xmlobj path value} {
+        $xmlobj put $path $value
+    }
+
+    private variable _win ""       ;# containing frame
+}
Index: /trunk/lang/tcl/scripts/validations/enable.tcl
===================================================================
--- /trunk/lang/tcl/scripts/validations/enable.tcl	(revision 2080)
+++ /trunk/lang/tcl/scripts/validations/enable.tcl	(revision 2080)
@@ -0,0 +1,17 @@
+# ----------------------------------------------------------------------
+#  VALIDATION: enable
+#
+#  Handles the type:validate=enable setting for an object attribute.
+#  Checks the given string to see if it is a valid Rappture <enable>
+#  settings.  Returns an error if something is wrong.
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+proc validate_enable {str} {
+    # punt for now
+    return "ok"
+}
Index: /trunk/lang/tcl/scripts/validations/int.tcl
===================================================================
--- /trunk/lang/tcl/scripts/validations/int.tcl	(revision 2080)
+++ /trunk/lang/tcl/scripts/validations/int.tcl	(revision 2080)
@@ -0,0 +1,18 @@
+# ----------------------------------------------------------------------
+#  VALIDATION: int
+#
+#  Handles the string:validate=int setting for an object attribute.
+#  Checks the given string to see if it is an integer value.  Returns
+#  an error if something is wrong.
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+proc validate_int {str} {
+    if {![string is integer $str]} {
+        error "bad value \"$str\": should be an integer"
+    }
+}
Index: /trunk/lang/tcl/scripts/validations/number.tcl
===================================================================
--- /trunk/lang/tcl/scripts/validations/number.tcl	(revision 2080)
+++ /trunk/lang/tcl/scripts/validations/number.tcl	(revision 2080)
@@ -0,0 +1,31 @@
+# ----------------------------------------------------------------------
+#  VALIDATION: number
+#
+#  Handles the type:validate=number setting for an object attribute.
+#  Checks the given string to see if it is a valid Rappture "number"
+#  value.  Returns an error if something is wrong.
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+proc validate_number_parse {str numvar unitsvar} {
+    upvar $numvar num
+    upvar $unitsvar units
+    return [regexp {^([-+]?(?:[0-9]+\.|\.)?[0-9]+(?:[eE][-+]?[0-9]+)?)( *(?:[a-zA-Z]+[0-9]*)+(?:\/(?:[a-zA-Z]+[0-9]*)+)*)*$} $str match num units]
+}
+
+proc validate_number {str} {
+    if {"" == $str} {
+        # empty string is okay
+        return "ok"
+    } elseif {[validate_number_parse $str num units]} {
+        if {"" != $units && "" == [Rappture::Units::description $units]} {
+            error "units \"$units\" not recognized"
+        }
+        return "ok"
+    }
+    error "should be a real number with units"
+}
Index: /trunk/lang/tcl/scripts/validations/size.tcl
===================================================================
--- /trunk/lang/tcl/scripts/validations/size.tcl	(revision 2080)
+++ /trunk/lang/tcl/scripts/validations/size.tcl	(revision 2080)
@@ -0,0 +1,23 @@
+# ----------------------------------------------------------------------
+#  VALIDATION: size
+#
+#  Handles the string:validate=size setting for an object attribute.
+#  Checks the given string to see if it is a valid size for a <string>
+#  object.  Returns an error if something is wrong.
+# ======================================================================
+#  AUTHOR:  Michael McLennan, Purdue University
+#  Copyright (c) 2004-2010  Purdue Research Foundation
+#
+#  See the file "license.terms" for information on usage and
+#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+# ======================================================================
+proc validate_size {str} {
+    switch -regexp -- $str {
+        ^$ - ^[0-9]+$ - ^[0-9]+x[0-9]+$ - binary {
+            return "ok"
+        }
+        default {
+            error "bad size \"$str\": should be WW or WWxHH or binary"
+        }
+    }
+}
Index: /trunk/p2p/client.tcl
===================================================================
--- /trunk/p2p/client.tcl	(revision 2079)
+++ /trunk/p2p/client.tcl	(revision 2080)
@@ -86,6 +86,4 @@
     public method send {message}
     public method address {}
-
-    protected method handlerType {}
 }
 
@@ -101,5 +99,5 @@
             set _sid ""
         } else {
-            log debug "sending: $message"
+            log debug "outgoing message to [address]: $message"
             puts $_sid $message
         }
@@ -116,13 +114,2 @@
     return $_addr
 }
-
-# ----------------------------------------------------------------------
-#  USAGE: handlerType
-#
-#  Returns a descriptive string describing this handler.  Derived
-#  classes override this method to provide their own string.  Used
-#  for debug messages.
-# ----------------------------------------------------------------------
-itcl::body Client::handlerType {} {
-    return "client"
-}
Index: /trunk/p2p/foreman.tcl
===================================================================
--- /trunk/p2p/foreman.tcl	(revision 2079)
+++ /trunk/p2p/foreman.tcl	(revision 2080)
@@ -119,4 +119,5 @@
 
     if {"" != [statedata authoritycnx]} {
+        [statedata authoritycnx] send "identity foreman"
         [statedata authoritycnx] send "workers"
     } else {
@@ -160,4 +161,5 @@
 
     if {"" != [statedata workercnx]} {
+        [statedata workercnx] send "identity foreman"
         [statedata workercnx] send "solicit -job [expr {rand()}]"
     } else {
Index: /trunk/p2p/handler.tcl
===================================================================
--- /trunk/p2p/handler.tcl	(revision 2079)
+++ /trunk/p2p/handler.tcl	(revision 2080)
@@ -59,5 +59,4 @@
     protected method finalize {protocol}
     protected method dropped {cid}
-    protected method handlerType {}
 }
 
@@ -196,5 +195,5 @@
                 append mesg "exception: $result"
             }
-            log debug "[handlerType] message from [connectionName $cid]: [string trimright $request \n] $mesg"
+            log debug "incoming message from [connectionName $cid]: [string trimright $request \n] $mesg"
         }
     }
@@ -237,13 +236,2 @@
     catch {unset _cname($cid)}
 }
-
-# ----------------------------------------------------------------------
-#  USAGE: handlerType
-#
-#  Returns a descriptive string describing this handler.  Derived
-#  classes override this method to provide their own string.  Used
-#  for debug messages.
-# ----------------------------------------------------------------------
-itcl::body Handler::handlerType {} {
-    return "handler"
-}
Index: /trunk/p2p/protocols.tcl
===================================================================
--- /trunk/p2p/protocols.tcl	(revision 2079)
+++ /trunk/p2p/protocols.tcl	(revision 2080)
@@ -81,5 +81,13 @@
             $obj protocol $name
             $obj define $name exception {message} {
-                log error "ERROR from client:  $message"
+                variable cid
+                variable handler
+                log error "ERROR from client [$handler connectionName $cid]:  $message"
+            }
+            $obj define $name identity {name} {
+                variable cid
+                variable handler
+                $handler connectionName $cid $name
+                return ""
             }
 
Index: /trunk/p2p/server.tcl
===================================================================
--- /trunk/p2p/server.tcl	(revision 2079)
+++ /trunk/p2p/server.tcl	(revision 2080)
@@ -106,6 +106,4 @@
 
     protected method dropped {cid}
-    protected method handlerType {}
-
     private method accept {cid addr port}
 }
@@ -235,13 +233,2 @@
     chain $cid
 }
-
-# ----------------------------------------------------------------------
-#  USAGE: handlerType
-#
-#  Returns a descriptive string describing this handler.  Derived
-#  classes override this method to provide their own string.  Used
-#  for debug messages.
-# ----------------------------------------------------------------------
-itcl::body Server::handlerType {} {
-    return "server"
-}
Index: /trunk/p2p/test.tcl
===================================================================
--- /trunk/p2p/test.tcl	(revision 2079)
+++ /trunk/p2p/test.tcl	(revision 2080)
@@ -142,5 +142,13 @@
     # ------------------------------------------------------------------
     public proc draw {canvas time} {
+        global times
         if {[info exists _shapesOnCanvas($canvas)]} {
+            set y0 5
+            if {[info exists times($time)]} {
+                $canvas create text 5 $y0 -anchor nw -text $times($time)
+                incr y0 15
+            }
+            $canvas create text 5 $y0 -anchor nw -tags entity
+
             foreach obj $_shapesOnCanvas($canvas) {
                 if {[$obj exists $time]} {
@@ -222,4 +230,8 @@
 pack .player.fwd -side left -padx 4 -pady 2
 
+button .player.err -text "0 errors" -command {wm deiconify .errors; raise .errors}
+pack .player.err -side right -padx 4 -pady 2
+.player.err configure -state disabled
+
 scale .player.scale -label "Frame" -orient horizontal \
     -from 0 -to 1 -showvalue 0 -command {test_frame_go 1}
@@ -242,4 +254,15 @@
 after idle .view.traffic invoke
 
+toplevel .errors
+wm title .errors "Error Messages"
+wm withdraw .errors
+wm protocol .errors WM_DELETE_WINDOW {wm withdraw .errors}
+scrollbar .errors.ysbar -orient vertical -command {.errors.info yview}
+pack .errors.ysbar -side right -fill y
+text .errors.info -yscrollcommand {.errors.ysbar set} -font {Courier 12}
+pack .errors.info -expand yes -fill both
+.errors.info tag configure timecode -foreground gray
+.errors.info tag configure error -foreground red -font {Courier 12 bold}
+
 proc test_stop {} {
     global processes
@@ -279,14 +302,18 @@
 
 proc test_reload {} {
-    global time0 nodes actions nodeRadius
+    global time0 nodes actions times nodeRadius
 
     array set colors {
         authority blue
         worker gray
+        foreman red
     }
 
     Shape::clear .diagram.network
     Shape::clear .diagram.traffic
+    .errors.info configure -state normal
+    .errors.info delete 1.0 end
     set tmax 0
+    set errs 0
 
     #
@@ -298,26 +325,42 @@
         close $fid
 
-        if {[regexp -- {foreman<-} $info]} {
-            # skip log file from foreman
+        set lasttime ""
+        set t0val ""; set first ""
+        set t1val ""; set last ""
+        set info [split $info \n]
+        foreach line $info {
+            if {[regexp {^([0-9]+/[0-9]+/[0-9]+ [0-9]+:[0-9]+:[0-9]+)} $line match tval]} {
+                if {"" == $t0val} {
+                    set first $line
+                    set t0val [expr {([clock scan $tval]-$time0)*100}]
+                } else {
+                    set last $line
+                    set t1val [expr {([clock scan $tval]-$time0)*100 + 99}]
+                }
+            }
+        }
+
+        if {"" == $t0val || "" == $t1val} {
+            # can't find any log statements -- skip this file!
             continue
         }
 
         # get the address for this host
-        regexp {started at port ([0-9]+)} $info match port
-        if {[regexp {options [^\n]+ ip ([^ ]+)} $info match ip]} {
-            set addr $ip:$port
+        if {[regexp {started at port ([0-9]+)} $info match port]} {
+            if {[regexp {options [^\n]+ ip ([^ ]+)} $info match ip]} {
+                set addr $ip:$port
+            } else {
+                set addr 127.0.0.1:$port
+            }
+            set shape oval
+            regexp {^([0-9]+/[0-9]+/[0-9]+ [0-9]+:[0-9]+:[0-9]+) +(authority|worker)} $first match t0 type
+        } elseif {[regexp -- {foreman<-} $info]} {
+            set shape rectangle
+            set addr "foreman"
+            set type "foreman"
         } else {
-            set addr 127.0.0.1:$port
-        }
-
-        set lasttime ""
-        set info [split $info \n]
-        set first [lindex $info 0]
-        regexp {^([0-9]+/[0-9]+/[0-9]+ [0-9]+:[0-9]+:[0-9]+) +(authority|worker)} $first match t0 type
-        set t0val [expr {([clock scan $t0]-$time0)*100}]
-
-        set last [lindex $info end-1]
-        regexp {^([0-9]+/[0-9]+/[0-9]+ [0-9]+:[0-9]+:[0-9]+)} $last match t1
-        set t1val [expr {([clock scan $t1]-$time0)*100 + 99}]
+            # unknown log file -- skip it
+            continue
+        }
         set margin 20
         set r $nodeRadius
@@ -337,5 +380,5 @@
         foreach canv {.diagram.traffic .diagram.network} {
             set s [Shape ::#auto $canv -command \
-                [list %c create oval [expr {$x-$r}] [expr {$y-$r}] \
+                [list %c create $shape [expr {$x-$r}] [expr {$y-$r}] \
                 [expr {$x+$r}] [expr {$y+$r}] \
                 -outline black -fill $colors($type) \
@@ -359,9 +402,4 @@
 puts "\nscanning $fname"
 
-        if {[regexp -- {foreman<-} $info]} {
-            # skip log file from foreman
-            continue
-        }
-
         catch {unset started}
         set peerlist(addrs) ""
@@ -380,4 +418,5 @@
                 if {$tval > $tmax} { set tmax $tval }
 
+                set cid ""
                 if {[regexp {accepted: +([^ ]+) +\((.+)\)} $mesg match addr cid]} {
                     append actions($tval) $mesg \n
@@ -386,4 +425,5 @@
 
                 } elseif {[regexp {dropped: +([^ ]+) +\((.+)\)} $mesg match addr cid] && [info exists started(connect$cid-time)]} {
+                    incr tval 99  ;# end of this second
                     append actions($tval) $mesg \n
                     set from $nodes($fname)
@@ -399,40 +439,51 @@
                     unset started(connect$cid-addr)
 
-                } elseif {[regexp {(server|client) message from ([a-zA-Z0-9\.]+:[0-9]+) \(([a-z0-9]+)\): +(.+) => (.*)} $mesg match which addr cid cmd result]} {
-                    if {![string match identity* $cmd]} {
-                        append actions($tval) $mesg \n
-                        set from $nodes($fname)
-                        set x0 $nodes($from-x)
-                        set y0 $nodes($from-y)
-                        set x1 $nodes($addr-x)
-                        set y1 $nodes($addr-y)
-                        set w [expr {[winfo width .diagram]/2}]
-
-                        set s [Shape ::#auto .diagram.traffic -command \
-                            [list %c create line [expr $x0-3] [expr $y0-3] [expr $x1-3] [expr $y1-3] -fill black -arrow first -tags transient]]
-                        $s addRange $tval $tval
-
-                        set s [Shape ::#auto .diagram.traffic -command \
-                            [list %c create text [expr {0.5*($x0+$x1)}] [expr {0.5*($y0+$y1)-1}] -width $w -fill black -anchor s -text $cmd -tags transient]]
-                        $s addRange $tval $tval
-
-                        if {"" != [string trim $result]} {
-                            if {[regexp {^ok:} $result]} {
-                                set color black
-                            } else {
-                                set color red
-                            }
-                            set s [Shape ::#auto .diagram.traffic -command \
-                                [list %c create line [expr $x0+3] [expr $y0+3] [expr $x1+3] [expr $y1+3] -fill $color -arrow last -tags transient]]
-                            $s addRange $tval $tval
-
-                            set s [Shape ::#auto .diagram.traffic -command \
-                                [list %c create text [expr {0.5*($x0+$x1)}] [expr {0.5*($y0+$y1)+1}] -width $w -fill $color -anchor n -text $result -tags transient]]
-                            $s addRange $tval $tval
+                } elseif {[regexp {(incoming) message from ([^ ]+) \((sock[0-9]+)\): +(.+) => (.*)} $mesg match which addr cid cmd result]
+                       || [regexp {(outgoing) message to ([^ ]+): +(.+)} $mesg match which addr cmd]} {
+                    switch -- $which {
+                        outgoing {
+                            set from $addr
+                            set to $nodes($fname)
+                        }
+                        incoming {
+                            set from $nodes($fname)
+                            set to $addr
+                            # show incoming messages later in time
+                            incr tval 50
                         }
                     }
+                    append actions($tval) $mesg \n
+                    set x0 $nodes($from-x)
+                    set y0 $nodes($from-y)
+                    set x1 $nodes($to-x)
+                    set y1 $nodes($to-y)
+                    set w [expr {[winfo width .diagram]/2}]
+
+                    set s [Shape ::#auto .diagram.traffic -command \
+                        [list %c create line [expr $x0-3] [expr $y0-3] [expr $x1-3] [expr $y1-3] -fill black -arrow first -tags transient]]
+                    $s addRange $tval $tval
+
+                    set s [Shape ::#auto .diagram.traffic -command \
+                        [list %c create text [expr {0.5*($x0+$x1)}] [expr {0.5*($y0+$y1)-1}] -width $w -fill black -anchor s -text $cmd -tags transient]]
+                    $s addRange $tval $tval
+
+                    if {$which == "incoming" && "" != [string trim $result]} {
+                        if {[regexp {^ok:} $result]} {
+                            set color black
+                        } else {
+                            set color red
+                        }
+                        set s [Shape ::#auto .diagram.traffic -command \
+                            [list %c create line [expr $x0+3] [expr $y0+3] [expr $x1+3] [expr $y1+3] -fill $color -arrow last -tags transient]]
+                        $s addRange $tval $tval
+
+                        set s [Shape ::#auto .diagram.traffic -command \
+                            [list %c create text [expr {0.5*($x0+$x1)}] [expr {0.5*($y0+$y1)+1}] -width $w -fill $color -anchor n -text $result -tags transient]]
+                        $s addRange $tval $tval
+                    }
 
                     # no address for this client yet?  then save this info
-                    if {[info exists started(connect$cid-addr)]
+                    if {"" != $cid
+                           && [info exists started(connect$cid-addr)]
                            && $started(connect$cid-addr) == "?"} {
                         set started(connect$cid-addr) $addr
@@ -466,5 +517,9 @@
                     set peerlist(addrs) $plist
                     set peerlist(time) $tval
+                } elseif {[regexp {ERROR} $mesg match addr]} {
+                    .errors.info insert end $time timecode $mesg error "\n"
+                    incr errs
                 }
+                set times($tval) $time
             }
         }
@@ -497,4 +552,5 @@
             %W itemconfigure $fname-cnx -fill red
             %W raise $fname-cnx
+            %W itemconfigure entity -text {$nodes($fname)}
         "
         .diagram.traffic bind $fname <Leave> "
@@ -502,4 +558,5 @@
             %W itemconfigure $fname-cnx -fill gray
             %W raise transient
+            %W itemconfigure entity -text {}
         "
 
@@ -537,4 +594,11 @@
     }
     .player.scale configure -to $tmax
+    .errors.info configure -state disabled
+    if {$errs == 0} {
+        .player.err configure -state normal -text "0 errors"
+        .player.err configure -state disabled
+    } else {
+        .player.err configure -state normal -text "$errs error[expr {($errs == 1) ? {} : {s}}]"
+    }
 
     after cancel test_visualize
@@ -565,5 +629,5 @@
 
 proc test_frame_go {dir position} {
-    global actions
+    global actions times
 
     set tmax [.player.scale cget -to]
Index: /trunk/p2p/worker.tcl
===================================================================
--- /trunk/p2p/worker.tcl	(revision 2079)
+++ /trunk/p2p/worker.tcl	(revision 2080)
@@ -118,5 +118,4 @@
     # ------------------------------------------------------------------
     define solicit {args} {
-log debug "SOLICIT from foreman: $args"
         variable cid
         log debug "solicitation request from foreman: $args"
@@ -161,5 +160,4 @@
     # ------------------------------------------------------------------
     define solicit {args} {
-log debug "SOLICIT from peer: $args"
         variable cid
         log debug "solicitation request from peer: $args"
@@ -177,5 +175,4 @@
     # ------------------------------------------------------------------
     define proffer {token details} {
-log debug "PROFFER from peer: $token $details"
         Solicitation::proffer $token $details
         return ""
@@ -226,5 +223,4 @@
     # ------------------------------------------------------------------
     define solicit {args} {
-log debug "SOLICIT from peer: $args"
         variable cid
         log debug "solicitation request from peer: $args"
@@ -242,5 +238,4 @@
     # ------------------------------------------------------------------
     define proffer {token details} {
-log debug "PROFFER from peer: $token $details"
         Solicitation::proffer $token $details
         return ""
@@ -636,5 +631,4 @@
             set mesg [list solicit -job $job -path $path -avoid "$avoid @RECIPIENTS" -token $_serial]
             set _waitfor [broadcast_to_peers $mesg $avoid]
-log debug "WAIT FOR: $_waitfor"
 
             if {$_waitfor > 0} {
@@ -643,5 +637,4 @@
             }
         }
-log debug "TIMEOUT: $delay"
         set _timeout [after $delay [itcl::code $this finalize]]
     }
@@ -656,5 +649,4 @@
         append _response $details "\n"
         if {[incr _waitfor -1] <= 0} {
-log debug "ALL RESPONSES"
             finalize
         }
@@ -676,5 +668,4 @@
         # add details about this client to the message
         append block "$myaddress -job $job -cost 1 -wonks [p2p::wonks::current]"
-log debug "FINALIZE {$block}"
 
         # send the composite results back to the caller
Index: /trunk/tester/pkgIndex.tcl.in
===================================================================
--- /trunk/tester/pkgIndex.tcl.in	(revision 2080)
+++ /trunk/tester/pkgIndex.tcl.in	(revision 2080)
@@ -0,0 +1,12 @@
+
+package ifneeded RapptureTester @PACKAGE_VERSION@ [format {
+    set dir [file normalize "%s"]
+    set version @PACKAGE_VERSION@
+    lappend auto_path [file join $dir scripts]
+    namespace eval RapptureTester {
+	variable version $version
+	variable library $dir
+    }
+    package provide RapptureTester $version
+} $dir]
+
Index: /trunk/tester/test.tcl
===================================================================
--- /trunk/tester/test.tcl	(revision 2079)
+++ /trunk/tester/test.tcl	(revision 2080)
@@ -24,4 +24,5 @@
     public method getResult {}
     public method getTestInfo {path}
+    public method getDiffs {}
 
     public method run {args}
@@ -32,25 +33,24 @@
     private variable _testobj ""  ;# Rappture::Library object for _testxml
 
-    private variable _added ""
-    private variable _diffs ""
-    private variable _missing ""
-    private variable _result "?"
-    private variable _runobj ""
+    private variable _result "?"  ;# current status of this test
+    private variable _runobj ""   ;# results from last run
+    private variable _diffs ""    ;# diffs with respect to _runobj
 
     # don't need this?
-    public method getAdded {}
-    public method getDiffs {}
-    public method getInputs {{path input}}
-    public method getMissing {}
-    public method getOutputs {{path output}}
     public method getRunobj {}
-    public method getTestobj {}
-
+
+    private method _setWaiting {{newval ""}}
     private method _setResult {name}
-    private method added {lib1 lib2 {path output}}
-    private method compareElements {lib1 lib2 path}
-    private method diffs {lib1 lib2 {path output}}
-    private method merge {toolobj golden driver {path input}}
-    private method missing {lib1 lib2 {path output}}
+    private method _computeDiffs {obj1 obj2 args}
+    private method _getStructure {xmlobj path}
+
+    # use this to add tests to the "run" queue
+    public proc queue {op args}
+
+    private common _queue       ;# queue of objects waiting to run
+    set _queue(tests) ""        ;# list of tests in the queue
+    set _queue(pending) ""      ;# after event for "next" call
+    set _queue(running) ""      ;# test object currently running
+    set _queue(outputcmd) ""    ;# callback for reporting output
 }
 
@@ -118,7 +118,9 @@
         itcl::delete object $_runobj
         set _runobj ""
+        set _diffs ""
     }
 
     # copy inputs from the test into the run file
+    $_toolobj reset
     foreach path [Rappture::entities -as path $_testobj input] {
         if {[$_testobj element -as type $path.current] ne ""} {
@@ -130,20 +132,36 @@
     # run the test case...
     _setResult "Running"
-    foreach {status _runobj} [eval $_toolobj run $args] break
-
-    if {$status == 0 && [Rappture::library isvalid $_runobj]} {
-        # HACK: Add a new input to differentiate between results
-        $_runobj put input.TestRun.current "Test result"
-        set _diffs [diffs $_testobj $_runobj]
-        set _missing [missing $_testobj $_runobj]
-        set _added [added $_testobj $_runobj]
-        if {$_diffs == "" && $_missing == "" && $_added == ""} {
-            _setResult "Pass"
+    foreach {status result} [eval $_toolobj run $args] break
+
+    if {$status == 0} {
+        if {$result eq "ABORT"} {
+            _setResult "?"
+            return "aborted"
+        } elseif {[Rappture::library isvalid $result]} {
+            set _runobj $result
+            set _diffs [_computeDiffs $_testobj $_runobj -section output]
+puts "DIFFS:"
+foreach {op path what v1 v2} $_diffs {
+puts "  $op $path ($what) $v1 $v2"
+}
+
+            # HACK: Add a new input to differentiate between results
+            $_runobj put input.TestRun.current "Test result"
+
+            # any differences from expected result mean test failed
+            if {[llength $_diffs] == 0} {
+                _setResult "Pass"
+            } else {
+                _setResult "Fail"
+            }
+            return "finished"
         } else {
             _setResult "Fail"
+            return "failed: $result"
         }
     } else {
-        set _runobj ""
-        set _setResult "Error"
+        _setResult "Fail"
+        tk_messageBox -icon error -message "Tool failed: $result"
+        return "finished"
     }
 }
@@ -160,30 +178,20 @@
 itcl::body Rappture::Tester::Test::regoldenize {} {
     if {$_runobj eq ""} {
-        error "Test has not yet been run."
+        error "no test result to goldenize"
     }
     $_runobj put test.label [$_testobj get test.label]
     $_runobj put test.description [$_testobj get test.description]
+
     set fid [open $_testxml w]
     puts $fid "<?xml version=\"1.0\"?>"
     puts $fid [$_runobj xml]
     close $fid
+
+    itcl::delete object $_testobj
     set _testobj $_runobj
+
+    set _runobj ""
     set _diffs ""
-    set _added ""
-    set _missing ""
     _setResult Pass
-}
-
-# ----------------------------------------------------------------------
-# USAGE: getAdded
-#
-# Return a list of paths that have been added that do not exist in the
-# golden results.  Throws an error if the test has not been ran.
-# ----------------------------------------------------------------------
-itcl::body Rappture::Tester::Test::getAdded {} {
-    if {$_runobj eq ""} {
-        error "Test has not yet been run."
-    }
-    return $_added
 }
 
@@ -196,86 +204,5 @@
 # ----------------------------------------------------------------------
 itcl::body Rappture::Tester::Test::getDiffs {} {
-    return [list \
-        input.number(temperature) label \
-        output.curve(f12) units \
-        output.curve(f12) result]
-}
-
-# -----------------------------------------------------------------------
-# USAGE: getInputs
-#
-# Returns a list of key value pairs for all inputs given in the test xml.
-# Each key is the path to the input element, and each key is its current
-# value. 
-# -----------------------------------------------------------------------
-itcl::body Rappture::Tester::Test::getInputs {{path input}} {
-    set retval [list]
-    foreach child [$_testobj children $path] {
-        set fullpath $path.$child
-        if {$fullpath != "input.TestRun"} {
-            set val [$_testobj get $fullpath.current]
-            if {$val != ""} {
-                lappend retval $fullpath $val
-            }
-        }
-        append retval [getInputs $fullpath]
-    }
-    return $retval
-}
-
-# ----------------------------------------------------------------------
-# USAGE: getMissing
-#
-# Return a list of paths that are present in the golden results, but are
-# missing in the new test results.  Throws an error if the test has not
-# been ran.
-# ----------------------------------------------------------------------
-itcl::body Rappture::Tester::Test::getMissing {} {
-    if {$_runobj eq ""} {
-        error "Test has not yet been run."
-    }
-    return $_missing
-}
-
-# ----------------------------------------------------------------------
-# USAGE: getOutputs
-#
-# Returns a list of key value pairs for all outputs in the runfile
-# generated by the last run of the test.  Each key is the path to the
-# element, and each value is its status (ok, diff, added, or missing).
-# Throws an error if the test has not been run.
-# ----------------------------------------------------------------------
-itcl::body Rappture::Tester::Test::getOutputs {{path output}} {
-    if {$_runobj eq ""} {
-        error "Test has not yet been run."
-    }
-    set retval [list]
-    foreach child [$_runobj children $path] {
-        set fullpath $path.$child
-        if {$fullpath != "output.time" && $fullpath != "output.user" \
-            && $fullpath != "output.status"} {
-            if {[lsearch $fullpath [getDiffs]] != -1} {
-                set status diff
-            } elseif {[lsearch $fullpath [getAdded]] != -1} {
-                set status added
-            } else {
-                if {[$_runobj get $fullpath] != ""} {
-                    set status ok
-                } else {
-                    set status ""
-                }
-            }
-            lappend retval $fullpath $status
-        }
-        append retval " [getOutputs $fullpath]"
-    }
-    # We won't find missing elements by searching through runobj.  Instead,
-    # tack on all missing items at the end (only do this once)
-    if {$path == "output"} {
-        foreach item $_missing {
-            lappend retval $item missing
-        }
-    }
-    return $retval
+    return $_diffs
 }
 
@@ -294,123 +221,4 @@
 
 # ----------------------------------------------------------------------
-# USAGE: getTestobj
-# 
-# Returns the test library object containing the set of golden results.
-# ----------------------------------------------------------------------
-itcl::body Rappture::Tester::Test::getTestobj {} {
-    return $_testobj
-}
-
-# ----------------------------------------------------------------------
-# USAGE: added lib1 lib2 ?path?
-#
-# Compares two library objects and returns a list of paths that have
-# been added in the second library and do not exist in the first.
-# Return value will contain all differences that occur as descendants of
-# an optional starting path.  If the path argument is not given, then 
-# only the output sections will be compared.
-# ----------------------------------------------------------------------
-itcl::body Rappture::Tester::Test::added {lib1 lib2 {path output}} {
-    set paths [list]
-    foreach child [$lib2 children $path] {
-        foreach p [added $lib1 $lib2 $path.$child] {
-            lappend paths $p
-        }
-    }
-    if {[$lib1 get $path] == "" && [$lib2 get $path] != ""} {
-        lappend paths $path
-    }
-    return $paths
-}
-
-# ----------------------------------------------------------------------
-# USAGE: compareElements <lib1> <lib2> <path>
-#
-# Compare data found in two library objects at the given path.  Returns
-# 1 if match, 0 if no match.  For now, just check if ascii identical.
-# Later, we can do something more sophisticated for different types of 
-# elements.
-# ----------------------------------------------------------------------
-itcl::body Rappture::Tester::Test::compareElements {lib1 lib2 path} {
-    set val1 [$lib1 get $path]
-    set val2 [$lib2 get $path]
-    return [expr {$val1} != {$val2}]
-}
-
-# ----------------------------------------------------------------------
-# USAGE: diffs <lib1> <lib2> ?path?
-#
-# Compares two library objects and returns a list of paths that do not
-# match.  Only paths which exist in both libraries are considered.
-# Return value will contain all differences that occur as descendants of
-# an optional starting path.  If the path argument is not given, then 
-# only the output sections will be compared.
-# ----------------------------------------------------------------------
-itcl::body Rappture::Tester::Test::diffs {lib1 lib2 {path output}} {
-    set paths [list]
-    set clist1 [$lib1 children $path]
-    set clist2 [$lib2 children $path]
-    foreach child $clist1 {
-        # Ignore if not present in both libraries
-        if {[lsearch -exact $clist2 $child] != -1} {
-            foreach p [diffs $lib1 $lib2 $path.$child] {
-                lappend paths $p
-            }
-        }
-    }
-    if {[compareElements $lib1 $lib2 $path]} {
-        # Ignore output.time and output.user
-        if {$path != "output.time" && $path != "output.user"} {
-            lappend paths $path
-        }
-    }
-    return $paths
-}
-
-# ----------------------------------------------------------------------
-# USAGE: merge <toolobj> <golden> <driver> ?path?
-#
-# Used to recursively build up a driver library object for running a
-# test.  Should not be called directly - see makeDriver.
-# ----------------------------------------------------------------------
-itcl::body Rappture::Tester::Test::merge {toolobj golden driver {path input}} {
-    foreach child [$toolobj children $path] {
-        set val [$golden get $path.$child.current]
-        if {$val != ""} {
-            $driver put $path.$child.current $val
-        } else {
-            set def [$toolobj get $path.$child.default]
-            if {$def != ""} {
-                $driver put $path.$child.current $def
-            }
-        }
-        merge $toolobj $golden $driver $path.$child
-    }
-    return $driver
-}
-
-# ----------------------------------------------------------------------
-# USAGE: added lib1 lib2 ?path?
-#
-# Compares two library objects and returns a list of paths that do not
-# exist in the first library and have been added in the second.
-# Return value will contain all differences that occur as descendants of
-# an optional starting path.  If the path argument is not given, then 
-# only the output sections will be compared.
-# ----------------------------------------------------------------------
-itcl::body Rappture::Tester::Test::missing {lib1 lib2 {path output}} {
-    set paths [list]
-    foreach child [$lib1 children $path] {
-        foreach p [missing $lib1 $lib2 $path.$child] {
-            lappend paths $p
-        }
-    }
-    if {[$lib1 get $path] != "" && [$lib2 get $path] == ""} {
-        lappend paths $path
-    }
-    return $paths
-}
-
-# ----------------------------------------------------------------------
 # USAGE: _setResult ?|Pass|Fail|Waiting|Running
 #
@@ -420,9 +228,283 @@
 # ----------------------------------------------------------------------
 itcl::body Rappture::Tester::Test::_setResult {name} {
-puts "CHANGED: $this => $name"
     set _result $name
     if {[string length $notifycommand] > 0} {
-puts "  notified $notifycommand"
         uplevel #0 $notifycommand $this
     }
 }
+
+# ----------------------------------------------------------------------
+# USAGE: _setWaiting ?boolean?
+#
+# Used to mark a Test as "waiting".  This usually happens when a test
+# is added to the queue, about to be run.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Tester::Test::_setWaiting {{newval ""}} {
+    if {$newval ne "" && [string is boolean $newval]} {
+        if {$newval} {
+            _setResult "Waiting"
+        } else {
+            _setResult "?"
+        }
+    }
+    return $_result
+}
+
+# ----------------------------------------------------------------------
+# USAGE: _computeDiffs <xmlObj1> <xmlObj2> ?-section xxx? \
+#            ?-what value|structure|all?
+#
+# Used internally to compute differences between two different XML
+# objects.  This is normally used to look for differences in the
+# output section between a test case and a new run, but can also
+# be used to look for differences in other sections via the -section
+# flag.
+#
+# Returns a list of the following form:
+#     <op> <path> <what> <val1> <val2>
+#
+#       where <op> is one of:
+#         - ...... element is missing from <xmlObj2>
+#         c ...... element changed between <xmlObj1> and <xmlObj2>
+#         + ...... element is missing from <xmlObj1>
+#
+#       and <what> is something like:
+#         value .............. difference affects "current" value 
+#         structure <path> ... affects structure of parent at <path>
+# ----------------------------------------------------------------------
+itcl::body Rappture::Tester::Test::_computeDiffs {obj1 obj2 args} {
+    Rappture::getopts args params {
+        value -section output
+        value -what all
+    }
+    if {$params(-what) == "all"} {
+        set params(-what) "structure value"
+    }
+
+    # query the values for all entities in both objects
+    set v1paths [Rappture::entities $obj1 $params(-section)]
+    set v2paths [Rappture::entities $obj2 $params(-section)]
+
+    # scan through values for obj1 and compare against obj2
+    set rlist ""
+    foreach path $v1paths {
+puts "checking $path"
+        set i [lsearch -exact $v2paths $path]
+        if {$i < 0} {
+puts "  missing from $obj2"
+            # missing from obj2
+            foreach {raw norm} [Rappture::LibraryObj::value $obj1 $path] break
+            lappend rlist - $path value $raw ""
+        } else {
+            foreach part $params(-what) {
+                switch -- $part {
+                  value {
+                    foreach {raw1 norm1} \
+                        [Rappture::LibraryObj::value $obj1 $path] break
+                    foreach {raw2 norm2} \
+                        [Rappture::LibraryObj::value $obj2 $path] break
+puts "  checking values $norm1 vs $norm2"
+                    if {![string equal $norm1 $norm2]} {
+puts "  => different!"
+                        # different from obj2
+                        lappend rlist c $path value $raw1 $raw2
+                    }
+                    # handled this comparison
+                    set v2paths [lreplace $v2paths $i $i]
+                  }
+                  structure {
+                    set what [list structure $path]
+                    set s1paths [_getStructure $obj1 $path]
+                    set s2paths [_getStructure $obj2 $path]
+                    foreach spath $s1paths {
+puts "  checking internal structure $spath"
+                        set i [lsearch -exact $s2paths $spath]
+                        if {$i < 0} {
+puts "    missing from $obj2"
+                            # missing from obj2
+                            set val1 [$obj1 get $spath]
+                            lappend rlist - $spath $what $val1 ""
+                        } else {
+                            set val1 [$obj1 get $spath]
+                            set val2 [$obj2 get $spath]
+                            if {![string match $val1 $val2]} {
+puts "    different from $obj2 ($val1 vs $val2)"
+                                # different from obj2
+                                lappend rlist c $spath $what $val1 $val2
+                            }
+                            # handled this comparison
+                            set s2paths [lreplace $s2paths $i $i]
+                        }
+                    }
+
+                    # look for leftover values
+                    foreach spath $s2paths {
+                        set val2 [$obj2 get $spath]
+puts "    extra $spath in $obj2"
+                        lappend rlist + $spath $what "" $val2
+                    }
+                  }
+                  default {
+                    error "bad part \"$part\": should be structure, value"
+                  }
+                }
+            }
+        }
+    }
+
+    # add any values left over in the obj2
+    foreach path $v2paths {
+puts "    extra $path in $obj2"
+        foreach {raw2 norm2} [Rappture::LibraryObj::value $obj2 $path] break
+        lappend rlist + $path value "" $raw2
+    }
+    return $rlist
+}
+
+# ----------------------------------------------------------------------
+# USAGE: _getStructure <xmlObj> <path>
+#
+# Used internally by _computeDiffs to get a list of paths for important
+# parts of the internal structure of an object.  Avoids the "current"
+# element, but includes "default", "units", etc.
+# ----------------------------------------------------------------------
+itcl::body Rappture::Tester::Test::_getStructure {xmlobj path} {
+    set rlist ""
+    set queue $path
+    while {[llength $queue] > 0} {
+        set qpath [lindex $queue 0]
+        set queue [lrange $queue 1 end]
+
+        foreach p [$xmlobj children -as path $qpath] {
+            if {[string match *.current $p]} {
+                continue
+            }
+            if {[llength [$xmlobj children $p]] > 0} {
+                # continue exploring nodes with children
+                lappend queue $p
+            } else {
+                # return the terminal nodes
+                lappend rlist $p
+            }
+        }
+    }
+    return $rlist
+}
+
+# ======================================================================
+# RUN QUEUE
+# ======================================================================
+# USAGE: queue add <testObj> <testObj>...
+# USAGE: queue clear ?<testObj> <testObj>...?
+# USAGE: queue status <command>
+# USAGE: queue next
+# USAGE: queue output <string>
+#
+# Used to manipulate the run queue for the program as a whole.
+#
+# The "queue add" option adds the given <testObj> objects to the run
+# queue.  As soon as an object is added to the queue, it is marked
+# "waiting".  When it runs, it is marked "running", and it finally
+# goes to the "pass" or "fail" state.  If an object is already in
+# the queue, then this operation does nothing.
+#
+# The "queue clear" option clears specific objects from the queue.
+# If no objects are specified, then it clears all remaining objects.
+#
+# The "queue status" option is used to set the callback for handling
+# output from runs.  This command is called two ways:
+#    command start <testObj>
+#    command add <testObj> "string of output"
+#
+# The "queue next" option is used internally to run the next object
+# in the queue.  The "queue output" option is also used internally
+# to handle the output coming back from a run.  The output gets
+# shuttled along to the callback specified by "queue status".
+# ----------------------------------------------------------------------
+itcl::body Rappture::Tester::Test::queue {option args} {
+    switch -- $option {
+        add {
+            # add these tests to the run queue
+            foreach obj $args {
+                if {[catch {$obj isa Rappture::Tester::Test} valid] || !$valid} {
+                    error "bad value \"$obj\": should be Test object"
+                }
+                if {[lsearch $_queue(tests) $obj] < 0} {
+                    $obj _setWaiting 1
+                    lappend _queue(tests) $obj
+                }
+            }
+            if {$_queue(running) eq "" && $_queue(pending) eq ""} {
+                set _queue(pending) [after idle \
+                    Rappture::Tester::Test::queue next]
+            }
+        }
+        clear {
+            # remove these tests from the run queue
+            foreach obj $args {
+                if {[catch {$obj isa Rappture::Tester::Test} valid] || !$valid} {
+                    error "bad value \"$obj\": should be Test object"
+                }
+
+                # remove the test from the queue
+                set i [lsearch $_queue(tests) $obj]
+                if {$i >= 0} {
+                    set _queue(tests) [lreplace $_queue(tests) $i $i]
+                }
+
+                # mark object as no longer "waiting"
+                if {[$obj _setWaiting]} {
+                    $obj _setWaiting 0
+                }
+            }
+        }
+        status {
+            if {[llength $args] != 1} {
+                error "wrong # args: should be \"status command\""
+            }
+            set _queue(outputcmd) [lindex $args 0]
+        }
+        next {
+            set _queue(pending) ""
+
+            # get the next object from the queue
+            set obj [lindex $_queue(tests) 0]
+            set _queue(tests) [lrange $_queue(tests) 1 end]
+
+            if {$obj ne ""} {
+                set _queue(running) $obj
+                # invoke the callback to signal start of a run
+                if {[string length $_queue(outputcmd)] > 0} {
+                    uplevel #0 $_queue(outputcmd) start $obj
+                }
+
+                # run the test
+                set callback "Rappture::Tester::Test::queue output"
+                set status [$obj run -output $callback]
+                set _queue(running) ""
+
+                if {$status == "aborted"} {
+                    # if the test was aborted, clear any waiting tests
+                    Rappture::Tester::Test::queue clear
+                } elseif {[string match failed:* $status]} {
+                    bgerror $status
+                }
+
+                # set up to run the next test in the queue
+                set _queue(pending) [after idle \
+                    Rappture::Tester::Test::queue next]
+            }
+        }
+        output {
+            if {[llength $args] != 1} {
+                error "wrong # args: should be \"output string\""
+            }
+            if {[string length $_queue(outputcmd)] > 0} {
+                uplevel #0 $_queue(outputcmd) add $_queue(running) $args
+            }
+        }
+        default {
+            error "bad option \"$option\": should be add, clear, status, output, next"
+        }
+    }
+}
Index: /trunk/tester/tester.tcl
===================================================================
--- /trunk/tester/tester.tcl	(revision 2079)
+++ /trunk/tester/tester.tcl	(revision 2080)
@@ -77,7 +77,4 @@
 set Rappture::icon::iconpath [linsert $Rappture::icon::iconpath 0 [file join $testerdir images]]
 
-# current list of running tests
-set RunQueue ""
-
 
 Rappture::getopts argv params {
@@ -161,6 +158,9 @@
 # ----------------------------------------------------------------------
 frame $win.testrun
+label $win.testrun.title -text "Output from test run:" -anchor w
+pack $win.testrun.title -side top -anchor w
+
 button $win.testrun.abort -text "Abort"
-pack $win.testrun.abort -side bottom
+pack $win.testrun.abort -side bottom -pady {8 0}
 
 Rappture::Scroller $win.testrun.scrl -xscrollmode auto -yscrollmode auto
@@ -213,10 +213,11 @@
             pack forget $win
         }
-        pack $detailwidget -expand yes -fill both
+        if {$detailwidget ne ""} {
+            pack $detailwidget -expand yes -fill both -padx 8 -pady 8
+        }
     }
 
     if {[llength $tests] > 0} {
         eval $testview.overview show $tests
-        pack $testview -expand yes -fill both -padx 8 -pady 8
         if {[llength $tests] == 1 && [$tests getResult] eq "Fail"} {
             pack $testview.regoldenize -side bottom -anchor w
@@ -228,18 +229,36 @@
             set testobj [lindex $tests 0]
             $testview.details.scrl.list delete 0 end
-            foreach {path info} [$testobj getDiffs] {
-                set title [$testobj getTestInfo $path.about.label]
-                if {[string match output.* $path]} {
-                    set title "Output: $title"
-                }
-                switch -- [lindex $info 0] {
-                    result {
-                        set desc "Result differs from expected value"
-                        set icon [Rappture::icon fail16]
+            foreach {op path what v1 v2} [$testobj getDiffs] {
+                switch -- [lindex $what 0] {
+                  value {
+                    set title "Output: [$testobj getTestInfo $path.about.label]"
+                    set icon [Rappture::icon fail16]
+                    switch -- $op {
+                      - { set desc "Result is missing from current output" }
+                      + { set desc "Result was not expected to appear" }
+                      c { set desc "Result differs from expected value" }
+                      default {
+                          error "don't know how to handle difference $op"
+                      }
                     }
-                    default {
-                        set desc $info
-                        set icon [Rappture::icon warn16]
+                  }
+                  structure {
+                    set ppath [lindex $what 1]
+                    set title "Output: [$testobj getTestInfo $ppath.about.label]"
+                    set icon [Rappture::icon warn16]
+                    set pplen [string length $ppath]
+                    set tail [string range $path [expr {$pplen+1}] end]
+                    switch -- $op {
+                      - { set desc "Missing value \"$v1\" at $tail" }
+                      + { set desc "Extra value \"$v2\" at $tail" }
+                      c { set desc "Details at $tail have changed:\n       got: $v2\n  expected: $v1" }
+                      default {
+                          error "don't know how to handle difference $op"
+                      }
                     }
+                  }
+                  default {
+                    error "don't know how to handle difference \"$what\""
+                  }
                 }
 
@@ -265,62 +284,57 @@
 # ----------------------------------------------------------------------
 proc tester_run {args} {
-    global RunQueue
-    set testtree [.pw pane 0].tree
+    # set up a callback for handling output from runs
+    Rappture::Tester::Test::queue status tester_run_output
 
     # add these tests to the run queue
-    foreach obj $args {
-        if {[lsearch $RunQueue $obj] < 0} {
-            lappend RunQueue $obj
-        }
-    }
-
-    after idle tester_run_next
-}
-
-# ----------------------------------------------------------------------
-# USAGE: tester_run_next
-#
-# Takes the next test from the queue and runs it.  Displays any
-# output during the run, then compares results and shows a final
-# pass/fail status.
-# ----------------------------------------------------------------------
-proc tester_run_next {} {
-    global RunQueue
-
-    set obj [lindex $RunQueue 0]
-    set RunQueue [lrange $RunQueue 1 end]
-
-    if {$obj ne ""} {
-puts "RUNNING: $obj"
-        set testrun [.pw pane 1].testrun
-        $testrun.abort configure -command [list $obj abort]
-        $obj run -output tester_run_output
-    }
-
-    # keep running remaining tests
-    after idle tester_run_next
-}
-
-# ----------------------------------------------------------------------
-# USAGE: tester_run_output <string>
-#
-# Adds the <string> output from running a test case into the viewer
-# for that test.
-# ----------------------------------------------------------------------
-proc tester_run_output {string} {
+    eval Rappture::Tester::Test::queue add $args
+
+    # show the run output window
+    set rhs [.pw pane 1]
+    foreach win [pack slaves $rhs] {
+        pack forget $win
+    }
+    pack $rhs.testrun -expand yes -fill both -padx 8 -pady 8
+}
+
+# ----------------------------------------------------------------------
+# USAGE: tester_run_output start <testObj>
+# USAGE: tester_run_output add <testObj> <string>
+#
+# Handles the output from running tests.  The "start" option clears
+# the current output area.  The "add" option adds output from a run.
+# ----------------------------------------------------------------------
+proc tester_run_output {option testobj args} {
     set testrun [.pw pane 1].testrun
-    $testrun.scrl.info configure -state normal
-    $testrun.scrl.info insert end $string
-
-    # if there are too many lines, delete some
-    set lines [lindex [split [$testrun.scrl.info index end-2char] .] 0]
-    if {$lines > 500} {
-        set extra [expr {$lines-500+1}]
-        $testrun.scrl.info delete 1.0 $extra.0
-    }
-
-    # show the newest stuff
-    $testrun.scrl.info see end
-    $testrun.scrl.info configure -state disabled
+
+    switch -- $option {
+        start {
+            # clear out any previous output
+            $testrun.scrl.info configure -state normal
+            $testrun.scrl.info delete 1.0 end
+            $testrun.scrl.info configure -state disabled
+
+            # plug this object into the "Abort" button
+            $testrun.abort configure -command [list $testobj abort]
+        }
+        add {
+            $testrun.scrl.info configure -state normal
+            $testrun.scrl.info insert end [lindex $args 0]
+
+            # if there are too many lines, delete some
+            set lines [lindex [split [$testrun.scrl.info index end-2char] .] 0]
+            if {$lines > 500} {
+                set extra [expr {$lines-500+1}]
+                $testrun.scrl.info delete 1.0 $extra.0
+            }
+
+            # show the newest stuff
+            $testrun.scrl.info see end
+            $testrun.scrl.info configure -state disabled
+        }
+        default {
+            error "bad option \"$option\": should be start, add"
+        }
+    }
 }
 
Index: /trunk/tester/testtree.tcl
===================================================================
--- /trunk/tester/testtree.tcl	(revision 2079)
+++ /trunk/tester/testtree.tcl	(revision 2080)
@@ -225,5 +225,5 @@
                 Pass    { set data(result) "@[Rappture::icon pass16]" }
                 Fail    { set data(result) "@[Rappture::icon fail16]" }
-                Waiting { set data(result) "@[Rappture::icon wait]" }
+                Waiting { set data(result) "@[Rappture::icon wait16]" }
                 Running { set data(result) "@[spinner use]" }
                 default { set data(result) "" }
@@ -231,4 +231,13 @@
 puts "ICON: $data(result)"
             $itk_component(treeview) entry configure $n -data [array get data]
+
+            # if the node that's changed is selected, invoke the
+            # -selectcommand code so the GUI will react to the new state
+            if {[$itk_component(treeview) selection includes $n]} {
+                set cmd [$itk_component(treeview) cget -selectcommand]
+                if {[string length $cmd] > 0} {
+                    uplevel #0 $cmd
+                }
+            }
         }
     }
Index: /trunk/tester/testview.tcl
===================================================================
--- /trunk/tester/testview.tcl	(revision 2079)
+++ /trunk/tester/testview.tcl	(revision 2080)
@@ -144,4 +144,9 @@
                     set color $itk_option(-statusfailcolor)
                 }
+                Running - Waiting {
+                    set smesg "Test waiting to run"
+                    set sicon [Rappture::icon wait64]
+                    set color $itk_option(-statuspasscolor)
+                }
                 default { error "unknown test state \"[$obj getResult]\"" }
             }
@@ -161,5 +166,5 @@
         }
         default {
-            array set states { ? 0  Pass 0  Fail 0  total 0 }
+            array set states { ? 0  Pass 0  Fail 0  Running 0  Waiting 0  total 0 }
             foreach obj $_testobjs {
                 incr states(total)
