#!/bin/bash
# the next line restarts using the OS dependent executable \
if [ "$OSTYPE" = "cygwin" ]; then PLATFORM="Windows_NT"; SCRIPT=$(cygpath -w $0); else PLATFORM=$(uname -s); SCRIPT=$0; fi; exec ${0%vsd*}vsdwish$PLATFORM "$SCRIPT" -- "$@"

# Visual StatDisplay (vsd)
# $Id: vsd.tcl 31322 2013-08-22 23:15:00Z normg $
#

if {[string equal $tcl_platform(platform) "windows"]} {
    set isWindows 1
} else {
    set isWindows 0
}

if {![info exists vsd(restarting)]} {
    namespace import rbc::vector
    namespace import rbc::spline
    namespace import rbc::graph
    namespace import rbc::stripchart
    namespace import rbc::barchart
    namespace import rbc::busy
#    namespace import rbc::bitmap
}
#if {$isWindows} {
#    console show
   # the executable is in $GEMSTONE/bin; libs are in $GEMSTONE/bin
#    set libdir [file dirname [info nameofexecutable]]
#    set libext [info sharedlibextension]

#    tix resetoptions TK TK

#    global tixOption
#     set tixOption(bg)           "SystemButtonFace"
#     set tixOption(dark1_bg)     "SystemButtonHighlight"
#     set tixOption(dark1_fg)     "black"
#     set tixOption(dark2_bg)     "SystemBackground"
#     set tixOption(dark2_fg)     "black"
#     set tixOption(inactive_bg)  "SystemBackground"
#     set tixOption(inactive_fg)  "black"

#     set tixOption(light1_bg)    #ececec ;# off white
#     set tixOption(light1_fg)    "white"
#     set tixOption(light2_bg)    #fcfcfc ;# white
#     set tixOption(light2_fg)    "white"

#     set tixOption(active_bg)    "SystemButtonHighlight"
#     set tixOption(active_fg)    $tixOption(fg)
#     set tixOption(disabled_fg)  "SystemDisabledText"

#     set tixOption(input1_bg)    "SystemScrollbar"
#     set tixOption(input2_bg)    "SystemScrollbar"
#     set tixOption(output1_bg)   $tixOption(dark1_bg)
#     set tixOption(output2_bg)   $tixOption(bg)

#     set tixOption(select_fg)    "SystemHighlightText"
#     set tixOption(select_bg)    "SystemHighlight"


#     if [info exists sltcl(guifont)] {
# 	set tixOption(font)         $sltcl(guifont)
#     } else {
# 	set tixOption(font)         $sltcl(systemfont)
#     }
#     if [info exists sltcl(menufont)] {
# 	set tixOption(menu_font)    $sltcl(menufont)
#     } else {
# 	set tixOption(menu_font)    $tixOption(font)
#     }
#     set tixOption(bold_font)    [lreplace $tixOption(font) 2 2 "bold"]
#     set tixOption(italic_font)    [lreplace $tixOption(font) 2 2 "italic"]
#     set tixOption(fixed_font)   "ansifixed"
#     tixAppContext:CheckFontSets .
#     option add *font $tixOption(font)
#     if [info exists sltcl(menufont)] {
# 	option add *Menu.font $sltcl(menufont)
# 	option add *Menubutton.font $sltcl(menufont)
#     }
#     if [info exists sltcl(messagefont)] {
# 	option add *Text.font $sltcl(messagefont)
# 	option add *Message.font $sltcl(messagefont)
#     }
#     if [info exists sltcl(statusfont)] {
# 	option add *TixBalloon.font $sltcl(statusfont)
#     }
	
#    option add *selectColor SystemHighlight


#     option add *Text.background SystemWindow
#     option add *Listbox.background SystemWindow
#     option add *Entry.background SystemWindow
#     option add *TixComboBox.background SystemWindow
#     option add *TixComboBox*Listbox.exportSelection 0
#     option add *TixHList.background SystemWindow
#     option add *TixHList.activeForeground SystemWindowText
#     option add *TixHList.selectBackground SystemHighlight
#     option add *TixHList.selectForeground SystemHighlightText
#     option add *TixHList.foreground SystemWindowText
#     option add *TixHList.activeBackground SystemWindow
#     option add *TixTList.background SystemWindow
#     option add *TixTList.activeForeground SystemWindowText
#     option add *TixTList.selectBackground SystemHighlight
#     option add *TixTList.selectForeground SystemHighlightText


#    if [info exists sltcl(scrollwidth)] {
#	option add *Scrollbar.width $sltcl(scrollwidth)
#    }
#} else {
    # the executable is in $GEMSTONE/bin; libs are in $GEMSTONE/lib
#    set libdir [file join [file dirname [file dirname [info nameofexecutable]]] "lib"]
#    set libext [info sharedlibextension]
#    if {![info exists vsd(restarting)]} {
#	load [file join $libdir libBLT$libext] Blt
#	load [file join $libdir libtix$libext] Tix
#	load [file join $libdir libsltcl$libext] Sltcl
#    }
#}

set vsd(infoScript) [info script]

option add *Text.font normalTextFont
bind Entry <Control-a> +break


#set tcl_precision 10

proc patchTix {} {
    global tixSep
    # hack fixes for bug in Tix4.0.5
    if {[info commands "tixHList::GoState-33"] != ""} {
	set tixSep "::"
    } else {
	set tixSep ":"
    }

    proc tixHList${tixSep}GoState-33 {w x y} {
	global tixSep
	set ent [tixHList${tixSep}GetNearest $w $y]
	if {$ent != {}} {
	    $w anchor set $ent
	    if {[$w selection includes $ent]} {
		$w selection clear $ent
	    } else {
		$w selection set $ent
	    }
	    tixHList${tixSep}Browse $w $ent
	}
    }
}

if 0 {
    tixBind TixComboEntry <Next>	{
	global tixSep
	tixComboBox${tixSep}EntDirKey [tixGetMegaWidget %W TixComboBox] pagedown
    }
proc tixHList::Keyboard-Activate {w} {
    if {[tixHList::GetState $w] != 0} {
	return
    }
    set ent [$w info anchor]

    if {$ent == ""} {
	return
    }

    if {[$w cget -selectmode] == "single"} {
	$w select clear
	$w select set $ent
    }

    set command [$w cget -command]
    if {$command != {}} {
	set bind(specs) {%V}
	set bind(%V)    $ent

	tixEvalCmdBinding $w $command bind $ent
    }
}

proc tixHList::Keyboard-Browse {w} {
    if {[tixHList::GetState $w] != 0} {
	return
    }
    set ent [$w info anchor]

    if {$ent == ""} {
	return
    }

    if {[$w cget -selectmode] == "single"} {
	$w select clear
	$w select set $ent
    }

    tixHList::Browse $w $ent
}

proc tixHList${tixSep}UpDown {w spec mod} {
    global tixSep
    if {[tixHList${tixSep}GetState $w] != 0} {
	return
    }
    set anchor [$w info anchor]
    set done 0

    if {$anchor == ""} {
	set anchor [lindex [$w info children] 0]

	if {$anchor == {}} {
	    return
	}

	if {[$w entrycget $anchor -state] != "disabled"} {
	    # That's a good anchor
	    set done 1
	} else {
	    # We search for the first non-disabled entry (downward)
	    set spec next
	}
    }

    set ent $anchor
    # Find the prev/next non-disabled entry
    #
    while {!$done} {
	set ent [$w info $spec $ent]
	if {$ent == {}} {
	    break
	}
	if {[$w entrycget $ent -state] == "disabled"} {
	    continue
	}
	if [$w info hidden $ent] {
	    continue
	}
	break
    }

    if {$ent == {}} {
	return
    } else {
	$w see $ent
	$w anchor set $ent

	set selMode [$w cget -selectmode]
       if {$mod == "s" && ($selMode == "extended" || $selMode == "multiple")} {
	    global $w:priv:shiftanchor

	    if ![info exists $w:priv:shiftanchor] {
		set $w:priv:shiftanchor $anchor
	    }

	    $w selection clear
	    $w selection set $ent [set $w:priv:shiftanchor]
    
	    tixHList${tixSep}Browse $w $ent
	} else {
	    catch {
		uplevel #0 unset $w:priv:shiftanchor
	    }
	}
    }
}
} ;# if 0

proc myBusyOn {w} {
    busy hold $w
    update
}
proc myBusyOff {w} {
    if [winfo exists $w] {
	busy release $w
	busy forget $w
    }
}
####################

proc showAxis {graph axis} {
    global vsd
    $graph $axis configure -hide false -background $vsd(currentBgColor)
}
proc showMarker {graph id} {
    $graph marker configure $id -hide false
}
proc hideAxis {graph axis} {
    $graph $axis configure -hide true
}
proc hideMarker {graph id} {
    $graph marker configure $id -hide true
}
proc mapLegend {graph bool} {
    global vsd
    $graph legend configure -hide [expr {!$bool}] -background $vsd(currentBgColor)
}
proc isLegendMapped {graph} {
    expr {! [$graph legend cget -hide]}
}


####################

# The following Copyright applies to the tkerror implementation

# Copyright (c) 1993 Xerox Corporation.
# Use and copying of this software and preparation of derivative works based
# upon this software are permitted. Any distribution of this software or
# derivative works must comply with all applicable United States export
# control laws. This software is made available AS IS, and Xerox Corporation
# makes no warranty about the software, its performance or its conformity to
# any specification.

proc tkerror { msg } {
    global errorInfo
    global vsd isWindows

    if {$isWindows} {
	set font "ansifixed"
    } else {
	set font "fixed"
    }

    set base ".errorInfo"
    set title "Error Info"
    if [info exists errorInfo] {
	set savedErrorInfo $errorInfo
    } else {
	set savedErrorInfo {no errorInfo}
    }
    # Create a toplevel to contain the error trace back
    if [catch {
	# Choose a unique name
	for {set x 1} {$x < 10} {set x [expr {$x + 1}]} {
	    if {! [winfo exists $base-$x]} {
		break
	    }
	}
	set title $title-$x
	set name $base-$x

	toplevel $name -bd 2
	wm title $name $title
	wm group $name .
	wm minsize $name 20 5
    
	frame $name.buttons
	pack $name.buttons -side top -fill x
    
	if {! [info exists vsd(maintainer)]} {
	    set vsd(maintainer) "vsd@gemtalksystems.com"
	}

	button $name.buttons.quit -text "Ignore" -command [list destroy $name]
	pack append $name.buttons $name.buttons.quit {left}

	if {$isWindows} {
	    button $name.buttons.copy -text "Copy to Clipboard" \
		-command [list CopyError $name]
	    pack append $name.buttons $name.buttons.copy {right}
	} else {
	    button $name.buttons.mailto -text "Mail to $vsd(maintainer)" \
		-command [list MailError $name]
	    pack append $name.buttons $name.buttons.mailto {right}
	}

	global widgetText TextType

	message $name.ex -font $font -aspect 1000 -text \
"Please type a few words of explanation if you
are going to report this error. If you are logged
in as another user include your actual email address."
	pack $name.ex -side top -fill x
	text $name.user -font $font -width 60 -bd 2 -relief raised
	$name.user configure -height 5
	$name.user insert end "What happened: "
	$name.user tag add sel 1.0 1.14
	focus $name.user
	pack $name.user -side top -fill both -expand true
	$name.user mark set hlimit 1.0
	set widgetText($name.user,extend) 0
	set widgetText($name.user,geo) {}
	set TextType($name.user) text

	frame $name.msg
	pack $name.msg -side top -fill both -expand true

	text $name.msg.t -font $font -width 60 -bd 2 -relief raised \
		-setgrid true -yscrollcommand [list $name.msg.sy set]
	scrollbar $name.msg.sy -orient vertical -command [list $name.msg.t yview]
	$name.msg.t configure -height 20
	$name.msg.t insert end [getSysInfo]
	$name.msg.t insert end $savedErrorInfo
	pack $name.msg.sy -side right -fill y
	pack $name.msg.t -side left -fill both -expand true
	set widgetText($name.msg.t,extend) 0
	set widgetText($name.msg.t,geo) {}
	set TextType($name.msg.t) text
        setMasterBgColorForWindow $name
	
	tkwait visibility $name

    }] {
	puts stderr "tkerror: $msg"
	puts stderr "*** TCL Trace ***"
	puts stderr $savedErrorInfo
   }
}

proc getSysInfo {} {
    global vsd argv argv0 env tk_version isWindows tcl_platform
    set res ""
    if {[info commands clock] != ""} {
	append res "Date: [clock format [clock seconds]]\n"
    } elseif {![catch {eval exec $vsd(exec:date)} date]} {
	append res "Date: $date\n"
    }
    if [info exists env(USER)] {
	append res "$env(USER) got an error\n"
    }
    append res "command line: $argv0 $argv\n"
    append res "vsd version: $vsd(version)\n"
    append res "statistics version: $vsd(stats_version)\n"
    append res "TK version: $tk_version\n"
    append res "TCL version: [info tclversion]\n"
    if [info exists tcl_platform] {
	append res "host=[info hostname], type=$tcl_platform(machine), "
	append res "os=$tcl_platform(os) $tcl_platform(osVersion)\n"
    } elseif {! $isWindows} {
	catch {eval exec $vsd(exec:uname)} uname
	append res "$uname\n\n"
    }
    catch {pwd} pwdResult
    append res "Working directory is: $pwdResult"
    if {$vsd(statsrc) != {}} {
	append res "Info on current data file:\n"
	catch {$vsd(statsrc) -info} fileinfo
	foreach i $fileinfo {
	    append res "  $i\n"
	}
    }
    append res "\n"
    return $res
}

proc CopyError { w } {
    global vsd argv argv0
    set errText "To: $vsd(maintainer)\n"
    append errText "Subject: $argv0 error\n\n"
    append errText [$w.user get 1.0 end]
    append errText "\n\n"
    append errText [$w.msg.t get 1.0 end]
    append errText "\n"
    clipboard clear
    clipboard append $errText
    destroy $w
    return
}

proc MailError { w } {
    global vsd argv argv0
    if [catch {open /tmp/error.[pid] w} out] {
	puts stderr "Cannot open /tmp/error.[pid]"
	return
    }
    if [catch {
	puts $out "To: $vsd(maintainer)"
	puts $out "Subject: $argv0 error"
	puts $out ""
	puts $out [$w.user get 1.0 end]
	puts $out ""
	puts $out [$w.msg.t get 1.0 end]
	close $out
    } msg] {
	puts stderr "/tmp/error.[pid] $msg"
	return
    }
    if [catch {
	eval exec $vsd(exec:mail) $vsd(maintainer) < /tmp/error.[pid]
    } msg] {
	puts stderr "$vsd(exec:mail) error: $msg"
    } else {
	puts stderr "Mailed report to $vsd(maintainer)"
	destroy $w
    }
    catch {file delete -force /tmp/error.[pid]}
}

#################### some BLT graphing features ######################

proc Blt_CrosshairsOn { graph } {
    bind bltCrosshairs <Any-Motion>   {
	%W crosshairs configure -position @%x,%y
    }
    $graph crosshairs configure -color black
    bind $graph <Enter> [format {
	BltAddBindTag %s bltCrosshairs  
	%s crosshairs on
    } $graph $graph]
    bind $graph <Leave> [format {
	BltRemoveBindTag %s bltCrosshairs  
	%s crosshairs off
    } $graph $graph]
}

proc Blt_CrosshairsOff { graph } {
    bind bltCrosshairs <Any-Motion>   {}
    bind $graph <Enter> {}
    bind $graph <Leave> {}
}

proc Blt_ZoomStack { graph } {
    global bltZoom
    global bltActiveEntry
    global bltSelectedLines

    set bltActiveEntry($graph) -1
    set bltSelectedLines($graph) {}

    set bltZoom($graph,A,x) {}
    set bltZoom($graph,A,y) {}
    set bltZoom($graph,A,y2) {}
    set bltZoom($graph,B,x) {}
    set bltZoom($graph,B,y) {}
    set bltZoom($graph,B,y2) {}
    set bltZoom($graph,stack) {}
    set bltZoom($graph,corner) A

    bind $graph <1> {
	ChartHandleLeftClick %W %x %y 0
    }
    bind $graph <Control-1> {
	ChartHandleLeftClick %W %x %y 1
    }
    bind $graph <ButtonRelease-2> {
	ChartHandleMiddleClick %W %x %y 
    }
    bind $graph <ButtonPress-3> {
	ChartHandleRightClick %W
    }
}

proc removeSelectedLine {graph e} {
    global bltSelectedLines
    set l $bltSelectedLines($graph)
    set idx [lsearch -exact $l $e]
    if {$idx != -1} {
        $graph legend deactivate $e
        set bltSelectedLines($graph) [lreplace $l $idx $idx]
        #puts "DEBUG: removing $e from $l"
    }
}

proc addSelectedLine {graph e} {
    global bltSelectedLines
    set l $bltSelectedLines($graph)
    set idx [lsearch -exact $l $e]
    if {$idx != -1} {
        #puts "DEBUG: removing $e from $l"
        # it was already select so deselect it
        $graph legend deactivate $e
        set bltSelectedLines($graph) [lreplace $l $idx $idx]
    } else {
        #puts "DEBUG: adding $e to $l"
        lappend bltSelectedLines($graph) $e
        #puts "DEBUG: activating \"$bltSelectedLines($graph)\""
        eval $graph legend activate $bltSelectedLines($graph)
        # $graph legend activate $e
    }
}

proc getCommonFilter {graph filter} {
    global vsd bltSelectedLines
    foreach e $bltSelectedLines($graph) {
	set edata [$vsd(ed:$e:$graph) -info]
	if {![string equal $filter [lindex $edata 5]]} {
            return {}
        }
    }
    return $filter
}

proc getSelectedLines {graph} {
    global bltSelectedLines
    return $bltSelectedLines($graph)
}

proc clearSelectedLines {graph} {
    global bltSelectedLines
    set l $bltSelectedLines($graph)
    if {$l != {}} {
        eval $graph legend deactivate $l
        set bltSelectedLines($graph) {}
        #puts "DEBUG: clear all selected lines"
    }
    return $l
}

proc resetSelectedLines {graph lines} {
    global bltSelectedLines
    set bltSelectedLines($graph) $lines
    if {$lines != {}} {
        eval $graph legend activate $lines
        #puts "DEBUG: reset selected lines to $lines"
    }
}

proc deleteElement {graph element {doFree 1}} {
    global vsd
    global bltActiveGraph
    global bltActiveEntry

    set cleanup 0

    removeSelectedLine $graph $element

    if {$vsd($graph:chartOp) != {}} {
	chartCancelOp$vsd($graph:chartOp) $graph
    }
    if {$bltActiveEntry($graph) == $element} {
	set bltActiveEntry($graph) -1
	set cleanup 1
    }
    if {$bltActiveGraph($graph) == $element} {
	set bltActiveGraph($graph) 0
	set bltActiveGraph($graph,closest) {}
	set cleanup 1
    }
    if {$cleanup && $bltActiveEntry($graph) == -1} {
	deactivateAxis $graph
	showLineInfo $graph ""
    }
    if {$doFree} {
	$vsd(ed:$element:$graph) -free
    }
    unset vsd(ed:$element:$graph)
    set axisName [$graph element cget $element -mapy]
    $graph element delete $element
    foreach e [$graph element names] {
	if {[string equal $axisName [$graph element cget $e -mapy]]} {
	    return;
	}
    }
    # No more lines using this axis so unmap it
    hideAxis $graph ${axisName}axis
    if {[string equal $axisName "y"]} {
	$graph configure -leftmargin 2
    } else {
	$graph configure -rightmargin 2
    }
}

proc getLineUnitDescription {isAxis lineinfo} {
    set linectr [lindex $lineinfo 1]
    set linescale [lindex $lineinfo 4]
    set linefilter [lindex $lineinfo 5]
    set lineoperator [lindex $lineinfo 9]
    set lineoffset [lindex $lineinfo 12]
    set linedivider [lindex $lineinfo 13]
    if [catch {getStatType $linectr} ctrtype] {
	# This happens if its a derived line with more than one ctr
	# NYI: just go with defaults
	set ctrtype ""
	# NYI in many derived line cases the units could be figured out
	#     this should be done in statlib when the line is created
	set ctrunits "None"
	set linectr "([getCtrAlias $linectr])"
    } else {
	set ctrunits [string toupper [getStatUnits $linectr] 0 0]
	set linectr [getCtrAlias $linectr]
    }
    set axisLabel ""
    if {[string equal $linefilter "none"]} {
	if $isAxis {
	    if {[string equal $ctrtype "counter"]} {
		append axisLabel "total "
	    }
	}
	if {[string equal $ctrunits "None"]} {
	    append axisLabel $linectr
	} else {
	    append axisLabel $ctrunits
	}
    } elseif {[string equal $linefilter "aggregate"]} {
	if {[string equal $ctrunits "None"]} {
	    append axisLabel $linectr
	} else {
	    append axisLabel $ctrunits
	}
	append axisLabel " +"
    } elseif {[string equal $linefilter "smooth"]} {
	if {[string equal $ctrunits "None"]} {
	    append axisLabel $linectr
	} else {
	    append axisLabel $ctrunits
	}
	append axisLabel " ~"
    } else { # per filter 
	if {[string equal $ctrunits "None"]} {
	    append axisLabel $linectr
	} else {
	    append axisLabel $ctrunits
	}
	if {[string equal $linefilter "persecond"]} {
	    append axisLabel " / second"
	} elseif {[string equal $linefilter "persample"]} {
	    append axisLabel " / sample"
	}
    }
    if $isAxis {
	if {$linedivider != 1.0 && $linedivider != 1} {
	    if {[expr {abs($linedivider)}] >= 1.0} {
		append axisLabel " / $linedivider"
	    } else {
		append axisLabel " * [expr {1.0 / $linedivider}]"
	    }
	}
	if {$lineoffset != 0.0 && $lineoffset != 0} {
	    if {$lineoffset < 0} {
		append axisLabel " + [expr {- $lineoffset}]"
	    } else {
		append axisLabel " - $lineoffset"
	    }
	}
	if {$linescale != 1.0 && $linescale != 1} {
	    append axisLabel " * $linescale"
	}
    }
    return $axisLabel
}

proc getElementYAxisTitle {g e} {
    global vsd
    return [getLineUnitDescription 1 [$vsd(ed:$e:$g) -info]]
}

proc stripext {n} {
    set result [file rootname $n]
    while {![string equal $result $n]} {
	set n $result
	set result [file rootname $n]
    }
    return $result
}

proc calcUniqueFileName {dfid {addBaseName 0}} {
    global uniqueNameMap
    global uniqueNames
    set fullname [lindex [$dfid -info] 0]
    if {[string equal "relative" [file pathtype $fullname]]} {
	set fullname [file join [pwd] $fullname]
    }
    set dirname [file dirname $fullname]
    set dirlist [file split $dirname]
    set diridx [llength $dirlist]
    set needsBaseName 1
    if {$addBaseName} {
	set uname [stripext [file tail $fullname]]
    } else {
	incr diridx -1
	if {$diridx < 0} {
	    set needsBaseName 0
	    set uname $fullname
	} else {
	    set uname [lindex $dirlist $diridx]
            if {$diridx > 1} {
                # Want at least the parent and grandparent directory
                incr diridx -1
                set uname [file join [lindex $dirlist $diridx] $uname]
            }
	}
    }
    while {[info exists uniqueNames($uname)]} {
	set olddfid $uniqueNames($uname)
	if {$olddfid != {}} {
	    global vsd
	    set oldFileInfo [getFileInfoName $olddfid]
	    set uniqueNames($uname) {}
	    calcUniqueFileName $olddfid
	    # update vsd(filelist) and vsd(w:filelist) history
	    set newFileInfo [getFileInfoName $olddfid]
	    set newUniqueName $uniqueNameMap($olddfid)
	    set idx [lsearch -exact $vsd(filelist) $oldFileInfo]
	    if {$idx != -1} {
		set vsd(filelist) [lreplace $vsd(filelist) $idx $idx $newFileInfo]
	    }
	    set lb [$vsd(w:filelist) subwidget listbox]
	    set idx [lsearch -exact [$lb get 0 end] $oldFileInfo]
	    if {$idx != -1} {
		$lb insert $idx $newFileInfo
		incr idx
		$lb delete $idx $idx
	    }
	    addFileListMap $olddfid
	}
	incr diridx -1
	if {$diridx < 0} {
	    set needsBaseName 0
	    set uname $fullname
	    # this must be unique; its the full absolute name
	    break
	} else {
	    set uname [file join [lindex $dirlist $diridx] $uname]
	}
    }
    if {$needsBaseName} {
	# found a unique name
	set uniqueNames($uname) $dfid
	if {!$addBaseName} {
	    set uname [file join $uname [stripext [file tail $fullname]]]
	}
    } else {
	if {$addBaseName} {
	    # See how much of the extensions can be stripped off
	    while {![info exists uniqueNames([file rootname $uname])]} {
		set newname [file rootname $uname]
		if {![string equal $uname $newname]} {
		    set uname $newname
		} else {
		    break
		}
	    }
	} else {
	    calcUniqueFileName $dfid 1
	    return
	}
	set uniqueNames($uname) $dfid
    }
    set uniqueNameMap($dfid) $uname
}

proc getSortedGroupNames {} {
    global vsd
    return $vsd(sortedGroupNames)
}

proc groupFilesByPattern {dfid} {
    global vsd patternMap
    if {$vsd(combineFilePattern) == ""} {
        return
    }
    set fullname [lindex [$dfid -info] 0]
    set matches [regexp -inline -nocase -- $vsd(combineFilePattern) $fullname]
    if {$matches == {}} {
        # our pattern did not match any substring
        # so always group this file by itself
        set matches $fullname
    }
    if {[info exists patternMap($matches)]} {
        set v $patternMap($matches)
        lappend v $dfid
        set patternMap($matches) $v
    } else {
        set patternMap($matches) [list $dfid]
        lappend vsd(sortedGroupNames) $matches
    }
}

proc addUniqueFileName {dfid} {
    global uniqueNameMap
    if {[info exists uniqueNameMap($dfid)]} {
	# already added
	return
    }
    groupFilesByPattern $dfid
    
    calcUniqueFileName $dfid
}

proc getUniqueFileName {dfid} {
    global uniqueNameMap
    return $uniqueNameMap($dfid)
}

proc getShortOS {os} {
    if {[string first "Solaris" $os] != -1} {
	return "Solaris"
    } elseif {[string first "SunOS" $os] != -1} {
	return "Solaris"
    } elseif {[string first "NT" $os] != -1} {
	return "Windows"
    } elseif {[string first "Windows" $os] != -1} {
	return "Windows"
    } elseif {[string first "AIX" $os] != -1} {
	return "AIX"
    } elseif {[string first "HPUX" $os] != -1} {
	return "HPUX"
    } else {
	return $os
    }
}

proc getShortGsVer {ver} {
    set idx [string first "," $ver]
    if {$idx != -1} {
        incr idx -1
        return [string range $ver 0 $idx]
    }
    return $ver
}

proc getShortMachine {m} {
    set idx [string first " " $m]
    if {$idx == -1} {
	return $m
    }
    incr idx -1
    set res [string range $m 0 $idx]
    return [string trimright $res ":"]
}

proc getFileId {dfid} {
    # dfid is "slFile" followed by a bunch of digits
    return [string range $dfid 6 end]
}

proc getFileInfoName {dfid} {
    global vsd
    set id [getFileId $dfid]
    set finfo [$dfid -info]
    set fname [getUniqueFileName $dfid]
    set archiveFormat [lindex $finfo 1]
    if {$archiveFormat != 1} {
        set platform [lindex $finfo 2]
    } else {
        set platform [getShortOS [lindex $finfo 2]]
    }
    set gsVer [getShortGsVer [lindex $finfo 3]]
    if {$archiveFormat != 1} {
        set machine [lindex $finfo 4]
    } else {
        set machine [getShortMachine [lindex $finfo 4]]
    }
    return "$id. $fname $platform $machine $gsVer"
}

proc getTitleInfoName {dfid} {
    global vsd
    set id [getFileId $dfid]
    set finfo [$dfid -info]
    set fname [getUniqueFileName $dfid]
    if {[string match "*statArchive" $fname]} {
        set idx [string last "statArchive" $fname]
        incr idx -1
        set fname [string range $fname 0 $idx]
    }
    set gsVer [getShortGsVer [lindex $finfo 3]]
    set idx [string first " as of" $gsVer]
    if {$idx != -1} {
        incr idx -1
        set gsVer [string range $gsVer 0 $idx]
    }
    set archiveFormat [lindex $finfo 1]
    if {$archiveFormat != 1} {
        set machine [lindex [lindex $finfo 4] 1]
    } else {
        set machine [getShortMachine [lindex $finfo 4]]
    }
     return "$id. $fname $machine $gsVer"
}

proc getElementXAxisTitle {g e} {
    global vsd
    set linfo [$vsd(ed:$e:$g) -info]
    set dfids [lindex $linfo 7]
    if {[llength $dfids] == 1} {
	set dfid [lindex $dfids 0]
	return [getTitleInfoName $dfid]
    } else {
	foreach dfid $dfids {
	    append result [getUniqueFileName $dfid]
	    append result " "
	}
	return [string trimright $result]
    }
}

proc activateAxis {g e} {
    global vsd

    set axisName [$g element cget $e -mapy]
    append axisName "axis"
    $g $axisName configure -color $vsd(activecolor)
    if {$vsd($g:$axisName:showtitle)} {
	set axisLabel [getElementYAxisTitle $g $e]
	if {$axisLabel != ""} {
	    $g $axisName configure -title $axisLabel
	}
    }
    if {$vsd($g:xaxis:showtitle)} {
	set xaxisLabel [getElementXAxisTitle $g $e]
	if {$xaxisLabel != ""} {
	    $g xaxis configure -title $xaxisLabel
	}
    }
}

proc deactivateAxis {g} {
    global vsd

    $g yaxis configure -color "black"
    if {$vsd($g:yaxis:showtitle)} {
	$g yaxis configure -title $vsd(yaxis:defaultTitle)
    }
    $g y2axis configure -color "black"
    if {$vsd($g:y2axis:showtitle)} {
	$g y2axis configure -title $vsd(y2axis:defaultTitle)
    }
    if {$vsd($g:xaxis:showtitle)} {
	$g xaxis configure -title $vsd(xaxis:defaultTitle)
    }
}

proc getLineLabel {g e} {
    global vsd
    if [isLegendMapped $g] {
	set result ""
    } else {
	set lineinfo [$vsd(ed:$e:$g) -info]
	set fullname [lindex $lineinfo 0]
	# fullname = {name pid uniqueid}
	if {[lindex $fullname 1] == 0} {
	    # fix for bug 22816
	    set result [lindex $fullname 0]
	} else {
	    set result [join $fullname ", "]
	}
	append result ": "
    }
    set w [winfo toplevel $g]
    if {$vsd($w:showlinestats)} {
	set xStart [$g xaxis cget -min]
	set xEnd [$g xaxis cget -max]
	set lstats [$vsd(ed:$e:$g) -stats $xStart $xEnd]
	append result "points: [lindex $lstats 0]"
	append result " min: [lindex $lstats 1]"
	append result " max: [lindex $lstats 2]"
	append result " mean: [format %.6g [lindex $lstats 3]]"
	append result " sd: [format %.6g [lindex $lstats 4]]"
	$g marker configure triStart -coords [list [lindex $lstats 5] -Inf]
	showMarker $g triStart
	$g marker configure triEnd -coords [list [lindex $lstats 6] -Inf]
	showMarker $g triEnd
    }
    return $result
}

proc bltDoActivateGraph {graph x y new} {
    global bltActiveGraph
    global bltActiveEntry
    unset bltActiveGraph($graph,alarmid)
    unset bltActiveGraph($graph,x)
    unset bltActiveGraph($graph,y)
    set old $bltActiveGraph($graph)
    if { $old != $new } {
	if { $old != 0 } {
	    $graph legend deactivate $old
	    $graph element deactivate $old
	    $graph marker configure activeLine -text ""
	    deactivateAxis $graph
	    showLineInfo $graph ""
	    set bltActiveGraph($graph,closest) {}
	} else {
            if {[info exists bltActiveGraph($graph,oldSelectedLines)]} {
                set bltActiveGraph($graph,oldSelectedLines) [clearSelectedLines $graph]
            }
	    set legendEntry $bltActiveEntry($graph)
	    if {$legendEntry != -1} {
		if {$new != $legendEntry} {
		    $graph legend deactivate $legendEntry
		    $graph element deactivate $legendEntry
		    $graph marker configure activeLine -text ""
	            deactivateAxis $graph
		    showLineInfo $graph ""
		}
	    }
	}
        #puts "DEBUG: bltDoActivateGraph legend activate $new"
	$graph legend activate $new
	$graph element activate $new
	$graph marker configure activeLine -text [getLineLabel $graph $new]
	activateAxis $graph $new
	set bltActiveGraph($graph) $new
	showLineInfo $graph $new
	set bltActiveGraph($graph,closest) {}
    }
    bltActivatePoint $graph $x $y $new
    return
}

proc bltActivatePoint {graph x y new} {
    global bltActiveGraph
    global vsd
    if [$graph element closest $x $y info -halo 5 -interpolate 0 $new] {
	set coordinates "$info(x) $info(y)"
	if {[string equal $vsd($graph:chartOp) "Delta"]} {
	    if {[string equal $new $vsd($graph:deltaLine)]} {
		$graph config -cursor target
	    } else {
		$graph config -cursor crosshair
	    }
	} elseif {[string equal $vsd($graph:chartOp) "Compare"]} {
	    $graph config -cursor target
	} elseif {[string equal $vsd($graph:chartOp) "Trim"]} {
	    if {[string equal $new $vsd($graph:trimLine)]} {
		$graph config -cursor target
	    } else {
		$graph config -cursor crosshair
	    }
	}
	if {![string equal $coordinates $bltActiveGraph($graph,closest)]} {
	    setCurXY $graph $new $info(x) $info(y)
	    set bltActiveGraph($graph,closest) $coordinates
	}
    }
}

proc bltActivateGraph {g x y new} {
    global bltActiveGraph

    if {[info exists bltActiveGraph($g,alarmid)]} {
	set oldx $bltActiveGraph($g,x)
	set oldy $bltActiveGraph($g,y)
	if {abs($x - $oldx) < 3 && abs($y - $oldy) < 3} {
	    # still close to place that alarm already set for
	    return
	}
	# forget the old guy and setup a new one
	after cancel $bltActiveGraph($g,alarmid)
	unset bltActiveGraph($g,alarmid)
    }
    set old $bltActiveGraph($g)
    if { $old == $new } {
	# Don't bother delaying with an alarm since this is on
	# the same line
	bltActivatePoint $g $x $y $new
	return
    }

    # Set up an alarm so we can delay doing this in case the user
    # is just moving the mouse over the graph.
    set bltActiveGraph($g,x) $x
    set bltActiveGraph($g,y) $y
    set bltActiveGraph($g,alarmid) [after 500 \
					[list bltDoActivateGraph $g $x $y $new]]
    return
}

proc bltDeactivateGraph {g} {
    global bltActiveGraph
    global bltActiveEntry
    global vsd

    if {[string equal $vsd($g:chartOp) "Delta"] ||
	[string equal $vsd($g:chartOp) "Trim"] ||
	[string equal $vsd($g:chartOp) "Compare"]} {
	$g config -cursor crosshair
    }
    if {[info exists bltActiveGraph($g,alarmid)]} {
	after cancel $bltActiveGraph($g,alarmid)
	unset bltActiveGraph($g,alarmid)
	unset bltActiveGraph($g,x)
	unset bltActiveGraph($g,y)
    }
    if {![info exists bltActiveGraph($g)]} {
        return
    }
    if {$bltActiveGraph($g) == 0} {
	return
    }
    $g legend deactivate $bltActiveGraph($g)
    $g element deactivate  $bltActiveGraph($g)
    $g marker configure activeLine -text ""
    deactivateAxis $g
    set bltActiveGraph($g) 0
    if {[info exists bltActiveGraph($g,oldSelectedLines)]} {
        resetSelectedLines $g $bltActiveGraph($g,oldSelectedLines)
	unset bltActiveGraph($g,oldSelectedLines)
    }
    showLineInfo $g ""
    set bltActiveGraph($g,closest) {}
    set le $bltActiveEntry($g)
    if {$le != -1} {
	# If an active legend is in use then restore it
	$g legend activate $le
	$g element activate $le
	$g marker configure activeLine -text  [getLineLabel $g $le]
	activateAxis $g $le
	showLineInfo $g $le
    }
}

# For some reason <1> and <2> end up calling the <Leave> binding.
# So we make sure we are out of the graph before doing the <Leave> work.
proc chartHandleLeaveEvent {g x y} {
    set y [$g yaxis invtransform $y]
    set ylimits [$g yaxis limits]
    if {$y >= [lindex $ylimits 0] && $y <= [lindex $ylimits 1]} {
	set x [$g xaxis invtransform $x]
	set xlimits [$g xaxis limits]
	if {$x >= [lindex $xlimits 0] && $x <= [lindex $xlimits 1]} {
	    return
	}
    }
    bltDeactivateGraph $g
}

proc Blt_BA_ActiveGraph {W x y} {
    if [$W element closest $x $y info -interpolate true -halo 5] {
	bltActivateGraph $W $x $y $info(name)
    } else {
	bltDeactivateGraph $W
    }
}

proc Blt_ActiveGraph { graph } {
    global bltActiveGraph
    set bltActiveGraph($graph) 0
    set bltActiveGraph($graph,closest) {}
    set bltActiveGraph($graph,oldSelectedLines) {}
    bind bltActiveGraph <Any-Motion>   {Blt_BA_ActiveGraph %W %x %y}
    bind bltActiveGraph <Leave>   {
	chartHandleLeaveEvent %W %x %y
    }
    BltAddBindTag $graph bltActiveGraph
}

proc activateElement {graph new control} {
    global bltActiveEntry
    global bltSelectedLines
    set old $bltActiveEntry($graph)
    if { $old != $new } {
        if {!$control} {
            clearSelectedLines $graph
        }
        addSelectedLine $graph $new
	if { $old != -1 } {
	    #$graph legend deactivate $old
	    $graph element deactivate $old
	    $graph marker configure activeLine -text ""
	    deactivateAxis $graph
	    showLineInfo $graph ""
	}
	#$graph legend activate $new
	$graph element activate $new
	$graph marker configure activeLine -text [getLineLabel $graph $new]
	activateAxis $graph $new
	set bltActiveEntry($graph) $new
	showLineInfo $graph $new
    } else {
        if {!$control} {
            clearSelectedLines $graph
        } else {
            removeSelectedLine $graph $new
        }
	$graph legend deactivate $new
	$graph element deactivate $new
	$graph marker configure activeLine -text ""
	deactivateAxis $graph
	showLineInfo $graph ""
	set bltActiveEntry($graph) -1
    }
}

proc BltAddBindTag { graph name } {
    set oldtags [bindtags $graph]
    if { [lsearch $oldtags $name] < 0 } {
	bindtags $graph [concat $name $oldtags]
    }
}

proc BltRemoveBindTag { graph name } {
    set tagList {}
    foreach tag [bindtags $graph] {
	if { $tag != $name } {
	    lappend tagList $tag
	}
    }
    bindtags $graph $tagList
}

proc BltGetCoords { graph x y index } {

    set y2 [$graph y2axis invtransform $y]
    set coords [$graph invtransform $x $y]
    set x [lindex $coords 0]
    set y [lindex $coords 1]

    scan [$graph xaxis limits] "%s %s" xmin xmax
    scan [$graph yaxis limits] "%s %s" ymin ymax
    scan [$graph y2axis limits] "%s %s" y2min y2max

    if { $x > $xmax } { 
	set x $xmax 
    } elseif { $x < $xmin } { 
	set x $xmin 
    }

    if { $y > $ymax } { 
	set y $ymax 
    } elseif { $y < $ymin } { 
	set y $ymin 
    }

    if { $y2 > $y2max } { 
	set y2 $y2max 
    } elseif { $y2 < $y2min } { 
	set y2 $y2min 
    }

    global bltZoom
    set bltZoom($graph,$index,x) $x
    set bltZoom($graph,$index,y) $y
    set bltZoom($graph,$index,y2) $y2
}

proc updateActiveLine {g} {
    global bltActiveEntry

    if {[info exists bltActiveEntry($g)] && $bltActiveEntry($g) != -1} {
	set e $bltActiveEntry($g)
	$g marker configure activeLine -text [getLineLabel $g $e]
    }
    showMarker $g activeLine
}

proc updateAllActiveLines {} {
    global bltActiveEntry

    foreach g [array names bltActiveEntry] {
	if {$bltActiveEntry($g) != -1} {
	    updateActiveLine $g
	}
    }
}

proc updateAllTimeAxis {} {
    global bltActiveEntry

    foreach g [array names bltActiveEntry] {
	if {$bltActiveEntry($g) != -1} {
	    chartMenuTime $g
	}
    }
}

proc BltPopZoom { graph } {
    global bltZoom

    set zoomStack $bltZoom($graph,stack)
    if { [llength $zoomStack] > 0 } {
	set cmd [lindex $zoomStack 0]
	set bltZoom($graph,stack) [lrange $zoomStack 1 end]
	eval $cmd
	BltZoomTitleLast $graph
	myBusyOn $graph
	set cmd [format {
            if {[winfo exists %s]} {
		if { $bltZoom(%s,corner) == "A" } {
		    %s marker delete "bltZoom_title"
		    updateActiveLine %s
		}
	    }
	} $graph $graph $graph $graph]
	after 2000 $cmd
	myBusyOff $graph
    } else {
	$graph marker delete "bltZoom_title"
        updateActiveLine $graph
    }
}

proc ZoomHorizontalPage {g i} {
    global vsd

    set limits [$g xaxis limits]
    set screenMin [$g xaxis transform [lindex $limits 0]]
    set screenMax [$g xaxis transform [lindex $limits 1]]
    set width [expr {($screenMax - $screenMin) - 1}]
    ZoomHorizontal $g [expr {$width * $i}]
}

proc ZoomHorizontal {g i} {
    global vsd

    set axisMin [$g xaxis cget -min]
    if {$axisMin != ""} {
	set screenMin [$g xaxis transform $axisMin]
	set axisMin [$g xaxis invtransform [expr {$screenMin + $i}]]
    }

    set axisMax [$g xaxis cget -max]
    if {$axisMax != ""} {
	set screenMax [$g xaxis transform $axisMax]
	set axisMax [$g xaxis invtransform [expr {$screenMax + $i}]]
    }

    if {$axisMin != "" || $axisMax != ""} {
	$g xaxis configure -min $axisMin -max $axisMax
	updateActiveLine $g
    }
}

proc ZoomVertical {g i} {
    global vsd
    # NYI
}

# Push the old axis limits on the stack and set the new ones

proc BltPushZoom { graph } {
    deleteAllZoomMarkers $graph

    global bltZoom
    set xA $bltZoom($graph,A,x)
    set yA $bltZoom($graph,A,y)
    set y2A $bltZoom($graph,A,y2)
    set xB $bltZoom($graph,B,x)
    set yB $bltZoom($graph,B,y)
    set y2B $bltZoom($graph,B,y2)

    if { ($xA == $xB) && ($yA == $yB) && ($y2A == $y2B) } { 
	# No delta, revert to start
	updateActiveLine $graph
	return
    }

    set cmd [format {
	%s xaxis configure -min "%s" -max "%s"
	%s yaxis configure -min "%s" -max "%s"
	%s y2axis configure -min "%s" -max "%s"
    } $graph [$graph xaxis cget -min] [$graph xaxis cget -max] \
      $graph [$graph yaxis cget -min] [$graph yaxis cget -max] \
      $graph [$graph y2axis cget -min] [$graph y2axis cget -max] ]

    if { $xA > $xB } { 
	$graph xaxis configure -min $xB -max $xA 
    } elseif { $xA < $xB } {
	$graph xaxis configure -min $xA -max $xB
    } 
    if { $yA > $yB } { 
	$graph yaxis configure -min $yB -max $yA
    } elseif { $yA < $yB } {
	$graph yaxis configure -min $yA -max $yB
    } 
    if { $y2A > $y2B } { 
	$graph y2axis configure -min $y2B -max $y2A
    } elseif { $y2A < $y2B } {
	$graph y2axis configure -min $y2A -max $y2B
    } 
    set bltZoom($graph,stack) [linsert $bltZoom($graph,stack) 0 $cmd]

    update
    updateActiveLine $graph
}

proc chartFinishOp {g} {
    global vsd
    $g config -cursor $vsd(graphcursor)
    set vsd($g:chartOp) {}
}

proc ChartHandleRightClick { graph } {
    global vsd

    chartCancelOp$vsd($graph:chartOp) $graph
    chartFinishOp $graph
}

proc deleteAllZoomMarkers {graph} {
    foreach e [$graph marker names "bltZoom_*"] {
	$graph marker delete $e
    }
}
proc chartCancelOpZoom { graph } {
    global bltZoom

    deleteAllZoomMarkers $graph
    showMarker $graph activeLine

    if { $bltZoom($graph,corner) == "A" } {
	# Reset the whole axis
	BltPopZoom $graph
    } else {
	set bltZoom($graph,corner) A
	bind $graph <Motion> { }
    }
}

proc chartCancelOpDelta { g } {
    global vsd
    unset vsd($g:deltaLine)
    if [info exists vsd($g:deltapoint1)] {
	unset vsd($g:deltapoint1)
    }
    bind $g <Any-Motion> { }
    $g marker delete "chartop_title"
    if [$g marker exists "delta_line"] {
	$g marker delete "delta_line"
    }
    showMarker $g activeLine
    chartFinishOp $g
}

proc chartCancelOpCompare { g } {
    global vsd
    if [info exists vsd($g:compareLine1)] {
	unset vsd($g:compareLine1)
    }
    if [info exists vsd($g:comparepoint1)] {
	unset vsd($g:comparepoint1)
    }
    bind $g <Any-Motion> { }
    $g marker delete "chartop_title"
    if [$g marker exists "compare_line"] {
	$g marker delete "compare_line"
    }
    showMarker $g activeLine
    chartFinishOp $g
}

proc chartCancelOpCombine { g } {
    global vsd
    bind $g <Any-Motion> { }
    $g marker delete "chartop_title"
    showMarker $g activeLine
    chartFinishOp $g
}

proc chartCancelOpMinTime { g } {
    $g marker delete "chartop_title"
    showMarker $g activeLine
    chartFinishOp $g
}

proc chartCancelOpMaxTime { g } {
    chartCancelOpMinTime $g
}

proc BltZoomTitleNext {graph} {
    global bltZoom vsd

    set level [expr {[llength $bltZoom($graph,stack)] + 1}]
    set title "Zoom #$level (right click to cancel)"
    $graph config -cursor bottom_right_corner
    hideMarker $graph activeLine
    $graph marker create text -name "bltZoom_title" -text $title \
	    -coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
}

proc BltZoomTitleLast {graph} {
    global bltZoom vsd

    set level [llength $bltZoom($graph,stack)]
    if { $level > 0 } {
	hideMarker $graph activeLine
	set title "Zoom #$level"
     	$graph marker create text -name "bltZoom_title" -text $title \
		-coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
    }
}

proc getSelectedLine {g} {
    global bltActiveEntry
    global bltActiveGraph

    set e $bltActiveGraph($g)
    if {$e != 0} {
	return $e
    }
    set e $bltActiveEntry($g)    
    if {$e != -1} {
	return $e
    }
    return ""
}

proc chartOp {graph x y control} {
    global vsd
    global bltActiveGraph

    set e $bltActiveGraph($graph)
    if {$e != 0} {
	activateElement $graph $e $control
    }
}

proc chartOpZoom {graph x y control} {
    global vsd
    global bltZoom

    BltGetCoords $graph $x $y $bltZoom($graph,corner)
    if { $bltZoom($graph,corner) == "A" } {
	# First corner selected, start watching motion events

	BltZoomTitleNext $graph 
	bind $graph <Any-Motion> { 
	    BltGetCoords %W %x %y B
	    BltBox %W
	}
	set bltZoom($graph,corner) B
    } else {
	bind $graph <Any-Motion> { }
	BltPushZoom $graph
	chartFinishOp $graph
	set bltZoom($graph,corner) A
    }
}

proc DeltaLine {g x y} {
    global vsd
    set yaxis [$g element cget $vsd($g:deltaLine) -mapy]
    set x1 [lindex $vsd($g:deltapoint1) 0]
    set y1 [lindex $vsd($g:deltapoint1) 1]
    set x2 [$g xaxis invtransform $x]
    set y2 [$g ${yaxis}axis invtransform $y]
    set coords {$x1 $y1 $x2 $y2}
    if [$g marker exists "delta_line"] {
	$g marker configure "delta_line" -coords $coords
    } else {
	$g marker create line -coords $coords -name "delta_line" -mapy $yaxis
    }
    if [$g element closest $x $y info -halo 5 -interpolate 0 $vsd($g:deltaLine)] {
	$g marker configure "delta_line" -outline $vsd(activecolor)
    } else {
	$g marker configure "delta_line" -outline black
    }
}

proc CompareLine {g x y} {
    global vsd
    set yaxis [$g element cget $vsd($g:compareLine1) -mapy]
    set x1 [lindex $vsd($g:comparepoint1) 0]
    set y1 [lindex $vsd($g:comparepoint1) 1]
    set x2 [$g xaxis invtransform $x]
    set y2 [$g ${yaxis}axis invtransform $y]
    set coords {$x1 $y1 $x2 $y2}
    if [$g marker exists "compare_line"] {
	$g marker configure "compare_line" -coords $coords
    } else {
	$g marker create line -coords $coords -name "compare_line" -mapy $yaxis
    }
    if [$g element closest $x $y info -halo 5 -interpolate 0] {
	$g marker configure "compare_line" -outline $vsd(activecolor)
    } else {
	$g marker configure "compare_line" -outline black
    }
}

proc showData {str {wrap 0}} {
    global vsd widgetHelp
    set w .datawin
    set exists [winfo exists $w]
    if $exists {
	raise $w
	wm deiconify $w
    } else {
	set widgetHelp($w) {Log Window}
	toplevel $w
	wm title $w "Vsd Data Log"
	if {$vsd(geometry:$w) != {}} {
	    wm geometry $w $vsd(geometry:$w)
	}
	frame $w.top -relief raised -bd 1
	tixScrolledText $w.top.msg -width 500 -height 220
	[$w.top.msg subwidget text] configure -wrap none -font fixedTextFont
	pack $w.top.msg -expand yes -fill both
	pack $w.top -side top -fill both -expand yes
    }

    if {$wrap} {
	[$w.top.msg subwidget text] configure -wrap word
    } else {
	[$w.top.msg subwidget text] configure -wrap none
    }
    [$w.top.msg subwidget text] insert end $str
    [$w.top.msg subwidget text] insert end "\n"
    [$w.top.msg subwidget text] see end
    setMasterBgColorForWindow $w
}

proc elapsedTime {mseconds} {
    set result ""
    set seconds [expr {wide($mseconds / 1000)}]
    set ms [ expr {wide($mseconds) % 1000}]
    if {$seconds >= 86400} {
	set days [expr {wide($seconds / 86400)}]
	set seconds [expr {$seconds % 86400}]
	append result " $days day"
	if {$days != 1} {
	    append result "s"
	}
	if {$seconds != 0} {
	    append result ","
	}
    }
    if {$seconds >= 3600} {
	set hours [expr {wide($seconds / 3600)}]
	set seconds [expr {$seconds % 3600}]
	append result " $hours hour"
	if {$hours != 1} {
	    append result "s"
	}
	if {$seconds != 0} {
	    append result ","
	}
    }
    if {$seconds >= 60} {
	set minutes [expr {wide($seconds / 60)}]
	set seconds [expr {$seconds % 60}]
	append result " $minutes minute"
	if {$minutes != 1} {
	    append result "s"
	}
	if {$seconds != 0} {
	    append result ","
	}
    }
    if {$seconds != 0 || $result == {}} {
       append result " $seconds"
       if {$ms != 0} {
         append result ".$ms"	      
       }
	append result " second"
	if {$seconds != 1} {
	    append result "s"
	}
    }
    return $result
}

proc xToStr {g x} {
    global vsd
    if {[string equal $vsd($g:xformat) "elapsed"]} {
	return [showElapsedOnTicks $g $x]
    } elseif {[string equal $vsd($g:xformat) "time"]} {
	return [showTimeOnTicks $g $x]
    } else {
	return [showDateOnTicks $g $x]
    }
}

proc chartOpDelta {g x y control} {
    global vsd

    set e $vsd($g:deltaLine)
    if [$g element closest $x $y info -halo 5 -interpolate 0 $e] {
	set scale [lindex [$vsd(ed:$e:$g) -info] 4]
	set coordinates "$info(x) $info(y) $scale"
    } else {
	# Was not over a valid point when left click happened so ignore
	return
    }
    if [info exists vsd($g:deltapoint1)] {
	# Spit the results out
	set linfo [$vsd(ed:$e:$g) -info]
	set x1 [lindex $vsd($g:deltapoint1) 0]
	set y1 [expr {[lindex $vsd($g:deltapoint1) 1] / [lindex $vsd($g:deltapoint1) 2]}]
	set x2 [lindex $coordinates 0]
	set y2 [expr {[lindex $coordinates 1] / [lindex $coordinates 2]}]
	set deltax [expr {$x2 - $x1}]
	set deltax [expr {abs($deltax)}]
	set deltay [expr {$y2 - $y1}]
	set units [getLineUnitDescription 0 $linfo]
	showData "\nDelta on [lrange $linfo 0 1]
  point1: [xToStr $g $x1], [stripFloat $y1]
  point2: [xToStr $g $x2], [stripFloat $y2]
  time delta =      [elapsedTime $deltax].
  value delta =      [stripFloat $deltay] $units."
	if {$deltax != 0} {
	    showData "  value/time delta = [expr {$deltay / $deltax}] $units per second."
	    set lstats [$vsd(ed:$e:$g) -stats $x1 $x2]
	    showData \
"  Of the [lindex $lstats 0] data points in this range:
    the min is:     [lindex $lstats 1]
    the max is:     [lindex $lstats 2]
    the average is: [lindex $lstats 3]
    the stddev is:  [lindex $lstats 4]"
	}
	chartCancelOpDelta $g
    } else {
	# Save coordinates into vsd($g:deltapoint1)
	set vsd($g:deltapoint1) $coordinates
	# start watching motion events
	$g config -cursor crosshair
	set title "Click on second data point, right click to cancel"
	$g marker create text -name "chartop_title" -text $title \
	    -coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
	bind $g <Any-Motion> { 
	    DeltaLine %W %x %y
	}
    }
}

proc chartCancelOpTrim { g } {
    global vsd
    unset vsd($g:trimLine)
    unset vsd($g:trimLeft)
    bind $g <Any-Motion> { }
    $g marker delete "chartop_title"
    showMarker $g activeLine
    chartFinishOp $g
}


proc chartOpTrim {g x y control} {
    global vsd

    set e $vsd($g:trimLine)
    if [$g element closest $x $y info -halo 5 -interpolate 0 $e] {
	set ts [expr {wide($info(x))}]
	if {$vsd($g:trimLeft)} {
	    if {$ts == 0} {
		# can't trim left the very first point as it would be treated
		# as an untrim. Besides it would be a noop since "ts" is the
		# first timestamp to keep.
		return
	    }
	    $vsd(ed:$e:$g) -trimleft $ts
	} else {
	    $vsd(ed:$e:$g) -trimright $ts
	}
	chartCancelOpTrim $g
	trimUpdate $g $e
    } else {
	# Was not over a valid point when left click happened so ignore
	return
    }
}

proc chartOpCompare {g x y control} {
    global vsd

    if [$g element closest $x $y info -halo 5 -interpolate 0] {
	set e $info(name)
	set scale [lindex [$vsd(ed:$e:$g) -info] 4]
	set coordinates "$info(x) $info(y) $scale"
    } else {
	# Was not over a valid point when left click happened so ignore
	return
    }
    if [info exists vsd($g:comparepoint1)] {
	# Spit the results out
	set e1 $vsd($g:compareLine1)
	set e2 $e
	set sameline [expr {$e1 == $e2}]
	set linfo [$vsd(ed:$e1:$g) -info]
	set units [getLineUnitDescription 0 $linfo]
	set lname "\"[lrange $linfo 0 1]\""
	set header "Comparing data from $lname"
	if {!$sameline} {
	    set linfo2 [$vsd(ed:$e2:$g) -info]
	    set l2name "\"[lrange $linfo2 0 1]\""
	    set units2 [getLineUnitDescription 0 $linfo2]
	    if {![string equal $units $units2]} {
		append units "&$units2"
	    }
	    append header " and $l2name"
	}
	set x1 [lindex $vsd($g:comparepoint1) 0]
	set y1 [expr {[lindex $vsd($g:comparepoint1) 1] / [lindex $vsd($g:comparepoint1) 2]}]
	set x2 [lindex $coordinates 0]
	set y2 [expr {[lindex $coordinates 1] / [lindex $coordinates 2]}]
	set deltax [expr {$x2 - $x1}]
	set deltax [expr {abs($deltax)}]
	set deltay [expr {$y2 - $y1}]
	showData "\n$header
  point1: [xToStr $g $x1], [stripFloat $y1]
  point2: [xToStr $g $x2], [stripFloat $y2]
  time delta =      [elapsedTime $deltax].
  value delta =      [stripFloat $deltay] $units."
	if {$deltax != 0} {
	    showData "  value/time delta = [expr {$deltay / $deltax}] $units per second."
	    set lstats [$vsd(ed:$e1:$g) -stats $x1 $x2]
	    showData \
"  Of the [lindex $lstats 0] $lname points in this range:
    the min is:     [lindex $lstats 1]
    the max is:     [lindex $lstats 2]
    the average is: [lindex $lstats 3]
    the stddev is:  [lindex $lstats 4]"
            if {!$sameline} {
		set lstats [$vsd(ed:$e2:$g) -stats $x1 $x2]
		showData \
"  Of the [lindex $lstats 0] $l2name points in this range:
    the min is:     [lindex $lstats 1]
    the max is:     [lindex $lstats 2]
    the average is: [lindex $lstats 3]
    the stddev is:  [lindex $lstats 4]"
            }
	}
	chartCancelOpCompare $g
    } else {
	# Save coordinates into vsd($g:comparepoint1)
	set vsd($g:compareLine1) $e
	set vsd($g:comparepoint1) $coordinates
	$g config -cursor crosshair
	set title "Click on second data point, right click to cancel"
	$g marker create text -name "chartop_title" -text $title \
	    -coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
	# start watching motion events
	bind $g <Any-Motion> { 
	    CompareLine %W %x %y
	}
    }
}

proc chartOpMinTime {g x y control} {
    global vsd

    set x [$g xaxis invtransform $x]
    set xmin [lindex [$g xaxis limits] 0]
    if {$x >= $xmin} {
	$g xaxis configure -min $x
    } else {
	# reset as if no min was ever set
	$g xaxis configure -min ""
    }
    chartCancelOpMinTime $g
}

proc chartOpMaxTime {g x y control} {
    global vsd

    set x [$g xaxis invtransform $x]
    set xmax [lindex [$g xaxis limits] 1]
    if {$x <= $xmax} {
	$g xaxis configure -max $x
    } else {
	# reset as if no max was ever set
	$g xaxis configure -max ""
    }
    chartCancelOpMaxTime $g
}

proc chartOpCombine {g x y control} {
    global vsd

    set e2 [getSelectedLine $g]
    if {$e2 == {}} {
	return
    }
    set e1 [lindex $vsd($g:combineData) 0]
    if {$e2 == $e1} {
	return
    }
    set op [lindex $vsd($g:combineData) 1] 
    set l1 $vsd(ed:$e1:$g)
    set l2 $vsd(ed:$e2:$g)

    addDerivedLine [list $l1 $l2] $op

    chartCancelOpCombine $g
}

proc ChartHandleLeftClick {graph x y control} {
    global vsd

    focus $graph

    set legEntry [$graph legend get @$x,$y]
    if {$legEntry != {}} {
	activateElement $graph $legEntry $control
	if {![string equal $vsd($graph:chartOp) "Combine"]} {
	    return
	}
    }

    chartOp$vsd($graph:chartOp) $graph $x $y $control
}

proc quickZoom {g x y} {
    global vsd

    set gx [$g xaxis invtransform $x]
    set xlimits [$g xaxis limits]
    set xMinLimit [lindex $xlimits 0]
    set xMaxLimit [lindex $xlimits 1]
    if {$gx < $xMinLimit || $gx > $xMaxLimit} {
	return
    }
    set gy [$g yaxis invtransform $y]
    set ylimits [$g yaxis limits]
    if {$gy < [lindex $ylimits 0] || $gy > [lindex $ylimits 1]} {
	return
    }

    set cmd [format {
	%s xaxis configure -min "%s" -max "%s"
    } $g [$g xaxis cget -min] [$g xaxis cget -max] ]

    #We want to center 'gx' in the middle of the graph and reduce
    #the amount of X data displayed by half.
    set xrange [expr {wide(($xMaxLimit - $xMinLimit) / 4)}]
    set xmin [expr {($gx - $xrange)}]
    if {$xmin <= $xMinLimit} {
	set xmin [$g xaxis cget -min]
    }
    set xmax [expr {$gx + $xrange}]
    if {$xmax >= $xMaxLimit} {
	set xmax [$g xaxis cget -max]
    }

    set xminVal $xmin
    if {$xminVal == ""} {
	set xminVal $xMinLimit
    }
    set xmaxVal $xmax
    if {$xmaxVal == ""} {
	set xmaxVal $xMaxLimit
    }
    if {$xminVal < $xmaxVal} {
	$g xaxis configure -min $xmin -max $xmax

	global bltZoom
	set bltZoom($g,stack) [linsert $bltZoom($g,stack) 0 $cmd]
	updateActiveLine $g
    }
}

proc ChartHandleMiddleClick {graph x y} {
    global vsd

    focus $graph

    set legEntry [$graph legend get @$x,$y]
    if {$legEntry != {}} {
	deleteElement $graph $legEntry
    } else {
	quickZoom $graph $x $y
    }
}

proc BltBox {graph} {
    global bltZoom

    if { $bltZoom($graph,A,x) > $bltZoom($graph,B,x) } { 
	set x1 $bltZoom($graph,B,x)
	set x2 $bltZoom($graph,A,x) 
	set y1 $bltZoom($graph,B,y)
	set y2 $bltZoom($graph,A,y) 
    } else {
	set x1 $bltZoom($graph,A,x)
	set x2 $bltZoom($graph,B,x) 
	set y1 $bltZoom($graph,A,y)
	set y2 $bltZoom($graph,B,y) 
    }
    set coords {
	$x1 $y1 $x1 $y2 $x1 $y1 $x2 $y1 $x2 $y1 $x2 $y2 $x1 $y2 $x2 $y2 
    }
    if [$graph marker exists "bltZoom_outline"] {
	$graph marker configure "bltZoom_outline" -coords $coords
    } else {
	$graph marker create line -coords $coords -name "bltZoom_outline" \
	    -dashes { 4 2 }
    }
}

######################## start of vsd code #####################


proc searchHelp {w str {next 0} {forwards 1}} {
    global vsd
    if {$str == ""} {
	return
    }
    if {$forwards} {
	set direction "-forwards"
    } else {
	set direction "-backwards"
    }
    if [info exists vsd($w:searchidx)] {
	set idx $vsd($w:searchidx)
	if {$next} {
	    if {$forwards} {
		set idx [$w index "$idx +1chars"]
	    } else {
		set idx [$w index "$idx -1chars"]
	    }
	}
    } else {
	set idx "end"
    }
    set idx [$w search $direction -exact -nocase -- $str $idx]
    if {$idx == {}} {
	$w tag remove sel 1.0 end
	setStatus "Could not find \"$str\"."
	if {[string first $vsd(search:unfound) $str] != 0} {
	    set vsd(search:unfound) $str
	    bell
	}
    } else {
	$w see $idx
	$w tag remove sel 1.0 end
	$w tag add sel $idx "$idx +[string length $str]chars"
# Note - setting background color for the "sel" tag is broken.
#        This should work but does not:
#
#     $w configure -selectbackground yellow
#
# Next 2 lines are needed to fix 45176
        $w tag configure sel -foreground yellow
        $w tag raise sel
	set vsd($w:searchidx) $idx
    }
}

proc followHelpLink {w key} {
    doHelp $key $w
}

proc getHelpText {msgKey} {
    global vsdhelp
    set text $vsdhelp($msgKey)
    if [string match {TCLEVAL *} $text] {
	set cmd [lindex $text 1]
	set arglist [lindex $text 2]
	set text [$cmd $arglist]
    }
    return [string trimleft $text "\n"]
}

proc helpRefresh {w} {
    global vsdLinkVisited
    catch {unset vsdLinkVisited}
    restartVsd
    doHelp refresh $w
}

proc isHiddenTopic {topic} {
    expr {[string first "Topics that contain" $topic] == 0 ||
	  [lsearch -exact {"All Topics" "All Help Text" "All Statistics"} $topic] != -1}
}

proc searchAllTopics {} {
    global vsd vsdhelp
    set p $vsd(search:parent)
    set searchString [string tolower $vsd($p:st)]
    if {$searchString == {}} {
	return
    }
    
    myBusyOn .vsdhelpsearch

    set searchTopic "Topics that contain \"$searchString\":"
    if {![info exists vsdhelp($searchTopic)]} {
	set searchText ""
	foreach topic [lsort [array names vsdhelp]] {
	    if [isHiddenTopic $topic] {
		continue
	    }
	    if {[string first $searchString [string tolower $topic]] == -1} {
		set text [string tolower [getHelpText $topic]]
		if {[string first $searchString $text] == -1} {
		    continue
		}
	    }
	    append searchText "*\[" $topic "]\n"
	}
	if {$searchText == {}} {
	    set searchText "\n<em>no topics found</em>"
	}
	set vsdhelp($searchTopic) $searchText
    }
    doHelp $searchTopic [winfo toplevel $p]
    myBusyOff .vsdhelpsearch
}

proc allHelpWindows {} {
    set result {}
    foreach w [winfo children .] {
	if {[string first ".help" $w] == 0} {
	    lappend result $w
	}
    }
    return $result
}

proc rememberPosition {w} {
    global vsd
    set idx $vsd($w:helpHistoryIdx)
    set textw [$w.top.msg subwidget text]
    set vsd($w:historyPositions) [lreplace $vsd($w:historyPositions) $idx $idx [lindex [$textw yview] 0]]
}

proc closeHelpWindow {w} {
    global vsd

    #Do a focus so that the search window will go away
    focus $w
    update
    catch {unset vsd($w:helpHistoryIdx)}
    catch {unset vsd($w:helpHistory)}
    catch {unset vsd($w:historyPositions)}
    catch {unset vsd($w:normalCursor)}
    catch {unset vsd($w:hlinkCount)}
    destroy $w
}

proc doHelp {msgKey {w {}} {doFocus 1}} {
    global vsd vsdhelp vsdLinkVisited
    set doHistory 0
    if {[string equal $msgKey "back"]} {
	if {$vsd($w:helpHistoryIdx) == 0} {
	    setStatus "nothing to go back to."
	    bell
	    return
	}
	rememberPosition $w
	incr vsd($w:helpHistoryIdx) -1
	set doHistory 1
    } elseif {[string equal $msgKey "forward"]} {
	if {($vsd($w:helpHistoryIdx) + 1) == [llength $vsd($w:helpHistory)]} {
	    setStatus "nothing to go foward to."
	    bell
	    return
	}
	rememberPosition $w
	incr vsd($w:helpHistoryIdx)
	set doHistory 1
    } elseif {[string equal $msgKey "refresh"]} {
	set doHistory 1
    }
    if {$doHistory} {
	set msgKey [lindex $vsd($w:helpHistory) $vsd($w:helpHistoryIdx)]
    }
    if {![info exists vsdhelp($msgKey)]} {
	setStatus "no help for '$msgKey'."
	bell
	return
    }

    set vsdLinkVisited($msgKey) 1

    if {$w == {}} {
	# Look for a window that is already displaying this topic
	foreach w [allHelpWindows] {
	    set topic [lindex $vsd($w:helpHistory) $vsd($w:helpHistoryIdx)]
	    if {[string equal $topic $msgKey]} {
		# found an existing help window
		wm deiconify $w
		if {$doFocus} {
		    focus $w
		}
		raise $w
		return
	    }
	}
	if {$doFocus} {
	       # if doFocus is FALSE we end up using the last help window for
	       # this topic instead of always creating a new window. This the
	       # case for context sensitive help. if doFocus is TRUE then we
	       # need to clear $w so we will create a new window. This is the
	       # case of when a link was middle clicked on.
	    set w {}
	}
    }
    
    if {$w != {} && [winfo exists $w]} {
	wm deiconify $w
	if {$doFocus} {
	    focus $w
	}
	raise $w
	set textw [$w.top.msg subwidget text]
	if {!$doHistory} {
	    set currentTopic [lindex $vsd($w:helpHistory) $vsd($w:helpHistoryIdx)]
	    if {[string equal $currentTopic $msgKey]} {
		# Window already contains requested topic
		return
	    }
	       set vsd($w:historyPositions) \
		   [lreplace $vsd($w:historyPositions) $vsd($w:helpHistoryIdx) \
			     $vsd($w:helpHistoryIdx) [lindex [$textw yview] 0]]
	    incr vsd($w:helpHistoryIdx)
	    if {$vsd($w:helpHistoryIdx) == [llength $vsd($w:helpHistory)]} {
		lappend vsd($w:helpHistory) $msgKey
		lappend vsd($w:historyPositions) 0
	    } else {
		   set vsd($w:helpHistory) \
		       [lreplace $vsd($w:helpHistory) $vsd($w:helpHistoryIdx) end $msgKey]
		   set vsd($w:historyPositions) \
		       [lreplace $vsd($w:historyPositions) $vsd($w:helpHistoryIdx) end 0]
	    }
	}
	$textw configure -state normal
	$textw configure -cursor $vsd($w:normalCursor)
	$textw delete "1.0" end
	$textw tag delete bulletItem bold fixed italic underline
	while {$vsd($w:hlinkCount) > 0} {
	    $textw tag delete "hlink$vsd($w:hlinkCount)"
	    incr vsd($w:hlinkCount) -1
	}
        foreach wn [$textw window names] {
	    destroy $wn
	}
    } else {
	incr vsd(helpIdx)
	set w ".help$vsd(helpIdx)"
	toplevel $w

	global widgetHelp isWindows
	set widgetHelp($w) {Help Window Features}

	frame $w.top -relief raised -bd 1

	tixScrolledText $w.top.msg -scrollbar y -width 400
	pack $w.top.msg -expand yes -fill both

	set textw [$w.top.msg subwidget text]

# fix 45174
	$textw configure -font normalTextFont

	bind $w <Control-s> \
	    [list startSearch $textw searchHelp 0 .vsdhelpsearch]

	bind $w <Control-b> "doHelp back $w; break"
	bind $w <Control-f> "doHelp forward $w; break"

	bind $w <Down>  "$textw yview scroll +1 units; break"
	bind $w <Up>    "$textw yview scroll -1 units; break"
	bind $w <Next>  "$textw yview scroll +1 pages; break"
	bind $w <Prior> "$textw yview scroll -1 pages; break"
	bind $w <Home>  "$textw yview moveto 0; break"
	bind $w <End>   "$textw yview moveto 1; break"
	if [wizardMode] {
	    bind $w <F4> [list helpRefresh $w]
	}

	tixButtonBox $w.box
	$w.box add back -text Back -width 6 -command "doHelp back $w"
	$w.box add forward -text Forward -width 6 -command "doHelp forward $w"
	$w.box add search -text Search... -width 6 \
	    -command [list startSearch $textw searchHelp 0 .vsdhelpsearch]
	$w.box add dismiss -text Dismiss -width 6 -command [list closeHelpWindow $w]
	set but [$w.box subwidget dismiss]
	wm protocol $w WM_DELETE_WINDOW [list closeHelpWindow $w]

	pack $w.box -fill x -side bottom
	pack $w.top -side top -fill both -expand yes

	set vsd($w:normalCursor) [$textw cget -cursor]
	
	set vsd($w:helpHistory) [list $msgKey]
	set vsd($w:historyPositions) {0}
	set vsd($w:helpHistoryIdx) 0
	set vsd($w:hlinkCount) 0
    }
    if {[string match "Help*" $msgKey]} {
	wm title $w $msgKey
    } else {
	wm title $w "Help: $msgKey"
    }

    set b [$w.box subwidget back]
    if {$vsd($w:helpHistoryIdx) == 0} {
	$b configure -state disabled
    } else {
	$b configure -state normal
    }
    set b [$w.box subwidget forward]
    if {($vsd($w:helpHistoryIdx) + 1) == [llength $vsd($w:helpHistory)]} {
	$b configure -state disabled
    } else {
	$b configure -state normal
    }

    $textw tag configure bold -font boldTextFont
    $textw tag configure italic -font italicTextFont
    $textw tag configure fixed -font fixedTextFont
    $textw tag configure underline -underline 1
    $textw tag configure bulletItem -lmargin1 10 -lmargin2 30
    $textw tag configure bulletItem2 -lmargin1 30 -lmargin2 50
    $textw tag configure bulletItem3 -lmargin1 50 -lmargin2 70

#     $textw insert 1.0 "    $msgKey\n"
#     $textw tag add bold 1.0 "1.0 lineend"

    $textw insert end [getHelpText $msgKey]
    
    # decorate headers
    set idx [$textw search -forwards -regexp -- {^!} "1.0" end]
    while {$idx != {}} {
	# get rid of the exclamation point
	$textw delete $idx
	$textw tag add bold $idx "$idx lineend"
	set idx [$textw search -forwards -regexp -- {^!} $idx end]
    }
    
    # decorate bullet list items
    set idx [$textw search -forwards -regexp -- {^   \* } "1.0" end]
    while {$idx != {}} {
	# get rid of the '   * ' marker
	$textw delete $idx "$idx +5c"
	set imageIdx [$textw image create $idx -image $vsd(bulletImage) -align center -padx 3]
	$textw tag add bulletItem $imageIdx "$idx lineend"
	set idx [$textw search -forwards -regexp -- {^   \* } $idx end]
    }

    # decorate bullet2 list items
    set idx [$textw search -forwards -regexp -- {^      \* } "1.0" end]
    while {$idx != {}} {
	# get rid of the '      * ' marker
	$textw delete $idx "$idx +8c"
	set imageIdx [$textw image create $idx -image $vsd(bulletImage) -align center -padx 3]
	$textw tag add bulletItem2 $imageIdx "$idx lineend"
	set idx [$textw search -forwards -regexp -- {^      \* } $idx end]
    }

    # decorate bullet3 list items
    set idx [$textw search -forwards -regexp -- {^         \* } "1.0" end]
    while {$idx != {}} {
	# get rid of the '         * ' marker
	$textw delete $idx "$idx +11c"
	set imageIdx [$textw image create $idx -image $vsd(bulletImage) -align center -padx 3]
	$textw tag add bulletItem3 $imageIdx "$idx lineend"
	set idx [$textw search -forwards -regexp -- {^         \* } $idx end]
    }

    # decorate numbered list items
    set idx [$textw search -forwards -regexp -- {^   1 } "1.0" end]
    while {$idx != {}} {
	set itemCount 0
	while {1} {
	    incr itemCount
	    # get rid of the '   1 ' marker
	    $textw delete $idx  "$idx +5c"
	    $textw insert $idx " ${itemCount}. "
	    $textw tag add bulletItem $idx "$idx lineend"
	    set idx [$textw index "$idx +1lines linestart"]
	    if {![string equal {   1 } [$textw get $idx "$idx +5c"]]} {
		break
	    }
	}
	set idx [$textw search -forwards -regexp -- {^   1 } $idx end]
    }

    # decorate numbered list items
    set idx [$textw search -forwards -regexp -- {^      1 } "1.0" end]
    while {$idx != {}} {
	set itemCount 0
	while {1} {
	    incr itemCount
	    # get rid of the '      1 ' marker
	    $textw delete $idx  "$idx +8c"
	    $textw insert $idx " ${itemCount}. "
	    $textw tag add bulletItem2 $idx "$idx lineend"
	    set idx [$textw index "$idx +1lines linestart"]
	    if {![string equal {      1 } [$textw get $idx "$idx +8c"]]} {
		break
	    }
	}
	set idx [$textw search -forwards -regexp -- {^      1 } $idx end]
    }

    # decorate <b>...</b> tags
    set idx [$textw search -forwards -exact -- {<b>} "1.0" end]
    while {$idx != {}} {
	# get rid of the '<b>' marker
	$textw delete $idx "$idx +3c"
	set idx2 [$textw search -forwards -exact -- {</b>} $idx "$idx lineend"]
	if {$idx2 == {}} {
	    setStatus "missing </b> in help"
	    bell
	    set idx [$textw index "$idx +1c"]
	} else {
	    # get rid of the '</b>' marker
	    $textw delete $idx2 "$idx2 +4c"
	    $textw tag add bold $idx $idx2
	    set idx $idx2
	}
	set idx [$textw search -forwards -exact -- {<b>} $idx end]
    }
    
    # decorate <u>...</u> tags
    set idx [$textw search -forwards -exact -- {<u>} "1.0" end]
    while {$idx != {}} {
	# get rid of the '<u>' marker
	$textw delete $idx "$idx +3c"
	set idx2 [$textw search -forwards -exact -- {</u>} $idx "$idx lineend"]
	if {$idx2 == {}} {
	    setStatus "missing </u> in help"
	    bell
	    set idx [$textw index "$idx +1c"]
	} else {
	    # get rid of the '</u>' marker
	    $textw delete $idx2 "$idx2 +4c"
	    $textw tag add underline $idx $idx2
	    set idx $idx2
	}
	set idx [$textw search -forwards -exact -- {<u>} $idx end]
    }
    
    # decorate <tt>...</tt> tags
    set idx [$textw search -forwards -exact -- {<tt>} "1.0" end]
    while {$idx != {}} {
	# get rid of the '<tt>' marker
	$textw delete $idx "$idx +4c"
	set idx2 [$textw search -forwards -exact -- {</tt>} $idx "$idx lineend"]
	if {$idx2 == {}} {
	    setStatus "missing </tt> in help"
	    bell
	    set idx [$textw index "$idx +1c"]
	} else {
	    # get rid of the '</tt>' marker
	    $textw delete $idx2 "$idx2 +5c"
	    $textw tag add fixed $idx $idx2
	    set idx $idx2
	}
	set idx [$textw search -forwards -exact -- {<tt>} $idx end]
    }
    
    # decorate <em>...</em> tags
    set idx [$textw search -forwards -exact -- {<em>} "1.0" end]
    while {$idx != {}} {
	# get rid of the '<em>' marker
	$textw delete $idx "$idx +4c"
	set idx2 [$textw search -forwards -exact -- {</em>} $idx "$idx lineend"]
	if {$idx2 == {}} {
	    setStatus "missing </em> in help"
	    bell
	    set idx [$textw index "$idx +1c"]
	} else {
	    # get rid of the '</em>' marker
	    $textw delete $idx2 "$idx2 +5c"
	    $textw tag add italic $idx $idx2
	    set idx $idx2
	}
	set idx [$textw search -forwards -exact -- {<em>} $idx end]
    }

    # decorate ----
    set idx [$textw search -forwards -regexp -- {^----} "1.0" end]
    while {$idx != {}} {
	# get rid of the '----' marker
	$textw delete $idx "$idx +4c"
	incr vsd(ruleCount)
	set fn "$textw.rule$vsd(ruleCount)"
	frame $fn -relief raised -borderwidth 3 -height 6 -width 300
	$textw window create $idx -window $fn -align center -padx 20 -pady 8
	set idx [$textw search -forwards -regexp -- {^----} $idx end]
    }
    
    # decorate hlinks
    set idx [$textw search -forwards -exact -- \[ "1.0" end]
    while {$idx != {}} {
	# get rid of the '[' marker
	$textw delete $idx
	if {[string equal [$textw get $idx] "\["]} {
	    # [[ escapes the bracket
	    set idx [$textw index "$idx +1c"]
	} else {
	    set idx2 [$textw search -forwards -exact -- \] $idx "$idx lineend"]
	    if {$idx2 == {}} {
		setStatus "missing ']' in help"
		bell
		set idx [$textw index "$idx +1c"]
	    } else {
		# get rid of the ']' marker
		$textw delete $idx2
		incr vsd($w:hlinkCount)
		set hlinkName "hlink$vsd($w:hlinkCount)"
		set hlinkText [$textw get $idx $idx2]
		if {[string first ">" $hlinkText] != -1} {
		    set hlinkList [split $hlinkText ">"]
		    set hlinkDisplay [string trim [lindex $hlinkList 0]]
		    set hlinkText [string trim [lindex $hlinkList 1]]
		    set newIdx2 [$textw index  "$idx +[string length $hlinkDisplay]c"]
		    $textw delete $newIdx2 $idx2
		    set idx2 $newIdx2
		}
		if {[info exists vsdhelp($hlinkText)]} {
		    set brokenLink 0
		} else {
		    set brokenLink 1
		}
		if {$brokenLink && [wizardMode]} {
		    puts "warning: help link '$hlinkText' does not exist."
		}
		$textw tag add $hlinkName $idx $idx2
		if {$brokenLink} {
		    $textw tag configure $hlinkName -underline 1 -foreground $vsd(brokenLinkColor)
		} elseif [info exists vsdLinkVisited($hlinkText)] {
		    $textw tag configure $hlinkName -underline 1 -foreground $vsd(visitedLinkColor)
		} else {
		    $textw tag configure $hlinkName -underline 1 -foreground $vsd(normalLinkColor)
		}
		$textw tag bind $hlinkName <1> [list followHelpLink $w $hlinkText]
		$textw tag bind $hlinkName <Control-1> [list followHelpLink {} $hlinkText]
		$textw tag bind $hlinkName <2> [list followHelpLink {} $hlinkText]
		$textw tag bind $hlinkName <3> [list followHelpLink {} $hlinkText]
		$textw tag bind $hlinkName <Enter> "$textw configure -cursor hand2"
		$textw tag bind $hlinkName <Leave> "$textw configure -cursor $vsd($w:normalCursor)"
		set idx $idx2
	    }
	}
	set idx [$textw search -forwards -exact -- \[ $idx end]
    }
    # do special character substitutions
    set idx [$textw search -forwards -exact -- {&#91;} "1.0" end]
    while {$idx != {}} {
	$textw insert "$idx" \[
	$textw delete "$idx +1c" "$idx +6c"
	set idx [$textw search -forwards -exact -- {&#91;} $idx end]
    }

    $textw configure -state disabled -wrap word
    if {$doHistory} {
	$textw yview moveto [lindex $vsd($w:historyPositions) $vsd($w:helpHistoryIdx)]
    }
    setMasterBgColorForWindow $w
}

event add <<Help>> <KeyPress-F1> <KeyPress-Help>
bind all <<Help>> {ContextSensitiveHelp %W}

proc ContextSensitiveHelp {w} {
    global widgetHelp
    while {$w != ""} {
	if [info exists widgetHelp($w)] {
	    doHelp $widgetHelp($w) {} 0
	    return
	}
	set w [winfo parent $w]
    }
    setStatus "no help available"
    bell
}

proc showChartHelp {} {
    doHelp "Chart Window Features"
}

proc showMainHelp {} {
    doHelp "Main Window Features"
}

proc HowToHelp {} {
    global vsdhelp
    set howtoTopic "How To Guide"
    if {![info exists vsdhelp($howtoTopic)]} {
	set help {}
	foreach topic [lsort [array names vsdhelp]] {
	    if [string match {*How to*} $topic] {
		append help "*\[$topic]\n"
	    }
	}
	set vsdhelp($howtoTopic) $help
    }
    doHelp $howtoTopic
}

proc wizardMode {} {
    global env vsd
    return [expr {[info exists env(VSD_WIZARD)] || [info exists vsd(wizard)]}]
}

proc allHelp {} {
    global vsdhelp
    set allTopic "All Topics"
    if [wizardMode] {
	catch {unset vsdhelp($allTopic)}
    }
    if {![info exists vsdhelp($allTopic)]} {
	set help {}
	foreach topic [lsort [array names vsdhelp]] {
	    if [isHiddenTopic $topic] {
		continue
	    }
	    append help "*\[" $topic "]\n"
	}
	set vsdhelp($allTopic) $help
    }
    doHelp $allTopic
}

proc allFlatHelp {} {
    global vsdhelp
    set allTopic "All Help Text"
    if [wizardMode] {
	catch {unset vsdhelp($allTopic)}
    }
    if {![info exists vsdhelp($allTopic)]} {
	set help {}
	foreach topic [lsort [array names vsdhelp]] {
	    if [isHiddenTopic $topic] {
		continue
	    }
	    append help "----\n"
	    append help "!\t$topic\n"
	    append help [getHelpText $topic]
	}
	set vsdhelp($allTopic) $help
    }
    doHelp $allTopic
}

proc showAboutHelp {} {
    doHelp "About VSD"
}

proc UsageVSD {parent} {
    global vsd
    if {$vsd(warningGiven)} {
	return
    }
    set vsd(warningGiven) 1

    set usagevsd "Problem reports and enhancement requests should be sent to $vsd(maintainer).
If you want to use VSD, even though it is unsupported, click 'Yes'.
If you want to quit now, click 'No'."

    if {[info commands tk_messageBox] != ""} {
	set response [tk_messageBox -title "VSD Usage Notice" \
			  -parent $parent -icon question -type yesno \
			  -default yes -message $usagevsd]
	if {[string equal $response "no"]} {
	    exit
	}
    } else {
	set w [tixDialogShell .usagevsd -parent $parent \
	       -title "VSD Usage Notice"]

	frame $w.top -relief raised -bd 1
	pack $w.top -side top -fill both -expand yes

	tixScrolledText $w.top.msg -scrollbar y -width 410 -height 150
	[$w.top.msg subwidget text] insert end $usagevsd
	[$w.top.msg subwidget text] configure -state disabled -wrap word
	pack $w.top.msg -expand yes -fill both

	tixButtonBox $w.box
	$w.box add continue -text "Yes" -width 4 \
	    -command "destroy $w"
	$w.box add quit -text "No" -width 4 \
	    -command "destroy $w; exit"
	pack $w.box -fill x -side bottom
	$w popup
    }
}

if {[info commands tk_messageBox] != ""} {
  # use tk_messageBox
  proc makeErrorDialog {w} {
    # do nothing
  }

  proc showError {msg} {
    global vsd
    tk_messageBox -icon error -parent $vsd(w) -title "Error" -message $msg \
	-type ok
  }

  proc fatalError {msg} {
    showError $msg
    exit
  }

} else {
  proc makeErrorDialog {w} {
    global vsd
    set d [tixDialogShell .vsderror -parent $w -title "Error"]
    set vsd(dlg:error) $d

    frame $d.top -relief raised -bd 1
    pack $d.top -side top -fill both

    label $d.top.msg -wraplength 3i -justify left -text "foo" \
	    -font -Adobe-Times-Medium-R-Normal--*-180-*-*-*-*-*-*
    pack $d.top.msg -side right -expand 1 -fill both -padx 3m -pady 3m
    label $d.top.bitmap -bitmap "error"
    pack $d.top.bitmap -side left -padx 3m -pady 3m

    tixButtonBox $d.box
    $d.box add dismiss -text Dismiss -width 6 -underline 0 \
	-command {$vsd(dlg:error) popdown; set vsd(fatalError) 1}
    set but [$d.box subwidget dismiss]
    bind $d <Alt-d> "$but invoke"
    pack $d.box -fill x -expand yes -side bottom
  }

  proc showError {msg} {
    global vsd
    set w $vsd(dlg:error)
    $w.top.msg configure -text $msg
    regexp {(.*x.*)(\+.*\+.*)} [wm geometry $vsd(w)] junk parentSize parentPosition
    wm geometry $w $parentPosition
    $w popup
  }

  proc fatalError {msg} {
    global vsd
    set vsd(fatalError) 0
    showError $msg
    tkwait variable vsd(fatalError)
    exit
  }
}

proc replayLog {str} {
    # NYI
}

proc writeTemplateFile {} {
   global vsd vsdtemplates

    if [catch {open "~/.vsdtemplates" w+} initFile] {
        showError "Notice: could not write '~/.vsdtemplates' because:\n$initFile"
	return
    }
    puts $initFile {
# See the vsd help section 'Template Syntax' for a guide to editing this file.
}

    foreach tn [lsort [array names vsdtemplates]] {
	puts $initFile "set vsdtemplates($tn) [list $vsdtemplates($tn)]"
    }

    close $initFile
}

proc addFileListMap {dfid} {
    global filelistMap
    set key [getFileInfoName $dfid]
    set filelistMap($key) $dfid
    return $key
}

proc getFullFileName {fi} {
    global filelistMap
    if [info exists filelistMap($fi)] {
	return [lindex [$filelistMap($fi) -info] 0]
    } else {
	return $fi
    }
}

proc writeStartupFile {} {
    global vsd vsdtemplates

    if [catch {open "~/.vsdrc_tmp" w+} initFile] {
        showError "Notice: could not write '~/.vsdrc' because:\n$initFile"
	return
    }
puts $initFile "\# .vsdrc is written whenever vsd exits normally.
\# Each time vsd is started it reads .vsdrc and will use the configuration
\# values in it. If you want to always have some other default put it
\# in .vsdconfig. Any user changes to .vsdrc will be lost the next time
\# vsd exits.
"
    puts $initFile "set vsd(confirmonexit) $vsd(confirmonexit)"
    puts $initFile "set vsd(warningGiven) $vsd(warningGiven)"
    if 0 {
	puts $initFile "set vsd(timesync) [list $vsd(timesync)]"
    }
    foreach cw $vsd(winnames) {
	if [winfo exists $cw] {
	    set vsd(geometry:$cw) [wm geometry $cw]
	}
	puts $initFile "set vsd(geometry:$cw) [list $vsd(geometry:$cw)]"
    }

    puts $initFile "set vsd(def:geometry) [wm geometry $vsd(w)]"
    puts $initFile "set vsd(autoUpdateTime) [list $vsd(autoUpdateTime)]"
    puts $initFile "set vsd(def:showlegend) [list $vsd(def:showlegend)]"
    puts $initFile "set vsd(def:xformat) [list $vsd(def:xformat)]"
    puts $initFile "set vsd(def:linestyle) [list $vsd(def:linestyle)]"
    puts $initFile "set vsd(def:xaxis:showtitle) [list $vsd(def:xaxis:showtitle)]"
    puts $initFile "set vsd(def:yaxis:showtitle) [list $vsd(def:yaxis:showtitle)]"
    puts $initFile "set vsd(def:y2axis:showtitle) [list $vsd(def:y2axis:showtitle)]"
    puts $initFile "set vsd(def:showcrosshairs) [list $vsd(def:showcrosshairs)]"
    puts $initFile "set vsd(def:showgridlines) [list $vsd(def:showgridlines)]"
    puts $initFile "set vsd(def:showcurxy) [list $vsd(def:showcurxy)]"
    puts $initFile "set vsd(def:showminmax) [list $vsd(def:showminmax)]"
    puts $initFile "set vsd(def:showlinestats) [list $vsd(def:showlinestats)]"
    puts $initFile "set vsd(def:sortbytype) [list $vsd(def:sortbytype)]"
    puts $initFile "set vsd(def:sortdecreasing) [list $vsd(def:sortdecreasing)]"

    puts $initFile "set vsd(showCtrInfo) [list $vsd(showCtrInfo)]"
    puts $initFile "set vsd(absoluteTSMode) [list $vsd(absoluteTSMode)]"
    puts $initFile "set vsd(copyChildren) [list $vsd(copyChildren)]"
    puts $initFile "set vsd(singleFileMode) [list $vsd(singleFileMode)]"
    puts $initFile "set vsd(templatesUseSelection) [list $vsd(templatesUseSelection)]"

    puts $initFile "set vsd(wv:statmoninterval) [list $vsd(wv:statmoninterval)]"
    puts $initFile "set vsd(wv:statmonflush) [list $vsd(wv:statmonflush)]"
    puts $initFile "set vsd(wv:statmonlevel) [list $vsd(wv:statmonlevel)]"
    puts $initFile "set vsd(wv:statmonappstats) [list $vsd(wv:statmonappstats)]"
    puts $initFile "set vsd(wv:statmonsessions) [list $vsd(wv:statmonsessions)]"
    puts $initFile "set vsd(wv:statmonpids) [list $vsd(wv:statmonpids)]"
    puts $initFile "set vsd(wv:statmoncompress) [list $vsd(wv:statmoncompress)]"

    puts $initFile "set vsd(activecolor) $vsd(activecolor)"
    puts $initFile "set vsd(combineInstances) $vsd(combineInstances)"
    puts $initFile "set vsd(combineFiles) $vsd(combineFiles)"
    puts $initFile "set vsd(noFlatlines) $vsd(noFlatlines)"
    puts $initFile "set vsd(traceAPICalls) $vsd(traceAPICalls)"

    if {![info exists vsd(lastVersionRun)] || ($vsd(lastVersionRun) < $vsd(version))} {
	puts $initFile "set vsd(lastVersionRun) $vsd(version)"
    } else {
	puts $initFile "set vsd(lastVersionRun) $vsd(lastVersionRun)"
    }

    puts $initFile "set vsd(instancePaneSize) [.vsd.mainPane panecget instances -size]"
    puts $initFile "set vsd(statisticPaneSize) [.vsd.mainPane panecget statistics -size]"


    foreach n [array names vsd *:geomid] {
	set w [lindex [split $n ":"] 0]
	if [winfo exists $w] {
	    rememberGraphGeometry $w
	}
    }
    foreach n [array names vsd *:graphgeometry] {
	set geom $vsd($n)
	# don't bother remembering funny geometries
	if {![string match "1x1+*" $geom]} {
	    puts $initFile "set vsd($n) [list $geom]"
	}
    }

    puts $initFile "set vsd(smallfont) [list [font actual vsdsf]]"
    puts $initFile "set vsd(textfont) [list [font actual normalTextFont]]"

    set tmplist {}
    foreach fi $vsd(filelist) {
	set f [getFullFileName $fi]
	if {[file exists $f]} {
	    lappend tmplist $f
	}
    }
    # We only want to remember the last 10 files loaded
    puts $initFile "set vsd(filelist) [list [lrange $tmplist 0 9]]"

    puts $initFile "sl_stat -level [sl_stat -level]"
    foreach level [array names vsd level:*] {
	puts $initFile "set vsd($level) $vsd($level)"
    }
    foreach filter [array names vsd filter:*] {
	puts $initFile "set vsd($filter) $vsd($filter)"
    }

    global ctrAliases
    if [info exists ctrAliases] {
	puts $initFile "global ctrAliases"
	puts $initFile "array set ctrAliases [list [array get ctrAliases]]"
    }
    
    puts $initFile {
# templates are now stored in ~/.vsdtemplates.
}
    if [catch {close $initFile} errStr] {
        showError "Notice: could not close '~/.vsdrc' because:\n$errStr"
	return
    }
    if [catch {file rename -force "~/.vsdrc_tmp"  "~/.vsdrc"} errStr] {
        showError "Notice: could not rename '~/.vsdrc_tmp' to '~/.vsdrc' because:\n$errStr"
	return
    }
}

proc fillCounters {force procs} {
    global vsd

    set objlist {}
    set instIdList {}
    if {$procs != {}} {
	foreach ientry $procs {
	    set entryData [$vsd(instanceList) info data $ientry]
	    set objset([lindex $entryData 1]) 1
	    lappend instIdList [lindex $entryData 6]
	}
	set objlist [lsort [array names objset]]
    }

    if {$force || ![string equal $instIdList $vsd(selectedInstIds)]} {
	set selCtr [getSelCtr]
	if {$selCtr != {}} {
	    set vsd(lastSelCtr) $selCtr
	}
	clearCounters
	set vsd(counterType) $objlist
	set vsd(selectedInstIds) $instIdList
	set tc ""
	if [info exists vsd(lastSelCtr)] {
	    set tc $vsd(lastSelCtr)
	}
	set ctrlist [lsort -dictionary [sl_stat -objctrs $objlist]]
	set cl $vsd(w:counterHList)
	set anchorSet 0
	foreach c $ctrlist {
	    set isZero [sl_stat -ctrzero $c $instIdList]
	    if {$vsd(noFlatlines) && $isZero} {
		lappend vsd(zeroCtrs) $c
		# Skip this counter
		continue
	    }
	    set entry [$cl addchild "" -data $c -itemtype text -text $c -style $vsd(ctr$isZero:s)]
	    if {[lsearch -exact $tc $c] != -1} {
		if {!$anchorSet} {
		    set anchorSet 1
		    $cl anchor set $entry
		    $cl see $entry
 		    showCounterInfo $c
		}
		$cl selection set $entry
	    }
	}
	updateDisabledItems
    }
}

proc updateDisabledItems {} {
    global vsd
    set newstate "normal"
    set procs [$vsd(instanceList) info selection]
    if {$procs == {} || [getSelCtr] == {}} {
	set newstate "disabled"
    }

    # newstate should be "normal" or "disabled"
#    $vsd(w:counterList) configure -state $newstate
    $vsd(w:addline) configure -state $newstate
    #$vsd(w:newchart) configure -state $newstate
    $vsd(w:chartmenu) entryconfigure "Add To Chart" -state $newstate
    #$vsd(w:chartmenu) entryconfigure "New Chart..." -state $newstate

    $vsd(w:mainmenu) entryconfigure "Copy Selection" -state $newstate

    return $procs
}

proc updateGraphWidgetState {} {
    global vsd

    $vsd(w:templatemenu) entryconfigure "New Template Chart" -state normal

    fillCounters 0 [updateDisabledItems]
}

proc showFileForAnchor {} {
    global vsd
    set anchor [$vsd(instanceList) info anchor]
    if {$anchor != {}} {
	set data [$vsd(instanceList) info data $anchor]
	set fd [lindex $data 5]
	if {![string equal $fd $vsd(statsrc)]} {
	    set vsd(statsrc) $fd
	    changeFile $fd
	}
    }
}

proc instanceBrowse {junk} {
    set t [tixEvent type]
    # fix for bug 22784
    set updateEvents {"<ButtonRelease-1>" "<Application>" "<Up>" "<Down>"
	"<Shift-Up>" "<Shift-Down>" "<Left>" "<Right>"}
    if {[lsearch -exact $updateEvents $t] != -1} {
	showFileForAnchor
	updateGraphWidgetState
    }
}

proc getSortedFiles {} {
    global vsd
    
    if {$vsd(def:sortdecreasing)} {
        return [lsort -decreasing -dictionary [sl_stat -enabledfiles]]
    } else {
	return [lsort -dictionary [sl_stat -enabledfiles]]
    }
}
    
proc sortWithKeys {l} {
    global vsd
    
    if {$vsd(def:sortdecreasing)} {
	return [lsort -decreasing -dictionary -index end $l]
    } else {
	return [lsort -dictionary -index end $l]
    }
}

proc instSort {l} {
    return [sortWithKeys [addSortKeysToList $l]]
}

proc instCompare {i1 i2} {
    global vsd
    set x1 0
    set x2 0
    switch -exact $vsd(def:sortbytype) {
	"Type" -
	"Name" {
	    # Use the sort key that was appended to the end
	    set x1 [lindex $i1 end]
	    set x2 [lindex $i2 end]
	    if {$vsd(def:sortdecreasing)} {
		return [string compare $x2 $x1]
	    } else {
		return [string compare $x1 $x2]
	    }
	}
	"ProcessId" -
	"Samples" {
	    # Use the sort key that was appended to the end
	    set x1 [lindex $i1 end]
	    set x2 [lindex $i2 end]
	}
	"SessionId" -
	"StartTime" {
	    set x1 [lindex $i1 2]
	    set x2 [lindex $i2 2]
	}
	"File" {
	    set x1 [lindex $i1 5]
	    set x2 [lindex $i2 5]
	}
    }
    if {$x1 == $x2} {
	return 0
    }
    if {$vsd(def:sortdecreasing)} {
	if {$x1 > $x2} {
	    return -1
	} else {
	    return 1
	}
    } else {
	if {$x1 < $x2} {
	    return -1
	} else {
	    return 1
	}
    }
}

proc addInst {l inst {position ""}} {
    global vsd
    global vsdinstmap


    set needsPid 1
    set obj [lindex $inst 1]
    # strip off any object version extension
    set obj [file rootname $obj]
    if {[string equal $obj "AppStat"] ||
        [string equal $obj "IOStat"]} {
	set needsPid 0
    }

    set instid [lindex $inst 6]
    set fullname [lindex $inst 0]
    set name [lindex $fullname 0]
    global vsdnametable
    if [info exists vsdnametable($name)] {
	incr vsdnametable($name)
    } else {
	set vsdnametable($name) 1
    }

    if {$position == ""} {
	set row [$l addchild "" -data $inst]
    } else {
	set row [$l addchild "" -at $position -data $inst]
    }
    set vsdinstmap($instid) $row
    
    # Start time
    $l item create $row $vsd(ilColumnIdx:StartTime) -itemtype text \
	-text [sl_stat -getdate [lindex $inst 2] $vsd(time_shift_hours) "date"] -style $vsd(time:s)
    # File
    $l item create $row $vsd(ilColumnIdx:File) -itemtype text -text [getFileId [lindex $inst 5]] \
	-style $vsd(time:s)
    # Number of samples
    $l item create $row $vsd(ilColumnIdx:Samples) -itemtype text -text [lindex $inst 4] \
	-style $vsd(samples[lindex $inst 3]:s)
    # Pid
    if {$needsPid} {
	set pid [lindex $fullname 1]
	if {$pid != 0 && $pid != -1} {
	    $l item create $row $vsd(ilColumnIdx:ProcessId) -itemtype text -text $pid
	}
    }
    # Session ID
    # Fix 43132 - skip very large session ID's.
    set sid [lindex $fullname 2]
    if {$sid > 0 && $sid < 1073741824} {
      $l item create $row $vsd(ilColumnIdx:SessionId) -itemtype text -text $sid
    }
    # Type
    $l item create $row $vsd(ilColumnIdx:Type) -itemtype text -text [lindex $inst 1]
    # Name
    $l item create $row $vsd(ilColumnIdx:Name) -itemtype text -text $name -style $vsd(name:s)
    return $row
}

proc setInstanceList {} {
    global vsd
    global vsdinstmap
    if {![info exists vsd(instanceList)]} {
	return
    }

    set l $vsd(instanceList)

    set selectedInstances {}
    foreach e [$l info selection] {
	set instid [lindex [$l info data $e] 6]
	lappend selectedInstances $instid
    }
    set oldAnchor [$l info anchor]
    if {$oldAnchor != {}} {
	set instid [lindex [$l info data $oldAnchor] 6]
	set oldAnchor $instid
    }
    
    $l delete all
    if [info exists vsdinstmap] {
	unset vsdinstmap
    }
    set instances [sl_stat -enabledinstances]
    if {$instances == {}} {
	return
    }
    global vsdnametable
    if [info exists vsdnametable] {
	unset vsdnametable
    }
#    set start [getMillis]
    set prevSortKey "PSI:$vsd(def:sortbytype):$vsd(def:sortdecreasing)"
    if {[info exists vsd($prevSortKey)] && [string equal $instances $vsd(previousUnsortedInstances)]} {
        set sortedInstances $vsd($prevSortKey)
    } else {
        set sortedInstances [instSort $instances]
        set vsd(previousUnsortedInstances) $instances
        set vsd($prevSortKey) $sortedInstances
    }
#     set end [getMillis]
#     puts "DEBUG: sorting took [expr {$end - $start}]"
#     set vsd(stats:addInst:count) 0
#     set start [getMillis]
    foreach i $sortedInstances {
#    incr vsd(stats:addInst:count)
	set e [addInst $l $i]
	set instid [lindex $i 6]
	if {$instid == $oldAnchor} {
	    $l anchor set $e
	    $l see $e
	}
	if {[lsearch -exact $selectedInstances $instid] != -1} {
	    $l selection set $e
	}
    }
#     set end [getMillis]
#     puts "DEBUG: process sortedInstances took [expr {$end - $start}]"
#     puts "DEBUG: addInst count $vsd(stats:addInst:count)"
}

proc getMillis {} {
    #  -milliseconds
    return [clock clicks]
}

proc instanceCommand {e} {
    global vsd

    doChart 0
}

proc getPrimTypeSortKey {inst} {
    return [string tolower [lindex $inst 1]]
}
proc getPrimStartTimeSortKey {inst} {
    return [lindex $inst 2]
}
proc getPrimPidSortKey {inst} {
    return [lindex [lindex $inst 0] 1]
}
proc getPrimSidSortKey {inst} {
    set res  [lindex [lindex $inst 0] 2]
    if { $res <= 0 } {
       set res 0
    }
    return $res
}
proc getPrimFileSortKey {inst} {
    return [lindex $inst 5]
}
proc getPrimNameSortKey {inst} {
    set nameData [lindex $inst 0]
    set res [string tolower [lindex $nameData 0]]
    set nameId [lindex $nameData 2]
    if {$nameId != {}} {
        append res "_"
        append res $nameId
    }
    return $res
}

proc getTypeSortKey {inst} {
    set key [getPrimTypeSortKey $inst]
    append key "_"
    append key [getPrimNameSortKey $inst]
    append key "_"
    append key [getPrimFileSortKey $inst]
    append key "_"
    append key [getPrimPidSortKey $inst]
    append key "_"
    append key [getPrimStartTimeSortKey $inst]
    return $key
}

proc getNameSortKey {inst} {
    set key [getPrimNameSortKey $inst]
    append key "_"
    append key [getPrimTypeSortKey $inst]
    append key "_"
    append key [getPrimFileSortKey $inst]
    append key "_"
    append key [getPrimPidSortKey $inst]
    append key "_"
    append key [getPrimStartTimeSortKey $inst]
    return $key
}

proc getSamplesSortKey {inst} {
    set key [lindex $inst 4]
    if {[lindex $inst 3]} {
	set key [expr {$key ^ 0x04000000}]
    }
    append key "_"
    append key [getTypeSortKey $inst]
    return $key
}

proc getPidSortKey {inst} {
    set key [getPrimPidSortKey $inst]
    append key "_"
    append key [getPrimTypeSortKey $inst]
    append key "_"
    append key [getPrimNameSortKey $inst]
    append key "_"
    append key [getPrimFileSortKey $inst]
    append key "_"
    append key [getPrimStartTimeSortKey $inst]
    return $key
}

proc getSidSortKey {inst} {
    set key [getPrimSidSortKey $inst]
    append key "_"
    append key [getPrimPidSortKey $inst]
    append key "_"
    append key [getPrimNameSortKey $inst]
    append key "_"
    append key [getPrimFileSortKey $inst]
    append key "_"
    append key [getPrimStartTimeSortKey $inst]
    return $key
}


proc getFileSortKey {inst} {
    set key [getPrimFileSortKey $inst]
    append key "_"
    append key [getPrimTypeSortKey $inst]
    append key "_"
    append key [getPrimNameSortKey $inst]
    append key "_"
    append key [getPrimPidSortKey $inst]
    append key "_"
    append key [getPrimStartTimeSortKey $inst]
    return $key
}

proc getStartTimeSortKey {inst} {
    set key [getPrimStartTimeSortKey $inst]
    append key "_"
    append key [getPrimTypeSortKey $inst]
    append key "_"
    append key [getPrimNameSortKey $inst]
    append key "_"
    append key [getPrimFileSortKey $inst]
    append key "_"
    append key [getPrimPidSortKey $inst]
    return $key
}

proc addSortKeysToList {instlist} {
    global vsd
    set reslist {}
    switch -exact $vsd(def:sortbytype) {
	"Type" {
	    foreach inst $instlist {
		lappend inst [getTypeSortKey $inst]
		lappend reslist $inst
	    }
	}
	"Name" {
	    foreach inst $instlist {
		lappend inst [getNameSortKey $inst]
		lappend reslist $inst
	    }
	}
	"Samples" {
	    foreach inst $instlist {
		lappend inst [getSamplesSortKey $inst]
		lappend reslist $inst
	    }
	}
	"ProcessId" {
	    foreach inst $instlist {
		lappend inst [getPidSortKey $inst]
		lappend reslist $inst
	    }
	}
	"SessionId" {
	    foreach inst $instlist {
		lappend inst [getSidSortKey $inst]
		lappend reslist $inst
	    }
	}
	"File" {
	    foreach inst $instlist {
		lappend inst [getFileSortKey $inst]
		lappend reslist $inst
	    }
	}
	"StartTime" {
	    foreach inst $instlist {
		lappend inst [getStartTimeSortKey $inst]
		lappend reslist $inst
	    }
	}
	default {
	    set reslist $instlist
	}
    }
    return $reslist
}

proc addSortKey {inst} {
    global vsd
    switch -exact $vsd(def:sortbytype) {
	"Type" {
	    lappend inst [getTypeSortKey $inst]
	}
	"Name" {
	    lappend inst [getNameSortKey $inst]
	}
	"Samples" {
	    lappend inst [getSamplesSortKey $inst]
	}
	"ProcessId" {
	    lappend inst [getPidSortKey $inst]
	}
	"SessionId" {
	    lappend inst [getSidSortKey $inst]
	}
	"File" {
	    lappend inst [getFileSortKey $inst]
	}
	"StartTime" {
	    lappend inst [getStartTimeSortKey $inst]
	}
    }
    return $inst
}

# insertInstance currently assumes that only a single copy needs
# to be inserted.
proc insertInstance {l inst} {
    global vsd
    set inst [addSortKey $inst]
    set sortList {}
    lappend sortList $inst
    foreach c [$l info children] {
	lappend sortList [$l info data $c]
    }
    set sortList [sortWithKeys $sortList]
    set idx [lsearch -exact $sortList $inst]
    return [addInst $l $inst $idx]
}

proc updateInstanceList {} {
    setInstanceList
    # The following code used to be used instead of setInstanceList.
    # It works well if the instance list is small but was became very
    # slow with large instance lists.
#     global vsd
#     global vsdinstmap
#     if {![info exists vsd(instanceList)]} {
# 	return
#     }
#     set instances [sl_stat -enabledinstances]
#     if {$instances == {}} {
# 	return
#     }
#     set l $vsd(instanceList)
#     foreach i $instances {
# 	set n [lindex $i 6]
# 	if {[info exists vsdinstmap($n)]} {
# 	    set e $vsdinstmap($n)
# 	    set edata [$l info data $e]
# 	    if {[lindex $edata 3] != [lindex $i 3]} {
# 		set setAnchor [string equal $e [$l info anchor]]
# 		set setSelect [$l selection includes $e]   
# 		$l delete entry $e
# 		set e [insertInstance $l $i]
# 		if {$setAnchor} {
# 		    $l anchor set $e
# 		    $l see $e
# 		}
# 		if {$setSelect} {
# 		    $l selection set $e
# 		}
# 	    } else {
# 		set iSamples [lindex $i 4]
# 		if {[lindex $edata 4] != $iSamples} {
# 		    $l entryconfigure $e -data [addSortKey $i]
# 		    $l item configure $e $vsd(ilColumnIdx:Samples) -text $iSamples
# 		}
# 	    }
# 	} else {
# 	    insertInstance $l $i
# 	}
#     }
}

proc destroyProgress {w} {
    global vsd
    
    catch {focus $vsd(progress_oldFocus)}
    unset vsd(progress_oldFocus)
    destroy $w
    if {$vsd(progress_oldGrab) != ""} {
	if {$vsd(progress_grabStatus) == "global"} {
	    grab -global $vsd(progress_oldGrab)
	} else {
	    grab $vsd(progress_oldGrab)
	}
	unset vsd(progress_oldGrab)
	unset vsd(progress_grabStatus)
    }
    update
}

proc showProgress {percentCompleted} {
    global vsd
    set parent $vsd(w)
    set w "$parent.progress"
    set exists [winfo exists $w]

# Fix 43750 
# Always clean up and get out if progress == 100%
#
    if {$percentCompleted == 100} {
      if {$exists} {
	  destroyProgress $w
      }
      if {$vsd(progressCanceled)} {
        return 0
      }
        return 1
    }

    if {$exists} {
	update
	if {$vsd(progressCanceled)} {
	    destroyProgress $w
	    return 0
	}
    } else {
	set vsd(progressCanceled) 0
	toplevel $w -class Dialog
	wm title $w "Loading Data File"
	wm iconname $w Dialog
	wm protocol $w WM_DELETE_WINDOW { }
	wm transient $w $parent

	frame $w.bot -relief raised -bd 1
	pack $w.bot -side bottom -fill both
	frame $w.top -relief raised -bd 1
	pack $w.top -side top -fill both -expand 1

	label $w.top.title -text "Load in progress ...."
	pack $w.top.title -side top -expand 1 -fill x -padx 3m -pady 3m
	if {$vsd(hasMeter)} {
	    tixMeter $w.msg -value 0 -text "0%"
	} else {
	    label $w.msg -justify center -anchor center
	}
	pack $w.msg -in $w.top -side bottom -expand 1 -fill both -padx 3m -pady 3m -anchor c
	tixButtonBox $w.bot.box
	$w.bot.box add cancel -text "Interrupt" \
	    -command {set vsd(progressCanceled) 1}
	pack $w.bot.box -fill both -expand 1
	$vsd(balloon) bind $w.bot.box -msg "Interrupts can be continued later by doing a \"File|Update\""

	regexp {(.*x.*)(\+.*\+.*)} [wm geometry $parent] junk parentSize parentPosition
	wm geometry $w $parentPosition

	set vsd(progress_oldFocus) [focus]
	set vsd(progress_oldGrab) [grab current $w]
	if {$vsd(progress_oldGrab) != ""} {
	    set vsd(progress_grabStatus) [grab status $vsd(progress_oldGrab)]
	}
        setMasterBgColorForWindow $w

        # Next line fixes 45048, but perhaps not on Windows.
        tkwait visibility $w
	grab $w
	focus $w
    }
    if {$vsd(hasMeter)} {
	$w.msg config -value [expr {double($percentCompleted) / 100}] \
	    -text "$percentCompleted%"
    } else {
	$w.msg configure -text "loaded $percentCompleted%"
    }
    update
    return 1
}

proc getLastDataFileName {} {
    global vsd
    return [getFullFileName $vsd(lastdatafile)]
}

proc updateFileTrimMenuItems {finfo} {
    global vsd

    set firstTS [lindex $finfo 9]
    set trimLeftTS [lindex $finfo 10]
    set trimRightTS [lindex $finfo 11]

    if {$firstTS != $trimLeftTS} {
	$vsd(w:filemenu) entryconfigure "Untrim Left" -state normal
    } else {
	$vsd(w:filemenu) entryconfigure "Untrim Left" -state disabled
    }
    if {$trimRightTS != -1} {
	$vsd(w:filemenu) entryconfigure "Untrim Right" -state normal
    } else {
	$vsd(w:filemenu) entryconfigure "Untrim Right" -state disabled
    }
    
}

proc changeFile {fd} {
    global vsd
    set vsd(autoUpdate) $vsd(autoUpdate:$fd)
	
    if {$vsd(updateok:$fd)} {
	$vsd(w:filemenu) entryconfigure "Update" -state normal
	$vsd(w:filemenu) entryconfigure "Auto Update" -state normal
    } else {
	$vsd(w:filemenu) entryconfigure "Update" -state disabled
	$vsd(w:filemenu) entryconfigure "Auto Update" -state disabled
    }
	
    set statsrcInfo [$fd -info]
    set vsd(file:isEnabled) [lindex $statsrcInfo 7]

    updateFileTrimMenuItems $statsrcInfo
    
    # If the file info window is up then update it
# BUG this was deadcoded because fileInfo currently always steal the focus
#     if [winfo exists .vsdfileinfo] {
# 	fileInfo
#     }
    set vsd(lastdatafile) [addFileListMap $fd]
    $vsd(w:filelist) configure -disablecallback true
    $vsd(w:filelist) configure -value $vsd(lastdatafile)
    $vsd(w:filelist) configure -disablecallback false
}

proc setDataFile {fname} {
    global vsd

    if {$fname != {} && [string equal "relative" [file pathtype $fname]]} {
	set fname [file join [pwd] $fname]
    }
    if {$fname != {} && $fname != [getLastDataFileName]} {
	replayLog "setDataFile $fname"
	if {$vsd(appendMode)} {
	    if [catch {$vsd(statsrc) -append $fname} result] {
		set msg "Could not append data file \'$fname\' because: "
		append msg $result
		showError $msg
	    } else {
		# NYI: Its not clear how much needs to be done after an append
		setInstanceList
		updateGraphWidgetState
	    }
	    set vsd(appendMode) 0
	    return
	}
	if [catch {sl_create -file $fname showProgress} result] {
	    set msg "Could not load data file \'$fname\' because: "
	    append msg $result
	    showError $msg
	    # set the w:filelist back to the lastdatfile loaded
	    $vsd(w:filelist) configure -disablecallback true
	    $vsd(w:filelist) configure -value $vsd(lastdatafile)
	    $vsd(w:filelist) configure -disablecallback false
	    return
	}
	    
	addUniqueFileName $result

	foreach type [lindex [$result -info] 8] {
	    generateTypeHelp $type
	}
	
	if {$vsd(singleFileMode)} {
	    if {$vsd(statsrc) != {}} {
		$vsd(statsrc) -disable
	    }
	    $result -enable
	}
	
	set vsd(statsrc) $result
	fillCounters 1 {}
	updateCounterList

	if {![info exists vsd(updateok:$result)]} {
	    set vsd(updateok:$result) 1
	    set vsd(autoUpdate:$result) 0
	}

	changeFile $result

	if {[$vsd(w:filemenu) entrycget "Info..." -state] == "disabled"} {
	    # We have a file loaded so enable the 'file' menu items
	    $vsd(w:filemenu) entryconfigure "Info..." -state normal
	    # $vsd(w:filemenu) entryconfigure "Absolute TimeStamps" -state normal
	    $vsd(w:filemenu) entryconfigure "Enabled" -state normal
	    if [wizardMode] {
		$vsd(w:filemenu) entryconfigure "Dump" -state normal
	    }
	}

	set ldfn [getLastDataFileName]
	set idx [lsearch -exact $vsd(filelist) $ldfn]
	if {$idx != -1} {
	    set vsd(filelist) [lreplace $vsd(filelist) $idx $idx]
	    set lb [$vsd(w:filelist) subwidget listbox]
	    set historyList [$lb get 0 end]
	    set idx [lsearch -exact $historyList $ldfn]
	    if {$idx != -1} {
		$lb delete $idx $idx
	    }
	}
	set idx [lsearch -exact $vsd(filelist) $vsd(lastdatafile)]
	if {$idx != -1} {
	    # Delete from the list; it will go on the front
	    set vsd(filelist) [lreplace $vsd(filelist) $idx $idx]
	    set lb [$vsd(w:filelist) subwidget listbox]
	    set historyList [$lb get 0 end]
	    set idx [lsearch -exact $historyList $vsd(lastdatafile)]
	    if {$idx != -1} {
		$lb delete $idx $idx
	    }
	}
	$vsd(w:filelist) insert 1 $vsd(lastdatafile)
	set vsd(filelist) [linsert $vsd(filelist) 0 $vsd(lastdatafile)]

	setInstanceList
	updateGraphWidgetState
    } else {
	# set the w:filelist back to the lastdatfile loaded
	$vsd(w:filelist) configure -disablecallback true
	$vsd(w:filelist) configure -value $vsd(lastdatafile)
	$vsd(w:filelist) configure -disablecallback false
    }
    set vsd(appendMode) 0
}

proc browseDataFile {} {
    global vsd
    if {$vsd(w:fileselector) != ""} { # Not Windows...
	if 0 { # the -dir seems broken in Tix4.0.5
	    set fsbox [$vsd(w:fileselector) subwidget fsbox]
	    set lastfn [getLastDataFileName]
	    if {$lstfn != {}} {
		set dir [file dirname $lastfn]
		$fsbox configure -dir $dir
	    }
	}
	$vsd(w:fileselector) popup
    } else { # Is Windows...
	set lastfn [getLastDataFileName]
	if {$lastfn != {}} {
	    set dir [file dirname $lastfn]
	    regsub -all "/" $dir "\\" dir
	} else {
	    set dir "."
	}
	set types {
	    {"All Statistic Data Files" {.gfs .out .out.gz}}
	    {"All Compressed files" {*.gz}}
	    {"Uncompressed StatMonitor data files" {.out}}
	    {"Uncompressed GBS archive files" {.gfs}}
	    {"Compressed StatMonitor data files" {.out.gz}}
	    {"All files" {*}}
	}
	set fname [tk_getOpenFile -title "Open StatMonitor File" \
		       -parent $vsd(w) \
		       -initialdir $dir \
		       -filetypes $types]
	setDataFile $fname
    }
}

proc loadBrowsedDataFile {fname} {
    global vsd
    $vsd(w:fileselector) popdown 
    setDataFile $fname
}
    
proc chooseDataFile {fname} {
    if {$fname == "Browse For File..."} {
	global vsd
	$vsd(w:filelist) configure -disablecallback true
	$vsd(w:filelist) configure -value $vsd(lastdatafile)
	$vsd(w:filelist) configure -disablecallback false
	# Bring up a dialog that lets the user browse for a file
	browseDataFile
    } else {
	setDataFile [getFullFileName $fname]
    }
}

proc printGraph {graph name} {
    global vsd
    myBusyOn $graph
# NYI: BLT has special support for printing on NT. The graph widget has print1 and print2 commands. However 'rbc::printer names' always returns empty list for me
    if [catch {$graph postscript output $name \
		   -landscape true -decorations false \
		   -colormode grey -padx .25i -pady .25i} result] {
	showError $result
    } elseif [catch {eval exec $vsd(exec:lpr) $name} result] {
	showError "$vsd(exec:lpr) $name failed: $result"
    } else {
	catch {file delete -force $name}
    }
    myBusyOff $graph
}

proc snapshotGraph {graph name} {
    global vsd
    set outputName "snapshot.gif"
    myBusyOn $graph
    set photo [image create photo -format gif]
    $graph snap $photo
    catch {file delete -force $outputName}
    $photo write $outputName -format gif
    image delete $photo
    myBusyOff $graph
}

# stripFloat removes a trailing .0 from a number
proc stripFloat {v} {
    set l [string length $v]
    incr l -1
    if {[string index $v $l] == "0"} {
	incr l -1
	if {[string index $v $l] == "."} {
	    incr l -1
	    return [string range $v 0 $l]
	}
    }
    return $v
}

proc updateAllLineTrimMenuItems {} {
    global bltActiveEntry
    global vsd

    foreach g [array names bltActiveEntry] {
	set e $bltActiveEntry($g)
	if {$e != -1} {
	    set mf "[winfo parent $g].mf"
	    set linfo [$vsd(ed:$e:$g) -info]
	    updateLineTrimMenuItems $mf.line.m [lindex $linfo 7]
	}
    }
}

proc updateLineTrimMenuItems {m datafiles} {
    set isTrimmedLeft 0
    set isTrimmedRight 0
    foreach dfid $datafiles {
	set dfinfo [$dfid -info]
	set firstTS [lindex $dfinfo 9]
	set trimLeftTS [lindex $dfinfo 10]
	set trimRightTS [lindex $dfinfo 11]
	if {$firstTS != $trimLeftTS} {
	    set isTrimmedLeft 1
	}
	if {$trimRightTS != -1} {
	    set isTrimmedRight 1
	}
	if {$isTrimmedLeft && $isTrimmedRight} {
	    break;
	}
    }
    if {$isTrimmedLeft} {
	$m entryconfigure "Untrim Left" -state normal
    } else {
	$m entryconfigure "Untrim Left" -state disabled
    }
    if {$isTrimmedRight} {
	$m entryconfigure "Untrim Right" -state normal
    } else {
	$m entryconfigure "Untrim Right" -state disabled
    }
}

proc showLineInfo {graph element} {
    global vsd
    set mf "[winfo parent $graph].mf"
    if {$element == {}} {
	$mf.line configure -state disabled
	set min ""
	set max ""
	set filter none
	set symbol none
	set style linear
	set counter ""
	hideMarker $graph triStart
	hideMarker $graph triEnd
	set isDerived 0
    } else {
	$mf.line configure -state normal
	if {[$graph element cget $element -mapy] == "y"} {
	    set vsd($graph:graphonleft) 1
	} else {
	    set vsd($graph:graphonleft) 0
	}
	set edata [$vsd(ed:$element:$graph) -info]
	set vsd($graph:normalized) [lindex $edata 11]
	set counter [lindex $edata 1]
	set yvname [lindex $edata 3]
        set scale [lindex $edata 4]
	#set filter [lindex $edata 5]
        set filter [getCommonFilter $graph [lindex $edata 5]]
#	set obj [lindex $edata 6]
#	set dfids [lindex $edata 7]
	if {[lindex $edata 9] == {}} {
	    set isDerived 0
	} else {
	    set isDerived 1
	}
	set symbol [$graph element cget $element -symbol]
	set style [$graph element cget $element -smooth]
	global $yvname
	set min [set ${yvname}(min)]
	if {$min == {}} {
	    set min 0.0
	}
	set max [set ${yvname}(max)]
	if {$max == {}} {
	    set max 0.0
	}
	if {$scale != 1} {
	    # Need to unscale min and max
	    set min [expr {$min / $scale}]
	    set max [expr {$max / $scale}]
	}
	updateLineTrimMenuItems $mf.line.m [lindex $edata 7]
	showCounterInfo $counter
    }
    set vsd($graph:linesym) $symbol
    set vsd($graph:linestyle) $style

    set f [$mf.min subwidget frame]
    $f.l configure -text [stripFloat $min]

    set f [$mf.max subwidget frame]
    $f.l configure -text [stripFloat $max]

    $mf.linef.counter configure -state normal
    $mf.linef.counter configure -disablecallback true
    # Note that the contents of the counter listbox is not computed
    # until the user drops it down. At that time chartComputeCounters
    # is called.
    if {$isDerived} {
	$mf.linef.counter configure -value [getCtrAlias $counter]
	$mf.linef.counter configure -state disabled
    } else {
	$mf.linef.counter configure -value $counter
	$mf.linef.counter configure -disablecallback false
    }
    if {$filter != {}} {
        $mf.linef.filtertype configure -state normal
        $mf.linef.filtertype configure -disablecallback true
        $mf.linef.filtertype configure -value $filter
        $mf.linef.filtertype configure -disablecallback false
    } else {
	$mf.linef.filtertype configure -state disabled
    }
    if {$element == {}} {
	$mf.linef.counter configure -state disabled
	$mf.linef.filtertype configure -state disabled
	$mf.linef.opMenu configure -state disabled
	$mf.linef.const configure -state disabled
    } else {
	$mf.linef.opMenu configure -state normal
	$mf.linef.const configure -state normal
	changeConstOp $graph {}
    }

    set f [$mf.curx subwidget frame]
    $f.l configure -text ""
    set f [$mf.cury subwidget frame]
    $f.l configure -text ""

# 44955 - restore right click to previous setting 
    bind $graph <ButtonPress-3> {
	ChartHandleRightClick %W
    }
}

proc lineIncrConst {newVal} {
    global vsd
    switch -exact $vsd(constOp) {
	"divide" -
	"multiply" -
	"scale" {
	    return [expr {$newVal * 2.0}]
	}
	"add" -
	"subtract" {
	    return [expr {$newVal + 1}]
	}
    }
}

proc lineDecrConst  {newVal} {
    global vsd
    switch -exact $vsd(constOp) {
	"divide" -
	"multiply" -
	"scale" {
	    return [expr {$newVal / 2.0}]
	}
	"add" -
	"subtract" {
	    return [expr {$newVal - 1}]
	}
    }
}

proc lineValidateConst {g newVal} {
    global vsd
    if [catch {expr {double($newVal)}} val] {
	setStatus "The string \"$newVal\" is not a valid number."
	bell
	return 1
    }
    switch -exact $vsd(constOp) {
	"scale" -
	"multiply" {
	    if {$val == 0} {
		setStatus "Can't multiply by zero."
		bell
		return 1
	    }
	}
	"divide" {
	    if {$val == 0} {
		setStatus "Can't divide by zero."
		bell
		return 1
	    }
	}
	"add" {
	    set e [getSelectedLine $g]
	    if {$e != {}} {
		set l $vsd(ed:$e:$g)
		set linfo [$l -info]
		set normalized [lindex $linfo 11]
		set offset [expr {- [lindex $linfo 12]}]
		if {$normalized && $offset != $val} {
		    # can't change adder/subtractor if line is normalized
		    setStatus "Can't add to normalized line."
		    bell
		    return $offset
		}
	    }
	}
	"subtract" {
	    set e [getSelectedLine $g]
	    if {$e != {}} {
		set l $vsd(ed:$e:$g)
		set linfo [$l -info]
		set normalized [lindex $linfo 11]
		set offset [lindex $linfo 12]
		if {$normalized && $offset != $val} {
		    # can't change subtractor if line is normalized
		    setStatus "Can't subtract from normalized line."
		    bell
		    return $offset
		}
	    }
	}
    }
    return $newVal
}

proc lineChangeConst {g newVal} {
    global vsd
    switch -exact $vsd(constOp) {
	"scale" {
	    lineChangeScale $g $newVal
	}
	"divide" {
	    lineDivideConst $g $newVal
	}
	"multiply" {
	    lineDivideConst $g [expr {1.0 / $newVal}]
	}
	"add" {
	    lineAddConst $g $newVal
	}
	"subtract" {
	    lineAddConst $g [expr {- $newVal}]
	}
    }
}

proc changeConstOp {g constOp} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	set mf "[winfo parent $g].mf"
	set l $vsd(ed:$e:$g)
	set linfo [$l -info]
	set scale [lindex $linfo 4]
	set normalized [lindex $linfo 11]
	set offset [lindex $linfo 12]
	set divider [lindex $linfo 13]
	if {$constOp == {}} {
	    # pick the best one
	    set hasScale [expr {$scale != 1.0}]
	    set hasOffset [expr {$offset != 0.0}]
	    set hasDivider [expr {$divider != 1.0}]
	    # first check to see if constOp already set to something non-default for this line
	    switch -exact $vsd(constOp) {
		"scale" {
		    if {$hasScale} {
			set constOp $vsd(constOp)
		    }
		}
		"multiply" -
		"divide" {
		    if {$hasDivider} {
			set constOp $vsd(constOp)
		    }
		}
		"subtract" -
		"add" {
		    if {$hasOffset} {
			set constOp $vsd(constOp)
		    }
		}
	    }
	    if {$constOp == {}} {
		# still have not picked one so look for one for
		# which this line has a non-default value
		if {$hasDivider} {
		    # make it "divide" or "multiply"
		    if {[expr {abs($divider)}] >= 1.0} {
			set vsd(constOp) "divide"
		    } else {
			set vsd(constOp) "multiply"
		    }
		} elseif {$hasOffset} {
		    # make it "add" or "subtract"
		    if {$offset < 0} {
			set vsd(constOp) "add"
		    } else {
			set vsd(constOp) "subtract"
		    }
		} elseif {$hasScale} {
		    set vsd(constOp) "scale"
		}
		set constOp $vsd(constOp)
	    }
	}
	$mf.linef.const configure -disablecallback true
	switch -exact $constOp {
	    "scale" {
		$mf.linef.const configure -value $scale
	    }
	    "divide" {
		$mf.linef.const configure -value $divider
	    }
	    "multiply" {
		$mf.linef.const configure -value [expr {1.0 / $divider}]
	    }
	    "add" {
		if {$offset != 0} {
		    $mf.linef.const configure -value [expr {- $offset}]
		} else {
		    $mf.linef.const configure -value $offset
		}
	    }
	    "subtract" {
		$mf.linef.const configure -value $offset
	    }
	}
	$mf.linef.const configure -disablecallback false
    }
}

proc lineAddConst {g const} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	set l $vsd(ed:$e:$g)
	$l -adder $const
	updateLineDataDisplay $g $e $l
    }
}

proc lineDivideConst {g const} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	set l $vsd(ed:$e:$g)
	$l -divider $const
	updateLineDataDisplay $g $e $l
    }
}

proc lineChangeScale {g newVal} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	set l $vsd(ed:$e:$g)
	$l -scale $newVal
	updateLineDataDisplay $g $e $l
    }
}

# 44955 - copy Y value to the clipboard
proc copyYvalue {} {
    global vsd
    clipboard clear
    clipboard append $vsd(Yvalue)
}

proc setCurXY {graph elem x y} {
    global vsd
    set mf "[winfo parent $graph].mf"

    set linfo [$vsd(ed:$elem:$graph) -info]
    set scale [lindex $linfo 4]
    if {$scale != 1} {
	# Need to remove the scale so that the Y value reported will be real
	set y [expr {$y / $scale}]
    }

    set f [$mf.curx subwidget frame]
    set xstr [sl_stat -getdate [expr {wide($x)}] $vsd(time_shift_hours) $vsd($graph:xformat)]
    $f.l configure -text $xstr
    set f [$mf.cury subwidget frame]
    $f.l configure -text [stripFloat $y]

# 44955 - Enable right click open pop-up menu to copy Y to clipboard
    set vsd(Yvalue) [stripFloat $y]
    bind $graph <ButtonPress-3> {tk_popup %W.popupMenu %X %Y}
}

proc closeAllCharts {} {
    global vsd
    foreach name [array names vsd  ct:*] {
	set w $vsd($name)
	set g $w.graph
	closeGraph $w $g
    }
}

proc getGraphGeometry {w} {
    global vsd
    if {$vsd(freeGeometryIds) == {}} {
	set geomid $vsd(graphcount)
	set vsd($w:geomid) $geomid
	if [info exists vsd($geomid:graphgeometry)] {
	    set result $vsd($geomid:graphgeometry)
	} else {
	    set result "600x300+1+1"
	    set vsd($geomid:graphgeometry) $result
	}
    } else {
	set geomid [lindex $vsd(freeGeometryIds) end]
	set vsd(freeGeometryIds) [lreplace $vsd(freeGeometryIds) end end]
	set vsd($w:geomid) $geomid
	set result $vsd($geomid:graphgeometry)
    }
    return $result
}

proc rememberGraphGeometry {w} {
    global vsd
    set geomid $vsd($w:geomid)
    lappend vsd(freeGeometryIds) $geomid
    set vsd($geomid:graphgeometry) [wm geometry $w]
}

proc closeGraph {w g} {
    global vsd
    global bltActiveGraph
    global bltActiveEntry

    incr vsd(graphcount) -1
    rememberGraphGeometry $w

    if {[string equal $vsd(longOpW) $w]} {
	cancelLongOp
    }
	
    update idletasks

    if {[info exists bltActiveGraph($g,alarmid)]} {
	after cancel $bltActiveGraph($g,alarmid)
	unset bltActiveGraph($g,alarmid)
	unset bltActiveGraph($g,x)
	unset bltActiveGraph($g,y)
    }

    if [info exists bltActiveEntry($g)] {
	unset bltActiveEntry($g)
    }
    if [info exists bltActiveGraph($g)] {
	unset bltActiveGraph($g)
    }
    if [info exists bltActiveGraph($g,closest)] {
	unset bltActiveGraph($g,closest)
    }
    if [info exists bltActiveGraph($g,oldSelectedLines)] {
	unset bltActiveGraph($g,oldSelectedLines)
    }

    foreach e [$g element names] {
	$vsd(ed:$e:$g) -free
	unset vsd(ed:$e:$g)
    }

    set title [wm title $w]
    unset vsd(ct:$title)
    set idx 0
    set listbox [$vsd(w:chartlist) subwidget listbox]
    foreach t [$listbox get 0 end] {
	if {[string equal $t $title]} {
	    $listbox delete $idx
	    if {$idx == 0} {
		set curwintitle [$listbox get 0]
		if [info exists vsd(ct:$curwintitle)] {
		    $vsd(w:chartlist) pick 0
		} else {
		    $vsd(w:chartlist) configure -disablecallback true
		    $vsd(w:chartlist) pick 0
		    $vsd(w:chartlist) configure -disablecallback false
		}
	    }
	    break
	}
	incr idx
    }
    destroy $w
}

proc chartFocus {w} {
    global vsd
    set title [wm title $w]
    if {![info exists vsd(ct:$title)]} {
	return
    }
    if {[string equal $vsd(ct:$title) $w]} {
        if {![string equal $vsd(curchart) $title]} {
	    $vsd(w:chartlist) configure -disablecallback true
	    $vsd(w:chartlist) addhistory $title
	    $vsd(w:chartlist) pick 0
	    $vsd(w:chartlist) configure -disablecallback false
	}
    }
}

proc getAxisTitle {g axis} {
    global vsd
    global bltActiveEntry

    if {[info exists bltActiveEntry($g)] && $bltActiveEntry($g) != -1} {
	set e $bltActiveEntry($g)
	if {[string equal $axis "xaxis"]} {
	    return [getElementXAxisTitle $g $e]
	} else {
	    set activeAxis [$g element cget $e -mapy]
	    append activeAxis "axis"
	    if {[string equal $activeAxis $axis]} {
		return [getElementYAxisTitle $g $e]
	    }
	}
    }
    return $vsd($axis:defaultTitle)
}

proc chartAxisTitle {g axis} {
    global vsd
    if {$vsd($g:$axis:showtitle)} {
	set title [getAxisTitle $g $axis]
    } else {
	set title ""
    }
    $g $axis configure -title $title
}

proc chartShowCrossHairs {g} {
    global vsd
    if {$vsd($g:showcrosshairs)} {
	Blt_CrosshairsOn $g
    } else {
	Blt_CrosshairsOff $g
    }
}

proc chartShowLegend {g} {
    global vsd
    mapLegend $g $vsd($g:showlegend)
}

proc chartShowGridLines {g} {
    global vsd
    if {$vsd($g:showgridlines)} {
	$g grid on 
    } else {
	$g grid off
    }
}

proc chartShowCurXY {w mf} {
    global vsd
    if {[lsearch -exact [pack slaves $mf] $mf.min] != -1} {
	set afterW $mf.min
    } else {
	set afterW $mf.linef
    }
    if {$vsd($w:showcurxy)} {
	pack $mf.cury $mf.curx -after $afterW -side right -padx 2
    } else {
	pack forget $mf.cury $mf.curx
    }
}

proc chartShowMinMax {w mf} {
    global vsd
    if {$vsd($w:showminmax)} {
	pack $mf.max $mf.min -after $mf.linef -side right -padx 2
    } else {
	pack forget $mf.max $mf.min
    }
}

proc chartCancelOp {g} {
    # default to zoom out
    chartCancelOpZoom $g
}

proc chartZoom {g} {
    global vsd

    if {$vsd($g:chartOp) != {}} {
	# do the above check so that default right click action not taken
	chartCancelOp$vsd($g:chartOp) $g
    }

    set vsd($g:chartOp) "Zoom"
    $g config -cursor top_left_corner
    hideMarker $g activeLine
    set title "Click to start zoom, right click to cancel"
    $g marker create text -name "bltZoom_title" -text $title \
	    -coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
}

proc chartSetMinTime {g} {
    global vsd

    if {$vsd($g:chartOp) != {}} {
	# do the above check so that default right click action not taken
	chartCancelOp$vsd($g:chartOp) $g
    }

    set vsd($g:chartOp) "MinTime"
    $g config -cursor left_side
    set title "Click to set min time, right click to cancel"
    hideMarker $g activeLine
    $g marker create text -name "chartop_title" -text $title \
	    -coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
}

proc chartSetMaxTime {g} {
    global vsd

    if {$vsd($g:chartOp) != {}} {
	# do the above check so that default right click action not taken
	chartCancelOp$vsd($g:chartOp) $g
    }

    set vsd($g:chartOp) "MaxTime"
    $g config -cursor right_side
    set title "Click to set max time, right click to cancel"
    hideMarker $g activeLine
    $g marker create text -name "chartop_title" -text $title \
	    -coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
}

proc getTemplateProcName {pname ptype} {
    # added to fix bug 18996
    set res "*"
    switch -exact [string tolower $ptype] {
	disk -
	pgsvr -
        session -
        gcsession -
	gem {
	    # Need to strip unique id off end of name and replace with a *
	    regsub {[0-9]+$} $pname {*} res
	}
	vm {
	    switch -glob [string tolower $pname] {
		"gsjvm*" { set res "gsjVM*"}
		"gsvm*" { set res "gsVM*"}
		"gns*" { set res "gns*"}
		"*sap" { set res "*sap"}
		"*gc" { set res "*GC"}
		"*activator" { set res "*Activator"}
		"*otsagent" { set res "*OTSAgent"}
		"*rnsagent" { set res "*RNSAgent"}
	    }
	}
    }
    return $res
}

proc getTemplateLineSpec {li yaxis} {
    global vsd
    # proc-type proc-name stat-name scale filter axis
    set ptlist {}
    foreach pt [lindex $li 6] {
	# strip off any object type version
	lappend ptlist [file rootname $pt]
    }
    set procType $ptlist
    set instList [lindex $li 8]
    set operator [lindex $li 9]
    if {[llength $instList] > 1} {
	if {$operator != {}} {
	    set ls1 [getTemplateLineSpec [lindex $instList 0] $yaxis]
	    set ls2 [getTemplateLineSpec [lindex $instList 1] $yaxis]
	    switch -exact -- $operator {
		"+" {set opcode "plus"}
		"-" {set opcode "diff"}
		"/" {set opcode "divide"}
	    }
	    set lineSpec [list $opcode $ls1 $ls2 \
			      [lindex $li 4] [lindex $li 5] $yaxis \
			      [lindex $li 13] [lindex $li 12] [lindex $li 11]]
	    return $lineSpec
	} else {
	    append procType "+"
	    set procName "*"
	}
    } else {
	set procName [getTemplateProcName [lindex [lindex $li 0] 0] $procType]
    }
    set lineSpec [list $procType $procName [lindex $li 1] \
		      [lindex $li 4] [lindex $li 5] $yaxis \
		      [lindex $li 13] [lindex $li 12] [lindex $li 11]]
    return $lineSpec
}

proc getTemplateName {parent defaultName} {
    global vsd
    set vsd(template:tv) "$defaultName"
    update ;# allows startSearch to be called from popup menu
    set vsd(template:parent) $parent
    set vsd(template:oldfocus) [focus]
    set vsd(template:result) {}
    set w ".vsdtemplateName"
    set entry [$w.f.entry subwidget entry]
    
    set width [winfo width $parent]
    set x [winfo rootx $parent]
    set y [winfo rooty $parent]
    set dialogheight [winfo height $w]
    if {$dialogheight == 1} {
	set dialogheight [winfo reqheight $w]
	if {$dialogheight == 1} {
	    set dialogheight 32
	}
    }
    set y [expr {$y - $dialogheight}]
    raise $w
    wm deiconify $w
    wm geometry $w "${width}x$dialogheight+$x+$y"
    focus $entry
    tkwait variable vsd(template:result)
    return $vsd(template:result)
}

proc saveGraphTemplate {g n} {
    global vsd vsdtemplates
    set n [getTemplateName $g $n]
    if {![info exists vsdtemplates($n)]} {
	addTemplateMenu $vsd(w:templatecascade) $n
    }
    set vsdtemplates($n) {} ;# template line list
    foreach e [lsort -integer [$g element names]] {
	set yaxis [$g element cget $e -mapy]
	set li [$vsd(ed:$e:$g) -info]
	set lineSpec [getTemplateLineSpec $li $yaxis]
	if {[lsearch -exact $vsdtemplates($n) $lineSpec] == -1} {
	    lappend vsdtemplates($n) $lineSpec
	}
    }
    writeTemplateFile
}

proc lineUpdate {g} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	set l $vsd(ed:$e:$g)
	foreach dfid [lindex [$l -info] 7] {
	    fileUpdate $dfid
	}
    }
}

proc getLineStyle {g e} {
    $g element cget $e -smooth
}

proc addLineToClipboard {l g e} {
    global vsd
    emptyClipboard
    lappend vsd(clipboard) "linecmd"
    lappend vsd(clipboard) [list $l [$g element cget $e -mapy] [$g element cget $e -symbol] [getLineStyle $g $e]]
    
}

proc lineCut {g} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	addLineToClipboard $vsd(ed:$e:$g) $g $e
	deleteElement $g $e 0
    }
}

proc lineCopy {g} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	addLineToClipboard [$vsd(ed:$e:$g) -copy] $g $e
    }
}


proc lineDelete {g} {
    global vsd
    foreach e [getSelectedLines $g] {
	deleteElement $g $e
    }
}

proc lineCombine {g op title} {
    global vsd

    set e [getSelectedLine $g]
    if {$e == {}} {
	return
    }
    if {$vsd($g:chartOp) != {}} {
	# do the above check so that default right click action not taken
	chartCancelOp$vsd($g:chartOp) $g
    }
    set vsd($g:combineData) [list $e $op]
    set vsd($g:chartOp) "Combine"
    $g config -cursor crosshair
    hideMarker $g activeLine
    append title ", right click to cancel"
    $g marker create text -name "chartop_title" -text $title \
	    -coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
}

proc lineAdd {g} {
    lineCombine $g "+" "Select line to add with"
}
proc lineDivide {g} {
    lineCombine $g "/" "Select line to divide by"
}
proc lineDiff {g} {
    lineCombine $g "-" "Select line to diff with"
}

proc getLineInfoStr {linfo {indent ""}} {
    set nextindent "$indent  "
    foreach dfid [lindex $linfo 7] {
	lappend dfnames [lindex [$dfid -info] 0]
    }

    set ctrunits [getStatUnits [lindex $linfo 1]]
    set infoStr "${indent}Line: [lrange $linfo 0 1] "
    set subtractor [lindex $linfo 12]
    set divider [lindex $linfo 13]
    if {$divider != 1.0} {
	if {[expr {abs($divider)}] >= 1.0} {
	    append infoStr "/ $divider "
	} else {
	    append infoStr "* [expr {1.0 / $divider}] "
	}
    }
    if {$subtractor != 0} {
	if {$subtractor < 0} {
	    append infoStr "+ [expr {- $subtractor}] "
	} else {
	    append infoStr "- $subtractor "
	}
    }
    set ctr [lindex $linfo 1]
    set ctrAlias [getCtrAlias $ctr]
    if {![string equal $ctr $ctrAlias]} {
	append infoStr "alias: $ctrAlias "
    }
    append infoStr "filter: [lindex $linfo 5]  units: $ctrunits "
    if {[lindex $linfo 11] != 0} {
	append infoStr "normalized "
    }
    if {[llength $dfnames] > 1} {
	append infoStr "files: $dfnames"
    } else {
	append infoStr "file: $dfnames"
    }

    set instList [lindex $linfo 8]
    set operator [lindex $linfo 9]
    if {$operator != {}} {
	append infoStr "\n${indent}    derived using \"$operator\" from these two lines:"
	append infoStr "\n${indent}    [getLineInfoStr [lindex $instList 0] $nextindent]"
	append infoStr "\n${indent}    [getLineInfoStr [lindex $instList 1] $nextindent]"
    } elseif {[llength $instList] > 1} {
	append infoStr " dataSources:"
	foreach id $instList {
	    append infoStr "\n${indent}    [lindex [sl_stat -instinfo $id] 0]"
	}
    }
    return $infoStr
}

proc lineInfo {g} {
    global vsd

    set infoStr {}
    foreach e [getSelectedLines $g] {
        set l $vsd(ed:$e:$g)
        append infoStr [getLineInfoStr [$l -info]]

        set xStart [$g xaxis cget -min]
        set xEnd [$g xaxis cget -max]
        set lstats [$l -stats $xStart $xEnd]
        set samples [lindex $lstats 0]
        set min [lindex $lstats 1]
        set max [lindex $lstats 2]
        set ave [lindex $lstats 3]
        set stddev [lindex $lstats 4]
        set startString [xToStr $g [lindex $lstats 5]]
        set endString [xToStr $g [lindex $lstats 6]]
        append infoStr "\n  Starting at $startString and ending at $endString:"
        append infoStr "\n    sample count: $samples  min: $min  max: $max"
        append infoStr "\n    average: $ave  stddev: $stddev\n"
    }
    if {$infoStr != {}} {
        showData $infoStr
    }
}

proc lineDelta {g} {
    global vsd

    set e [getSelectedLine $g]
    if {$e == {}} {
	return
    }

    if {$vsd($g:chartOp) != {}} {
	# do the above check so that default right click action not taken
	chartCancelOp$vsd($g:chartOp) $g
    }

    set vsd($g:deltaLine) $e
    if [info exists vsd($g:deltapoint1)] {
	unset vsd($g:deltapoint1)
    }
    set vsd($g:chartOp) "Delta"
    $g config -cursor crosshair
    hideMarker $g activeLine
    set title "Click on first data point, right click to cancel"
    $g marker create text -name "chartop_title" -text $title \
	    -coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
}

proc lineTrimLeft {g} {
    global vsd

    set e [getSelectedLine $g]
    if {$e == {}} {
	return
    }

    if {$vsd($g:chartOp) != {}} {
	# do the above check so that default right click action not taken
	chartCancelOp$vsd($g:chartOp) $g
    }

    set vsd($g:trimLine) $e
    set vsd($g:trimLeft) 1
    set vsd($g:chartOp) "Trim"
    $g config -cursor crosshair
    hideMarker $g activeLine
    set title "Click on first good data point, right click to cancel"
    $g marker create text -name "chartop_title" -text $title \
	    -coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
}

proc lineTrimRight {g} {
    global vsd

    set e [getSelectedLine $g]
    if {$e == {}} {
	return
    }

    if {$vsd($g:chartOp) != {}} {
	# do the above check so that default right click action not taken
	chartCancelOp$vsd($g:chartOp) $g
    }

    set vsd($g:trimLine) $e
    set vsd($g:trimLeft) 0
    set vsd($g:chartOp) "Trim"
    $g config -cursor crosshair
    hideMarker $g activeLine
    set title "Click on last good data point, right click to cancel"
    $g marker create text -name "chartop_title" -text $title \
	    -coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
}


proc lineUntrimLeft {g} {
    global vsd

    set e [getSelectedLine $g]
    if {$e == {}} {
	return
    }

    $vsd(ed:$e:$g) -trimleft 0
    trimUpdate $g $e
}

proc lineUntrimRight {g} {
    global vsd

    set e [getSelectedLine $g]
    if {$e == {}} {
	return
    }

    $vsd(ed:$e:$g) -trimright -1
    trimUpdate $g $e
}

proc lineNormalize {g} {
    global vsd

    set e [getSelectedLine $g]
    if {$e == {}} {
	return
    }

    set l $vsd(ed:$e:$g)
    if {$vsd($g:normalized)} {
	$l -normalize
    } else {
	$l -unnormalize
    }
    updateDerivedLines
}

proc trimUpdate {graph element} {
    global vsd

    updateFileTrimMenuItems [$vsd(statsrc) -info]
    updateAllLineTrimMenuItems
    setInstanceList
    updateGraphWidgetState
    updateAllActiveLines
}

proc chartCompare {g} {
    global vsd

    if {$vsd($g:chartOp) != {}} {
	# do the above check so that default right click action not taken
	chartCancelOp$vsd($g:chartOp) $g
    }

    if [info exists vsd($g:compareLine1)] {
	unset vsd($g:compareLine1)
    }
    if [info exists vsd($g:comparepoint1)] {
	unset vsd($g:comparepoint1)
    }
    set vsd($g:chartOp) "Compare"
    $g config -cursor crosshair
    hideMarker $g activeLine
    set title "Click on first data point, right click to cancel"
    $g marker create text -name "chartop_title" -text $title \
	    -coords {-Inf Inf} -anchor nw -bg {} -font vsdsf
}

proc emptyClipboard {} {
    global vsd
    foreach {type data} $vsd(clipboard) {
	switch -exact $type {
	    "linecmd" {
		[lindex $data 0] -free
	    }
	}
    }
    set vsd(clipboard) {}
}

proc chartPaste {w g} {
    global vsd
    foreach {type data} $vsd(clipboard) {
	switch -exact $type {
	    "linecmd" {
		set mapaxis [lindex $data 1]
		set symbol [lindex $data 2]
		set style [lindex $data 3]
		addLineToChart [lindex $data 0] 0 1 $mapaxis $symbol $style
	    }
	    "selection" {
		addToChart 0 [lindex $data 0] [lindex $data 1]
	    }
	}
    }
    set vsd(clipboard) {}
}

proc getCtrAlias {ctr} {
    global ctrAliases
    if [info exists ctrAliases($ctr)] {
	return $ctrAliases($ctr)
    } else {
	return $ctr
    }
}

proc getLineLegendLabel {i lineinfo} {
    global vsd
    set instinfo [lindex $lineinfo 0]
    set lineinst [lindex $instinfo 0]
    set obj [lindex $lineinfo 6]
    # strip off any object version extension
    set obj [file rootname $obj]
    if {[string equal $obj "Gem"] ||
        [string equal $obj "Session"] ||
	[string equal $obj "Extent"] ||
	[string equal $obj "GcSession"]} {
	# add session id on end of name
	set session [lindex $instinfo 2]
	if {$session != 0 || [string equal $obj "Extent"]} {
	    append lineinst "-$session"
	}
    }
    global vsdnametable
    if {[info exists vsdnametable($lineinst)] && $vsdnametable($lineinst) > 1} {
	set pid [lindex $instinfo 1]
	if {$pid != 0 && $pid != -1} {
	    append lineinst "_[lindex $instinfo 1]"
	}
	if {[string equal $lineinst "_Total"]} {
	    set lineinst "$obj$lineinst"
	}
    }
    
    set linectr [getCtrAlias [lindex $lineinfo 1]]
    set linefilter [lindex $lineinfo 5]

    if {[string equal $linefilter "none"]} {
	set label "$i.  $lineinst, $linectr"
    } elseif {[string equal $linefilter "aggregate"]} {
	set label "$i.  $lineinst, $linectr+"
    } elseif {[string equal $linefilter "smooth"]} {
	set label "$i.  $lineinst, $linectr~"
    } else {
	if {[string equal $linefilter "persecond"]} {
	    set label "$i.  $lineinst, $linectr/sec"
	} elseif {[string equal $linefilter "persample"]} {
	    set label "$i.  $lineinst, $linectr/sample"
	} else {
	    set label "$i.  $lineinst, $linectr, $linefilter"
	}
    }
}

proc lineFilter {g filter} {
    global vsd
    foreach e [getSelectedLines $g] {
	set line $vsd(ed:$e:$g)
	$line -refilter $filter
    }
    updateDerivedLines
}

proc lineSymbol {g symbol} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	$g element configure $e -symbol $symbol
    }
}

proc lineMenuSymbol {g} {
    global vsd
    lineSymbol $g $vsd($g:linesym)
}

proc lineStyle {g style} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	$g element configure $e -smooth $style
    }
}

proc lineMenuStyle {g} {
    global vsd
    lineStyle $g $vsd($g:linestyle)
}

proc lineGraphOnLeft {g} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	if {$vsd($g:graphonleft)} {
	    set mapaxis "y"
	    set unmap "y2"
	} else {
	    set mapaxis "y2"
	    set unmap "y"
	}
	$g element configure $e -mapy $mapaxis
	deactivateAxis $g
	activateAxis $g $e

	showAxis $g ${mapaxis}axis
	if {[string equal $mapaxis "y"]} {
	    $g configure -leftmargin 0
	} else {
	    $g configure -rightmargin 0
	}

	foreach e [$g element names] {
	    if {[string equal $unmap [$g element cget $e -mapy]]} {
		return;
	    }
	}
	# No more lines using this axis so unmap it
	hideAxis $g ${unmap}axis
	if {[string equal $unmap "y"]} {
	    $g configure -leftmargin 2
	} else {
	    $g configure -rightmargin 2
	}
    }
}

proc updateLineDataDisplay {g e line} {
    $g marker configure activeLine -text [getLineLabel $g $e]
    set label [getLineLegendLabel $e [$line -info]]
    $g element configure $e -label $label
    chartAxisTitle $g [$g element cget $e -mapy]axis
    chartAxisTitle $g "xaxis"
    showLineInfo $g $e
}

proc chartChangeCounter {g newctr} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	set line $vsd(ed:$e:$g)
	$line -changectr $newctr
	updateDerivedLines
    }
}

# call updateDerivedLines if a line has been changed in a way that can
# cause the info about a derived line to change.
proc updateDerivedLines {} {
    global bltActiveEntry
    global vsd

    # make sure every active line's info is correct
    foreach g [array names bltActiveEntry] {
	if {$bltActiveEntry($g) != -1} {
	    set e $bltActiveEntry($g)
	    set line $vsd(ed:$e:$g)
	    updateLineDataDisplay $g $e $line
	}
    }
    # make sure the names in the legend of each graph
    foreach n [array names vsd ed:*] {
	set nl [split $n ':']
	set e [lindex $nl 1]
	set g [lindex $nl 2]
	set line $vsd($n)
	set label [getLineLegendLabel $e [$line -info]]
	$g element configure $e -label $label
     }
}
    
proc chartBrowseCounters {c} {
    showCounterInfo $c
}

proc chartComputeCounters {g mf} {
    global vsd
    set e [getSelectedLine $g]
    if {$e != {}} {
	set linfo [$vsd(ed:$e:$g) -info]
	set obj [lindex $linfo 6]
	set instId [lindex $linfo 10]
	set counter [$mf.linef.counter cget -value]
	if {$vsd(noFlatlines)} {
	    set newctrlistid [list $obj $instId]
	} else {
	    set newctrlistid $obj
	}
	if {$vsd($g:ctrlistid) != {}} {
	    if {[string equal $newctrlistid $vsd($g:ctrlistid)]} {
		# the listbox already contains the right stuff
		set lb [$mf.linef.counter subwidget listbox]
		set endIdx [$lb size]
		set idx 0
		while {$idx < $endIdx} {
		    if {[string equal $counter [$lb get $idx]]} {
			$mf.linef.counter configure -disablecallback true
			$mf.linef.counter pick $idx
			$mf.linef.counter configure -disablecallback false
			break
		    }
		    incr idx
		}
		return
	    }
	}
	set vsd($g:ctrlistid) $newctrlistid
	set cb $mf.linef.counter
	set cl [$cb subwidget listbox]
	$cl delete 0 end
	set idx 0
	set fi -1
	set ctrlist [sl_stat -objctrs $obj]
	if {$vsd(noFlatlines)} {
	    if {$instId != -1} {
		set lineCtr [lindex $linfo 1]
		set newlist {}
		foreach ctr $ctrlist {
		    if [sl_stat -ctrzero $ctr $instId] {
			if {![string equal $ctr $lineCtr]} {
			    # dont add this guy
			    continue
			}
		    }
		    lappend newlist $ctr
		}
		set ctrlist $newlist
	    }
	}
	set ctrlist [lsort -dictionary $ctrlist]
	
	eval $cl insert end $ctrlist
	set fi [lsearch -exact $ctrlist $counter]
	if {$fi != -1} {
	    $cb configure -disablecallback true
	    $cb pick $fi
	    $cb configure -disablecallback false
	}
    }
}

proc searchHList {w str {next 0} {forwards 1}} {
    global vsd
    if {$str == ""} {
	return
    }
    set anchor [$w info anchor]
    set l [$w info children]
    if {$anchor != ""} {
        set idx [lsearch -exact $l $anchor]
	if {$idx != -1} {
	    set oldidx $idx
	    incr idx
	    if {$idx <= [llength $l]} {
		set l [concat [lrange $l $idx end] [lrange $l 0 $oldidx]]
	    }
	}
    }
    if [string is digit [string index $str 0]] {
	foreach e $l {
	    if [$w item exists $e $vsd(ilColumnIdx:ProcessId)] {
		if {[string equal $str [$w item cget $e $vsd(ilColumnIdx:ProcessId) -text]]} {
		    $w anchor set $e
		    $w see $e
		    showFileForAnchor
		    setStatus "Found Pid \"$str\"."
		    bell
		    return
		}
	    }
	}
    } else {
	set pattern "*$str*"
	foreach e $l {
	    if [string match -nocase $pattern [$w entrycget $e -data]] {
		$w anchor set $e
		$w see $e
		showFileForAnchor
		return
            }
	}
	setStatus "Nothing matches \"$pattern\"."
	bell
    }
}

proc searchCtrHList {w str {next 0} {forwards 1}} {
    global vsd
    if {$str == ""} {
	return
    }
    set anchor [$w info anchor]
    set l [$w info children]
    if {$anchor != ""} {
        set idx [lsearch -exact $l $anchor]
	if {$idx != -1} {
	    set oldidx $idx
	    incr idx
	    if {$idx <= [llength $l]} {
		set l [concat [lrange $l $idx end] [lrange $l 0 $oldidx]]
	    }
	}
    }
    set pattern "*$str*"
    foreach e $l {
	if [string match -nocase $pattern [$w entrycget $e -text]] {
	    $w selection clear
	    $w anchor set $e
	    $w selection set $e
	    $w see $e
	    return
	}
    }
    setStatus "Nothing matches \"$pattern\"."
    bell
}

proc searchComboBox {w str {next 0} {forwards 1}} {
    global vsd
    set lb [$w subwidget listbox]
    set curIdx [$lb index active]
    set pattern "*$str*"
    if {$curIdx == -1} {
	set curIdx 0
    } else {
	incr curIdx
    }
    set endIdx [$lb size]
    set idx $curIdx
    while {$idx < $endIdx} {
	set c [$lb get $idx]
	if [string match -nocase $pattern $c] {
	    $w configure -disablecallback true
	    $w pick $idx
	    $w configure -disablecallback false
	    set browsecmd [$w cget -browsecmd]
	    if {$browsecmd != {}} {
		$browsecmd $c
	    }
	    return
	}
	incr idx
    }
    if {$curIdx != 0} {
	set endIdx $curIdx
	set idx 0
	while {$idx < $endIdx} {
	    set c [$lb get $idx]
	    if [string match -nocase $pattern $c] {
		$w configure -disablecallback true
		$w pick $idx
		$w configure -disablecallback false
		set browsecmd [$w cget -browsecmd]
		if {$browsecmd != {}} {
		    $browsecmd $c
		}
		return
	    }
	    incr idx
	}
    }
    setStatus "Nothing matches \"$pattern\"."
    bell
}

proc searchTrace {n1 n2 op} {
    global vsd
    $vsd(search:func) $vsd(search:parent) $vsd($n2)
}

proc nextSearch {} {
    global vsd
    set p $vsd(search:parent)
    $vsd(search:func) $p $vsd($p:st) 1
}

proc prevSearch {} {
    global vsd
    set p $vsd(search:parent)
    $vsd(search:func) $p $vsd($p:st) 1 0
}

proc endSearch {w restoreFocus} {
    global vsd
    wm withdraw $w
    if {[info exists vsd(search:parent)]} {
	set p $vsd(search:parent)
	trace vdelete vsd($p:st) w searchTrace
	if {$vsd(search:oldfocus) != ""} {
	    focus $vsd(search:oldfocus)
	}
    }
}

proc createTemplateName {} {
    global vsd widgetHelp
    set w .vsdtemplateName
    toplevel $w
    wm withdraw $w
    wm overrideredirect $w 1
    frame $w.f -bd 3 -relief raised
    pack $w.f -fill both -expand yes
    tixLabelEntry $w.f.entry -label "Template Name:"

    set widgetHelp($w) {String Entry Editing}

    set entry [$w.f.entry subwidget entry]
    set vsd(template:tv) ""
    $entry config -textvariable vsd(template:tv)
    pack $w.f.entry -fill both -expand yes
    update
    bind $w <FocusOut>  [list endTemplateName $w $entry 0]
    bind $entry <Return> [list endTemplateName $w $entry 1]
}

proc endTemplateName {w entry restoreFocus} {
    global vsd
    wm withdraw $w
    if {[info exists vsd(template:parent)]} {
	set p $vsd(template:parent)
	if {$vsd(template:oldfocus) != ""} {
	    focus $vsd(template:oldfocus)
	}
        unset vsd(template:parent)
        set vsd(template:result) $vsd(template:tv)
    }
}


proc createSearch {} {
    global vsd widgetHelp
    set w .vsdsearch
    toplevel $w
    wm withdraw $w
    wm overrideredirect $w 1
    frame $w.f -bd 3 -relief raised
    pack $w.f -fill both -expand yes
    tixLabelEntry $w.f.entry -label "Search:"

    set widgetHelp($w) {String Entry Editing}

    set entry [$w.f.entry subwidget entry]
    pack $w.f.entry -fill both -expand yes
    update
    bind $w <FocusOut>  [list endSearch $w 0]
    bind $entry <Return> [list endSearch $w 1]
    bind $entry <Control-s> nextSearch
    bind $entry <Control-r> prevSearch
    bind $entry <Tab> {nextSearch; break}
}

proc createHelpSearch {} {
    global vsd widgetHelp
    set w .vsdhelpsearch
    toplevel $w
    wm withdraw $w
    wm overrideredirect $w 1

    set widgetHelp($w) {Help Search Control}

    frame $w.f -bd 3 -relief raised
    pack $w.f -fill both -expand yes
    tixLabelEntry $w.f.entry -label "Search:"

    set entry [$w.f.entry subwidget entry]
    pack $w.f.entry -fill both -expand yes -side left
    button $w.f.all -text "All Topics" -command searchAllTopics
    button $w.f.next -text "Next" -command nextSearch
    button $w.f.prev -text "Prev" -command prevSearch
    pack $w.f.all $w.f.next $w.f.prev -side right -expand no -fill none
    update
    bind $w <FocusOut>  [list endSearch $w 0]
    bind $entry <Return> [list endSearch $w 1]
    bind $entry <Control-s> nextSearch
    bind $entry <Control-r> prevSearch
    bind $entry <Tab> {nextSearch; break}
    bind $entry <Meta-s> searchAllTopics
}

proc extraStartSearch {parent searchFunc g mf} {
    chartComputeCounters $g $mf
    startSearch $parent $searchFunc
    [$parent subwidget entry] icursor 0 
}

proc startSearch {parent searchFunc {yoffset 0} {w .vsdsearch}} {
    global vsd
    update ;# allows startSearch to be called from popup menu
    set vsd(search:parent) $parent
    set vsd(search:func) $searchFunc
    set vsd(search:oldfocus) [focus]
    set vsd(search:unfound) {}
    if {! [info exists vsd($parent:st)]} {
	set vsd($parent:st) ""
    }
    set entry [$w.f.entry subwidget entry]
    $entry config -textvariable vsd($parent:st)
    trace variable vsd($parent:st) w searchTrace
    
    set width [winfo width $parent]
    set x [winfo rootx $parent]
    set y [winfo rooty $parent]
    set searchheight [winfo height $w]
    if {$searchheight == 1} {
	set searchheight [winfo reqheight $w]
	if {$searchheight == 1} {
	    set searchheight 32
	}
    }
    set y [expr {$y - $searchheight - $yoffset}]
    raise $w
    wm deiconify $w
    wm geometry $w "${width}x$searchheight+$x+$y"
    focus $entry
}

proc findByFirstLetter {cb letter iscombo} {
    global vsd
    if {$letter >= "A" && $letter <= "Z"} {
	set letter [string tolower $letter]
    }
    if {$letter >= "a" && $letter <= "z"} {
	set lb [$cb subwidget listbox]
	set curIdx [$lb index active]
	if {$curIdx == -1} {
	    set curIdx 0
	} else {
	    incr curIdx
	}
	set endIdx [$lb size]
	set idx $curIdx
	while {$idx < $endIdx} {
	    set c [$lb get $idx]
	    set fc [string tolower [string index $c 0]]
	    if {$fc == $letter} {
		if {$iscombo} {
		    $cb configure -disablecallback true
		    $cb pick $idx
		    $cb configure -disablecallback false
		    set browsecmd [$cb cget -browsecmd]
		    if {$browsecmd != {}} {
			$browsecmd $c
		    }
		} else {
		    $lb selection clear 0 end
		    $lb selection set $idx
		    $lb activate $idx
		    $lb see $idx
		    showCounterInfo $c
		}
		return
	    }
	    incr idx
	}
	if {$curIdx != 0} {
	    set endIdx $curIdx
	    set idx 0
	    while {$idx < $endIdx} {
		set c [$lb get $idx]
		set fc [string tolower [string index $c 0]]
		if {$fc == $letter} {
		    if {$iscombo} {
			$cb configure -disablecallback true
			$cb pick $idx
			$cb configure -disablecallback false
			set browsecmd [$cb cget -browsecmd]
			if {$browsecmd != {}} {
			    $browsecmd $c
			}
		    } else {
			$lb selection clear 0 end
			$lb selection set $idx
			$lb activate $idx
			$lb see $idx
			showCounterInfo $c
		    }
		    return
		}
		incr idx
	    }
	}
	setStatus "No statistic starts with \"$letter\"."
	bell
    }
}

proc HListPrefixClear {w} {
    global vsd
    set vsd(prefix:$w) {}
}

proc HListPrefixSearch {w letter} {
    global vsd
    if {$letter >= "A" && $letter <= "Z"} {
	set letter [string tolower $letter]
    }
    if {$letter >= "a" && $letter <= "z"} {
	if [info exists vsd(prefix:$w)] {
	    set prefix $vsd(prefix:$w)
	    append prefix $letter
	} else {
	    set prefix $letter
	}
	set vsd(prefix:$w) $prefix
	
	set l [$w info children]
	foreach e $l {
	    set ctr [string tolower [$w entrycget $e -text]]
	    if {[string first $prefix $ctr] == 0} {
		$w selection clear
		$w selection set $e
		$w anchor set $e
		$w see $e
		showCounterInfo $ctr
		return
	    }
	}
	setStatus "No statistic starts with \"$vsd(prefix:$w)\"."
	bell
    }
    HListPrefixClear $w
}

proc extraFindByFirstLetter {cb letter g mf} {
    if {$letter >= "A" && $letter <= "Z"} {
	set letter [string tolower $letter]
    }
    if {$letter >= "a" && $letter <= "z"} {
	chartComputeCounters $g $mf
	findByFirstLetter $cb $letter 1
	[$cb subwidget entry] icursor 0 
    }
}

proc showElapsedOnTicks {g x} {
    global vsd
    set x [expr {wide($x)}]
    if [catch {sl_stat -getdate $x $vsd(time_shift_hours) "elapsed"} result] {
	return $x
    } else {
	return $result
    }
}

proc showTimeOnTicks {g x} {
    global vsd
    set x [expr {wide($x)}]
    if [catch {sl_stat -getdate $x $vsd(time_shift_hours) "time"} result] {
	return $x
    } else {
	return $result
    }
}

proc showDateOnTicks {g x} {
    global vsd
    set x [expr {wide($x)}]
    if [catch {sl_stat -getdate $x $vsd(time_shift_hours) "date"} result] {
	return $x
    } else {
	return $result
    }
}

proc chartMenuTime {g} {
    global vsd
    chartAxisTitle $g xaxis
    if {[string equal $vsd($g:xformat) "elapsed"]} {
	$g xaxis configure -command showElapsedOnTicks
    } elseif {[string equal $vsd($g:xformat) "time"]} {
	$g xaxis configure -command showTimeOnTicks
    } else {
	$g xaxis configure -command showDateOnTicks
    }
}

proc computeScale {g e} {
    global vsd
    set l $vsd(ed:$e:$g)
    set yaxis [$g element cget $e -mapy]
    append yaxis "axis"
    scan [$g xaxis limits] "%s %s" xmin xmax
    scan [$g $yaxis limits] "%s %s" ymin ymax

    set edata [$l -info]
    set xvname [lindex $edata 2]
    set yvname [lindex $edata 3]
    set oldscale [lindex $edata 4]
    global $xvname
    set lxmin [set ${xvname}(min)]
    set lxmax [set ${xvname}(max)]
    if {$lxmin > $xmax || $lxmax < $xmin} {
	# No data points in current graph
	return
    }
    if {$lxmin < $xmin} {
	set lxmin $xmin
    }
    if {$lxmax > $xmax} {
	set lxmax $xmax
    }
    # calculate minidx
    set xvsize [$xvname length]
    incr xvsize -1
    set minidx 0
    set maxidx $xvsize
#     set dfid [lindex $edata 7]
#     set interval [lindex [$dfid -info] 6]
#     if {$interval != 0} {
# 	set minidx [expr wide($lxmin / $interval)]
# 	if {$minidx > $xvsize} {
# 	    set minidx 0
# 	}
# 	set maxidx [expr wide($lxmax / $interval)]
# 	if {$maxidx > $xvsize} {
# 	    set maxidx $xvsize
# 	}
#     }
#     while {[set ${xvname}($minidx)] > $lxmin} {
# 	if {$minidx == 0} {
# 	    break
# 	}
# 	incr minidx -1
#     }
    while {[set ${xvname}($minidx)] < $lxmin} {
	incr minidx
	if {$minidx > $xvsize} {
	    return
	}
    }
    while {[set ${xvname}($maxidx)] < $lxmax} {
	if {$maxidx == $xvsize} {
	    break
	}
	incr maxidx
    }
    while {[set ${xvname}($maxidx)] > $lxmax} {
	incr maxidx -1
	if {$maxidx <= $minidx} {
	    return
	}
    }
    # Need to unscale so that y values used will be correct
    vector create tmpy
    tmpy set [$yvname range $minidx $maxidx]
    set tmpyMax [vector expr {max(tmpy)}]
    vector destroy tmpy
    if {$tmpyMax == 0} {
	return
    }
    # NYI: Should handle negative numbers better.
    set newscale  [expr {$ymax / $tmpyMax}]
    if {$newscale >= 1.5} {
	set newscale [expr {$newscale * $oldscale}]
	$l -scale $newscale
	#updateLineDataDisplay $g $e $l
    }
}

proc lineComputeScale {g} {
    global vsd
    foreach e [getSelectedLines $g] {
	catch {computeScale $g $e} result
	if [wizardMode] {
	    if {$result != {}} {
		showError "computeScale: $result"
	    }
	}
        if {[string equal $e [getSelectedLine $g]]} {
            set l $vsd(ed:$e:$g)
            updateLineDataDisplay $g $e $l
        }
    }
}

proc lineUnscale {g} {
    lineChangeScale $g 1
    global vsd
    foreach e [getSelectedLines $g] {
	set l $vsd(ed:$e:$g)
	$l -scale 1
        if {[string equal $e [getSelectedLine $g]]} {
            updateLineDataDisplay $g $e $l
        }
    }
}

proc allComputeScale {g} {
    global vsd
    foreach e [$g element names] {
	catch {computeScale $g $e} result
	if [wizardMode] {
	    if {$result != {}} {
		showError "computeScale: $result"
	    }
	}
    }
    set e [getSelectedLine $g]
    if {$e != {}} {
	set l $vsd(ed:$e:$g)
	updateLineDataDisplay $g $e $l
    }
}

proc allUnscale {g} {
    global vsd
    foreach e [$g element names] {
	$vsd(ed:$e:$g) -scale 1
    }
    set e [getSelectedLine $g]
    if {$e != {}} {
	set l $vsd(ed:$e:$g)
	updateLineDataDisplay $g $e $l
    }
}

proc createGraphWindow {title} {
    global vsd isWindows widgetHelp
    global bltActiveEntry
    global bltActiveGraph
    

    set w ".chart$vsd(graphcreates)"
    set geom [getGraphGeometry $w]
    toplevel $w
    wm geometry $w $geom

    set widgetHelp($w) {Chart Window Features}

    if [info exists vsd(ct:$title)] {
	set title {}
    }
    if {$title == {}} {
	set title "Chart $vsd(graphcreates)"
	set templateName "chart$vsd(graphcreates)"
    } else {
	regsub -all { } $title {} templateName
    }

    incr vsd(graphcount)
    incr vsd(graphcreates)

    set vsd(ct:$title) $w
    $vsd(w:chartlist) configure -disablecallback true
    $vsd(w:chartlist) addhistory $title
    $vsd(w:chartlist) pick 0
    $vsd(w:chartlist) configure -disablecallback false
    set g $w.graph
    set bltActiveGraph($g) 0
    set bltActiveEntry($g) -1
    
    wm title $w $title

    set mf [frame $w.mf -bd 2 -relief raised]
    menubutton $mf.chart -menu $mf.chart.m -text "Chart" -underline 0 \
	-takefocus 0 -font [tix option get bold_font]
    menu $mf.chart.m -tearoff 1

    set mftmp $mf.chart.m.templates
    set widgetHelp($mftmp) {Chart Menu Add From Template SubMenu}
    menu $mftmp -tearoff 1
    createGraphTemplateMenu $mftmp $title
    $mf.chart.m add cascade -label "Add From Template" \
	-menu $mftmp -underline 0

    $mf.chart.m add command -label "Save Template" -underline 0 \
	-command "saveGraphTemplate $g $templateName"
    $mf.chart.m add command -label "Paste" \
	-command [list chartPaste $w $g] \
	-accelerator "Ctrl+v"
    if {! $isWindows} {
 	$mf.chart.m add command -label "Print"  \
 	    -command "printGraph $g $w.ps" \
 	    -accelerator "Ctrl+p"
    }
    $mf.chart.m add command -label "Snapshot"  \
	-command "snapshotGraph $g $w.ps"
    $mf.chart.m add command -label "Help..." -underline 0 \
	-command {showChartHelp}
    $mf.chart.m add separator

    set vsd($g:chartOp) {}
    set vsd($g:showlegend) $vsd(def:showlegend)
    set vsd($g:xformat) $vsd(def:xformat)
    set vsd($g:xaxis:showtitle) $vsd(def:xaxis:showtitle)
    set vsd($g:yaxis:showtitle) $vsd(def:yaxis:showtitle)
    set vsd($g:y2axis:showtitle) $vsd(def:y2axis:showtitle)
    set vsd($g:showcrosshairs) $vsd(def:showcrosshairs)
    set vsd($g:showgridlines) $vsd(def:showgridlines)
    set vsd($w:showcurxy) $vsd(def:showcurxy)
    set vsd($w:showminmax) $vsd(def:showminmax)
    set vsd($w:showlinestats) $vsd(def:showlinestats)

    $mf.chart.m add command -label "Zoom In" \
	-command [list chartZoom $g] \
	-accelerator "Ctrl+z"
# 45172 - call ChartHandleRightClick instead of ChartCancelOpZoom
    $mf.chart.m add command -label "Zoom Out" \
	-command [list ChartHandleRightClick $g]
    $mf.chart.m add command -label "Compare Two Points" \
	-command [list chartCompare $g]
#	-accelerator "Ctrl+c"
    if 0 {
	$mf.chart.m add command -label "Set Min Time" \
	    -command [list chartSetMinTime $g]
	$mf.chart.m add command -label "Set Max Time" \
	    -command [list chartSetMaxTime $g]
    }
    $mf.chart.m add command -label "Compute Scale All" \
	-command [list allComputeScale $g] \
	-accelerator "Ctrl+S"
    $mf.chart.m add command -label "Unscale All" \
	-command [list allUnscale $g] \
	-accelerator "Ctrl+N"
    $mf.chart.m add separator

    set mtime $mf.chart.m.time
    set widgetHelp($mtime) {Chart Menu Time Format SubMenu}
    menu $mtime -tearoff 1
    $mtime add radio -label "Elapsed Time in Seconds" -value "elapsed" \
	-variable vsd($g:xformat) \
	-command [list chartMenuTime $g]
    $mtime add radio -label "Hour:Minute:Second" -value "time" \
	-variable vsd($g:xformat) \
	-command [list chartMenuTime $g]
    $mtime add radio -label "Month/Day Hour:Minute:Second" -value "date" \
	-variable vsd($g:xformat) \
	-command [list chartMenuTime $g]

    $mf.chart.m add check -label "Show Legend" \
	-command [list chartShowLegend $g] \
	-variable vsd($g:showlegend)
    $mf.chart.m add cascade -label "Time Format" -menu $mtime -underline 0
    $mf.chart.m add check -label "Show Time Axis Title" \
	-command [list chartAxisTitle $g "xaxis"] \
	-variable vsd($g:xaxis:showtitle)
    $mf.chart.m add check -label "Show Left Axis Title" \
	-command [list chartAxisTitle $g "yaxis"] \
	-variable vsd($g:yaxis:showtitle)
    $mf.chart.m add check -label "Show Right Axis Title" \
	-command [list chartAxisTitle $g "y2axis"] \
	-variable vsd($g:y2axis:showtitle)
    $mf.chart.m add check -label "Show Current Values" \
	-command [list chartShowCurXY $w $mf] \
	-variable vsd($w:showcurxy)
    $mf.chart.m add check -label "Show Min and Max" \
	-command [list chartShowMinMax $w $mf] \
	-variable vsd($w:showminmax)
    $mf.chart.m add check -label "Show Line Stats" \
	-variable vsd($w:showlinestats)
    $mf.chart.m add check -label "Show CrossHairs" \
	-command [list chartShowCrossHairs $g] \
	-variable vsd($g:showcrosshairs)
    $mf.chart.m add check -label "Show Grid Lines" \
	-command [list chartShowGridLines $g] \
	-variable vsd($g:showgridlines)
    $mf.chart.m add separator
    $mf.chart.m add command -label "Close   " -command "closeGraph $w $g"
    pack $mf.chart -side left
    set widgetHelp($mf.chart) {Chart Window Chart Menu}

    menubutton $mf.line -menu $mf.line.m -text "Line" -underline 0 \
	-takefocus 0 -state disabled -font [tix option get bold_font]
    menu $mf.line.m -tearoff 1
    $mf.line.m add command -label "Log Info" -underline 4 \
	-command [list lineInfo $g]
    $mf.line.m add command -label "Log Delta" \
	-command [list lineDelta $g] \
	-accelerator "Ctrl+d"
    $mf.line.m add command -label "Compute Scale" \
	-command [list lineComputeScale $g] \
	-accelerator "Ctrl+s"
    $mf.line.m add command -label "Unscale" \
	-command [list lineUnscale $g] \
	-accelerator "Ctrl+n"
    $mf.line.m add check -label "Graph on Left Axis" \
	-command [list lineGraphOnLeft $g] \
	-variable vsd($g:graphonleft) \
	-accelerator "Ctrl+a"

    set msym $mf.line.m.symbols
    set widgetHelp($msym) {Line Menu Symbol SubMenu}
    menu $msym -tearoff 1
    set vsd($g:linesym) none
    foreach s $vsd(symbollist) {
	$msym add radio -label $s -variable vsd($g:linesym) \
	    -command [list lineMenuSymbol $g]
    }
    $mf.line.m add cascade -label "Symbol" -menu $msym -underline 0
    set mstyle $mf.line.m.styles
    set widgetHelp($mstyle) {Line Menu Sytle SubMenu}
    menu $mstyle -tearoff 1
    set vsd($g:linestyle) linear
    foreach style {linear step natural quadratic} {
	$mstyle add radio -label $style -variable vsd($g:linestyle) \
	    -command [list lineMenuStyle $g]
    }
    $mf.line.m add cascade -label "Style" -menu $mstyle
    $mf.line.m add command -label "Update" \
	-command [list lineUpdate $g] \
	-accelerator "Ctrl+u"

    $mf.line.m add separator
    $mf.line.m add command -label "Add Lines" \
	-command [list lineAdd $g] \
	-accelerator "Ctrl++"
    $mf.line.m add command -label "Diff Lines" \
	-command [list lineDiff $g] \
	-accelerator "Ctrl+-"
    $mf.line.m add command -label "Divide Lines" \
	-command [list lineDivide $g] \
	-accelerator "Ctrl+/"

    $mf.line.m add separator
    $mf.line.m add check -label "Normalize" \
	-command [list lineNormalize $g] \
	-variable vsd($g:normalized)
    $mf.line.m add command -label "Trim Left" \
	-command [list lineTrimLeft $g]
    $mf.line.m add command -label "Trim Right" \
	-command [list lineTrimRight $g]
    $mf.line.m add command -label "Untrim Left" \
	-command [list lineUntrimLeft $g]
    $mf.line.m add command -label "Untrim Right" \
	-command [list lineUntrimRight $g]

    $mf.line.m add separator
    $mf.line.m add command -label "Copy" -command "lineCopy $g" \
	-accelerator "Ctrl+c"
    $mf.line.m add command -label "Cut" -command "lineCut $g" \
	-accelerator "Ctrl+x"
    $mf.line.m add command -label "Delete" -command "lineDelete $g" \
	-accelerator "Del"

    pack $mf.line -side left
    set widgetHelp($mf.line) {Chart Window Line Menu}

    tixLabelFrame $mf.curx -label "X:" -labelside left
    [$mf.curx subwidget label] configure -font vsdsf
    set f [$mf.curx subwidget frame]
    label $f.l -text "" -font vsdsf
    pack $f.l
    set widgetHelp($mf.curx) {Chart Window X: Display}
    $vsd(balloon) bind $mf.curx -msg "Show time offset of data at mouse pointer"

    tixLabelFrame $mf.cury -label "Y:" -labelside left
    [$mf.cury subwidget label] configure -font vsdsf
    set f [$mf.cury subwidget frame]
    label $f.l -text "" -font vsdsf
    pack $f.l
    set widgetHelp($mf.cury) {Chart Window Y: Display}
    $vsd(balloon) bind $mf.cury -msg "Show statistic value of data at mouse pointer"

    tixLabelFrame $mf.min -label "Min:" -labelside left
    [$mf.min subwidget label] configure -font vsdsf
    set f [$mf.min subwidget frame]
    label $f.l -text "" -font vsdsf
    set widgetHelp($mf.min) {Chart Window Min: Display}
    pack $f.l
    tixLabelFrame $mf.max -label "Max:" -labelside left
    [$mf.max subwidget label] configure -font vsdsf
    set f [$mf.max subwidget frame]
    label $f.l -text "" -font vsdsf
    set widgetHelp($mf.max) {Chart Window Max: Display}
    pack $f.l

    frame $mf.linef -bd 0

    set vsd($g:ctrlistid) {}

    tixComboBox $mf.linef.counter -dropdown true -editable false -value "" \
	-listcmd [list chartComputeCounters $g $mf] \
	-browsecmd chartBrowseCounters \
	-command [list chartChangeCounter $g] \
	-state disabled	-options {
	    entry.width 18
	    listbox.height 4
	    listbox.width 33
	}
    set widgetHelp($mf.linef.counter) {Chart Window Statistic ComboBox}
    [$mf.linef.counter subwidget entry] configure -font vsdsf
    [$mf.linef.counter subwidget listbox] configure -font vsdsf
    bind [$mf.linef.counter subwidget entry] <KeyPress> \
	[list extraFindByFirstLetter $mf.linef.counter %A $g $mf]
    bind [$mf.linef.counter subwidget entry] <Control-s> \
	[list extraStartSearch $mf.linef.counter searchComboBox $g $mf]
    $vsd(balloon) bind $mf.linef.counter -msg "Change the line's statistic"

    set fw $mf.linef.filtertype
    tixOptionMenu $fw -command [list lineFilter $g] \
	-state disabled -dynamicgeometry 1
    set widgetHelp($fw) {Chart Window Filter MenuButton}
    [$fw subwidget menubutton] configure -font vsdsf
    [$fw subwidget menu] configure -font vsdsf
    $fw configure -disablecallback true
    $fw add command none -label "No Filter"
    $fw add command persecond -label "PerSecond"
    $fw add command persample -label "PerSample"
#    $fw add command smooth -label "Smooth"
    $fw add command aggregate -label "Aggregate"
    $fw configure -disablecallback false
    $vsd(balloon) bind $fw -msg "Change the line's filter"

    
    set ow $mf.linef.opMenu
    tixOptionMenu $ow -command [list changeConstOp $g] -variable vsd(constOp) \
	-state disabled
    set widgetHelp($ow) {Chart Window Operator MenuButton}
    $vsd(balloon) bind $ow -msg "Select (S)cale, /, *, +, or -"
    [$ow subwidget menubutton] configure -font vsdsf -indicatoron 0 -padx 1
    [$ow subwidget menu] configure -font vsdsf
    $ow configure -disablecallback true
    $ow add command scale -label "S"
    $ow add command divide -label "/"
    $ow add command multiply -label "*"
    $ow add command add -label "+"
    $ow add command subtract -label "-"
    $ow configure -disablecallback false
    tixControl $mf.linef.const -label ":" -state disabled \
        -autorepeat false \
	-incrcmd lineIncrConst -decrcmd lineDecrConst \
	-validatecmd [list lineValidateConst $g] \
	-command [list lineChangeConst $g]
    set widgetHelp($mf.linef.const) {Chart Window Number Entry}
    [$mf.linef.const subwidget label] configure -font vsdsf
    [$mf.linef.const subwidget entry] configure -font vsdsf -width 7

    $vsd(balloon) bind $mf.linef.const -msg "Change the constant the line is modified with"

    pack $mf.linef.counter $fw $ow $mf.linef.const -side left ;# -padx 2
    pack $mf.linef -side right
    if {$vsd($w:showcurxy)} {
	pack $mf.cury $mf.curx -after $mf.linef -side right -padx 2
    }
    if {$vsd($w:showminmax)} {
	pack $mf.max $mf.min -after $mf.linef -side right -padx 2
    }

    graph $g -title "" -topmargin 3 -leftmargin 2 -rightmargin 2 -takefocus 1 \
	-plotbackground $vsd(currentPlotBgColor) -cursor $vsd(graphcursor)

    $g pen configure "activeLine" -color $vsd(activecolor) -fill "" -symbol ""
    #      -outline [lindex $vsd(colorlist) $cidx]
    set widgetHelp($g) {Chart Window Graph}
    hideAxis $g yaxis
    hideAxis $g y2axis

    if {! $isWindows} {
	bind $g <Control-p> [list $mf.chart.m invoke "Print"]
    }
    bind $g <Control-z> [list $mf.chart.m invoke "Zoom In"]
    bind $g <Control-S> [list $mf.chart.m invoke "Compute Scale All"]
#    bind $g <Control-c> [list $mf.chart.m invoke "Compare Two Points"]
    bind $g <Control-N> [list $mf.chart.m invoke "Unscale All"]
    bind $g <Control-plus> [list $mf.line.m invoke "Add Lines"]
    bind $g <Control-minus> [list $mf.line.m invoke "Diff Lines"]
    bind $g <Control-slash> [list $mf.line.m invoke "Divide Lines"]
    bind $g <Control-d> [list $mf.line.m invoke "Log Delta"]
    bind $g <Control-s> [list $mf.line.m invoke "Compute Scale"]
    bind $g <Control-n> [list $mf.line.m invoke "Unscale"]
    bind $g <Control-a> [list $mf.line.m invoke "Graph on Left Axis"]
    bind $g <Control-u> [list $mf.line.m invoke "Update"]
    bind $g <Delete> [list $mf.line.m invoke "Delete"]
    bind $g <Left> [list ZoomHorizontal $g -2]
    bind $g <Right> [list ZoomHorizontal $g +2]
    bind $g <Control-Left> [list ZoomHorizontalPage $g -1]
    bind $g <Control-Right> [list ZoomHorizontalPage $g +1]
#    bind $g <Up> [list ZoomVertical $g +1]
#    bind $g <Down> [list ZoomVertical $g -1]
    bind $g <<Paste>> [list $mf.chart.m invoke "Paste"]
    bind $g <<Copy>> [list $mf.line.m invoke "Copy"]
    bind $g <<Cut>> [list $mf.line.m invoke "Cut"]

    if {1} {
	$g configure -font vsdsf
        $g xaxis configure -tickfont vsdsf -titlefont vsdsf  -background $vsd(currentBgColor)
        $g yaxis configure -tickfont vsdsf -titlefont vsdsf  -background $vsd(currentBgColor)
        $g y2axis configure -tickfont vsdsf -titlefont vsdsf -background $vsd(currentBgColor)
    }
    chartMenuTime $g
    chartAxisTitle $g yaxis
    chartAxisTitle $g y2axis
    
    $g legend configure -position bottom -anchor w -font vsdsf -activeforeground \
        $vsd(activecolor) -activerelief raised -background $vsd(currentBgColor)
    mapLegend $g $vsd($g:showlegend)

    if {$vsd($g:showcrosshairs)} {
	Blt_CrosshairsOn $g
    }
    $g grid configure -dashes {4 6}
    if {$vsd($g:showgridlines)} {
	$g grid on
    }
    Blt_ZoomStack $g
    Blt_ActiveGraph $g

    pack $mf -side top -fill x
    pack $g -side bottom -fill both -expand yes
    wm protocol $w WM_DELETE_WINDOW "closeGraph $w $g"

    $g marker create text -name activeLine -text "" \
	-coords {-Inf Inf} -anchor nw -bg {} -under 0 -font vsdsf
    $g marker create bitmap -name triStart -under 1 \
        -fg $vsd(activecolor) \
	-fill "" -yoffset 6
    $g marker create bitmap -name triEnd -under 1 \
        -fg $vsd(activecolor) \
	-fill "" -yoffset 6

# 44955 - Make right click open pop-up menu to copy Y to clipboard
    set m [menu $g.popupMenu -font vsdsf -tearoff 0]
    $m add command -label "Copy Y Value" -command copyYvalue

    # The <Configure> type can be used to get resize and window move notification
    # bind $w <Configure> {+puts "Configure %W %R %S [wm geometry %W]"}
    setMasterBgColorForWindow $w
    return $w
}

proc getFreeGraphSlot {gw} {
    set elements [$gw.graph element names]
    if {[llength $elements] == 0} {
        return 1
    } else {
        set slot [lindex $elements 0]
        foreach e $elements {
            if {$e > $slot} {
                set slot $e
            }
        }
        incr slot
        return $slot
    }
}

# statFilter returns 1 if the line is ok, 0 if the filter does not want it
proc statFilter {line filter} {
    global vsd
    set stats [$line -stats {} {}]
    #stats = {count min max average stddev}
    set fcount [lindex $filter 0]
    if {$fcount != {}} {
	if {[llength $fcount] == 2} {
	    # we only wants lines who have the number of samples in the range
	    set actualCount [lindex $stats 0]
	    if {$actualCount < [lindex $fcount 0] ||
		$actualCount > [lindex $fcount 1]} {
		return 0
	    }
	} elseif {$fcount < 0} {
	    # we only wants lines who have less samples than the filter
	    set fcount [expr {- $fcount}]
	    if {[lindex $stats 0] > $fcount} {
		# to many samples so reject it
		return 0
	    }
	} else {
	    # we only wants lines who have more samples than the filter
	    if {[lindex $stats 0] < $fcount} {
		# not enough samples so reject it
		return 0
	    }
	}
    }
    set fmin [lindex $filter 1]
    if {$fmin != {}} {
	if {[llength $fmin] == 2} {
	    # we only wants lines who have a min in the range
	    set actualMin [lindex $stats 1]
	    if {$actualMin < [lindex $fmin 0] ||
		$actualMin > [lindex $fmin 1]} {
		return 0
	    }
	} elseif {$fmin < 0} {
	    # we only wants lines whose min is less than the filter
	    if {[lindex $stats 1] > $fmin} {
		# smallest item is larger than the min filter
		return 0
	    }
	} else {
	    # we only wants lines whose min is greater than the filter
	    if {[lindex $stats 1] < $fmin} {
		# smallest item is less than the min filter
		return 0
	    }
	}
    }
    set fmax [lindex $filter 2]
    if {$fmax != {}} {
	if {[llength $fmax] == 2} {
	    # we only wants lines who have a max in the range
	    set actualMax [lindex $stats 2]
	    if {$actualMax < [lindex $fmax 0] ||
		$actualMax > [lindex $fmax 1]} {
		return 0
	    }
	} elseif {$fmax < 0} {
	    set fmax [expr {- $fmax}]
	    # we only wants lines whose max is less than the filter
	    if {[lindex $stats 2] > $fmax} {
		# largest item is greater than the max filter
		return 0
	    }
	} else {
	    # we only wants lines whose max is greater than the filter
	    if {[lindex $stats 2] < $fmax} {
		# largest item is less than the max filter
		return 0
	    }
	}
    }
    set fmean [lindex $filter 3]
    if {$fmean != {}} {
	if {[llength $fmean] == 2} {
	    # we only wants lines who have a mean in the range
	    set actualMean [lindex $stats 3]
	    if {$actualMean < [lindex $fmean 0] ||
		$actualMean > [lindex $fmean 1]} {
		return 0
	    }
	} elseif {$fmean < 0} {
	    set fmean [expr {- $fmean}]
	    # we only wants lines whose mean is less than the filter
	    if {[lindex $stats 3] > $fmean} {
		# average item is greater than the mean filter
		return 0
	    }
	} else {
	    # we only wants lines whose mean is greater than the filter
	    if {[lindex $stats 3] < $fmean} {
		# average item is less than the mean filter
		return 0
	    }
	}
    }
    set fstddev [lindex $filter 4]
    if {$fstddev != {}} {
	if {[llength $fstddev] == 2} {
	    # we only wants lines who have a stddev in the range
	    set actualSd [lindex $stats 3]
	    if {$actualSd < [lindex $fstddev 0] ||
		$actualSd > [lindex $fstddev 1]} {
		return 0
	    }
	} elseif {$fstddev < 0} {
	    set fstddev [expr {- $fstddev}]
	    # we only wants lines whose stddev is less than the filter
	    if {[lindex $stats 4] > $fstddev} {
		# line stddev is greater than the stddev filter
		return 0
	    }
	} else {
	    # we only wants lines whose stddev is greater than the filter
	    if {[lindex $stats 4] < $fstddev} {
		# line stdev is less than the stddev filter
		return 0
	    }
	}
    }
    return 1
}

proc lineMin {l} {
    set yvec [lindex [$l -info] 3]
    global $yvec
    return [set ${yvec}(min)]
}

proc lineMax {l} {
    set yvec [lindex [$l -info] 3]
    global $yvec
    return [set ${yvec}(max)]
}

proc addLineToChart {line new activate mapaxis symbol {style {}}} {
    global vsd
    
    if {! $new} {
	if {![info exists vsd(ct:$vsd(curchart))]} {
	    setStatus "no title for $vsd(curchart)"
	    bell
	    return
#	    set new 1
	}
    }
    set lineinfo [$line -info]
    set lineyv [lindex $lineinfo 3]
    global $lineyv
    set linexv [lindex $lineinfo 2]
    global $linexv

    if {$new} {
	set gw [createGraphWindow $vsd(curchart)]
	if {$new == 2} {
	    startLongOp $gw
	}
    } else {
	set gw $vsd(ct:$vsd(curchart))
	if {![winfo exists $gw]} {
	    if {$vsd(longOpW) != ""} {
		cancelLongOp
	    } else {
		setStatus "missing chart window $gw"
		bell
	    }
	    return
	}
    }
    raise $gw
    wm deiconify $gw

    set numColors [llength $vsd(colorlist)]
    set i [getFreeGraphSlot $gw]
    set cidx [expr {($i - 1) % $numColors}]
    set dashes [expr {(($i - 1) / $numColors) * 2}]
    if {$cidx >= $numColors} {
	set cidx 0
	incr dashes 2
    }
    set g $gw.graph
    set vsd(ed:$i:$g) $line
    showAxis $g ${mapaxis}axis
    if {[string equal $mapaxis "y"]} {
	$g configure -leftmargin 0
    } else { ;# y2 axis
	$g configure -rightmargin 0
    }
    set label [getLineLegendLabel $i $lineinfo]
    if {$style == {}} {
	set style $vsd(def:linestyle)
    }
    $g element create $i -label $label -mapy $mapaxis -symbol $symbol \
	-xdata $linexv -ydata $lineyv -dashes $dashes \
	-color [lindex $vsd(colorlist) $cidx] \
	-outline [lindex $vsd(colorlist) $cidx] \
	-pixels 2 -fill "" -smooth $style

    setMasterBgColorForWindow $g

# The following is done to get the graph to redraw.
#    puts "DEBUG: [lsort -integer [$g element names]]"
#    $g element show [lsort -integer [$g element names]]
    if {$activate} {
	activateElement $g $i 0
    }
}

proc createOperatorLine {lineList op copyChildren {filter "default"} {scale 1}
			 {divider 1} {offset 0} {normalized 0}
			 {statFilter {}}} {
    global vsd
    if [catch {sl_create -derivedline $lineList $op $filter $copyChildren} line] {
	setStatus $line
	bell
	return {}
    }
    if {$scale != 1} {
	$line -scale $scale
    }
    if {$divider != 1} {
	$line -divider $divider
    }
    if {$normalized} {
	$line -normalize
    } elseif {$offset != 0} {
	$line -adder [expr {- $offset}]
    }
    if {$statFilter != {}} {
	if {! [statFilter $line $statFilter]} {
	    $line -free
	    return {}
	}
    }
    return $line
}

proc addDerivedLine {lineList op {filter "default"} {scale 1} {mapaxis "y"}} {
    global vsd
    replayLog "addDerivedLine $lineList $op $filter $scale $mapaxis"
    set line [createOperatorLine $lineList $op $vsd(copyChildren) $filter $scale]
    if {$line != {}} {
	addLineToChart $line 0 1 $mapaxis "none"
    }
}

proc createSimpleLine {instList counter
	       {filter "default"} {scale 1}
		       {divider 1} {offset 0} {normalized 0}
		       {statFilter {}}} {
    global vsd

    set line [sl_create -line $instList $counter $filter $vsd(absoluteTSMode)]
    if {$vsd(noFlatlines)} {
	if {[lineMax $line] == 0 && [lineMin $line] == 0} {
	    $line -free
	    return {}
	}
    }
    if {$scale != 1} {
	$line -scale $scale
    }
    if {$divider != 1} {
	$line -divider $divider
    }
    if {$normalized} {
	$line -normalize
    } elseif {$offset != 0} {
	$line -adder [expr {- $offset}]
    }
    if {$statFilter != {}} {
	if {! [statFilter $line $statFilter]} {
	    $line -free
	    return {}
	}
    }
    return $line
}

proc doOneCounter {new instList activate counter
                   {filter "default"} {scale 1} {mapaxis "y"}
		   {divider 1} {offset 0} {normalized 0}
                   {statFilter {}}} {
    global vsd

    replayLog "doOneCounter $new $instList $activate $counter $filter $scale $mapaxis $divider $offset $normalized $statFilter"
    set line [createSimpleLine $instList $counter $filter $scale $divider $offset $normalized $statFilter]
    if {$line != {}} {
	addLineToChart $line $new $activate $mapaxis "none"
	return 1
    } else {
	return 0
    }
}

# proc doTemplateCounter {new instList templateInfo} {
#     global vsd
#     set counter [lindex $templateInfo 2]
#     set scale [lindex $templateInfo 3]
#     set filter [lindex $templateInfo 4]
#     set mapaxis [lindex $templateInfo 5]
#     set infoArgs [llength $templateInfo]
#     if {$infoArgs <= 7} {
# 	# old style with default divider, offset, and normalize
# 	set divider 1
# 	set offset 0
# 	set normalized 0
# 	set statFilter [lindex $templateInfo 6]
#     } else {
# 	set divider [lindex $templateInfo 6]
# 	set offset [lindex $templateInfo 7]
# 	set normalized [lindex $templateInfo 8]
# 	set statFilter [lindex $templateInfo 9]
#     }
#     if {$vsd(combineFiles) || [llength $instList] == 1} {
# 	set result [doOneCounter $new $instList 0 $counter $filter $scale $mapaxis \
# 			$divider $offset $normalized $statFilter]
#     } else {
# 	set result 0
# 	foreach df [sl_stat -enabledfiles] {
# 	    set dfInstList {}
# 	    foreach inst $instList {
# 		set instData [sl_stat -instinfo $inst]
# 		if {[string equal $df [lindex $instData 5]]} {
# 		    lappend dfInstList $inst
# 		}
# 	    }
# 	    if {$dfInstList != {}} {
# 		if {[doOneCounter $new $dfInstList 0 $counter $filter $scale $mapaxis \
# 			$divider $offset $normalized $statFilter]} {
# 		    set result 1
# 		    set new 0
# 		    update
# 		}
# 	    }
# 	}
#     }
#     return $result
# }


proc addToChart {new procs ctrs} {
    global vsd

    set count 0
    disableAutoUpdates
    set fileCount [llength [sl_stat -enabledfiles]]
    if {[llength $ctrs] == 1 && ([llength $procs] == 1 ||
				 ($vsd(combineInstances) && ($vsd(combineFiles) || $fileCount == 1)))} {
	set activate 1
    } else {
	set activate 0
    }
	
    set chartname [$vsd(w:chartlist) cget -selection]
    if {![string equal $chartname $vsd(curchart)]} {
	set vsd(curchart) $chartname
    }
    if {!$activate} {
	if {$new} {
	    # Setting new to 2 means that startLongOp should be done when
	    # a window is created
	    set new 2
	} else {
	    set gw $vsd(ct:$vsd(curchart))
	    startLongOp $gw
	}
    }
    if {$vsd(combineInstances)} {
	if {$vsd(combineFiles)} {
            if {$vsd(combineFilePattern) == ""} {
                set instList {}
                foreach ientry $procs {
                    set instData [$vsd(instanceList) info data $ientry]
                    lappend instList [lindex $instData 6]
                }
                foreach ctr $ctrs {
                    if {[doOneCounter $new $instList $activate $ctr]} {
                        incr count
                        set new 0
                        update
                        if {$vsd(longOpCancel)} {break}
                    }
                }
            } else {
                # Use combineFilePattern to group files
                global patternMap
                foreach fGroupName [getSortedGroupNames] {
                    set fGroupIds $patternMap($fGroupName);
                    set instList {}
                    foreach ientry $procs {
                        set instData [$vsd(instanceList) info data $ientry]
                        if {[lsearch -exact $fGroupIds [lindex $instData 5]] != -1} {
                            lappend instList [lindex $instData 6]
                        }
                    }
                    if {$instList != {}} {
                        foreach ctr $ctrs {
                            if {[doOneCounter $new $instList $activate $ctr]} {
                                incr count
                                set new 0
                                update
                                if {$vsd(longOpCancel)} {break}
                            }
                        }
                    }
                    if {$vsd(longOpCancel)} {break}
                }
            }
	} else {
	    foreach df [getSortedFiles] {
		set instList {}
		foreach ientry $procs {
		    set instData [$vsd(instanceList) info data $ientry]
		    if {[string equal $df [lindex $instData 5]]} {
			lappend instList [lindex $instData 6]
		    }
		}
		if {$instList != {}} {
		    foreach ctr $ctrs {
			if {[doOneCounter $new $instList $activate $ctr]} {
			    incr count
			    set new 0
			    update
			    if {$vsd(longOpCancel)} {break}
			}
		    }
		}
		if {$vsd(longOpCancel)} {break}
	    }
	}
    } else {
	foreach ientry $procs {
	    set instData [$vsd(instanceList) info data $ientry]
	    set instId [lindex $instData 6]
	    foreach ctr $ctrs {
		if {[doOneCounter $new [list $instId] $activate $ctr]} {
		    incr count
		    set new 0
		    update
		    if {$vsd(longOpCancel)} {break}
		}
	    }
	    if {$vsd(longOpCancel)} {break}
	}
    }
    if {$count == 0} {
	if {$vsd(noFlatlines) && !$vsd(longOpCancel)} {
	    # ring the bell since no lines were added due to flatlines
	    setStatus "Line was not created because \"No Flatlines\" is enabled."
	    bell
	}
    }
    enableAutoUpdates
    endLongOp
}

proc doChart {new} {
    global vsd

    set procs [$vsd(instanceList) info selection]
    set ctrs [getSelCtr]
    if {$procs == {} || $ctrs == {}} {
	if {$new} {
	    createGraphWindow {}
	}
    } else {
	if {!$new && $vsd(curchart) == {}} {
	    set new 1
	}
	addToChart $new $procs $ctrs
    }
}

proc doExitVSD {} {
    global vsd
    writeStartupFile
    foreach smon [array names vsd statmonpid:*] {
	catch {sl_kill $vsd($smon) 2}
    }
    destroy $vsd(w)
    exit
}

proc ExitVSD {} {
    global vsd

    if {! $vsd(confirmonexit)} {
	doExitVSD
    }

    set msgtext "Are you sure you want to exit?"

    if {[info commands tk_messageBox] != ""} {
	set response [tk_messageBox -title "Confirm Exit" \
			  -parent $vsd(w) -icon question -type yesno \
			  -default yes -message $msgtext]
	if {[string equal $response "yes"]} {
	    doExitVSD
	}
    } else {
	set d [tixDialogShell .vsdexit -parent $vsd(w) -title "Confirm Exit"]

	frame $d.top -relief raised -bd 1
	pack $d.top -side top -fill both

	label $d.top.msg -text $msgtext
	pack $d.top.msg -side right -expand 1 -fill both -padx 3m -pady 3m
	label $d.top.bitmap -bitmap "question"
	pack $d.top.bitmap -side left -padx 3m -pady 3m
	

	tixButtonBox $d.box
	$d.box add yes -text Yes -command doExitVSD
	$d.box add no -text No -command {destroy .vsdexit}

	pack $d.box -fill x -expand yes

	$d popup
	focus [$d.box subwidget yes]
    }
}

proc ChangeXAuto {w} {
    global vsd

    if {$vsd(xautoscale)} {
	$w.min configure -state disabled
	$w.max configure -state disabled
    } else {
	$w.min configure -state normal
	$w.max configure -state normal
    }
}

proc ChangeYAuto {w} {
    global vsd

    if {$vsd(yautoscale)} {
	$w.min configure -state disabled
	$w.max configure -state disabled
    } else {
	$w.min configure -state normal
	$w.max configure -state normal
    }
}

proc getSelCtr {} {
    global vsd
    set res {}
    foreach i [$vsd(w:counterHList) info selection] {
	lappend res [$vsd(w:counterHList) info data $i]
    }
    return $res
}

proc clearCounters {} {
    global vsd
    set selCtr [getSelCtr]
    if {$selCtr != {}} {
	set vsd(lastSelCtr) $selCtr
    }
    $vsd(w:counterHList) delete all
    set vsd(selectedCtr) {}
    set vsd(counterType) {}
    set vsd(selectedInstIds) {}
    set vsd(zeroCtrs) {}
}

proc showCounter {c} {
    global vsd

    if {$c == {}} {
	return
    }
    set vsd(lastctr) $c
    $vsd(doctext:w) configure -state normal
    $vsd(doctext:w) delete 1.0 end

    set ctype [getStatType $c]
    if {[string equal $ctype "uvalue"]} {
	set ctype "unsigned value"
    } elseif {[string equal $ctype "svalue"]} {
	set ctype "signed value"
    }
    $vsd(ctrtype:w) configure -text $ctype
    $vsd(ctrunits:w) configure -text [getStatUnits $c]
    set objList [getStatObjList $c]
    if {[string length $objList] == 0} {
	$vsd(ctrobjs:w) configure -text "unknown"
    } else {
	$vsd(ctrobjs:w) configure -text $objList
    }

    $vsd(ctrfilter:w) configure -disablecallback true -state normal
    set vsd(ctrfilter) [getStatFilter $c]
    $vsd(ctrfilter:w) configure -disablecallback false
    $vsd(ctrlevel:w) configure -disablecallback true -state normal
    set vsd(ctrlevel) [getStatLevel $c]
    $vsd(ctrlevel:w) configure -disablecallback false
    set counterDoc [getPlainStatDescription $c]
    if {$counterDoc != {}} {
	$vsd(doctext:w) insert 1.0 $counterDoc
    }
    $vsd(doctext:w) configure -state disabled
}

proc showCounterInfo {c} {
    global vsd
    
    if {$c == {}} {
	return
    }


    set oldctr $vsd(lastctr)
    if {[string equal $c $vsd(lastctr)]} {
	return
    }
    set vsd(lastctr) $c
    if {![string equal withdrawn [wm state .ctrinfo]]} {
	if {[info exists vsd(ctrbox:w)] && [winfo exists $vsd(ctrbox:w)]} {
	    set lb [$vsd(ctrbox:w) subwidget listbox]
	    set idx 0
	    foreach ctr [$lb get 0 end] {
		if {[string equal $c $ctr]} {
		    $vsd(ctrbox:w) pick $idx
		    break
		}
		incr idx
	    }
	}
    }
}

proc fileLogInfo {} {
    global vsd
    if {$vsd(statsrc) == {}} {
	return
    }

    set info [$vsd(statsrc) -info]
    set filename [file tail [lindex $info 0]]
    set gsver "[lindex $info 3] for [lindex $info 2]"
    set machine [lindex $info 4]
    set interval [lindex $info 6]
    if {$interval < 1000} {
       set units "millisecond"
    } else {
       set units "second"
       set interval [expr {$interval / 1000}]
    }
    set date "[lindex $info 5] in $interval $units intervals"
    set firstTS [lindex $info 9]
    set trimLeftTS [lindex $info 10]
    set trimRightTS [lindex $info 11]

    set fileData "\nFile: [lindex $info 0]\n  Gemstone Version: $gsver\n  Machine: $machine\n  Time: $date"

    if {$firstTS != $trimLeftTS} {
	append fileData "\n  TrimLeft: [sl_stat -getdate $trimLeftTS $vsd(time_shift_hours) date]"
    }
    if {$trimRightTS != -1} {
	append fileData "\n  TrimRight: [sl_stat -getdate $trimRightTS $vsd(time_shift_hours) date]"
    }
    
    showData $fileData
}

proc appendDataFile {} {
    global vsd
    if {$vsd(statsrc) == {}} {
	return
    }
    set vsd(appendMode) 1
    browseDataFile
}

proc fileInfo {} {
    global vsd widgetHelp
    if {$vsd(statsrc) == {}} {
	return
    }

    set info [$vsd(statsrc) -info]
    set filename [file tail [lindex $info 0]]
    set gsver "[lindex $info 3] for [lindex $info 2]"
    set machine [lindex $info 4]
    set interval [lindex $info 6]
    if {$interval < 1000} {
       set units "millisecond"
    } else {
       set units "second"
       set interval [expr {$interval / 1000}]
    }
    set date "timestamps since [lindex $info 5] in $interval $units intervals"

    set w .vsdfileinfo
    if [winfo exists $w] {
	regexp {(.*x.*)(\+.*\+.*)} [wm geometry $w] junk parentSize position
	destroy $w
    } else {
	regexp {(.*x.*)(\+.*\+.*)} [wm geometry $vsd(w)] junk parentSize position
    }
	
    set widgetHelp($w) {File Information Window}
    toplevel $w
    wm geometry $w $position
    wm title $w "info on $filename"

    frame $w.top -relief raised -bd 1

    tixLabelFrame $w.top.gsver -label "GemStone Version"
    set f [$w.top.gsver subwidget frame]
    label $f.l -text $gsver
    pack $f.l
    pack $w.top.gsver -fill x -expand yes

    tixLabelFrame $w.top.machine -label "Machine Information"
    set f [$w.top.machine subwidget frame]
    label $f.l -text $machine
    pack $f.l
    pack $w.top.machine -fill x -expand yes

    tixLabelFrame $w.top.time -label "Time Information"
    set f [$w.top.time subwidget frame]
    label $f.l -text $date
    pack $f.l
    pack $w.top.time -fill x -expand yes

    pack $w.top -side top -fill both -expand yes

    tixButtonBox $w.box
    $w.box add dismiss -text Dismiss -width 6 -command "destroy $w"
    $w.box add log -text "Log..." -width 6 -command fileLogInfo
    set but [$w.box subwidget dismiss]
    pack $w.box -fill x -side bottom
    setMasterBgColorForWindow $w
}

proc fileDump {} {
    global vsd
    if {$vsd(statsrc) != {}} {
	# NYI: hack implementation
	$vsd(statsrc) -dump
    }
}

proc singleFileMode {} {
    global vsd
    if {$vsd(singleFileMode)} {
	set vsd(lastEnabledFiles) [sl_stat -enabledfiles]
	foreach f $vsd(lastEnabledFiles) {
	    if {![string equal $f $vsd(statsrc)]} {
		$f -disable
	    }
	}
    } else {
	set files $vsd(lastEnabledFiles)
	if {$files == {}} {
	    # enable them all
	    set files [sl_stat -allfiles]
	} else {
	    if {$vsd(statsrc) != {}} {
		lappend files $vsd(statsrc)
	    }
	}
	foreach f $files {
	    $f -enable
	}
    }
    setInstanceList
    updateGraphWidgetState
}

proc fileEnableMode {} {
    global vsd
    if {$vsd(statsrc) != {}} {
	if {$vsd(file:isEnabled)} {
	    $vsd(statsrc) -enable
	} else {
	    $vsd(statsrc) -disable
	}
	setInstanceList
	updateGraphWidgetState
    }
}

proc fileUntrimLeft {f} {
    if {$f != {}} {
	$f -trimleft 0
    }
    updateFileTrimMenuItems [$f -info]
    updateAllLineTrimMenuItems
}

proc fileUntrimRight {f} {
    if {$f != {}} {
	$f -trimright -1
    }
    updateFileTrimMenuItems [$f -info]
    updateAllLineTrimMenuItems
}

proc fileUpdateAll {} {
    global vsd
    foreach f [sl_stat -enabledfiles] {
        fileUpdate $f
    }
}

proc fileUpdate {f} {
    global vsd
    if {$f != {} && $vsd(updateok:$f)} {
	if [catch {$f -update} updateCount] {
	    set vsd(updateok:$f) 0
	    set vsd(autoUpdate:$f) 0
	    if [info exists vsd(autoUpdateId:$f)] {
		after cancel $vsd(autoUpdateId:$f)
		unset vsd(autoUpdateId:$f)
	    }
	    if {$f == $vsd(statsrc)} {
		$vsd(w:filemenu) entryconfigure "Update" -state disabled
		$vsd(w:filemenu) entryconfigure "Auto Update" -state disabled
		set vsd(autoUpdate) 0
	    }
	    showError "Update failed because: $updateCount"
	}
	if {$updateCount != 0} {
	    if {$vsd(noFlatlines)} {
		# NYI optimize this so it doesn't unconditionally zap everyone
		foreach idx [array names vsd {*:ctrlistid}] {
		    set vsd($idx) {}
		}
	    }
	    set isEnabled [lindex [$f -info] 7]
	    if {$isEnabled} {
		foreach c $vsd(zeroCtrs) {
		    if {![sl_stat -ctrzero $c $vsd(selectedInstIds)]} {
			fillCounters 1 [$vsd(instanceList) info selection]
			break
		    }
		}
		updateInstanceList
# Next line fixes 43834
                updateAllActiveLines
	    }
	}
    }
}

proc doAutoUpdate {f t} {
    global vsd
    if {!$vsd(autoUpdatesDisabled)} {
	fileUpdate $f
    }
    set vsd(autoUpdateId:$f) [after $t [list doAutoUpdate $f $t]]
}

proc disableAutoUpdates {} {
    global vsd
    set vsd(autoUpdatesDisabled) 1
}

proc enableAutoUpdates {} {
    global vsd
    set vsd(autoUpdatesDisabled) 0
}

proc clearStatus {} {
    global vsd
    set vsd(status) ""
}

proc setStatus {msg} {
    global vsd
    if [info exists vsd(statusTimeout)] {
	after cancel $vsd(statusTimeout)
	unset vsd(statusTimeout)
    }
    set vsd(status) $msg
    set vsd(statusTimeout) [after 10000 clearStatus]
}

proc autoUpdate {} {
    global vsd
    set f $vsd(statsrc)

    if {$f == {}} {
	return
    }
    
    if [info exists vsd(autoUpdateId:$f)] {
	after cancel $vsd(autoUpdateId:$f)
	unset vsd(autoUpdateId:$f)
    }

    set vsd(autoUpdate:$f) $vsd(autoUpdate)

    if {$vsd(autoUpdate)} {
# Bug 44960 - Interval is already in now ms, so remove "* 1000"
	set interval [expr {[lindex [$f -info] 6]}]
	if {$interval == 0} {
	    set interval $vsd(autoUpdateTime)
	}
	doAutoUpdate $f $interval
    }
}

proc monitorBrowse {e} {
    global vsd
    set w .monitors
    if {![winfo exists $w]} {
	return
    }
    set l [$w.top.monlist subwidget hlist]

    set data [$l info data $e]
    set name [lindex $data 0]
    set version [lindex $data 1]
    set gemstone [lindex $data 3]
    if [info exists vsd(statmonpid:$name)] {
	[$w.box subwidget start] configure -state disabled
	[$w.box subwidget status] configure -state normal
	[$w.box subwidget stop] configure -state normal

	if [info exists vsd(statmonoutput:$name)] {
	    $w.statmonfile configure -state normal
	    set vsd(wv:statmonfile) $vsd(statmonoutput:$name)
	}
	$w.statmonfile configure -state disabled

	if [info exists vsd(statmoninterval:$name)] {
	    $w.ctr.statmoninterval configure -state normal
	    set vsd(wv:statmoninterval) $vsd(statmoninterval:$name)
	}
	$w.ctr.statmoninterval configure -state disabled
	if [info exists vsd(statmonflush:$name)] {
	    $w.ctr.statmonflush configure -state normal
	    set vsd(wv:statmonflush) $vsd(statmonflush:$name)
	}
	$w.ctr.statmonflush configure -state disabled
	if [info exists vsd(statmonlevel:$name)] {
	    $w.ctr.statmonlevel configure -state normal
	    set vsd(wv:statmonlevel) $vsd(statmonlevel:$name)
	}
	$w.ctr.statmonlevel configure -state disabled
	if [info exists vsd(statmonappstats:$name)] {
	    $w.ctr.statmonappstats configure -state normal
	    set vsd(wv:statmonappstats) $vsd(statmonappstats:$name)
	}
	$w.ctr.statmonappstats configure -state disabled
	if [info exists vsd(statmoncompress:$name)] {
	    $w.ctr2.compress configure -state normal
	    set vsd(wv:statmoncompress) $vsd(statmoncompress:$name)
	}
	$w.ctr2.compress configure -state disabled
	if [info exists vsd(statmonsessions:$name)] {
	    $w.ctr2.statmonsessions configure -state normal
	    set vsd(wv:statmonsessions) $vsd(statmonsessions:$name)
	}
	$w.ctr2.statmonsessions configure -state disabled
	if [info exists vsd(statmonpids:$name)] {
	    $w.ctr2.statmonpids configure -state normal
	    set vsd(wv:statmonpids) $vsd(statmonpids:$name)
	}
	$w.ctr2.statmonpids configure -state disabled
    } else {
	set statmonlist {}
	[$w.box subwidget start] configure -state normal
	[$w.box subwidget status] configure -state disabled
	[$w.box subwidget stop] configure -state disabled
	set vsd(wv:statmonfile) ""
	$w.statmonfile configure -state normal
	$w.ctr.statmoninterval configure -state normal
	$w.ctr.statmonflush configure -state normal
	$w.ctr.statmonlevel configure -state normal
	$w.ctr.statmonappstats configure -state normal
	$w.ctr2.statmonsessions configure -state normal
	$w.ctr2.statmonpids configure -state normal
	set compressState "normal"
	if {[string equal $compressState "disabled"]} {
	    set vsd(wv:statmoncompress) 0
	}
	$w.ctr2.compress configure -state $compressState
    }
}

proc updateMonitorState {name updatelist} {
    global vsd
    set w .monitors
    if {![winfo exists $w]} {
	return
    }
    set l [$w.top.monlist subwidget hlist]
    set e [$l info selection]
    if {$e == {}} {
	return
    }
    set data [$l info data $e]
    if {[string equal $name [lindex $data 0]]} {
	monitorBrowse $e
    }
    if {$updatelist} {
	foreach e [$l info children] {
	    set data [$l info data $e]
	    if {[string equal $name [lindex $data 0]]} {
		if [info exists vsd(statmonpid:$name)] {
		    $l item create $e 1 -itemtype text \
			-text [lindex $vsd(statmonpid:$name) 0]
		} else {
		    $l item create $e 1 -itemtype text -text "<none>"
		}
	    }
	}
    }
}

proc showMonitorStatus {name} {
    global vsd
    set w .monstatus
    set exists [winfo exists $w]
    if $exists {
	raise $w
	wm deiconify $w
	[$w.top.msg subwidget text] delete 1.0 end
    } else {
	toplevel $w
	wm title $w "Monitor Status"
	if {$vsd(geometry:$w) != {}} {
	    wm geometry $w $vsd(geometry:$w)
	}
	frame $w.top -relief raised -bd 1
	tixScrolledText $w.top.msg -width 500 -height 100
	[$w.top.msg subwidget text] configure -wrap none -font fixedTextFont
	pack $w.top.msg -expand yes -fill both
	pack $w.top -side top -fill both -expand yes
	tixButtonBox $w.box
	$w.box add dismiss -text Dismiss -width 6 \
	    -command "dismissWindow $w"
	pack $w.box -fill x -side bottom
    }

    [$w.top.msg subwidget text] insert end $vsd(statmoncmd:$name)
    [$w.top.msg subwidget text] insert end "\n"
    [$w.top.msg subwidget text] insert end $vsd(statmonstatus:$name)
}

proc readMonitorOutput {f name} {
    global vsd
    if [eof $f] {
	catch {close $f}
	showMonitorStatus $name
	unset vsd(statmoncmd:$name)
	unset vsd(statmonpid:$name)
	unset vsd(statmonoutput:$name)
	unset vsd(statmoninterval:$name)
	unset vsd(statmonflush:$name)
	unset vsd(statmonstatus:$name)
	unset vsd(statmonsessions:$name)
	unset vsd(statmonpids:$name)
	unset vsd(statmoncompress:$name)
	unset vsd(statmonlevel:$name)
	unset vsd(statmonappstats:$name)
	updateMonitorState $name true
    } else {
	gets $f line
	append vsd(statmonstatus:$name) $line
	append vsd(statmonstatus:$name) "\n"
	if {$vsd(statmonoutput:$name) == {}} {
	    if [regexp {Output file is:[ ]+(.+)$} $line match file] {
		set vsd(statmonoutput:$name) $file
		updateMonitorState $name false
	    }
	} elseif {$vsd(statmoninterval:$name) == {}} {
	    if [regexp {Sample Interval .+is:[ ]+([0-9.]+)} $line match interval] {
		set vsd(statmoninterval:$name) $interval
		updateMonitorState $name false
	    }
	} elseif {$vsd(statmonflush:$name) == {}} {
	    if [regexp {Write Interval .+is:[ ]+([0-9.]+)} $line match flushinterval] {
		set vsd(statmonflush:$name) $flushinterval
		updateMonitorState $name false
		if {$flushinterval == 0} {
		    set i $vsd(statmoninterval:$name)
		} else {
		    set i $flushinterval
		}
		after [expr {wide(($i + 3) * 1000)}] [list loadStatmonFile $name]
	    }
	}
    }
}

proc loadStatmonFile {name} {
    global vsd
    if [info exists vsd(statmonoutput:$name)] {
	setDataFile $vsd(statmonoutput:$name)
	# file from statmonitors started by vsd default to auto update
	set vsd(autoUpdate) 1
	autoUpdate
    }
}

proc statusMonitor {} {
    global vsd
    set w .monitors
    if {![winfo exists $w]} {
	return
    }
    set l [$w.top.monlist subwidget hlist]
    set e [$l info selection]
    if {$e == {}} {
	return
    }
    set data [$l info data $e]
    set name [lindex $data 0]
    showMonitorStatus $name
}

proc stopMonitor {} {
    global vsd
    set w .monitors
    if {![winfo exists $w]} {
	return
    }
    set l [$w.top.monlist subwidget hlist]
    set e [$l info selection]
    if {$e == {}} {
	return
    }
    set data [$l info data $e]
    set name [lindex $data 0]
    if [info exists vsd(statmonpid:$name)] {
	sl_kill $vsd(statmonpid:$name) 2
    }
}

proc stashStatmonUsage {exe} {
    global vsd
    if [info exists vsd(usage:$exe)] {
	return
    }
    catch {exec $exe} vsd(usage:$exe)
}

proc checkStatmonUsage {exe switch} {
    global vsd
    if {![info exists vsd(usage:$exe)]} {
	return 0
    }
    if {[string first " $switch " $vsd(usage:$exe)] == -1} {
	return 0
    } else {
	return 1
    }
}

proc startMonitor {} {
    global vsd isWindows env
    set w .monitors
    if {![winfo exists $w]} {
	return
    }
    set l [$w.top.monlist subwidget hlist]
    set e [$l info selection]
    if {$e == {}} {
	return
    }
    set data [$l info data $e]
    set name [lindex $data 0]
    set version [lindex $data 1]
    set gemstone [lindex $data 3]

    if [info exists vsd(statmonpid:$name)] {
	showError "StatMon is already running on cache $name."
	return
    }

    if {![string equal $name "none"]} {
	if {$version == ""} {
	    showError "No support for starting statmonitor on GemStone/S versions 4.1.3 and earlier."
	    return
	}
    }

    if [info exists vsd(statmonexe)] {
	set statmonexe $vsd(statmonexe)
    } else {
	set statmonexe ""
    }
    if {$statmonexe == {} || ![file exists $statmonexe]} {
	set statmonbase "statmonitor"
	if {$isWindows} {
	    append statmonbase ".exe"
	}
	set statmonexe [file join $gemstone bin $statmonbase]
	if {$gemstone == {} || ![file exists $statmonexe]} {
	    set statmondir [file join [file dirname [file dirname [file dirname [info nameofexecutable]]]] bin]
	    set statmonexe [file join $statmondir $statmonbase]
	    if {![file exists $statmonexe]} {
		global env
		set loaded 0
		if [info exists env(GEMSTONE)] {
		    set statmonexe [file join $env(GEMSTONE) bin $statmonbase]
		    if [file exists $statmonexe] {
			set gemstone {}
			set loaded 1
		    }
		}
		if {! $loaded} {
		    showError "Could not find statmonitor executable."
		    return
		}
	    } else {
		set gemstone [file dirname $statmondir]
	    }
	}
    }

    $vsd(w:statmoninterval) update
    $vsd(w:statmonflush) update

    stashStatmonUsage $statmonexe
    
    set statmoncmdline "$statmonexe $name"
    if {$vsd(wv:statmonfile) != {}} {
	if {[string equal ".out" [file extension $vsd(wv:statmonfile)]]} {
	    append statmoncmdline " -f [file rootname $vsd(wv:statmonfile)]"
	} else {
	    append statmoncmdline " -f $vsd(wv:statmonfile)"
	}
    }
    if {$vsd(wv:statmoninterval) != {}} {
	append statmoncmdline " -i $vsd(wv:statmoninterval)"
    }
    if {$vsd(wv:statmonflush) != {}} {
	append statmoncmdline " -u $vsd(wv:statmonflush)"
    } else {
	append statmoncmdline " -u 0"
    }
    $vsd(w:statmonlevel) update
    if {$vsd(wv:statmonlevel) != 1} {
	append statmoncmdline " -s $vsd(wv:statmonlevel)"
    }
    $vsd(w:statmonappstats) update
    if {$vsd(wv:statmonappstats) != 0} {
	append statmoncmdline " -n $vsd(wv:statmonappstats)"
    }
    if {$vsd(wv:statmonsessions) != {}} {
	foreach id $vsd(wv:statmonsessions) {
	    append statmoncmdline " -p $id"
	}
    }
    if [checkStatmonUsage $statmonexe "-P"] {
	if {$vsd(wv:statmonpids) != {}} {
	    foreach id $vsd(wv:statmonpids) {
		append statmoncmdline " -P $id"
	    }
	}
    }
    if {$vsd(wv:statmoncompress)} {
	append statmoncmdline " -z"
    }
# Fix 43734 - Comment out this check.
#   What did statmonitor -v <VSDpid> ever do?  It's not in the statmonitor code 
#   as far back as GS 5.0!  Maybe it was a GemFire thing?
#    if [checkStatmonUsage $statmonexe "-v"] {
#	append statmoncmdline " -v [pid]"
#    }
    set oldGemstone {}
    if {$gemstone != {}} {
	if [info exists env(GEMSTONE)] {
	    set oldGemstone $env(GEMSTONE)
	}
	set env(GEMSTONE) $gemstone
    }
    set cmdstr "|$statmoncmdline 2>@stdout"
    if [catch {open $cmdstr r} result] {
	showError "The command '$statmoncmdline'\nfailed with: $result"
	if {$oldGemstone != {}} {
	    set env(GEMSTONE) $oldGemstone
	}
	return
    }
    if {$oldGemstone != {}} {
	set env(GEMSTONE) $oldGemstone
    }
    set vsd(statmoncmd:$name) $statmoncmdline
    set vsd(statmonpid:$name) [lindex [pid $result] 0]
    set vsd(statmonoutput:$name) ""
    set vsd(statmoninterval:$name) ""
    set vsd(statmonflush:$name) ""
    set vsd(statmonstatus:$name) ""
    set vsd(statmonsessions:$name) $vsd(wv:statmonsessions)
    set vsd(statmonpids:$name) $vsd(wv:statmonpids)
    set vsd(statmoncompress:$name) $vsd(wv:statmoncompress)
    set vsd(statmonlevel:$name) $vsd(wv:statmonlevel)
    if {$vsd(wv:statmonappstats) != 0} {
	set vsd(statmonappstats:$name) $vsd(wv:statmonappstats)
    } else {
	set vsd(statmonappstats:$name) ""
    }
    updateMonitorState $name true
    fileevent $result readable [list readMonitorOutput $result $name]
}

proc sl_caches {} {
    set result {}
    if [catch {exec gslist -x} gslistOutput] {
	# something went wrong. Probably no gslist.
    } else {
	# parse the result
	set matchData [regexp -all -inline {([^\n]+)\s+status=[^\n]+\s+type=\s+([^\n]+)\s+version=\s+([^\n]+)\s+owner=\s+([^\n]+)\s+(?:\S+=[^\n]+\s+){3,7}(GEMSTONE|product)=\s*([^\n]+)\s*} $gslistOutput]
	foreach {junk name type version owner junk2 dir} $matchData {
	    if {[string equal $type "SAP"] || [string equal $type "cache"]} {
		lappend result [list $name $version $owner $dir]
	    }
	}
    }
    return $result
}

proc getMonitorTargets {} {
    global tcl_platform
    set res [sl_caches]
    lappend res [list none $tcl_platform(osVersion) [info hostname] [file dirname [file dirname [info nameofexecutable]]]]
    return $res
}
proc refreshMonitors {} {
    global vsd
    set w .monitors
    if {![winfo exists $w]} {
	return
    }
    set l [$w.top.monlist subwidget hlist]
    $l delete all
    [$w.box subwidget start] configure -state disabled
    [$w.box subwidget status] configure -state disabled
    [$w.box subwidget stop] configure -state disabled
    foreach c [getMonitorTargets] {
	set name [lindex $c 0]
	set row [$l addchild "" -data $c -itemtype text -text $name]
	if [info exists vsd(statmonpid:$name)] {
	    $l item create $row 1 -itemtype text \
		-text [lindex $vsd(statmonpid:$name) 0]
	} else {
	    $l item create $row 1 -itemtype text -text "<none>"
	}
	$l item create $row 2 -itemtype text -text [lindex $c 1]
	$l item create $row 3 -itemtype text -text [lindex $c 2]
    }
    updateMonitorListBgColor
}

proc dismissWindow {w} {
    global vsd
    set vsd(geometry:$w) [wm geometry $w]
    destroy $w
}

proc changeCtrFilter {newFilter} {
    global vsd
    set ctr $vsd(lastctr)
    set curfilter [getStatFilter $ctr]
    if {[string equal $curfilter $newFilter]} {
	return
    } else {
	setStatFilter $ctr $newFilter
    }
}

proc showStatisticInfoHelp {} {
    global vsd
    set topic "$vsd(lastctr) Statistic"
    doHelp $topic
}

proc changeCtrLevel {newLevel} {
    global vsd
    set ctr $vsd(lastctr)
    if {[string equal [getStatLevel $ctr] $newLevel]} {
	return
    } else {
	setStatLevel $ctr $newLevel
    }
}

proc getUsedStatNames {} {
    if {[llength [sl_stat -allfiles]] > 0} {
	return [sl_stat -objctrs {}]
    } else {
	return [sl_stat -names]
    }
}

proc updateCounterList {} {
    global vsd
    set ctrnames [getUsedStatNames]
    set newStatNameCount [llength $ctrnames]
    if {$vsd(statNameCount) != $newStatNameCount} {
	set vsd(statNameCount) $newStatNameCount
	if {[info exists vsd(ctrbox:w)] && [winfo exists $vsd(ctrbox:w)]} {
	    set w $vsd(ctrbox:w)
	    [$w subwidget listbox] delete 0 end
	    foreach c [lsort -dictionary $ctrnames] {
		$w insert end $c
	    }
	    set c $vsd(lastctr)
	    set vsd(lastctr) {}
	    showCounterInfo $c
	}
    }
}

proc destroyCtrInfo {w} {
    global vsd
    set vsd(showCtrInfo) 0
    wm withdraw $w
}

proc createCtrInfo {w} {
    global vsd widgetHelp

    toplevel $w
    wm protocol $w WM_DELETE_WINDOW "destroyCtrInfo $w"

    if {$vsd(geometry:$w) != {}} {
	wm geometry $w $vsd(geometry:$w)
    }
    set widgetHelp($w) {Statistic Information Window}
    wm title $w "Statistic Information"

    set vsd(ctrbox:w) $w.counters
    tixComboBox $w.counters -dropdown true -editable false -value "" \
	-command showCounter
    $vsd(balloon) bind $w.counters -msg "Selects statistic to display/modify information on"
    bind [$w.counters subwidget entry] <KeyPress> \
	[list findByFirstLetter $w.counters %A 1]
    bind [$w.counters subwidget entry] <Control-s> \
	[list startSearch $w.counters  searchComboBox]
    set ctrlist [lsort -dictionary [getUsedStatNames]]
    if {$vsd(lastctr) == {}} {
	set vsd(lastctr) [lindex $ctrlist 0]
    }
    set vsd(statNameCount) [llength $ctrlist]
    foreach c $ctrlist {
	$w.counters insert end $c
    }
    pack $w.counters -fill x -padx 3 -pady 3

    frame $w.top
    tixLabelFrame $w.top.type -labelside left -label "Kind:"
    set f [$w.top.type subwidget frame]
    label $f.l -text "none"
    set vsd(ctrtype:w) $f.l
    pack $f.l
    pack $w.top.type -fill x -side left
    $vsd(balloon) bind $w.top.type -msg "Shows the statistic's kind"

    tixLabelFrame $w.top.units -labelside left -label "Units:"
    set f [$w.top.units subwidget frame]
    label $f.l -text "none"
    set vsd(ctrunits:w) $f.l
    pack $f.l
    pack $w.top.units -fill x -side right
    $vsd(balloon) bind $w.top.units -msg "Shows the units that the statistic measures"

    pack $w.top -fill x -padx 3 -pady 3
    
    tixLabelFrame $w.ctrobjs -labelside left -label "Types:"
    set f [$w.ctrobjs subwidget frame]
    label $f.l -text "none"
    set vsd(ctrobjs:w) $f.l
    pack $f.l
    pack $w.ctrobjs -padx 3 -pady 3 -anchor w
    $vsd(balloon) bind $w.ctrobjs -msg "Shows all instance types that have this statistic"

    tixOptionMenu $w.filtertype -label "Default Filter:" -variable vsd(ctrfilter) \
	-state disabled -command changeCtrFilter \
	-options {
	    label.width 12
	}
    $vsd(balloon) bind $w.filtertype -msg "Click to change statistic's default filter"
    set vsd(ctrfilter:w) $w.filtertype
    $vsd(ctrfilter:w) configure -disablecallback true
    $w.filtertype add command default -label "Default"
    $w.filtertype add command none -label "None"
    $w.filtertype add command persecond -label "PerSecond"
    $w.filtertype add command persample -label "PerSample"
#    $w.filtertype add command smooth -label "Smooth"
    $w.filtertype add command aggregate -label "Aggregate"
    set vsd(ctrfilter) default
    $vsd(ctrfilter:w) configure -disablecallback false
    pack $w.filtertype -padx 3 -pady 3 -anchor w

    tixOptionMenu $w.level -label "Level:" -variable vsd(ctrlevel) \
	-state disabled -command changeCtrLevel \
	-options {
	    label.width 12
	}
    $vsd(balloon) bind $w.level -msg "Click to change statistic's level"
    set vsd(ctrlevel:w) $w.level
    $vsd(ctrlevel:w) configure -disablecallback true
    $w.level add command common
    $w.level add command advanced
    $w.level add command wizard
    set vsd(ctrlevel) common
    $vsd(ctrlevel:w) configure -disablecallback false
    pack $w.level -padx 3 -pady 3 -anchor w

    button $w.help -text "Statistic Help" -command {showStatisticInfoHelp}
    pack $w.help -padx 3 -pady 3
    $vsd(balloon) bind $w.help -msg "Click to see statistic's help topic"

    tixLabelFrame $w.fdoc -label "Statistic Description"
    set fdoc [$w.fdoc subwidget frame]
    tixScrolledText $fdoc.doc -scrollbar y -width 250 -height 120
    set vsd(doctext:w) [$fdoc.doc subwidget text]
    $vsd(doctext:w) configure -wrap word -takefocus 0 -state disabled
    $vsd(balloon) bind $w.fdoc -msg "Describes the current statistic"

    pack $fdoc.doc -fill both -expand yes
    pack $w.fdoc -fill both -expand yes
}

proc dumpCtrInfo {} {
    global vsd

    set str {}
    foreach c [lsort -dictionary [sl_stat -names]] {
	append str "\n" $c
	append str "\n  type: " [getStatType $c] "  level: " [getStatLevel $c] "  units: " [getStatLevel $c] "  filter: " [getStatFilter $c] "\n" [getPlainStatDescription $c] "\n  os: " [isOSStat $c] "  objects: " [getStatObjList $c] "\n"
    }
    showData $str 1
}

proc doCtrInfo {} {
    global vsd
    set w .ctrinfo
    if {$vsd(showCtrInfo)} {
	if [winfo exists $w] {
	    raise $w
            wm deiconify $w
	} else {
	    createCtrInfo $w
	}
	set c $vsd(lastctr)
	set vsd(lastctr) {}
	showCounterInfo $c
    } else {
	if {![winfo exists $w]} {
	    createCtrInfo $w
	    set vsd(lastctr) {}
	}
	wm withdraw $w
    }
}

proc doCopySelection {} {
    global vsd
    set procs [$vsd(instanceList) info selection]
    if {$procs == {}} {
	return
    }
    set ctrs [getSelCtr]
    if {$ctrs == {}} {
	return
    }
    set vsd(clipboard) {}
    lappend vsd(clipboard) "selection"
    lappend vsd(clipboard) [list $procs $ctrs]
}

# Added to fix bug 27336
proc doChangeDirectory {} {
    global vsd isWindows
    if {$isWindows} {
      set newDir [tk_chooseDirectory -parent $vsd(w) -mustexist true -title "VSD Working Directory"]
    } else {
      set newDir [tk_chooseDirectory -parent $vsd(w) -mustexist true -title "VSD Working Directory" -background $vsd(currentBgColor)]
    }
    if {$newDir != {}} {
	cd $newDir
    }
}

proc leaveTimeShifter {} {
  grab release .timeShifter
  destroy .timeShifter
}

# Feature 43200
proc doTimeShift {} {
  global vsd
#  puts "old_time_shift_hours is $vsd(old_time_shift_hours),  time_shift_hours is $vsd(time_shift_hours)"
  if {$vsd(old_time_shift_hours) != $vsd(time_shift_hours)} {
    setInstanceList
    updateAllTimeAxis
#    updateGraphWidgetState
#    updateAllActiveLines
    set vsd(old_time_shift_hours) $vsd(time_shift_hours)
  }
  leaveTimeShifter
}

# Feature 43200
proc doAdjustTimeOffset {} {
    global vsd
    # Save the old value
    set vsd(old_time_shift_hours) $vsd(time_shift_hours)
    set w .timeShifter
    toplevel $w -bd 2
    wm title $w "Change Time Offset"
    if {$vsd(geometry:$w) != {}} {
	wm geometry $w $vsd(geometry:$w)
    }
    wm group $w .
    wm minsize $w 250 100
    wm maxsize $w 250 100
    frame $w.top -relief raised -bd 1
    spinbox $w.top.sbox -bd 1 -relief raised -from -23.0 -to 23.0 -increment 1.0 -format %2.0f \
       -textvariable vsd(time_shift_hours) -width 4
    pack $w.top.sbox -side top
    text $w.top.t -font boldTextFont -width 6 -height 1
    $w.top.t insert end "Hours"
    $w.top.t configure -state disabled
    pack $w.top.t -side top
    button $w.top.okButton -text "Ok" -command { doTimeShift }
    pack $w.top.okButton -side left
    button $w.top.cancelButton -text "Cancel" -command \
       { set vsd(time_shift_hours) $vsd(old_time_shift_hours) ; leaveTimeShifter }
    pack $w.top.cancelButton -side right
    pack $w.top -side top -fill both -expand yes
    if { $vsd(masterBgColorChanged) == 1 } {
      setMasterBgColorForWindow $w
    }
# Try to create a modal window here...
    grab $w
    wm transient $w
    wm protocol $w WM_DELETE_WINDOW { leaveTimeShifter }
    focus $w
    raise $w
    tkwait window .timeShifter
}

# Code for 44951
proc doSetColor {w color} {
  catch { $w config -background $color }
  catch { $w config -highlightbackground $color }
}

# Update the background color for all active graphs.
# Ignore any windows that no longer exist.
proc updateAllGraphBgColor {} {
  global vsd
  set i 0
  while { $i < $vsd(graphcreates) } {
    set w ".chart$i"
    if [winfo exists $w] {
      set g $w.graph
      $g xaxis configure -background $vsd(currentBgColor)
      $g yaxis configure -background $vsd(currentBgColor)
      $g y2axis configure -background $vsd(currentBgColor)
      $g configure -plotbackground $vsd(currentBgColor) \
        -background $vsd(currentBgColor)
      $g legend configure -background $vsd(currentBgColor)
    }
    incr i
  }
}

# Update the background color for the Monitor list window
proc updateMonitorListBgColor {} {
    global vsd
    set w .monitors
    if {! [winfo exists $w] } {
      return
    }
    setMasterBgColorForWindow $w
    set l [$w.top.monlist subwidget hlist]
    set i 0
    while { $i < 4 } {
      $l header configure $i -headerbackground $vsd(currentBgColor)
      incr i
    }
}


# Set the background color for window $w to $color.
# Then do the same for all children of $w by 
# recursively calling this proc.
proc doSetMasterBgColorForWindow {w color} {
  doSetColor $w $color
  foreach child [winfo children $w] {
    doSetMasterBgColorForWindow $child $color
  }
}

# Set the background color for window $w to the current
# background color (stored in $vsd(currentBgColor) )
proc setMasterBgColorForWindow {w} {
  global vsd
  if { $vsd(masterBgColorChanged) == 1 } {
     doSetMasterBgColorForWindow $w $vsd(currentBgColor)
  }
}

# Open the color chooser dialog to select a new master background color.
proc doChooseColor {title parent} {
  global vsd isWindows
  if { $vsd(masterBgColorChanged) == 1 && $isWindows == 0 } {
     # we have been here before.  Make the dialog match the current BG color
     set color [tk_chooseColor -title $title -parent $parent \
       -background $vsd(currentBgColor)]
  } else {
     # first time here.  Use default color for the dialog.
     set color [tk_chooseColor -title $title -parent $parent]
  }
  return $color
}

proc setMasterBackgroundColor {color} {
    global vsd
    set vsd(masterBgColorChanged) 1
    set vsd(currentBgColor) $color
    set vsd(currentPlotBgColor) $color
#
# The following code has been tried but does not do what we want.
#    tk_setPalette $color
#    tix resetoptions TK TK
#    tk_setPalette background $color highlightBackground $color

# Update colors in the VSD styles.  Not sure if this is required.
    catch { doSetMasterBgColorForWindow $vsd(name:s) $color }
    catch { doSetMasterBgColorForWindow $vsd(time:s) $color }
    catch { doSetMasterBgColorForWindow $vsd(samples0:s) $color }
    catch { doSetMasterBgColorForWindow $vsd(samples1:s) $color }
    catch { doSetMasterBgColorForWindow $vsd(ctr0:s) $color }
    catch { doSetMasterBgColorForWindow $vsd(ctr1:s) $color }
    catch { doSetMasterBgColorForWindow $vsd(header:s) $color }
    catch { doSetMasterBgColorForWindow $vsd(buthdr:s) $color }

    set i 0
    while { $i < 7 } {
      $vsd(instanceList) header configure $i -headerbackground $color
      incr i
    }
    updateAllGraphBgColor
    updateMonitorListBgColor
    if {[string compare $color ""]} {
      doSetMasterBgColorForWindow . $color
  }
}

proc pickMasterBackgroundColor {} {
    global vsd
    set w $vsd(w)
    set initialColor [$w cget -background]
    set title "Choose a background color"
    set color [doChooseColor $title $w]

    if { $color == "" || $color == $initialColor } {
      return
    }
    setMasterBackgroundColor $color
}

proc doMonitor {} {
    global vsd widgetHelp
    set w .monitors
    if [winfo exists $w] {
	wm deiconify $w
	focus $w
	raise $w
	refreshMonitors
	return
    }

    set widgetHelp($w) {Monitor Window}

    toplevel $w
    wm protocol $w WM_DELETE_WINDOW "wm withdraw $w"
    wm title $w "Monitor"
    if {$vsd(geometry:$w) != {}} {
	wm geometry $w $vsd(geometry:$w)
    }
    frame $w.top -relief raised -bd 1

    tixScrolledHList $w.top.monlist -width 300 -options {
	hlist.columns 4
	hlist.header true
	hlist.height 3
	hlist.selectMode single
	hlist.BrowseCmd monitorBrowse
    }
    set l [$w.top.monlist subwidget hlist]
#     global isWindows
#     if {$isWindows} {
# 	$l configure -font [tix option get font] \
# 	    -selectbackground SystemHighlight \
# 	    -selectforeground SystemHighlightText \
#     }

    # First some styles for the headers
    set vsd(header:s) [tixDisplayStyle text -fg black \
			   -anchor c -padx 8 -pady 2 \
			   -font [tix option get bold_font]]

    $l header create 0 -itemtype text -text "Cache Name" \
	-style $vsd(header:s)
    $l header create 1 -itemtype text -text "StatMon" \
	-style $vsd(header:s)
    $l header create 2 -itemtype text -text "Version" \
	-style $vsd(header:s)
    $l header create 3 -itemtype text -text "Creator" \
	-style $vsd(header:s)

    pack $w.top.monlist -expand yes -fill both
    $vsd(balloon) bind $w.top.monlist -msg "Lists/Selects statistic sources and monitor processes"

    set vsd(wv:statmonfile) ""
    tixLabelEntry $w.statmonfile -label "StatMon Output:" -state disabled \
	-options {
	    entry.textVariable vsd(wv:statmonfile)
	}
    $w.statmonfile subwidget label configure -background $vsd(currentBgColor)

    $vsd(balloon) bind $w.statmonfile -msg "Click to enter file name that monitor will write to"

    frame $w.ctr -relief flat -bd 0
    set vsd(w:statmoninterval) $w.ctr.statmoninterval
    tixControl $w.ctr.statmoninterval -label "Sample Interval:" -state disabled \
	-integer 1 -min 1 -autorepeat false -variable vsd(wv:statmoninterval) \
	-value $vsd(wv:statmoninterval) \
	-options {
	    entry.width 3
	}
    $vsd(balloon) bind $w.ctr.statmoninterval -msg "How often, in seconds, monitor should sample"

    set vsd(w:statmonflush) $w.ctr.statmonflush
    tixControl $w.ctr.statmonflush -label "Write Interval:" -state disabled \
	-integer 1 -min -1 -autorepeat false -variable vsd(wv:statmonflush) \
	-value $vsd(wv:statmonflush) \
	-options {
	    entry.width 3
	}
    $vsd(balloon) bind $w.ctr.statmonflush -msg "How often, in seconds, monitor should flush collected data to disk"

    set vsd(w:statmonlevel) $w.ctr.statmonlevel
    tixControl $w.ctr.statmonlevel -label "Level:" -state disabled \
	-integer 1 -min 0 -max 4 -autorepeat false \
	-variable vsd(wv:statmonlevel) \
	-value $vsd(wv:statmonlevel) \
	-options {
	    entry.width 1
	}
    $vsd(balloon) bind $w.ctr.statmonlevel -msg "Controls the operating system statistics that are collected"

    set vsd(w:statmonappstats) $w.ctr.statmonappstats
    tixControl $w.ctr.statmonappstats -label "AppStat Count:" -state disabled \
	-integer 1 -min 0 -max 2048 -autorepeat false \
	-variable vsd(wv:statmonappstats) \
	-value $vsd(wv:statmonappstats) \
	-options {
	    entry.width 4
	}
    $vsd(balloon) bind $w.ctr.statmonappstats -msg "Controls how many shared counters are collected"

    pack $w.ctr.statmoninterval $w.ctr.statmonflush $w.ctr.statmonlevel $w.ctr.statmonappstats -side left
    
    frame $w.ctr2 -relief flat -bd 0
    checkbutton $w.ctr2.compress -text "Compress" \
	-variable vsd(wv:statmoncompress) -state disabled
    pack $w.ctr2.compress -expand no -side left
    tixLabelEntry $w.ctr2.statmonpids -label "Pids:" \
        -state disabled \
	-options {
	    entry.textVariable vsd(wv:statmonpids)
	}
    $vsd(balloon) bind $w.ctr2.compress -msg "Check if output should be compressed"
    pack $w.ctr2.statmonpids -expand yes -fill x -side left
    $vsd(balloon) bind $w.ctr2.statmonpids -msg "List of extra process ids to collect OS stats on"
    tixLabelEntry $w.ctr2.statmonsessions -label "Sessions:" \
        -state disabled \
	-options {
	    entry.textVariable vsd(wv:statmonsessions)
	    entry.width 4
	}
    pack $w.ctr2.statmonsessions -side left
    $vsd(balloon) bind $w.ctr2.statmonsessions -msg "Restricts session statistic collection to this list of ids"

    tixButtonBox $w.box
    $w.box add refresh -text Refresh -width 6 \
      -command refreshMonitors
    $vsd(balloon) bind [$w.box subwidget refresh] -msg "Update display of statistic sources that can be monitored"
    $w.box add start -text Start -width 6 -state disabled \
      -command startMonitor
    $vsd(balloon) bind [$w.box subwidget start] -msg "Start monitoring the select statistic source"
    $w.box add status -text Status -width 6 -state disabled \
      -command statusMonitor
    $vsd(balloon) bind [$w.box subwidget status] -msg "Show the status of the selected monitor task"
    $w.box add stop -text Stop -width 6 -state disabled \
      -command stopMonitor
    $vsd(balloon) bind [$w.box subwidget stop] -msg "Stop the selected monitor task"
    $w.box add dismiss -text Dismiss -width 6 \
      -command "wm withdraw $w"
    set but [$w.box subwidget dismiss]
    $vsd(balloon) bind $but -msg "Close the monitor window"


    pack $w.box -fill x -side bottom
    pack $w.ctr2 -expand no -fill x -side bottom
    pack $w.ctr -fill x -side bottom
    pack $w.statmonfile -expand no -fill x -side bottom
    pack $w.top -side top -fill both -expand yes

    refreshMonitors
}

proc createVsdConfig {fname} {
    global vsd

    if [catch {open $fname w+} f] {
        showError "Notice: could not write $fname because:\n$f"
	return
    }
puts $f "\# .vsdconfig is never changed by vsd. If the user deletes it then
\# the next time vsd is started it will be recreated with default values.
\# Users can configure vsd by setting default values in this file.
\# Any value set in .vsdconfig will override the same definition in .vsdrc.
\# Make sure and put braces around the value if it contains whitespace.
\# For example: set vsd(exec:lpr) {lpr -h}
"

    puts $f "\# vsd(exec:lpr) is the name of the command used to print.
\# It is called with one argument; the name of the file to be printed."
    puts $f "set vsd(exec:lpr) [list $vsd(exec:lpr)]"

    puts $f "\n\# vsd(exec:mail) is the name of the command used to send mail.
\# It is called with one argument; the name of the user to send mail to.
\# It also expects the message to mail from stdin."
    puts $f "set vsd(exec:mail) [list $vsd(exec:mail)]"

    puts $f "\n\# vsd(exec:date) is the name of the command used to get the date.
\# It is called with no arguments."
    puts $f "set vsd(exec:date) [list $vsd(exec:date)]"

    puts $f "\n\# vsd(exec:uname) is the name of the command used to get system info.
\# It is called with no arguments."
    puts $f "set vsd(exec:uname) [list $vsd(exec:uname)]"

    puts $f "\n\# Uncomment the next line if you do not want the cursor to blink.
\# set vsd(cursorblink) 0"

puts $f {
# See the vsd help section "Statistic Definitions" for a guide to adding
# your own definitions to this file.
#
# See the vsd help section "Statistic Aliases" for a guide to adding
# your own aliases to this file.
}
    catch {close $f}
}

proc chooseChart {title} {
    global vsd
    if [info exists vsd(ct:$title)] {
	set w $vsd(ct:$title)
	if [winfo exists $w] {
	    raise $w
	    wm deiconify $w
	}
    }
}

proc changeNoFlatlines {} {
    global vsd

    foreach idx [array names vsd {*:ctrlistid}] {
	set vsd($idx) {}
    }
    fillCounters 1 [$vsd(instanceList) info selection]
}

proc changeLevel {} {
    global vsd
    if {[string equal [sl_stat -level] $vsd(statlevel)]} {
	return
    }
    sl_stat -level $vsd(statlevel)
    # Cause each chart windows counter listbox to be recalculated
    foreach i [array names vsd *:ctrlistid] {
	set vsd($i) {}
    }
    # fix for bug 26924
    updateCounterList
    # Make sure main window statistic list updated
    fillCounters 1 [$vsd(instanceList) info selection]
}

proc traceAPICalls {} {
    global vsd
    sl_stat -trace $vsd(traceAPICalls)
}

proc ctrHlistBrowse {junk} {
    global vsd
    set te [tixEvent type]
    if {![string equal $te "<ButtonRelease-1>"]} {
	set lb $vsd(w:counterHList)
	if {![string equal $te "<Up>"] &&
	    ![string equal $te "<Down>"] &&
	    ![string equal $te "<Application>"]} {
	    set i [$lb nearest [tixEvent flag y]]
	} else {
	    set i [$lb info anchor]
	}
	if {$i != {} && [$lb selection includes $i]} {
	    set itext [$lb entrycget $i -text]
	    showCounterInfo $itext
	}
	updateDisabledItems
    }
}

proc ctrHlistCommand {e} {
    global vsd

    doChart 0
}

proc setActiveColor {} {
    global vsd isWindows
    set title "Choose Selected Line Color"
    if { $vsd(masterBgColorChanged) == 1 && $isWindows == 0 } {
      set color [tk_chooseColor -initialcolor $vsd(activecolor) \
                   -parent $vsd(w) -title $title -background $vsd(currentBgColor)]
    } else {
      set color [tk_chooseColor -initialcolor $vsd(activecolor) \
                   -parent $vsd(w) -title $title]
    }
    if {$color != ""} {
        set vsd(activecolor) $color
	foreach name [array names vsd  ct:*] {
	    set g $vsd($name).graph
	    $g pen configure "activeLine" -color $vsd(activecolor)
	    $g marker configure triStart -fg $vsd(activecolor)
	    $g marker configure triEnd -fg $vsd(activecolor)
	}
    }
}

proc applyChartFont {res} {
    font delete vsdsf
    eval font create vsdsf $res
}

proc setChartFont {} {
    set res [Font_Select "Chart Font" applyChartFont [font actual vsdsf]]
    if {[string length $res] != 0} {
	applyChartFont $res
    }
}

proc createTextFonts {} {
    global vsd
    eval font create normalTextFont $vsd(textfont)
    eval font create boldTextFont $vsd(textfont) -weight bold
    eval font create italicTextFont $vsd(textfont) -slant italic
    eval font create boldItalicTextFont $vsd(textfont) -weight bold -slant italic
    eval font create fixedTextFont $vsd(textfont) -family Courier -weight bold
}

proc applyTextFont {res} {
    global vsd
    set vsd(textfont) $res
    font delete normalTextFont boldTextFont italicTextFont boldItalicTextFont fixedTextFont
    createTextFonts
}
proc setTextFont {} {
    set res [Font_Select "Help Font" applyTextFont [font actual normalTextFont]]
    if {[string length $res] != 0} {
	applyTextFont $res
    }
}

proc Font_Select {title applyCmd {defaults {}}} {
    global font widgetHelp

    set font(applyCalled) 0
    set font(applyCmd) $applyCmd
    set font(defaults) $defaults
    set font(otherSize) 0
    set top .fontsel
    set widgetHelp($top) {Font Window}
	# Create the menus for the menu bar

	toplevel $top -class Fontsel -bd 10
        wm title $top $title
	set menubar [menu $top.menubar]
	$top config -menu $menubar
	foreach x {File Font Size Format} {
		set menu [menu $menubar.[string tolower $x]]
		$menubar add cascade -menu $menu -label $x
	}
        $menubar.file configure -tearoff 0
	$menubar.file add command -label Reset -command FontReset
	$menubar.file add command -label Apply -command FontApply
	$menubar.file add command -label OK \
		-command {set font(ok) 1}
	$menubar.file add command -label Cancel \
		-command {set font(ok) 0}

	# Build a cascaded family menu if there are lots of fonts

	set allfonts [lsort [font families]]
	set numfonts [llength $allfonts]
	set i 0
	foreach family $allfonts {
	    incr i
	    set cb 0
	    if {($i % 15) == 0} {
		set cb 1
	    }
	    $menubar.font add radio -label $family \
		-variable font(-family) \
		-value $family \
		-columnbreak $cb \
		-command FontUpdate
	}

	# Complete the other menus

	foreach size {6 7 8 10 12 14 18 24} {
		$menubar.size add radio -label $size \
			-variable font(-size) \
			-value $size \
			-command FontUpdate
	}
	$menubar.size add command -label Other... \
			-command [list FontSetSize $top]
	$menubar.format add check -label Bold \
			-variable font(-weight) \
			-onvalue bold -offvalue normal \
			-command FontUpdate
	$menubar.format add check -label Italic \
			-variable font(-slant) \
			-onvalue italic -offvalue roman \
			-command FontUpdate
	$menubar.format add check -label Underline \
		-variable font(-underline) \
		-command FontUpdate
	$menubar.format add check -label Overstrike \
		-variable font(-overstrike) \
		-command FontUpdate

	FontReset

	# This label displays the current font
	label $top.font -textvar font(name) -bd 5

	# A message displays a string in the font.
	message $top.msg -aspect 1000 \
					-borderwidth 10 -font fontsel \
					-text  "
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789
!@#$%^&*()_+-=[]{};:\"'` ~,.<>/?\\|
"

	# Lay out the dialog

	pack $top.font $top.msg  -side top
	set f [frame $top.buttons]
	button $f.ok -text Ok -command {set font(ok) 1}
        button $f.apply -text Apply -command FontApply
	button $f.cancel -text Cancel -command {set font(ok) 0}
	pack $f.ok $f.apply $f.cancel -padx 10 -side left
	pack $f -side top

    set font(ok) -1
    setMasterBgColorForWindow $top
	Dialog_Wait $top
	destroy $top
	if {$font(ok)} {
		return [array get font -*]
	} else {
	        FontReset
		return {}
	}
}
proc FontApply {} {
    global font

    set font(applyCalled) 1
    $font(applyCmd) [array get font -*]
}

proc FontUpdate { } {
	global font

	# The elements of font that have a leading - are
	# used directly in the font configuration command.

	eval {font configure fontsel} [array get font -*]
	FontSet
}
proc FontReset {} {
        global font
	catch {font delete fontsel}
	eval font create fontsel $font(defaults)
	FontSet
        if {$font(applyCalled)} {
	    FontApply
	    set font(applyCalled) 0
	}
}
proc FontSet {} {
	global font

	# The name is the font configuration information
	# with a line break so it looks nicer

	set font(name) [font actual fontsel]
	regsub -- "-slant" $font(name) "\n-slant" font(name)

	# Save the actual parameters after any font substitutions

	array set font [font actual fontsel]
}
proc FontSetSize {top} {
        global font

    if {$font(otherSize)} {
	return
    }
	# Add an entry to enter a specific size.

        set font(otherSize) 1
	set f [frame $top.size -borderwidth 10]
	pack $f -side top -fill x
	label $f.msg -text "Size:"
	entry $f.entry -textvariable font(-size)
	bind $f.entry <Return> FontUpdate
	pack $f.msg -side left
	pack $f.entry -side top -fill x
}
proc Dialog_Wait {top {focus {}}} {
    global font

	# Poke the variable if the user nukes the window
        bind $top <Destroy> {if {$font(ok) == -1} {set font(ok) 0}}

	# Grab focus for the dialog
	if {[string length $focus] == 0} {
		set focus $top
	}
	set old [focus -displayof $top]
	focus $focus
	catch {tkwait visibility $top}
	catch {grab $top}

	# Wait for the dialog to complete
	tkwait variable font(ok)
	catch {grab release $top}
	focus $old
}

proc isCombineTemplate {tl} {
    string match {*+} [lindex $tl 0]
}
proc isOperatorTemplate {tl} {
    expr {[lsearch -exact {"plus" "diff" "divide"} [lindex $tl 0]] != -1}
}

proc fileMatches {mf df fids} {
    if {[llength $fids] > 0} {
        expr {[lsearch -exact $fids [getFileId $mf]] != -1}
    } else {
        expr {$df == {} || [string equal $df $mf]}
    }
}

proc findTemplateMatch {tl {df {}}} {
    global vsd
    set instList {}

    set typeList [string trimright [lindex $tl 0] "+"]
    set objs {}
    set fids {}
    foreach t $typeList {
        if {[string is integer -strict $t]} {
            lappend fids $t
        } else {
            lappend objs $t
        }
    }
    set name [lindex $tl 1]
    set ctr [lindex $tl 2]

    if [catch {getStatObjList $ctr} statObjList] {
	setStatus "Unknown statistic \"$ctr\"."
	bell
	return {}
    }

    if {$objs != {}} {
	set ctrobjs {}
	foreach co $statObjList {
	    set noverco [file rootname $co]
	    if {[lsearch -exact $objs $noverco] != -1} {
		lappend ctrobjs $co
	    }
	}
    } else {
	set ctrobjs $statObjList
    }
    if {$ctrobjs == {}} {
	# We don't have any instances of the target objects
	return {}
    }

    if {$vsd(templatesUseSelection)} {
	set procs [$vsd(instanceList) info selection]
	if {$procs != {}} {
	    # if some procs are selected restrict the template to them
	    foreach i $procs {
		set data [$vsd(instanceList) info data $i]
		set iobj [lindex $data 1]
		if {[lsearch -exact $ctrobjs $iobj] != -1} {
		    set fullname [lindex $data 0]
		    if {[string match $name [lindex $fullname 0]]} {
			if {[fileMatches [lindex $data 5] $df $fids]} {
			    lappend instList [lindex $data 6]
			}
		    }
		}
	    }
	    # Only return the matched selected instances if at least
	    # one of the selected types was the kind this template
	    # was trying to match.
	    if {$instList != {}} {
		return $instList
	    }
	}
    }

    set instList {}
    foreach i [instSort [sl_stat -enabledobjinstances $ctrobjs]] {
	set fullname [lindex $i 0]
	if {[string match $name [lindex $fullname 0]]} {
            if {[fileMatches [lindex $i 5] $df $fids]} {
		lappend instList [lindex $i 6]
	    }
	}
    }

    return $instList
}

proc createLinesFromTemplate {tl {df {}}} {
    global vsd
    set result {}
    set scale [lindex $tl 3]
    set filter [lindex $tl 4]
    set infoArgs [llength $tl]
    if {$infoArgs <= 7} {
	# old style with default divider, offset, and normalize
	set divider 1
	set offset 0
	set normalized 0
	set statFilter [lindex $tl 6]
    } else {
	set divider [lindex $tl 6]
	set offset [lindex $tl 7]
	set normalized [lindex $tl 8]
	set statFilter [lindex $tl 9]
    }
    if {[isOperatorTemplate $tl]} {
	set childLines {}
	foreach childSpec [lrange $tl 1 2] {
	    set isChildOp [isOperatorTemplate $childSpec]
	    lappend childLines [createLinesFromTemplate $childSpec $df]
	}
	set lines1 [lindex $childLines 0]
	set lines2 [lindex $childLines 1]
	if {[llength $lines1] > 0 && [llength $lines2] > 0} {
	    set opcode [lindex $tl 0]
	    switch -exact $opcode {
		"plus" {set operator "+"}
		"diff" {set operator "-"}
		"divide" {set operator "/"}
	    }
	    while {[llength $lines1] < [llength $lines2]} {
		lappend lines1 [lindex $lines1 end]
	    }
	    while {[llength $lines2] < [llength $lines1]} {
		lappend lines2 [lindex $lines2 end]
	    }
	    foreach l1 $lines1 l2 $lines2 {
		set line [createOperatorLine [list $l1 $l2] $operator 0 $filter $scale $divider $offset $normalized $statFilter]
		if {$line != {}} {
		    lappend result $line
		}
	    }
	}
	
	foreach tmp $childLines {
	    foreach l $tmp {
		$l -free
	    }
	}
    } else {
	set instList [findTemplateMatch $tl $df]
	if {$instList == {}} {
	    return {}
	}
	set counter [lindex $tl 2]
	if {[isCombineTemplate $tl]} {
	    if {$vsd(combineFiles) || [llength $instList] == 1} {
                if {$vsd(combineFilePattern) == "" || [llength $instList] == 1} {
                    set line [createSimpleLine $instList $counter $filter $scale $divider $offset $normalized $statFilter]
                    if {$line != {}} {
                        lappend result $line
                    }
                } else {
                    # Use combineFilePattern to group files
                    global patternMap
                    foreach fGroupName [getSortedGroupNames] {
                        set fGroupIds $patternMap($fGroupName);
                        set dfInstList {}
                        foreach inst $instList {
                            set instData [sl_stat -instinfo $inst]
                            if {[lsearch -exact $fGroupIds [lindex $instData 5]] != -1} {
                                lappend dfInstList $inst
                            }
                        }
                        if {$dfInstList != {}} {
                            set line [createSimpleLine $dfInstList $counter $filter $scale $divider $offset $normalized $statFilter]
                            if {$line != {}} {
                                lappend result $line
                            }
                        }
                    }
                }
	    } else {
		foreach fIt [getSortedFiles] {
		    set dfInstList {}
		    foreach inst $instList {
			set instData [sl_stat -instinfo $inst]
			if {[string equal $fIt [lindex $instData 5]]} {
			    lappend dfInstList $inst
			}
		    }
		    if {$dfInstList != {}} {
			set line [createSimpleLine $dfInstList $counter $filter $scale $divider $offset $normalized $statFilter]
			if {$line != {}} {
			    lappend result $line
			}
		    }
		}
	    }
	} else {
	    foreach fn $instList {
		set line [createSimpleLine [list $fn] $counter $filter $scale $divider $offset $normalized $statFilter]
		if {$line != {}} {
		    lappend result $line
		}
	    }
	}
    }
    return $result
}

proc startLongOp {w} {
    global vsd
    set w [winfo toplevel $w]
    set vsd(longOpW) $w
    set vsd(longOpCancel) 0
    myBusyOn $w
    set busyWin ${w}._Busy
    focus $busyWin
    bind $busyWin <Escape> {cancelLongOp}
    bind $busyWin <Control-g> {cancelLongOp}
}

proc cancelLongOp {} {
    global vsd
    set vsd(longOpCancel) 1
    setStatus "Cancelled operation"
    bell
}

proc endLongOp {} {
    global vsd
    if {$vsd(longOpW) != ""} {
	myBusyOff $vsd(longOpW)
	set vsd(longOpW) ""
    }
    set vsd(longOpCancel) 0
}

proc newFromTemplate {t} {
    global vsd vsdtemplates
    if {[info exists vsdtemplates($t)]} {
	if {[string equal "@" [lindex $vsdtemplates($t) 0]]} {
	    foreach tn [lrange $vsdtemplates($t) 1 end] {
		newFromTemplate $tn
	    }
	    return
	}
	disableAutoUpdates
	foreach f [getSortedFiles] {
	    set new 1
	    set w ""
	    foreach tl $vsdtemplates($t) {
		set lineList [createLinesFromTemplate $tl $f]
		if {$lineList != {}} {
		    set mapaxis [lindex $tl 5]
		    if {$new} {
			set vsd(curchart) "$t $vsd(graphcreates)"
			set w [createGraphWindow $vsd(curchart)]
			startLongOp $w
			set new 0
		    }
		    foreach line $lineList {
			if {$w != "" && ![winfo exists $w]} {set vsd(longOpCancel) 1; break}
			addLineToChart $line 0 0 $mapaxis "none"
			update
			if {$vsd(longOpCancel)} {break}
		    }
		}
		if {$vsd(longOpCancel)} {break}
	    }
	    if {$vsd(longOpCancel)} {break}
	    endLongOp
	}
	enableAutoUpdates
	endLongOp
    }
}

proc addFromTemplate {t title} {
    global vsd vsdtemplates
    if {[info exists vsdtemplates($t)]} {
	if {[string equal "@" [lindex $vsdtemplates($t) 0]]} {
	    foreach tn [lrange $vsdtemplates($t) 1 end] {
		addFromTemplate $tn $title
	    }
	    return
	}
	set w $vsd(ct:$title)
	startLongOp $w
	set vsd(curchart) $title
	disableAutoUpdates
	foreach tl $vsdtemplates($t) {
	    set lineList [createLinesFromTemplate $tl]
	    set mapaxis [lindex $tl 5]
	    foreach line $lineList {
		if {![winfo exists $w]} {set vsd(longOpCancel) 1; break}
		addLineToChart $line 0 0 $mapaxis "none"
		update
		if {$vsd(longOpCancel)} {break}
	    }
	    if {$vsd(longOpCancel)} {break}
	}
	enableAutoUpdates
	endLongOp
    }
}

proc createGraphTemplateMenu {m title} {
    global vsd vsdtemplates
    foreach t [lsort [array names vsdtemplates]] {
	$m add command -label $t -command [list addFromTemplate $t $title]
    }
}

proc reloadTemplates {m} {
    global vsd vsdtemplates

    if [file exists "~/.vsdtemplates"] {
	if [catch {source "~/.vsdtemplates"} msg] {
	    showError "Notice: could not read '~/.vsdtemplates' because:\n$msg"
	} else {
	    $m delete 0 end
	    createTemplateMenu $m
	}
    } else {
	showError "Notice: could not read '~/.vsdtemplates' because:\nfile does not exist"
    }
}

proc createTemplateMenu {m} {
    global vsd vsdtemplates
    foreach t [lsort [array names vsdtemplates]] {
	addTemplateMenu $m $t
    }
}

proc addTemplateMenu {m t} {
    $m add command -label $t -command [list newFromTemplate $t]
}

proc defaultTemplates {} {
    global vsdtemplates
    set vsdtemplates(CacheMix) {
        {Shrpc {*} FreeFrameCount 1 none y2}
        {Shrpc {*} LocalDirtyPageCount 1 none y}
        {Shrpc {*} FreeFrameLimit 1 none y}
        {Shrpc {*} BitlistPagesWrittenByGem 1 none y}
        {Shrpc {*} BitlistPagesWrittenByStone 1 none y}
        {Shrpc {*} BmInternalPagesWrittenByGem 1 none y}
        {Shrpc {*} BmInternalPagesWrittenByStone 1 none y}
        {Shrpc {*} BmLeafPagesWrittenByGem 1 none y}
        {Shrpc {*} BmLeafPagesWrittenByStone 1 none y}
        {Shrpc {*} CommitRecordPagesWrittenByGem 1 none y}
        {Shrpc {*} CommitRecordPagesWrittenByStone 1 none y}
        {Shrpc {*} DataPagesWrittenByGem 1 none y}
        {Shrpc {*} OtInternalPagesWrittenByGem 1 none y}
        {Shrpc {*} OtInternalPagesWrittenByStone 1 none y}
        {Shrpc {*} OtLeafPagesWrittenByGem 1 none y}
        {Shrpc {*} OtLeafPagesWrittenByStone 1 none y}
    }
    set vsdtemplates(CacheTooSmall) {
	{Shrpc ShrPcMonitor FreeFrameCount 1 none y2}
	{+ {*} FramesFromFreeList 1 persecond y}
	{+ {*} FramesFromFindFree 1 persecond y}
    }
    set vsdtemplates(CommitInfo) {
	{Stn {*} TotalCommits 1 persecond y}
	{Stn {*} CommitRecordCount 1 none y2}
	{Stn {*} CommitQueueSize 1 none y2}
    }
# Fix 43319
    set vsdtemplates(CPU) {
	{+ {*} PercentCpuActive 1 none y}
	{+ {*} PercentCpuWaiting 1 none y}
	{+ {*} PercentCpuIdle 1 none y}
	{+ {*} PercentCpuUser 1 none y}
	{+ {*} PercentCpuSystem 1 none y}
	{+ {*} PercentCpuIOWait 1 none y}
	{+ {*} PercentCpuSwapWait 1 none y}
	{NtSystem {*} TotalProcessorTime 1 persecond y}
	{NtSystem {*} ProcessorQueueLength 1 none y2}
    }
    set vsdtemplates(CRBacklog) {
	{Stn {*} TotalCommits 1 persecond y2}
	{Stn {*} CommitRecordCount 1 none y2}
	{Stn {*} CommitQueueSize 1 none y2}
	{Stn {*} OldestCrSession 1 none y}
    }
    set vsdtemplates(EpochSweeps) {
	{Stn {*} EpochGcCount 1 persecond y}
	{Stn {*} EpochScannedObjs 1 none y2}
	{Stn {*} EpochNewObjsSize 1 none y2}
	{Stn {*} EpochPossibleDeadSize 1 none y2}
	{Stn {*} PossibleDeadSize 1 none y2}
    }
    set vsdtemplates(Garbage) {
        {Stn {*} PagesNeedReclaimSize 1 none y2}
        {Stn {*} ReclaimedPagesCount 1 none y2}
        {Stn {*} EpochGcCount 1 persecond y}
        {Stn {*} ReclaimCount 1 persecond y}
        {Gem+ {*Gc*} CommitCount 1 persecond y}
    }
    set vsdtemplates(PageServer) {
	{Pgsvr+ {*} AioDirtyCount 1 persecond y}
	{Pgsvr+ {*} AioCkptCount 1 persecond y}
	{Shrpc {*} LocalDirtyPageCount 1 none y}
    }
    set vsdtemplates(SpaceFree) {
        {Shrpc {*} FreeFrameCount 1 none y}
        {Stn {*} FreePages 1 none y2}
    }
}
proc getStatType {s} {
    return [lindex [sl_stat -info $s] 0]
}
proc getStatLevel {s} {
    return [lindex [sl_stat -info $s] 1]
}
proc getStatFilter {s} {
    return [lindex [sl_stat -info $s] 2]
}
proc setStatFilter {s f} {
    global vsd
    sl_stat -info $s [list {} {} $f]
    set vsd(filter:$s) $f
    if {[string equal $f "Default"]} {
	unset vsd(filter:$s)
    }
}
proc setStatLevel {s l} {
    global vsd
    sl_stat -info $s [list {} $l]
    set vsd(level:$s) $l
}
proc getStatObjList {s} {
    return [lindex [sl_stat -info $s] 3]
}
proc getPlainStatDescription {s} {
    set txt [getStatDescription $s]
    regsub -all {\[(\w+) > \w+ Statistic\]} $txt {\1} res
    return $res
}

proc getStatDescription {s} {
    global statDocs
  
    if {[string equal -length 17 $s "PersistentCounter"]} {
      return $statDocs(PersistentCounter)
    }

    if [info exists statDocs($s)] {
	return $statDocs($s)
    } else {
	if {[string equal -length 13 $s "sharedCounter"]} {
	    return $statDocs(sharedCounter)
	} else {
            if [fetchStatDef $s] {
                return $statDocs($s)
            } else {
                return ""
            }
	}
    }
}

proc isOSStat {s} {
    global statDefinitions
    if [info exists statDefinitions($s)] {
	return [lindex $statDefinitions($s) 3]
    } else {
        if [fetchStatDef $s] {
            return [lindex $statDefinitions($s) 3]
        } else {
            return false
        }
    }
}

proc getStatUnits {s} {
    global statDefinitions
    if [info exists statDefinitions($s)] {
	return [lindex $statDefinitions($s) 2]
    } else {
        if [fetchStatDef $s] {
            return [lindex $statDefinitions($s) 2]
        } else {
            return none
        }
    }
}

proc fetchStatDef {s} {
    if [catch {sl_stat -info $s} statDef] {
        return 0
    } else {
        set kind [lindex $statDef 0]
        set level [lindex $statDef 1]
        # 2 is filter
        # 3 is object list
        set isOSStat [lindex $statDef 4]
        set units [lindex $statDef 5]
        set docs [lindex $statDef 6]

        global statDefinitions statDocs
	set statDefinitions($s) [list $kind $level $units $isOSStat]
        set statDocs($s) $docs
        return 1
    }
}

proc selectByStatistic {} {
    global vsd
    set selCtr [getSelCtr]
    if {$selCtr != {}} {
	foreach ctr $selCtr {
	    set objlist [getStatObjList $ctr]
	    foreach obj $objlist {
		set objset($obj) 1
	    }
	}
	set objnames [lsort [array names objset]]
	if {$objnames != {}} {
	    foreach i [$vsd(instanceList) info children] {
		set iobj [lindex [$vsd(instanceList) info data $i] 1]
		if {[lsearch -exact $objnames $iobj] != -1} {
		    $vsd(instanceList) selection set $i
		}
	    }
	}
    }
    updateGraphWidgetState
}

proc selectAllInstances {} {
    global vsd
    foreach i [$vsd(instanceList) info children] {
	$vsd(instanceList) selection set $i
    }
    updateGraphWidgetState
#    set il [$vsd(instanceList) info children]
#    if {[llength $il] > 1} {
#	$vsd(instanceList) selection set [lindex $il 0] [lindex $il end]
#	updateGraphWidgetState
#    }
}

proc selectByType {} {
    global vsd
    set typeList {}
    foreach i [$vsd(instanceList) info selection] {
	set data [$vsd(instanceList) info data $i]
	set iobj [lindex $data 1]
	if {[lsearch -exact $typeList $iobj] == -1} {
	    lappend typeList $iobj
	}
    }
    if {$typeList != {}} {
	foreach i [$vsd(instanceList) info children] {
	    set iobj [lindex [$vsd(instanceList) info data $i] 1]
	    if {[lsearch -exact $typeList $iobj] != -1} {
		$vsd(instanceList) selection set $i
	    }
	}
	updateGraphWidgetState
    }
}

proc doPopup {w m x y} {
    global vsd
    if {[string equal $w [winfo containing $x $y]]} {
	tk_popup $m $x $y
    }
}

proc setHdrSortHighlight {} {
    global vsd
    set type $vsd(def:sortbytype)
    if {$vsd(def:sortdecreasing)} {
	set relief groove
    } else {
	set relief ridge
    }
# Workaround bug 44084
    set w $vsd(instanceList).hdrBut$type
    if [winfo exists $w] {
      $w configure -relief $relief
    }
    return
}

proc sortInstances {type} {
    global vsd
    set oldtype $vsd(def:sortbytype)
    if {[string equal $type $oldtype]} {
	set vsd(def:sortdecreasing) [expr {!$vsd(def:sortdecreasing)}]
    } else {
	set oldw $vsd(instanceList).hdrBut$oldtype
	if {[winfo exists $oldw]} {
	    $oldw configure -relief flat
	}
	set vsd(def:sortbytype) $type
	set vsd(def:sortdecreasing) 1
    }
    setHdrSortHighlight
    setInstanceList
    return
}

proc getScriptName {} {
    global vsd
    set result $vsd(infoScript)
    if {$result == {}} {
	set exe [info nameofexecutable]
	set result [file join [file dirname $exe] "vsd"]
    }
    return $result
}

proc restartVsd {} {
    global vsd
    set vsd(restarting) 1
    uplevel #0 {source [getScriptName]}
}

proc tixItemStyle {args} {
  return [eval tixDisplayStyle $args]
}

proc RunVSD {w} {
    global vsd vsdtemplates isWindows widgetHelp env

    set vsd(time_shift_hours) 0
    set vsd(old_time_shift_hours) 0
    set widgetHelp($w) {Main Window Features}
    
    if {[info exists env(GEMSTONE_LANG)]} {
	unset env(GEMSTONE_LANG)
    }

    set vsd(maintainer) "vsd@gemtalksystems.com"


    set vsd(helpIdx) 0
    set vsd(bulletImage) [image create photo -data "R0lGODlhEAAFAID/AMDAwAAAACH5BAEAAAAALAAAAAAQAAUAAAINhA+hyKff2FvRzYogKwA7"]
    
    set vsd(exec:lpr) "lpr"
    set vsd(exec:mail) "/usr/sbin/sendmail"
    set vsd(exec:date) "date"
    set vsd(exec:uname) "uname -a"
    set vsd(symbollist) {none scross splus square triangle circle diamond plus cross}

    bind Toplevel <FocusIn> {+ chartFocus %W}
    set vsd(w) $w

    set vsd(initialBgColor) [$w cget -background]
    set vsd(currentBgColor) $vsd(initialBgColor)
    set vsd(currentPlotBgColor) white
    set vsd(masterBgColorChanged) 0

    set vsd(confirmonexit) 1
    set vsd(traceAPICalls) 0
    set vsd(warningGiven) 0
    set vsd(sdtrace) 0
    set vsd(xcount) 0
    set vsd(ycount) 0
    set vsd(lastdatafile) {}
    set vsd(lastctr) {}
    set vsd(counterType) {}
    set vsd(selectedInstIds) {}
    set vsd(zeroCtrs) {}
    set vsd(autoUpdatesDisabled) 0
    if {$isWindows} {
	set vsd(graphcursor) arrow
    } else {
	set vsd(graphcursor) top_left_arrow
    }
    set vsd(xaxis:defaultTitle) "Time Axis"
    set vsd(yaxis:defaultTitle) "Left  Axis"
    set vsd(y2axis:defaultTitle) "Right  Axis"
    set vsd(obsoleteCounters) "StatTypeNum Time ProcessName ProcessNumber ProcessId SessionId Offset DeviceNumber"
    if {[winfo depth .] == 1} {
	set vsd(colorlist) {black}
	set vsd(activecolor) black
    } else {
	set vsd(colorlist) {blue cyan brown green \
			    purple pink magenta black \
			    PeachPuff SeaGreen DodgerBlue orchid }
	set vsd(activecolor) red
    }

    set vsd(brokenLinkColor) red
    set vsd(normalLinkColor) blue
    set vsd(visitedLinkColor) brown
    
    set vsd(freeGeometryIds) {}
    set vsd(graphcount) 0
    set vsd(graphcreates) 0

    # Fix 41952 - add .fileselector to the list
    set vsd(winnames) {.monitors .monstatus .ctrinfo .datawin .timeShifter .fileselector}
    foreach cw $vsd(winnames) {
	set vsd(geometry:$cw) {}
    }
    set vsd(def:geometry) {}
    set vsd(def:xformat) "time"
    set vsd(def:linestyle) "linear"
    set vsd(def:xaxis:showtitle) 1
    set vsd(def:yaxis:showtitle) 1
    set vsd(def:y2axis:showtitle) 1
    set vsd(def:showcurxy) 1
    set vsd(def:showminmax) 0
    set vsd(def:showlinestats) 1
    set vsd(def:showcrosshairs) 0
    set vsd(def:showlegend) 1
    set vsd(def:showgridlines) 0
    set vsd(def:sortbytype) Type
    set vsd(def:sortdecreasing) 1
    set vsd(filelist) {}
    set vsd(statsrc) {}
    set vsd(appendMode) 0
    set vsd(autoUpdate) 0
    set vsd(autoUpdateTime) 10000
    set vsd(showCtrInfo) 0
    set vsd(absoluteTSMode) 1
    set vsd(copyChildren) 1
    set vsd(singleFileMode) 1
    set vsd(lastEnabledFiles) {}
    set vsd(templatesUseSelection) 0
    set vsd(file:isEnabled) 1
    set vsd(cursorblink) 1
    auto_load tk_chooseColor    
    auto_load tk_messageBox    
    auto_load tk_getOpenFile    
    auto_load tixMeter
    set vsd(hasMeter) [expr {[info commands tixMeter] != ""}]

    set vsd(wv:statmoninterval) 20
    set vsd(wv:statmonflush) 0
    set vsd(wv:statmonlevel) 1
    set vsd(wv:statmonappstats) 0
    set vsd(wv:statmonsessions) ""
    set vsd(wv:statmonpids) ""
    set vsd(wv:statmoncompress) 0
    set vsd(combineInstances) 0
    set vsd(combineFiles) 0
    set vsd(combineFilePattern) ""
    set vsd(sortedGroupNames) {}
    set vsd(noFlatlines) 0
    set vsd(clipboard) {}
    set vsd(ruleCount) 0
    set vsd(longOpCancel) 0
    set vsd(longOpW) ""

    set vsd(instancePaneSize) 115
    set vsd(statisticPaneSize) 50
    

    defaultTemplates

    makeErrorDialog $w

    loadStatisticAliases

    if [file exists "~/.vsdrc"] {
	if [catch {source "~/.vsdrc"} msg] {
	    showError "Notice: could not read '~/.vsdrc' because:\n$msg"
	}
	if {[string equal $vsd(def:sortbytype) "Start Time"]} {
	    set vsd(def:sortbytype) "StartTime"
	}
    }
    if [file exists "~/.vsdtemplates"] {
	if [catch {source "~/.vsdtemplates"} msg] {
	    showError "Notice: could not read '~/.vsdtemplates' because:\n$msg"
	}
    } else {
	writeTemplateFile
    }
    if [file exists "~/.vsdconfig"] {
	global statdef
	if [catch {source "~/.vsdconfig"} msg] {
	    showError "Notice: could not read '~/.vsdconfig' because:\n$msg"
	}
    } else {
	createVsdConfig "~/.vsdconfig"
    }

    loadStatisticDefinitions ;# do this after reading .vsdconfig and .vsdrc

    if {![info exists vsd(smallfont)]} {
	if {$isWindows} {
#        set vsd(smallfont) [lreplace [tix option get font] 1 1 "8"]
#        set vsd(smallfont) "-Adobe-Helvetica-Bold-R-Normal--*-120-*"
	    set vsd(smallfont) {-family Helvetica -size 8}
	} else {
	    set vsd(smallfont) {-family lucida -size 8}
	}
    }
    eval font create vsdsf $vsd(smallfont)

    if {![info exists vsd(textfont)]} {
	# does a better way of getting default text font exist?
        # Why yes it does!  Use TkDefaultFont here to fix 45174
        set vsd(textfont) [font configure TkDefaultFont]
    }
    createTextFonts
    
    if {! $vsd(cursorblink)} {
	option add *insertOffTime 0
    }
    
    # Sometimes the geometry gets saved with a strange value
    if {[string match "1x1+*" $vsd(def:geometry)]} {
	set vsd(def:geometry) ""
    }
    foreach cw $vsd(winnames) {
	if {[string match "1x1+*" $vsd(geometry:$cw)]} {
	    set vsd(geometry:$cw) ""
	}
    }

    if {$vsd(def:geometry) != {}} {
	wm geometry $vsd(w) $vsd(def:geometry)
    }

    set vsdExeName [info nameofexecutable]

    set mf [frame $w.mf -bd 2 -relief raised]
    
    menubutton $mf.main -menu $mf.main.m -text "Main" -underline 0 \
	-takefocus 0 -font [tix option get bold_font]
    menu $mf.main.m -tearoff 0
    set vsd(w:mainmenu) $mf.main.m
    $mf.main.m add command -label "Load Data File..." -underline 0 \
	-command browseDataFile -font [tix option get bold_font]
    if {$isWindows} {
        # fix for bug 27746
        $mf.main.m add command -label "Monitor..." -command {doMonitor} \
            -accelerator "Ctrl+m" -state disabled -font [tix option get bold_font]
    } else {
        $mf.main.m add command -label "Monitor..." -command {doMonitor} \
            -accelerator "Ctrl+m" -font [tix option get bold_font]
    }
    $mf.main.m add command -label "Change Directory..." -command {doChangeDirectory} \
        -font [tix option get bold_font]
    $mf.main.m add command -label "Change Time Offset..." -command {doAdjustTimeOffset} \
        -font [tix option get bold_font]
    $mf.main.m add command -label "Set Master Background Color..." -command {pickMasterBackgroundColor} \
        -accelerator "Ctrl+b" -font [tix option get bold_font]

    $mf.main.m add command -label "Copy Selection" -command {doCopySelection} \
	-accelerator "Ctrl+c" -font [tix option get bold_font]
    bind $vsd(w) <Control-m> [list $mf.main.m invoke "Monitor..."]
    bind $vsd(w) <Control-b> [list $mf.main.m invoke "Set Master Background Color..."]
    bind $vsd(w) <<Copy>> [list $mf.main.m invoke "Copy Selection"]
    $mf.main.m add check -label "Show Statistic Info" -underline 0 \
	-variable vsd(showCtrInfo) \
	-command {doCtrInfo} -font [tix option get bold_font]
    $mf.main.m add check -label "Combine" \
	-variable vsd(combineInstances) -font [tix option get bold_font]
    $mf.main.m add check -label "Combine Across Files" \
	-variable vsd(combineFiles) -font [tix option get bold_font]
    $mf.main.m add check -label "No Flatlines" \
	-variable vsd(noFlatlines) -command changeNoFlatlines \
        -font [tix option get bold_font]
    $mf.main.m add check -label "Single File Mode" \
	-variable vsd(singleFileMode) -command singleFileMode \
        -font [tix option get bold_font]
    $mf.main.m add check -label "Absolute TimeStamps" \
	-variable vsd(absoluteTSMode) -font [tix option get bold_font]
    $mf.main.m add check -label "Copy Referenced Lines" \
	-variable vsd(copyChildren) -font [tix option get bold_font]

    set mclevel $mf.main.m.clevel
    menu $mclevel -tearoff 0
    set vsd(statlevel) [sl_stat -level]
    $mclevel add radio -label "Common Statistics Only" -value "common" \
	-variable vsd(statlevel) \
	-command changeLevel -font [tix option get bold_font]
    $mclevel add radio -label "Advanced & Common Statistics" -value "advanced" \
	-variable vsd(statlevel) \
	-command changeLevel -font [tix option get bold_font]
    $mclevel add radio -label "All Statistics" -value "wizard" \
	-variable vsd(statlevel) \
	-command changeLevel -font [tix option get bold_font]

    $mf.main.m add cascade -label "Statistic Level" -menu $mclevel \
        -font [tix option get bold_font]

    if [wizardMode] {
	$mf.main.m add command -label "Dump Statistic Info"  -command dumpCtrInfo \
            -font [tix option get bold_font]
	$mf.main.m add check -label "Trace API Calls" \
	    -variable vsd(traceAPICalls) -command traceAPICalls \
            -font [tix option get bold_font]
	$mf.main.m add command -label "ForceError"  -command {forcedError } \
            -font [tix option get bold_font]
	$mf.main.m add command -label "Restart" \
	    -command {restartVsd} -font [tix option get bold_font]
	$mf.main.m add command -label "Debug" \
	    -command {source "~/tkcon.tcl"} -font [tix option get bold_font]
    }
    $mf.main.m add separator
    $mf.main.m add check -label "Confirm Exit" \
	-variable vsd(confirmonexit) -font [tix option get bold_font]
    $mf.main.m add separator
    $mf.main.m add command -label "Exit     " -underline 1 -command ExitVSD \
         -font [tix option get bold_font]
    pack $mf.main -side left

    set widgetHelp($mf.main) {Main Window Main Menu}

    menubutton $mf.file -menu $mf.file.m -text "File" -underline 0 \
	-takefocus 0 -font [tix option get bold_font]
    menu $mf.file.m -tearoff 0
    set vsd(w:filemenu) $mf.file.m
    $mf.file.m add command -label "Append Data File..." \
	-command appendDataFile -font [tix option get bold_font]
    $mf.file.m add command -label "Info..." -underline 0 -state disabled \
	-command fileInfo -font [tix option get bold_font]
    $mf.file.m add command -label "Update" -state disabled \
	-command {fileUpdate $vsd(statsrc)} \
	-accelerator "Ctrl+u" -font [tix option get bold_font]
    $mf.file.m add command -label "Update All" \
	-command {fileUpdateAll} \
	-accelerator "Ctrl+U" -font [tix option get bold_font]
    bind $vsd(w) <Control-u> [list $mf.file.m invoke "Update"]
    bind $vsd(w) <Control-U> [list $mf.file.m invoke "Update All"]
    $mf.file.m add check -label "Auto Update" -state disabled \
	-command autoUpdate -variable vsd(autoUpdate) \
        -font [tix option get bold_font]
    $mf.file.m add check -label "Enabled" -state disabled \
	-command fileEnableMode -variable vsd(file:isEnabled) \
        -font [tix option get bold_font]
    $mf.file.m add command -label "Untrim Left" -state disabled \
	-command {fileUntrimLeft $vsd(statsrc)} \
        -font [tix option get bold_font]
    $mf.file.m add command -label "Untrim Right" -state disabled \
	-command {fileUntrimRight $vsd(statsrc)} \
        -font [tix option get bold_font]
    if [wizardMode] {
	$mf.file.m add command -label "Dump" -state disabled -command fileDump \
          -font [tix option get bold_font]
    }
    pack $mf.file -side left
    set widgetHelp($mf.file) {Main Window File Menu}

    menubutton $mf.chart -menu $mf.chart.m -text "Chart" -underline 0 \
	-takefocus 0 -font [tix option get bold_font]
    menu $mf.chart.m -tearoff 1
    set vsd(w:chartmenu) $mf.chart.m
    $mf.chart.m add command -label "Add To Chart" \
	-command {doChart 0} -accelerator "Ctrl+a" -state disabled \
        -font [tix option get bold_font]
    bind $vsd(w) <Control-a> [list $vsd(w:chartmenu) invoke "Add To Chart"]
    $mf.chart.m add command -label "New Chart..." \
	-command {doChart 1} -accelerator "Ctrl+n" -state normal \
        -font [tix option get bold_font]
    bind $vsd(w) <Control-n> [list $vsd(w:chartmenu) invoke "New Chart..."]

    $mf.chart.m add separator
    $mf.chart.m add check -label "Show Legend" \
	-variable vsd(def:showlegend) -font [tix option get bold_font]

    set mtime $mf.chart.m.time
    set widgetHelp($mtime) {Main Chart Menu Time Format SubMenu}
    menu $mtime -tearoff 0
    $mtime add radio -label "Elapsed Time in Seconds" -value "elapsed" \
	-variable vsd(def:xformat) -font [tix option get bold_font]
    $mtime add radio -label "Hour:Minute:Second" -value "time" \
	-variable vsd(def:xformat) -font [tix option get bold_font]
    $mtime add radio -label "Month/Day Hour:Minute:Second" -value "date" \
	-variable vsd(def:xformat) -font [tix option get bold_font]

    $mf.chart.m add cascade -label "Time Format" -menu $mtime -underline 0 \
        -font [tix option get bold_font]

    set mstyle $mf.chart.m.styles
    set widgetHelp($mstyle) {Main Chart Menu Default Line Style SubMenu}
    menu $mstyle -tearoff 1
    foreach style {linear step natural quadratic} {
	$mstyle add radio -label $style -variable vsd(def:linestyle) \
           -font [tix option get bold_font]
    }
    $mf.chart.m add cascade -label "Default Line Style" -menu $mstyle \
        -font [tix option get bold_font]

    $mf.chart.m add check -label "Show Time Axis Title" \
	-variable vsd(def:xaxis:showtitle) -font [tix option get bold_font]
    $mf.chart.m add check -label "Show Left Axis Title" \
	-variable vsd(def:yaxis:showtitle) -font [tix option get bold_font]
    $mf.chart.m add check -label "Show Right Axis Title" \
	-variable vsd(def:y2axis:showtitle) -font [tix option get bold_font]
    $mf.chart.m add check -label "Show Current Values" \
	-variable vsd(def:showcurxy) -font [tix option get bold_font]
    $mf.chart.m add check -label "Show Min and Max" \
	-variable vsd(def:showminmax) -font [tix option get bold_font]
    $mf.chart.m add check -label "Show Line Stats" \
	-variable vsd(def:showlinestats) -font [tix option get bold_font]
    $mf.chart.m add check -label "Show CrossHairs" \
	-variable vsd(def:showcrosshairs) -font [tix option get bold_font]
    $mf.chart.m add check -label "Show Grid Lines" \
	-variable vsd(def:showgridlines) -font [tix option get bold_font]
    if {[info commands tk_chooseColor] != ""} {
        $mf.chart.m add command -label "Selected Line Color..." \
            -command setActiveColor -font [tix option get bold_font]
    }
    $mf.chart.m add command -label "Choose Chart Font..." \
            -command setChartFont -font [tix option get bold_font]
    $mf.chart.m add separator
    $mf.chart.m add command -label "Close All Charts" -command {closeAllCharts} \
             -font [tix option get bold_font]
    pack $mf.chart -side left
    set widgetHelp($mf.chart) {Main Window Chart Menu}

    menubutton $mf.template -menu $mf.template.m -text "Template" -underline 0 \
	-takefocus 0 -font [tix option get bold_font]
    menu $mf.template.m -tearoff 1
    set vsd(w:templatemenu) $mf.template.m
    set vsd(w:templatecascade) $mf.template.m.templates

    $mf.template.m add command -label "Reload Template File" \
	-command "reloadTemplates $vsd(w:templatecascade)" -underline 0 -font [tix option get bold_font]

    set widgetHelp($vsd(w:templatecascade)) {Template Menu New Template Chart SubMenu}
    menu $vsd(w:templatecascade) -tearoff 1
    createTemplateMenu $vsd(w:templatecascade)
    $mf.template.m add cascade -label "New Template Chart" \
	-menu $vsd(w:templatecascade) -underline 0 -state disabled -font [tix option get bold_font]
    $mf.template.m add check -label "Templates Use Selection" \
	-variable vsd(templatesUseSelection) -font [tix option get bold_font]

    pack $mf.template -side left
    set widgetHelp($mf.template) {Main Window Template Menu}

    menubutton $mf.help -menu $mf.help.m -text "Help" -underline 0 \
	-takefocus 0 -font [tix option get bold_font]
    menu $mf.help.m -tearoff 0
    $mf.help.m add command -label "How to..." -underline 0 -command HowToHelp -font [tix option get bold_font]
    $mf.help.m add command -label "Main Window..." -command {showMainHelp} -font [tix option get bold_font]
    $mf.help.m add command -label "Chart Window..." -command {showChartHelp} -font [tix option get bold_font]
    $mf.help.m add command -label "All Topics..." -command {allHelp} -font [tix option get bold_font]
    $mf.help.m add command -label "All Help Text..." -command {allFlatHelp} -font [tix option get bold_font]
    $mf.help.m add separator
    $mf.help.m add command -label "Choose Text Font..." -command setTextFont -font [tix option get bold_font]
    $mf.help.m add separator
    $mf.help.m add command -label "About VSD..." -underline 0 -command {showAboutHelp} -font [tix option get bold_font]
    pack $mf.help -side right
    set widgetHelp($mf.help) {Main Window Help Menu}

    pack $mf -side top -fill x

    # We create the frame and the ScrolledHList widget
    # at the top of the dialog box
    #
    tixComboBox $w.filelist -label "File:" -anchor e \
	-editable true -command chooseDataFile -options {
	    listbox.height 6
	}
    set vsd(w:filelist) $w.filelist
    $vsd(w:filelist) appendhistory "Browse For File..."
    set dirlist {}
    set tmplist {}
    foreach f $vsd(filelist) {
        if {[file exists $f]} {
	    if {[lsearch -exact $tmplist $f] == -1} {
		lappend tmplist $f
	    }
        }
    }
    set vsd(filelist) $tmplist
    foreach f $vsd(filelist) {
	$vsd(w:filelist) appendhistory $f
	set dir [file dirname $f]
	if {[lsearch -exact $dirlist $dir] == -1} {
	    lappend dirlist $dir
	}
    }

    set xpad 3
    set ypad 3

    set widgetHelp($w.filelist) {Main Window File ComboBox}

    pack $vsd(w:filelist) -side top -fill x -padx $xpad -pady $ypad
    update ;# so that winfo height will work

    set filelistHeight [winfo height $vsd(w:filelist)]
    if {$filelistHeight == 1} {
	set filelistHeight [winfo reqheight $vsd(w:filelist)]
	if {$filelistHeight == 1} {
	    set filelistHeight 24
	}
    }
    incr filelistHeight $ypad
    incr filelistHeight $ypad
    incr filelistHeight $ypad

    if {$isWindows} {
        # info commands tk_getOpenFile
	# use tk_getOpenFile
        set vsd(w:fileselector) ""
    } else {
	tixExFileSelectDialog .fileselector -command loadBrowsedDataFile
	set vsd(w:fileselector) .fileselector
        # Fix 41952
        if {$vsd(geometry:.fileselector) != {}} {
          wm geometry .fileselector $vsd(geometry:.fileselector)
        }
	set fsbox [$vsd(w:fileselector) subwidget fsbox]
	$fsbox configure -filetypes {
	    {{*.gfs *.out *.out.gz} "All statistic data files"}
       	    {{*.gz} "All Compressed files"}
	    {{*.out} "Uncompressed StatMonitor data files"}
	    {{*.gfs} "Uncompressed GBS archive files"}
	    {{*.out.gz} "Compressed StatMonitor data files"}
	    {{*} "All files"}
	} -pattern {*.gfs *.out *.out.gz}
	if {[llength $dirlist] > 0} {
	    set fsboxdir [$fsbox subwidget dir]
	    foreach d $dirlist {
		$fsboxdir appendhistory $d
	    }
	}
    }

    tixPanedWindow $w.mainPane -orient vertical
    set p1 [$w.mainPane add instances -min 115 -size $vsd(instancePaneSize) -expand 3]
    set p2 [$w.mainPane add statistics -min 50 -size $vsd(statisticPaneSize) -expand 1]

    tixScrolledHList $p1.instanceList -options {
	hlist.columns 7
	hlist.header true
	hlist.selectMode extended
	hlist.command instanceCommand
	hlist.BrowseCmd instanceBrowse
    }
    set vsd(instanceList) [$p1.instanceList subwidget hlist]

#     if {$isWindows} {
# 	$vsd(instanceList) configure -font [tix option get font] \
# 	    -selectbackground SystemHighlight \
# 	    -selectforeground SystemHighlightText \
#     }
    
    set vsd(buthdr:s) [tixDisplayStyle window -padx 0 -pady 0]
    set i 0
    set instList {StartTime File Samples ProcessId SessionId Type Name}
    foreach n $instList {
	set buttonName "$vsd(instanceList).hdrBut$n"
        set vsd(ilColumnIdx:$n) $i
	button $buttonName -text $n -relief flat \
	    -font [tix option get bold_font] -takefocus 0 -padx 0 -pady 0 \
	    -command [list sortInstances $n] -anchor w
	$vsd(instanceList) header create $i -itemtype window \
	    -window $buttonName -style $vsd(buthdr:s)
	incr i
    }
    setHdrSortHighlight
    set sfg [$vsd(instanceList) cget -selectforeground]
    set vsd(name:s) [tixItemStyle text -refwindow $vsd(instanceList) \
			 -font [tix option get bold_font] \
			 -selectforeground $sfg]
    set vsd(time:s) [tixItemStyle text -refwindow $vsd(instanceList) \
			 -font [tix option get font] -padx 8 \
			 -selectforeground $sfg]
    set vsd(samples0:s) [tixItemStyle text -refwindow $vsd(instanceList) \
			     -font [tix option get font] \
			     -selectforeground $sfg]
# 45000 - use LimeGreen instead of Green here
    set vsd(samples1:s) [tixItemStyle text -refwindow $vsd(instanceList) \
			  -fg LimeGreen \
			  -selectforeground $sfg \
			  -font [tix option get bold_font]]

    pack $p1.instanceList -expand yes -fill both
    set widgetHelp($p1.instanceList) {Main Window Instance Table}

    bind $vsd(instanceList) <Control-s> \
	[list startSearch $vsd(instanceList) searchHList $filelistHeight]

    bind all <Button-4> \
      {event generate [focus -displayof %W] <MouseWheel> -delta  120}

    bind all <Button-5> \
      {event generate [focus -displayof %W] <MouseWheel> -delta -120}

    if 0 {
	tixPopupMenu $w.instanceMenu -title "Process Menu"
	$w.instanceMenu bind 
	$w.instanceMenu bind $vsd(instanceList).tixsw:header
	set m [$w.instanceMenu subwidget menu]
    } else {
	set m [menu $w.processmenu]
	set bindcmd [list doPopup %W $m %X %Y]
	bind $vsd(instanceList) <ButtonRelease-3> $bindcmd
	bind $vsd(instanceList).tixsw:header <ButtonRelease-3> $bindcmd
	set widgetHelp($w.processmenu) {Instance List PopupMenu}
    }
#     if 0 {
# 	$m add cascade -label "Hide" -menu $m.hb
# 	menu $m.hb
# 	$m.hb add check -label "Inactive" \
# 	    -variable vsd(def:hideInactive) -command setInstanceList
#     }
    $m add command -label "Search..." -accelerator "Ctrl+s" \
	-command [list startSearch $vsd(instanceList) searchHList $filelistHeight] 

#     $m add cascade -label "Sort By" -menu $m.sb
#     menu $m.sb -tearoff 1
#     foreach {n v} [concat $instList {Activity activity}] {
# 	$m.sb add radio -label $n -value $v \
# 	    -variable vsd(def:sortbytype) -command setInstanceList
#     }

    $m add cascade -label "Select" -menu $m.select
    menu $m.select -tearoff 1
    $m.select add command -label "Clear" \
	-command {$vsd(instanceList) selection clear; updateGraphWidgetState}
    $m.select add command -label "by Statistic" \
	-command {selectByStatistic}
    $m.select add command -label "by Type" \
	-command {selectByType}
    $m.select add command -label "All" \
	-command {selectAllInstances}
    $m add check -label "Combine" \
	-variable vsd(combineInstances)
    $m add check -label "Combine Across Files" \
	-variable vsd(combineFiles)
    $m add check -label "No Flatlines" \
	-variable vsd(noFlatlines) -command changeNoFlatlines
    $m add check -label "Single File Mode" \
	-variable vsd(singleFileMode) -command singleFileMode
    $m add check -label "Absolute TimeStamps" \
	-variable vsd(absoluteTSMode)

    set vsd(selectedCtr) ""

    tixScrolledHList $p2.counterHList -options {
	hlist.columns 1
	hlist.header false
	hlist.selectMode extended
	hlist.command ctrHlistCommand
	hlist.BrowseCmd ctrHlistBrowse
	hlist.exportSelection 0
	hlist.takeFocus 1
    }
    set vsd(w:counterHList) [$p2.counterHList subwidget hlist]
    bind $vsd(w:counterHList) <KeyPress> \
	[list HListPrefixSearch $vsd(w:counterHList) %A]
    bind $vsd(w:counterHList) <Control-s> \
	[list startSearch $vsd(w:counterHList) searchCtrHList]
    event add <<ClearSearch>> <Up> <Down> <Shift-Up> <Shift-Down> <Left> <Right> \
	<Prior> <Next> <Return> <space> <Double-1> <1> <Shift-1> <Control-1> \
	<FocusOut>
    bind $vsd(w:counterHList) <<ClearSearch>> "+[list HListPrefixClear $vsd(w:counterHList)]"
    set sfg [$vsd(w:counterHList) cget -selectforeground]
    # the font for normal stats
    set vsd(ctr0:s) [tixItemStyle text -refwindow $vsd(w:counterHList) \
			 -font [tix option get bold_font] \
			 -selectforeground $sfg]
    # the font for zero stats
    set vsd(ctr1:s) [tixItemStyle text -refwindow $vsd(w:counterHList) \
			 -font [tix option get font] \
			 -selectforeground $sfg]
#			     -font [tix option get italic_font]

    pack $p2.counterHList -fill both -expand yes
    set widgetHelp($p2.counterHList) {Main Window Statistic List}

    set vsd(curchart) {}
    tixComboBox $w.chartlist -label "Chart:" -dropdown true \
	-command chooseChart -history true -prunehistory true \
        -editable false -variable vsd(curchart) -options {
          listbox.height 4
	}

    set vsd(w:chartlist) $w.chartlist
    set widgetHelp($w.chartlist) {Main Window Chart ComboBox}

    tixButtonBox $w.box -padx $xpad -pady $ypad
    $w.box add additem -text "Add Line" -command {doChart 0} -state disabled
    set vsd(w:addline) [$w.box subwidget additem]
    $w.box add newchart -text "New Chart" -command {doChart 1} -state normal
    set vsd(w:newchart) [$w.box subwidget newchart]
    set widgetHelp($vsd(w:addline)) {Main Window Add Line Button}
    set widgetHelp($vsd(w:newchart)) {Main Window New Chart Button}

    set sf [frame $w.statusFrame -relief raised -bd 1]
    set vsd(status) ""
    label $sf.status -relief sunken -bd 1 -textvariable vsd(status) -padx 2
    pack $sf.status -fill x
    pack $sf -fill x -side bottom -padx $xpad -pady $ypad

    pack $w.box -fill x -side bottom -padx $xpad -pady $ypad

    pack $w.chartlist -side bottom -padx $xpad -pady $ypad -fill x

    pack $w.mainPane -side top -expand yes -fill both -padx $xpad -pady $ypad

    set widgetHelp($w.box) {Main Window Status Display}

    set vsd(balloon) [tixBalloon .vsd_balloon -statusbar $sf.status -state status]
    $vsd(balloon) bind $vsd(w:filelist) -msg "Show/Select/Load current statmonitor file"
    foreach n $instList {
	$vsd(balloon) bind "$vsd(instanceList).hdrBut$n" -msg "Click to sort by \"$n\""
    }
    $vsd(balloon) bind $vsd(w:chartlist) -msg "Show/Select/Name current chart"
    $vsd(balloon) bind $vsd(w:addline) -msg "Add selected stats to current chart"
    $vsd(balloon) bind $vsd(w:newchart) -msg "Creates a new chart window and add selected stats to it"

    wm protocol $w WM_DELETE_WINDOW ExitVSD

    patchTix

    createSearch
    createTemplateName
    createHelpSearch
    createAboutHelp
    #UsageVSD $w
    doCtrInfo

    traceAPICalls
    set color -1
    set appendIt 0
    set autoUpdate 0
    global argv argc
    set i 0
    while { $i < $argc } {
        set f [lindex $argv $i]
	switch -exact -- $f {
	    "-a" {set appendIt 1}
            "-b" {incr i ; set color [lindex $argv $i]}
            "-u" {set autoUpdate 1}
	    default {
		if {$appendIt} {
		    if {$vsd(statsrc) != {}} {
			set vsd(appendMode) 1
		    } else {
			set vsd(appendMode) 0
		    }
		}
		setDataFile $f
	    }
	}
        incr i
    }
    set vsd(appendMode) 0

# 45211 - Setup autoupdate last, after a stats file has hopefully been specified on the command line.
#         Otherwise the autoUpdate proc does nothing.
    set vsd(autoUpdate) $autoUpdate
    if { $autoUpdate == 1 } {
      autoUpdate
    }

    if { $color != -1 } {
      setMasterBackgroundColor $color
    } else {
      if [info exists env(VSD_MASTER_BG_COLOR)] {
        set color $env(VSD_MASTER_BG_COLOR)
        setMasterBackgroundColor $color
      } 
    }
}

proc loadStatisticDefinitions {} {
    global statDefinitions vsd
    foreach s [array names statDefinitions] {
	set statAttributes $statDefinitions($s)
	set type [lindex $statAttributes 0]
	set level [lindex $statAttributes 1]
	set filter {}
	if [info exists vsd(filter:$s)] {
	    set filter $vsd(filter:$s)
	}
	if [info exists vsd(level:$s)] {
	    if {[string equal $level $vsd(level:$s)]} {
		unset vsd(level:$s)
	    } else {
		set level $vsd(level:$s)
	    }
	}
	sl_stat -info $s [list $type $level]
    }
    # convert old vsd(ctr:*) definitions
    foreach ctr [array names vsd ctr:*] {
	set statname [string range $ctr 4 end]
	set ctrlist $vsd($ctr)
	set level [lindex $ctrlist 1]
	set filter [lindex $ctrlist 3]
	if {$level != {}} {
	    setStatLevel $statname $level
	}
	if {$filter != {}} {
	    setStatFilter $statname $filter
	}
	unset vsd($ctr)
    }
    processUserStatDefs
    # 45220 - generateAllStatHelp deleted
}

proc processUserStatDefs {} {
    global statdef statDefinitions statDocs
    foreach name [array names statdef] {
	set attributes $statdef($name)
	if {[llength $attributes] != 6} {
	    fatalError "The statistic definition for $name does not have six attributes. Check ~/.vsdconfig for a line that sets statdef($name) and correct it. To learn more about statistic definitions see the vsd help section entitled \"Statistic Definitions\"."
	}
	set kind [lindex $attributes 0]
	set level [lindex $attributes 1]
	set units [lindex $attributes 2]
	set isOSStat [lindex $attributes 3]
	set filter [lindex $attributes 4]
	set docs [lindex $attributes 5]
	if {$kind != {}} {
	    if [catch {sl_stat -info $name [list $kind]} err] {
		fatalError "The statistic definition for $name does not have a valid value for the kind attribute. The illegal value found is: \"$kind\". The problem is: \"$err\". Check ~/.vsdconfig for a line that sets statdef($name) and correct it. To learn more about statistic definitions see the vsd help section entitled \"Statistic Definitions\"."
	    }
	} else {
	    set kind "uvalue"
	}
	if {$level != {}} {
	    if [catch {sl_stat -info $name [list {} $level]} err] {
		fatalError "The statistic definition for $name does not have a valid value for the level attribute. The illegal value found is: \"$level\". The problem is: \"$err\". Check ~/.vsdconfig for a line that sets statdef($name) and correct it. To learn more about statistic definitions see the vsd help section entitled \"Statistic Definitions\"."
	    }
	} else {
	    set level "common"
	}
	if {$filter != {}} {
	    if [catch {sl_stat -info $name [list {} {} $filter]} err] {
		fatalError "The statistic definition for $name does not have a valid value for the filter attribute. The illegal value found is: \"$filter\". The problem is: \"$err\". Check ~/.vsdconfig for a line that sets statdef($name) and correct it. To learn more about statistic definitions see the vsd help section entitled \"Statistic Definitions\"."
	    }
	} else {
	    set filter "default"
	}
	if {$isOSStat != {}} {
	    if {![string is boolean $isOSStat]} {
		fatalError "The statistic definition for $name does not have a valid boolean value for the isOSStat attribute. The illegal value found is: \"$isOSStat\". Check ~/.vsdconfig for a line that sets statdef($name) and correct it. To learn more about statistic definitions see the vsd help section entitled \"Statistic Definitions\"."
	    }
	} else {
	    set isOSStat false
	}
	if {$units == {}} {
	    set units "none"
	}
	sl_stat -info $name {} ;# make sure it gets pushed to lower level
	set statDefinitions($name) [list $kind $level $units $isOSStat]
	if {$docs != {}} {
	    set statDocs($name) $docs
	}
    }
}

proc debugvar {varname} {
    upvar $varname var
    puts "$varname is: '$var'"
    return
}

# The stathelp array contains extra information about statistics that
# needs to be added to the standard information from 'sl_stat -info'.
array set stathelp {
{FreeFrameCount} {
In the [shrpc > Shrpc Type], the FreeFrameCount displays the current number of free frames available in the [Shared Page Cache]. The cache is considered full as this count approaches zero.

See also: [FramesAddedToFreeList > FramesAddedToFreeList Statistic],\
[PagesPreempted > PagesPreempted Statistic],\
[PagesRemovedForStone > PagesRemovedForStone Statistic],\
and [Shared Page Cache Health].
}

{IVolCSW} {
A large number of [involuntary context switches > Context Switch] indicates contention for the cpu. 
}
{VolCSW} {
A large number of [voluntary context switches > Context Switch] indicates an increase in non-cpu resources.
}
{LocalPageCacheMisses} {
NOTE: prior to 4.6, the LocalPageCacheMisses statistic was grossly overstated. You can sum the extent stat [ExtentReadKBytes > ExtentReadKBytes Statistic] to approximate LocalPageCacheMisses.
}

{PrivatePageCacheSize} {
The private page cache is used by a session to cache freshly written temporary pages. If a session is writing a large number of objects, the number of temporary pages needed may exceed the default size of the private page cache. If the private page cache is large enough, you will see the stat [FramesAddedToFreeList > FramesAddedToFreeList Statistic] flat-lined at zero. 

!How big should I make the private page cache?
You can tell you need a larger private page cache if:
   * The session is doing [FramesAddedToFreeList > FramesAddedToFreeList Statistic]. Optimally a session's [FramesAddedToFreeList > FramesAddedToFreeList Statistic] will be flat-lined at zero.

<b>Problem:</b> you can't set the private page cache size on activated VM's that use session pools!
}

{FramesAddedToFreeList} {
In the [shrpc > Shrpc Type], the FramesAddedToFreeList stat is a summary of all such activity in the system.

There are two active sources of FramesAddedToFreeList in the system; either a [session > Session Type] or the [AIO page servers]. 

The page server named <b>pageService</b> is implemented with a thread in the [SAP] vm. This particular thread is removing pages from the shared page cache that are ready to be re-used by the stone. These [removed pages > PagesRemovedForStone Statistic] are the residue of commit record disposal and reclaim activity. The <b>pageService</b> thread also performs [page preemption > PagesPreempted Statistic], which adds frames to the free list.

Optimally, a [session > Session Type] will have no FramesAddedToFreeList activity. Excessive activity of this stat for a [session > Session Type] indicates that the [private page cache > PrivatePageCacheSize Statistic] for the [session > Session Type] is too small. Thousands of FramesAddedToFreeList per second for a session is a significant performance degradation. You will also notice that [FramesFromFindFree > FramesFromFindFree Statistic] will dramatically increase when a [session > Session Type] has non-zero FramesAddedToFreeList.

See also: [FreeFrameCount > FreeFrameCount Statistic]
}
}

proc initStatHelp {name} {
    global vsdhelp
    set topic "$name Statistic"
    set vsdhelp($topic) [list TCLEVAL generateStatHelp $name]
}

proc generateStatHelp {name} {
    global stathelp vsdhelp
    set type [getStatType $name]
    set level [getStatLevel $name]
    set units [getStatUnits $name]
    set filter [getStatFilter $name]
    set description [getStatDescription $name]
    set isOS [isOSStat $name]
    set objects [getStatObjList $name]

    set help ""
    append help $description
    append help "\n\n"
    append help "   * <b>Kind:</b>      $type\n"
    append help "   * <b>Units:</b>     $units\n"
    append help "   * <b>Level:</b>     $level\n"
    if {![string equal $filter "default"]} {
	append help "   * <b>Filter:</b>    $filter\n"
    }
    append help "   * <b>Source:</b> "
    if {$isOS} {
	append help "operating system\n"
    } else {
	append help "product\n"
    }
    if {$objects != {}} {
	append help "   * <b>Types:</b>   "
	foreach obj $objects {
	    set typeName [file rootname $obj]
	    set typeVersion [file extension $obj]
	    if {$typeVersion == {}} {
		set typeVersion ".1"
	    }
	    set versionNumber [string trimleft $typeVersion "."]
	    set topicName "$typeName Type Version $versionNumber"
	    if [info exists vsdhelp($topicName)] {
		append help { [} $obj " > $topicName]"
	    } else {
		append help " " $obj 
	    }
	}
	append help "\n"
    }
    if [info exists stathelp($name)] {
	append help "----\n"
	append help $stathelp($name)
    }
    return $help
}

proc loadStatisticAliases {} {
    sl_stat -alias "numberattached" "AttachedCount"
    sl_stat -alias "numberoffreeframes" "FreeFrameCount"
    sl_stat -alias "numberofcommitrecords" "CommitRecordCount"
    sl_stat -alias "asynchwritesinprogress" "AsyncWritesInProgress"
    sl_stat -alias "aynschwritesiocount" "AsyncWritesCount"
    sl_stat -alias "messagestostn" "MessagesToStone"
    sl_stat -alias "numincommitqueue" "CommitQueueSize"
    sl_stat -alias "numinlockreqqueue" "LockReqQueueSize"
    sl_stat -alias "numinnotifyqueue" "NotifyQueueSize"
    sl_stat -alias "numinloginwaitqueue" "LoginQueueSize"
    sl_stat -alias "numinrunqueue" "RunQueueSize"
    sl_stat -alias "numinsymbolcreatequeue" "SymbolCreationQueueSize"
    sl_stat -alias "numberofscavenges" "ScavengeCount"
    sl_stat -alias "numberofdeadobjs" "DeadObjCount"
    sl_stat -alias "numberofmakeroominoldspace" "MakeRoomInOldSpaceCount"
    sl_stat -alias "numberofgcnotconnected" "GcNotConnectedCount"
    sl_stat -alias "numberofgcnotconnecteddead" "GcNotConnectedDeadCount"
    sl_stat -alias "norollbacksize" "NoRollbackSetSize"
    sl_stat -alias "notconnectedobjssize" "NotConnectedObjsSetSize"
    sl_stat -alias "numberofsigabort" "SigAbortCount"
    sl_stat -alias "numberofsiglostot" "SigLostOtCount"
    sl_stat -alias "numberofreads" "ReadCount"
    sl_stat -alias "numberofwrites" "WriteCount"
    sl_stat -alias "numberofseeks" "SeekCount"
    sl_stat -alias "numberoftransfers" "TransferCount"
    sl_stat -alias "numswaps" "SwapCount"
    sl_stat -alias "epochgccount" "EpochGcCount"
    sl_stat -alias "localdirtypagecount" "LocalDirtyPageCount"
    sl_stat -alias "globaldirtypagecount" "GlobalDirtyPageCount"
    sl_stat -alias "pagereads" "PageReads"
    sl_stat -alias "pagewrites" "PageWrites"
    sl_stat -alias "deadobjscount" "DeadObjsCount"
    sl_stat -alias "reclaimcount" "ReclaimCount"
    sl_stat -alias "reclaimedpagescount" "ReclaimedPagesCount"
    sl_stat -alias "checkpointcount" "CheckpointCount"
    sl_stat -alias "pagesneedreclaimsize" "PagesNeedReclaimSize"
    sl_stat -alias "possdeadsize" "PossibleDeadSize"
    sl_stat -alias "deadnotreclaimedsize" "DeadNotReclaimedSize"
    sl_stat -alias "pgsvraiodirtycount" "AioDirtyCount"
    sl_stat -alias "pgsvraiockptcount" "AioCkptCount"
    sl_stat -alias "numberofcommits" "CommitCount"
    sl_stat -alias "numberoffailedcommits" "FailedCommitCount"
    sl_stat -alias "numberofaborts" "AbortCount"
    # The following old names only existed for a 5.0 alpha
    sl_stat -alias "vccachenumscavenges" "VcCacheScavengesCount"
    sl_stat -alias "vccachesizebytes" "VcCacheSizeBytes"
    sl_stat -alias "codecachesizebytes" "CodeCacheSizeBytes"
    sl_stat -alias "codecachenumentries" "CodeCacheEntries"
    sl_stat -alias "codecachenumstaleentries" "CodeCacheStaleEntries"
    sl_stat -alias "codecachenumscavenges" "CodeCacheScavengesCount"
    sl_stat -alias "datepageswrittenbygem" "DataPagesWrittenByGem"
    sl_stat -alias "datepageswrittenbystone" "DataPagesWrittenByStone"
    set i 0
    while {$i < 10} {
	sl_stat -alias "sessionstat0$i" "SessionStat0$i"
	incr i
    }

    set i 0
    while {$i < 48} {
	sl_stat -alias "sessionstat$i" "SessionStat$i"
	incr i
    }
    # Names changed in gsj fiji (4.0)
    sl_stat -alias "sweepcount" "RGCSweepCount"
    sl_stat -alias "possibledeadwsunionsize" "RGCPossibleDeadWsUnionSize"
    sl_stat -alias "pagesneedreclaiming" "RGCPagesNeedReclaiming"
    sl_stat -alias "reclaimnewdatapagescount" "RGCReclaimNewDataPagesCount"
    # Names changed in gsj guatamala (4.6)
    sl_stat -alias "jdbcconnectionsreturned" "JDBCConnectionsAcquired"
    sl_stat -alias "webrequestcount" "WebRequestsReceived"
}
	
proc generateTypeHelp {name} {
    global vsdhelp

    set typeName [file rootname $name]
    set typeVersion [file extension $name]
    if {$typeVersion == {}} {
	set typeVersion ".1"
    }
    set versionNumber [string trimleft $typeVersion "."]
    set topicName "$typeName Type Version $versionNumber"
    if [info exists vsdhelp($topicName)] {
	# Already Done
	return
    }
    set help ""
    set strippedType "$typeName Type"
    if [info exists vsdhelp($strippedType)] {
	append help  "This is version $versionNumber of the \[$typeName > $strippedType\] instance type.\n\n"
	append vsdhelp($strippedType) "   * \[$topicName\]\n"
    }


    # add statistic links; make sure all level documented
    set saveLevel [sl_stat -level]
    sl_stat -level "wizard"
    append help "\n!Statistics\n"
    foreach s [lsort -dictionary [sl_stat -objctrs $name]] {
	if {![isOSStat $s]} {
	    append help "   * \[$s > $s Statistic\]\n"
	}
    }
    append help "\n!Operating System Statistics\n"
    foreach s [lsort -dictionary [sl_stat -objctrs $name]] {
	if {[isOSStat $s]} {
	    append help "   * \[$s > $s Statistic\]\n"
	}
    }
    sl_stat -level $saveLevel

    set vsdhelp($topicName) $help
}

# 45220 - generateAllStatHelp deleted

proc createAboutHelp {} {
    global vsd tk_version env tix_version isWindows vsdhelp
    set topic {About VSD}
    if [info exists vsdhelp($topic)] {
	return
    }

# Get the executable architecture (32 or 64 bit)
if [catch {sl_arch} resultArch] {
   set msg "Could not get architecture from sl_arch because: "
   append msg $resultArch
   showError $msg
   return
}

    set vsdhelp($topic) \
"<b>VSD:</b>      Visual Statistics Display
<b>Versions:</b>  vsd=$vsd(version), statistics=$vsd(stats_version)
<b>Build ID:</b>  $vsd(svn_revision)
<b>Build URL:</b> $vsd(svn_url)
<b>Build Date:</b> $vsd(build_date)
<b>Architecture:</b> $resultArch bit
<b>Creator:</b>    Darrel Schneider
<b>Maintainer:</b>  Norm Green
<b>Support:</b>  send mail to $vsd(maintainer)
<b>Home Page:</b> http://www.gemtalksystems.com/vsd
<b>Purpose:</b>   To display GemStone statistics. The statistics must come from a \[statmonitor] output file or from GBS.
<b>Credits:</b>  Tcl[info tclversion],  Tk$tk_version,  Tix$tix_version.
<b>Platforms:</b>    Oracle Solaris SPARC, Oracle Solaris x86_64, IBM AIX, Linux, Apple Macintosh and Microsoft Windows.
\[<b>Files:</b> > VSD Files]
   * <tt>$env(HOME)/.vsdrc</tt>
   * <tt>$env(HOME)/.vsdconfig</tt>
   * <tt>$env(HOME)/.vsdtemplates</tt>
   * <tt>[getScriptName]</tt> contains VSD's \[Tcl > Tcl Language] source code implementation.
   * <tt>[info nameofexecutable]</tt> contains VSD's binary virtual machine.

See http://gemtalksystems.com/products/vsd/history/ to learn about what's new in this version.
"
}

# Get the location of the vsdtree/bin/vsd TCL script.
# vsd.stats.tcl will always be in the same location.
#
# expand the filename of this script
set STATSFILE [file normalize $::argv0]
# get the directory name
set STATSFILE [file dirname $STATSFILE]
set STATSFILE [file join $STATSFILE "vsd.stats.tcl"]

# Uncomment to debug
# puts stderr "filename is $STATSFILE"
# Pull in the stat definitions
source "$STATSFILE"


set i 1
while {$i <= 47} {
    set statDocs(SessionStat$i) $statDocs(SessionStat0)
    set statDocs(GlobalStat$i) $statDocs(GlobalStat0)
    incr i
}

set i 0
while {$i < 10} {
    set statDocs(SessionStat0$i) $statDocs(SessionStat0)
    set statDocs(GlobalStat0$i) $statDocs(GlobalStat0)
    incr i
}

set i 0
while {$i <= 10} {
    set statDocs(sharedCounter$i) $statDocs(sharedCounter)
    incr i
}

# foreach i [array names statDefinitions] {
#     if {[llength $statDefinitions($i)] != 4} {
# 	puts "DEBUG: bad stat def for $i: $statDefinitions($i)"
#     }
# }
array set vsdhelp {
{Context Switch} {
An operating system context switch occurs when a thread is moved from executing to non-executing status. If a thread needs a non-cpu resource (disk, lock, semaphore, and timer are examples) then its called an [voluntary context switch > VolCSW Statistic]. If a thread still wants to execute but the operating system scheduler decides to preempt it so some other thread can execute then its called a [involuntary context switch > IVolCSW Statistic].
}
{Chart Window Features} {
Multiple chart windows can exist.

!Chart Information
   * [General Interface Features]
   * [Creating Chart Windows > How to Create a New Chart]

!Chart Menus
   * [Chart > Chart Window Chart Menu]
   * [Line > Chart Window Line Menu]

!Chart Controls
   * optional [X: > Chart Window X: Display]
   * optional [Y: > Chart Window Y: Display]
   * optional [Min: > Chart Window Min: Display]
   * optional [Max: > Chart Window Max: Display]
   * [Statistic Selector > Chart Window Statistic ComboBox]
   * [Filter Selector > Chart Window Filter MenuButton]
   * [Operator Selector > Chart Window Operator MenuButton]
   * [Number Entry > Chart Window Number Entry]
   * [Graph > Chart Window Graph]
}

{Chart Window X: Display} {
This display shows the time coordinate of the data point currently under the mouse pointer. The format of the displayed information it determined by [Chart Menu <b>Time Format</b> SubMenu].
This display will only exist if [Chart Menu <b>Show Current Values</b> Item] is on. 
This display is on each [chart window > Chart Window Features].
}
{Chart Window Y: Display} {
This display shows the value coordinate of the data point currently under the mouse pointer.
This display will only exist if [Chart Menu <b>Show Current Values</b> Item] is on. 
This display is on each [chart window > Chart Window Features].
}
{Chart Window Min: Display} {
This display shows the minimum value of the currently selected line's data points. Only data points displayed on the graph are considered (see [trimming > File Trimming] and [zooming > How to Zoom] to learn how to control what data points are displayed).
This display will only exist if [Chart Menu <b>Show Min and Max</b> Item] is on.
This display is on each [chart window > Chart Window Features].
}
{Chart Window Max: Display} {
This display shows the maximum value of the currently selected line's data points. Only data points displayed on the graph are considered (see [trimming > File Trimming] and [zooming > How to Zoom] to learn how to control what data points are displayed).
This display will only exist if [Chart Menu <b>Show Min and Max</b> Item] is on.
This display is on each [chart window > Chart Window Features].
}
{Chart Window Statistic ComboBox} {
This control allows you to change the statistic of the currently selected line. It also display the statistic of the currently selected line. Changing the selection will also update the [Statistic Information Window].

!Bindings
   * Clicking on a name with the <em>mouse</em> both selects it and causes it to become the current line's statistic.
   * The <em>down</em> arrow key selects the next statistic.
   * The <em>up</em> arrow key selects the previous statistic.
   * The <em>letter keys</em> select the next statistic whose first letter matches the key.
   * <tt>control-s</tt> starts a [search > List Search Control] which results in selecting a statistic.
   * <em>Return</em> causes the selected statistic to become the current line's statistic.
   * <em>Esc</em> cancels the change leaving the current line's statistic unchanged.
This combobox is on each [chart window > Chart Window Features].
}
{Chart Window Filter MenuButton} {
Displays the current line's filter and allows the filter to be changed. Possible filters are:
   * No Filter (None)
   * PerSecond
   * PerSample
   * Smooth
   * Aggregate
See [How to Filter Statistics] for a description of what each filter does.
This menu button is on each [chart window > Chart Window Features].
}
{Chart Window Operator MenuButton} {
Displays and sets the tranforming operation that will be applied to the current line using the value in the [number entry > Chart Window Number Entry]. The supported operations are:
   * <b>S</b>: [scale > Display Scaling a Line]; uses the line's <em>display scale</em> constant
   * <b>/</b>: [divide > Value Scaling a Line]; uses the line's <em>value scale</em> constant
   * <b>*</b>: [multiply > Value Scaling a Line]; uses the line's <em>value scale</em> constant
   * <b>+</b>: [add > Offsetting a Line]; uses the line's <em>offset</em> constant
   * <b>-</b>: [subtract > Offsetting a Line]; uses the line's <em>offset</em> constant
This menu button is on each [chart window > Chart Window Features].
}
{Chart Window Number Entry} {
This entry displays and sets numeric constants associated with the current line. Which constant is displayed is controlled by which operator is selected by the [operator menu button > Chart Window Operator MenuButton]. Each line has three constants:
   * a <em>display scale</em> used by the <b>S</b> operator.
   * a <em>value scale</em> used by the <b>/</b> and <b>*</b> operators.
   * an <em>offset</em> used by the <b>+</b> and <b>-</b> operators.
For the scale constants the up spinner button doubles the constant and the down spinner button halves the constant.
For the offset constant the up spinner button adds one to the constant and the down spinner subtracts one from the constant.
Scale constants can not be set to zero.
This entry is on each [chart window > Chart Window Features].
}

{Chart Window Graph} {
!Graph Controls
   * [Graph Display]
   * [X Axis]
   * [Left Y Axis]
   * [Right Y Axis]
   * optional [Graph Legend]
A graph is on each [chart window > Chart Window Features].
}

{Graph Display} {
Contains a graphical display of each line on the chart. An effort is made to give each line a unique color or style. The selected line's color is determined by the [Main Chart Menu <b>Selected Line Color...</b> Item].

Information about the current line is shown in the upper left corner of the graph. This information can be [disabled > Chart Menu Show Line Stats Item]. Two small red triangles at the bottom of the graph display indicate the range of data points used to calculate the line statistics. During [auto updating > File Menu Auto Update Item] this range will not automatically expand. To get it to expand <em>right click</em> in the graph display.

If [cross hairs > Chart Menu Show CrossHairs Item] are enabled then a single vertical and horizontal black line will be drawn and they will always intersect where the mouse points in the graph. If the mouse leaves the graph the cross hairs disappear.

If [grid lines > Chart Menu Show Grid Lines Item] are enabled then faint dashed lines are drawn from every axis tick.

!Bindings
   * <em>Left clicking</em> on a line will select it.
   * <em>Middle clicking</em> will do a [time zoom > How to Zoom].
   * <em>Right clicking</em> [zooms out > How to Zoom] one level.
   * <em>Moving</em> the mouse over a data point temporarily selects the line and [displays > Chart Menu Show Current Values Item] the data point's coordinates.
   * The <em>left</em> arrow key move a [zoom level > How to Zoom] one sample to the left.
   * The <em>right</em> arrow key move a [zoom level > How to Zoom] one sample to the right.
   * The <em>control-left</em> arrow key move a [zoom level > How to Zoom] to the left by however many time samples are in the graph.
   * The <em>control-right</em> arrow key move a [zoom level > How to Zoom] to the right by however many time samples are in the graph.
 
This display is on each [graph > Chart Window Graph].
}
{X Axis} {
The ticks on this axis are labeled with the time in a format determined by [Chart Menu <b>Time Format</b> SubMenu]. The labels reflect the data plotted in the graph of this axis. Each line's time coordinates are plotted on this axis.
This axis's title, if not [disabled > Chart Menu Show Time Axis Title Item], will show a description of the file the current line's data came from.
This axis is on each [graph > Chart Window Graph].
}
{Left Y Axis} {
The ticks on this axis are labeled with numbers that reflect the data plotted in the graph on this axis. Each line's values are plotted on either this axis or the other Y axis. An axis only exists if at least one line is plotted on it.
This axis's title, if not [disabled > Chart Menu Show Left Axis Title Item], will show a description of the current line's units if it was [plotted > Line Menu Graph on Left Axis Item] on the left axis.
This axis is on each [graph > Chart Window Graph].
}
{Right Y Axis} {
The ticks on this axis are labeled with numbers that reflect the data plotted in the graph on this axis. Each line's values are plotted on either this axis or the other Y axis. An axis only exists if at least one line is plotted on it.
This axis's title, if not [disabled > Chart Menu Show Right Axis Title Item], will show a description of the current line's units if it was [plotted > Line Menu Graph on Left Axis Item] on the right axis.
This axis is on each [graph > Chart Window Graph].
}
{Graph Legend} {
A graph's legend has an entry for every line on a graph. For each line the legend shows:
   * the line's unselected color
   * a description of the instance and statistic the line represents
   * the line's [symbol > Line Menu Symbol SubMenu]
A graph's legend can be [hidden > Chart Menu Show Legend Item] to save space. If it is hidden then a description of the current's line instance will be written in the upper left corner of the [graph > Graph Display]. Legends are very helpful so are usually not disabled. The best reason for disabling a legend is if your graph contains a large number of lines.

!Bindings
   * <em>Left clicking</em> on a legend entry toggles selection of that line.
   * <em>Middle clicking</em> on a legend entry deletes the line.

A legend is on each [graph > Chart Window Graph].
}
{Chart Window Chart Menu} {
Operations on this menu apply to the entire chart.
Configuration done with this menu will only effect its chart.\
For global configuration changes use the [main chart menu > Main Window Chart Menu].

[Selection Key > Keyboard Selection Keys]: <tt>Alt-c</tt>

This menu can be [torn off > Tear Off Menus].

This menu is on each [chart window > Chart Window Features].

!Items
   * [Add From Template > Chart Menu Add From Template SubMenu]
   * [Save Template > Chart Menu Save Template Item]
   * [Paste > Chart Menu Paste Item]
   * [Print > Chart Menu Print Item]
   * [Snapshot > Chart Menu Snapshot Item]
   * [Help... > Chart Menu Help... Item]
   * [Zoom In > Chart Menu Zoom In Item]
   * [Zoom Out > Chart Menu Zoom Out Item]
   * [Compare Two Points > Chart Menu Compare Two Points Item]
   * [Compute Scale All > Chart Menu Compute Scale All Item]
   * [Unscale All > Chart Menu Unscale All Item]
   * [Show Legend > Chart Menu Show Legend Item]
   * [Time Format > Chart Menu Time Format SubMenu]
   * [Show Time Axis Title > Chart Menu Show Time Axis Title Item]
   * [Show Left Axis Title > Chart Menu Show Left Axis Title Item]
   * [Show Right Axis Title > Chart Menu Show Right Axis Title Item]
   * [Show Current Values > Chart Menu Show Current Values Item]
   * [Show Min and Max > Chart Menu Show Min and Max Item]
   * [Show Line Stats > Chart Menu Show Line Stats Item]
   * [Show CrossHairs > Chart Menu Show CrossHairs Item]
   * [Show Grid Lines > Chart Menu Show Grid Lines Item]
   * [Close > Chart Menu Close Item]
}

{vsdsh} {
vsdsh is the text version if vsd. It allows scripts to be written that will load and process statmonitor data.
When vsdsh is started it will first attempt to load and interpret [Tcl code > Tcl Language] from the file <tt>~/.vsdshrc</tt>.
Then if it was given a file on the command line it will load and interpret it as [Tcl code > Tcl Language] and exit. Otherwise it display a prompt at which [Tcl code > Tcl Language] can be interactively entered. To exit back to the environment that started vsdsh type <tt>exit</tt>.
}
{Tcl Language} {
Tcl stands for tool command language. Tcl is pronounced <em>tickle</em>.\
Learn more about it at <tt><u>www.scriptics.com</u></tt>. For a quick overview\
of the language see:
   * <tt><u>http://www.scriptics.com/scripting/primer.html</u></tt>
   * <tt><u>http://www.scriptics.com/scripting/syntax.html</u></tt>
In the context of VSD and [vsdsh] the following extension to standard Tcl are available. These extensions tend to be valuable when writing scripting code that VSD or [vsdsh] will load:
   * [BLT Vectors]
   * [sltcl]
In the context of VSD the following additional extensions to standard Tcl are available. These extensions are used for GUI features are probably not of interest to those writing scripting code:
   * Tk
   * Tix
   * BLT
}
{BLT Vectors} {
!Synopsis
   * <tt>vector create</tt> <em>vecName</em> <em>?switches?</em>
   * <tt>vector destroy</tt> <em>vecName</em>
   * <tt>vector expr</tt> <em>expression</em>
   * <tt>vector names</tt> <em>?pattern...?</em>

!Description
The <tt>vector</tt> command creates a vector of floating poing values. The vector's values can be manipulated through a Tcl array variable or with Tcl commands.

!Introduction
A vector is simply an ordered set of numbers. The components of a vector are real numbers, indexed by counting numbers. 
Vectors are common data structures for many applications. For example, a graph may use two vectors to represent the X-Y coordinates of the data plotted. The graph will automatically be redrawn when the vectors are updated or changed. By using vectors, you can separate data analysis from the graph widget. This makes it easier, for example, to add data transformations, such as splines. It's possible to plot the same data to in multiple graphs, where each graph presents a different view or scale of the data. 
You could try to use Tcl's associative arrays as vectors. Tcl arrays are easy to use. You can access individual elements randomly by specifying the index, or the set the entire array by providing a list of index and value pairs for each element. The disadvantages of associative arrays as vectors lie in the fact they are implemented as hash tables. 
   * There's no implied ordering to the associative arrays. If you used vectors for plotting, you would want to insure the second component comes after the first, an so on. This isn't possible since arrays are actually hash tables. For example, you can't get a range of values between two indices. Nor can you sort an array. 
   * Arrays consume lots of memory when the number of elements becomes large (tens of thousands). This is because each element's index and value are stored as strings in the hash table The C programming interface is unwieldy. Normally with vectors, you would like to view the Tcl array as you do a C array, as an array of floats or doubles. But with hash tables, you must convert both the index and value to and from decimal strings, just to access an element in the array. This makes it cumbersome to perform operations on the array as a whole. 

The <tt>vector</tt> command tries to overcome these disadvantages while still retaining the ease of use of Tcl arrays. The <tt>vector</tt> command creates both a new Tcl command and associate array which are linked to the vector components. You can randomly access vector components though the elements of array. Not have all indices are generated for the array, so printing the array (using the <tt>parray</tt> procedure) does not print out all the component values. You can use the Tcl command to access the array as a whole. You can copy, append, or sort vector using its command. If you need greater performance, or customized behavior, you can write your own C code to manage vectors. 

!Examples
   * When you create a new vector you give it a name. Both a Tcl command and an array variable with that name are created. You can use either the command or variable to query or modify components of the vector. The number of components in a vector can be given when its created. By default they are initialized to zero. This example creates a vector named y that contains fifty components:  <tt>vector create y(50)</tt>
   * Indexing vector components
      * Vector components are indexed from zero. The vector's array variable can be used to read or set individual components. This example sets y's first element:  <tt>set y(0) 9.25</tt>
      * The array index must be a number less than the number of components. For example, it's an error if you try to set the 51st element of y:  <tt>puts "y has &#91;y length] components"; set y(50) 0.02</tt>
      * You can also specify a range of indices using a colon <tt>:</tt> to separate the first and last indices of the range. This example sets the first six components in y to 25.2:  <tt>set y(0:5) 25.2</tt>
      * If you don't include an index, then it will default to the first and/or last component of the vector. This example leaves out both indexes so it will print out all the components of y:  <tt>puts "y = $y(:)"</tt>  
      * Non-numeric Indices
         * <tt>end</tt> The index end, specifies the last component of the vector. It's an error to use this index if the vector is empty (length is zero).
         * <tt>++end</tt> The index ++end can be used to extend the vector by one component and initialize it to a specific value. You can't read from the array using this index, though. For example <tt>set y(++end) 0.02</tt> extends the vector by one component.
         * <tt>min</tt> The index min returns the component with the smallest value.
         * <tt>max</tt> The index max returns the component with the largest value.
   * To delete components from a vector, simply unset the corresponding array element. In the following example, the first component of y is deleted. All the remaining components of y will be moved down by one index as the length of the vector is reduced by one. Example: <tt>unset y(0); puts "new first element is $y(0)"</tt>
   * In this example a vector x is created without an initial length specification. In this case, the length is zero. The <b>set</b> operation resets the vector, extending it and setting values for each new component. The name of the vector is used as a command to set its component values given a list of them: <tt>vector create x; x set { 0.02 0.04 0.06 0.08 0.10 0.12 0.14 0.16 0.18 0.20}</tt>
   * The <b>range</b> operation lists the components of a vector between two indices. This example lists all the components in vector x: <tt>puts "x = &#91;x range 0 end]"</tt>
   * You can search for a particular value using the <b>search</b> operation. It returns a list of indices of the components with the same value. If no component has the same value, it returns "". This example finds the index of the components with the largest value: <tt>x search $x(max)</tt>
   * You can append vectors or new values onto an existing vector with the <b>append</b> operation. This example appends assorted vectors and values to x: <tt>x append x2 x3 { 2.3 4.5 } x4</tt>
   * The <b>sort</b> operation sorts the vector. If any additional vectors are specified, they are rearranged in the same order as the vector. For example, you could use it to sort data points represented by x and y vectors. In this example the vector x is sorted while the components of y are rearranged so that the original x,y coordinate pairs are retained: <tt>x sort y</tt>
   * The <b>expr</b> operation lets you perform arithmetic on vectors. The result is stored in the vector. This example adds y to x and then multiplies x by 2: <tt>x expr { x + y }; x expr { x * 2 }</tt>
   * When a vector is modified, resized, or deleted, it may trigger call-backs to notify the clients of the vector. For example, when a vector used in the graph widget is updated, the vector automatically notifies the widget that it has changed. The graph can then redrawn itself at the next idle point. By default, the notification occurs when Tk is next idle. This way you can modify the vector many times without incurring the penalty of the graph redrawing itself for each change. You can change this behavior using the <b>notify</b> operation. To make vector x notify after every change: <tt>x notify always</tt>. To turn off notification on vector x: <tt>x notify never</tt>. To force a notification now: <tt>x notify now</tt>.
   * To delete a vector, use the vector <b>delete</b> command. Both the vector and its corresponding Tcl command are destroyed. For example to remove vector x: <tt>vector destroy x</tt>

!Syntax
Vectors are created using the vector <b>create</b> operation. The create operation can be invoked in one of three forms: 
   * <tt>vector create</tt> <em>vecName</em>:  This creates a new vector <em>vecName</em> which initially has no components. 
   * <tt>vector create</tt> <em>vecName</em> <tt>(</tt><em>size</em><tt>)</tt>:  This form creates a new vector which will contain <em>size</em> number of components. The components will be indexed starting from zero <tt>(0)</tt>. The default value for the components is zero.
   * <tt>vector create</tt> <em>vecName</em> <tt>(</tt><em>first</em><tt>:</tt><em>last</em><tt>)</tt>: This form creates a new vector with components indexed <em>first</em> through <em>last</em>. <em>First</em> and <em>last</em> can be any integer value so long as <em>first</em> is less than <em>last</em>.

Vector names must start with a letter and consist of letters, digits, or underscores. 

You can automatically generate vector names using the <tt>#auto</tt> vector name. The <b>create</b> operation will return the unique vector name.

!Vector Indices
Vectors are indexed by integers. You can access the individual vector components via its array variable or Tcl command. The string representing the index can be an integer, a numeric expression, a range, or a special keyword.
The index must lie within the current range of the vector, otherwise an an error message is returned. Normally the indices of a vector are start from 0. But you can use the <b>offset</b> operation to change a vector's indices on-the-fly. 
You can also use numeric expressions as indices. The result of the expression must be an integer value. 
The following special non-numeric indices are available: <b>min</b>, <b>max</b>, <b>end</b>, and <b>++end</b>.
The indices <b>min</b> and <b>max</b> will return the minimum and maximum values of the vector.
The index <b>end</b> returns the value of the last component in the vector.
The index <b>++end</b> is used to append new value onto the vector. It automatically extends the vector by one component and sets its value.
A range of indices can be indicated by a colon <tt>:</tt> seperating two indices. The colon seperated indices can be integers, keywords, or empty. If no index is supplied the first or last component is assumed. 

For more information on BLT vectors get the public domain BLT distribution and see the <b>vector</b> man page or html file.
}

{sltcl} {
The sltcl set of commands all start with the <tt>sl_</tt> prefix. These are the actual commands used to read statmon files and convert their data to [vectors > BLT Vectors].
!Builtin Commands
   * [sl_create]
   * [sl_stat]
   * [sl_kill]
}

{Instance List Data} {
For each instance a sublist of the following exists:
   1 instance name
   1 object name
   1 start time
   1 isActive
   1 sample count
   1 file id
   1 instanceId
}

{Data File Commands} {
Whenever a file is created with [sl_create -file > sl_create] a new Tcl data file command is created. File commands support the following options:
   * <b>-info</b>: return a list of information about the file. The list has the following items:
      1 name
      1 version
      1 platform
      1 productVersion
      1 machine
      1 time string
      1 estimated sampleInterval
      1 isEnabled
      1 list of object types
      1 first timestamp
      1 trimLeft timestamp
      1 trimRight timestamp
   * <b>-instancecount</b>: returns the number of instances the file has.
   * <b>-instances</b>: returns a list of all the files instances. See [Instance List Data] for a description of the result.
   * <b>-objinstances</b> <em>objName</em>: returns a list of all the files instances of the named object type. See [Instance List Data] for a description of the result.
   * <b>-free</b>: frees up all resources used by loading the file and deletes the command.
   * <b>-dump</b>: dump the internal data structures, that contain the files data, in a printable form, to stdout.
   * <b>-update</b>: rereads the file to so if it has more data that can be read. This can be used to continue an interrupted create or read more data from a file that has grown.
   * <b>-disable</b>: Act as if the file has not been loaded.
   * <b>-enable</b>: Act as if the file has been loaded.
   * <b>-trimleft</b> <em>timeStamp</em>: Trim all of the data collected before the timestamp from the file. See [File Trimming] for more information.
   * <b>-trimright</b> <em>timeStamp</em>: Trim all of the data collected after the timestamp from the file. See [File Trimming] for more information.
   * <b>-append</b> <em>fileName</em>: causes this file to start reading the new named file onto the end of the current data. The new files data needs to be newer than the current data. Also the current file needs to be fully loaded.
}

{Line Commands} {
Whenever a file is created with [sl_create -line > sl_create] or [sl_create -derivedline > sl_create] a new Tcl line command is created. Line commands support the following options:
   * <b>-info</b>: return a list of information about the line. The list has the following items:
      1 instance name
      1 statistic name
      1 x vector name
      1 y vector name
      1 scale
      1 filter
      1 object name
      1 fileId list
      1 source list
      1 combo operator
      1 instId
      1 isNormalized
      1 normalize offset
      1 divider
   * <b>-changectr</b> <em>statName</em>: changes the line's statistic.
   * <b>-refilter</b> <em>filter</em>: changes the line's filter.
   * <b>-scale</b> <em>number</em>: scales the y values by <em>number</em>.
   * <b>-adder</b> <em>number</em>: offset the y values by <em>number</em>.
   * <b>-divider</b> <em>number</em>: divides the y values by <em>number</em>.
   * <b>-normalize</b>: forces the min y value to always be zero by subtracting to raw y min value from every y data point.
   * <b>-unnormalize</b>: undoes any normalization.
   * <b>-stats</b> <em>ts1 ts2</em>: returns a list of stats for y data between the specified timestamps. This returned list is:
      1 total number of samples in the range
      1 minimum y value in the range
      1 maximum y value in the range
      1 average of all y values in the range
      1 standard deviation of all y values in the range
      1 first actual timestamp in the range
      1 last actual timestamp in the range
   * <b>-trimleft</b> <em>timeStamp</em>: Trim all of the data collected before the timestamp from all the files used to make the line. See [File Trimming] for more information.
   * <b>-trimright</b> <em>timeStamp</em>: Trim all of the data collected after the timestamp from all the files used to make the line. See [File Trimming] for more information.
   * <b>-copy</b>: copies a line and returns the name of the copies line command.
   * <b>-free</b>: frees up all the resources used by the line and deletes the command.
}

{sl_create} {
The sl_create command lets you create [Data File Commands] and [Line Commands].
!Usages
   * <b>sl_create -file</b> <em>filename</em> ?<em>progressCallback</em>?: Creates a [Data File Commands] by loading the named statmon file. Returns the name of the created [command > Data File Commands]. If a progress callback is specified then it must be a Tcl proc that takes a single argument which is an integer in the range 0..100. The callback will always be called with a value of 100 when reading is complete. The callback should return 1 if loading should continue and 0 if it should be interrupted.
   * <b>sl_create -line</b> <em>instIdList statName filter isAbsolute</em>: Creates a [line > Line Commands] for the given instances and statistic name, and using the given [filter > Statistic Definitions]. Returns the name of the created [command > Line Commands]. If more than one instance is given then their data is all [combined > Main Menu Combine Item] together. The <em>isAbsolute</em> boolean determines if the time data for the created line will be [absolute or relative > Main Menu Absolute TimeStamps Item].
   * <b>sl_create -derivedline</b> <em>lineList</em> <b>+|-|/</b> <em>filter copyChildren</em>: Creates a [line > Line Commands] for the given lines using the given operator,and [filter > Statistic Definitions]. Returns the name of the created [command > Line Commands].  The <em>copyChildren</em> boolean determines if the input lines will be [copied or referenced > Main Menu Copy Referenced Lines Item]. For more information see [Line Arithmetic].
}

{sl_stat} {
The sl_stat command is used to perform global operations that are not limited to a particular data file.
!Usages
   * <b>sl_stat -names</b>: Returns a list of all known statistic names.
   * <b>sl_stat -enabledinstances</b>: Returns a list of instances from all the enabled files. See [Instance List Data] for a description of the result.
   * <b>sl_stat -enabledobjinstances</b> <em>objTypeList</em>: Returns a list of instances from all the enabled files of the given obj types. See [Instance List Data] for a description of the result.
   * <b>sl_stat -ctrzero</b> <em>statName instIdList</em>: Returns boolean indicating if named statistic is zero for all the given instances.
   * <b>sl_stat -enabledfiles</b>: Returns a list of [files > Data File Commands] that are enabled.
   * <b>sl_stat -allfiles</b>: Returns a list of all the [files > Data File Commands] that are loaded.
   * <b>sl_stat -alias</b> <em>oldname newname</em>: Causes the statistic <em>newname</em> to be used whenever <em>oldname</em> is found in a loaded statmon file.
   * <b>sl_stat -info</b> <em>name</em> ?<em>infolist</em>?: Returns a list of information on the named statistic. If the optional <em>infolist</em> exists then it must have at most three elements. Empty elements will be ignored. Non-empty ones will modify that value in the statistic's definition:
      1 statistic's [kind > Statistic Definitions]
      1 statistic's [level > Statistic Definitions]
      1 statistic's [default filter > Statistic Definitions]
          The result list has the following elements:
      1 statistic's [kind > Statistic Definitions]
      1 statistic's [level > Statistic Definitions]
      1 statistic's [default filter > Statistic Definitions]
      1 possible empty list of object types that use the statistic
   * <b>sl_stat -level</b> ?<em>levelname</em>?: With no argument returns the current statistic level. Otherwise sets the statistic level. See [Main Menu Statistic Level SubMenu].
   * <b>sl_stat -getdate</b> <em>ts</em> ?<b>elapsed</b>|<b>date</b>|<b>time</b>?: Given a timestamp convert it to a formatted string and return it. In no format is specified it defaults to <tt>date</tt>.
   * <b>sl_stat -objctrs</b> <em>objList</em>: returns a list of statistic names for the given object types.
   * <b>sl_stat -instinfo</b> <em>instId</em>: returns data describing the given instance id. See [Instance List Data] for a description of the result.
}
{sl_kill} {
The sl_kill command can be usd to kill a process. Vsd uses it to stop a statmonitor it is managing.
!Usages
   * <b>sl_kill</b> <em>pid</em>: kills the process with the given pid.
}

{VSD Files} {
The following files are created by VSD:
   * <u><tt>~/.vsdrc</tt></u> The <em>memory file</em> is written each time VSD exits. Its read\
each time VSD starts. VSD uses it to remember its configuration. Deleting it\
will force VSD back to its factory settings.
   * <u><tt>~/.vsdconfig</tt></u> The <em>config file</em> is never written be VSD. Its read\
and interpreted each time VSD is started. It can be used to reconfigure VSD's\
defaults. Its syntax is [Tcl > Tcl Language].
   * <u><tt>~/.vsdtemplates</tt></u> The <em>template file</em> is read when VSD is started\
and any time the [Template Menu <b>Reload Template File</b> Item] is selected.\
Its written whenever the [Chart Menu <b>Save Template</b> Item] is selected.\
See [Template Syntax] for a description of its contents.
   * <u><tt>bin/vsd</tt></u> The <em>source file</em> is never written be VSD. Its read and interpreted each time VSD is started. It contains most of VSD's implementation. Its syntax is [Tcl > Tcl Language].
   * <u><tt>bin/vsdwish</tt><em>OS</em></u> The <em>binary file</em> is never written be VSD. Its used to start VSD. Its the virtual machine that interprets the [Tcl > Tcl Language] code. The <em>OS</em> part of the name is a platform dependent suffix that names the operating system the binary file will run on.

The <tt>~</tt> represents your home directory. If you are not sure what\
directory VSD is using as your home you can see the absolute paths to these files [here > About VSD].
}

{CacheTooSmall Template} {
The intent of this template is to give you the statistics that will allow you to determine if the shared page cache needs to be made larger.
   * [FreeFrameCount > FreeFrameCount Statistic] for each [shrpc > Shrpc Type] on the [Right Y Axis].
   * [FramesFromFindFree > FramesFromFindFree Statistic] for each [shrpc > Shrpc Type].
   * [FramesFromFreeList > FramesFromFreeList Statistic] for each [shrpc > Shrpc Type]

See [Shared Page Cache Health] for help on shared page cache sizing. 
}

{CommitInfo Template} {
The intent of this template is to give a picture of the overall transactional throughput.
   * [TotalCommits > TotalCommits Statistic] for each [stone > Stn Type].
   * [CommitRecordCount > CommitRecordCount Statistic] for each [stone > Stn Type] on the [Right Y Axis].
   * [CommitQueueSize > CommitQueueSize Statistic] for each [stone > Stn Type] on the [Right Y Axis].
}

{EpochSweeps Template} {
The intent of this template is to show statistics related to repository epoch garbage collection.
   * [EpochCount > EpochCount Statistic] by [combining > Main Menu Combine Item] all [stone > Stn Type].
   * [EpochScannedObjs > EpochScannedObjs Statistic] by [combining > Main Menu Combine Item] all [stone > Stn Type] on the [Right Y Axis].
   * [EpochNewObjsSize > EpochNewObjsSize Statistic] by [combining > Main Menu Combine Item] all [stone > Stn Type] on the [Right Y Axis].
   * [EpochPossibleDeadSize > EpochPossibleDeadSize Statistic] by [combining > Main Menu Combine Item] all [stone > Stn Type] on the [Right Y Axis].
   * [PossibleDeadSize > PossibleDeadSize Statistic] by [combining > Main Menu Combine Item] all [stone > Stn Type] on the [Right Y Axis].
}

{Garbage Template} {
The intent of this template is to give a picture of the overall repository garbager collection activity.
   * [PagesNeedReclaimSize > PagesNeedReclaimSize Statistic] by [combining > Main Menu Combine Item] all [stone > Stn Type] on the [Right Y Axis].
   * [ReclaimedPagesCount > ReclaimedPagesCount Statistic] by [combining > Main Menu Combine Item] all [stone > Stn Type] on the [Right Y Axis].
   * [EpochCount > EpochCount Statistic] by [combining > Main Menu Combine Item] all [stone > Stn Type].
   * [ReclaimCount > ReclaimCount Statistic] by [combining > Main Menu Combine Item] all [stone > Stn Type].
   * [CommitCount > CommitCount Statistic] by [combining > Main Menu Combine Item] all [sessions > Session Type] named <b>*Gc</b>.
}

{PageServer Template} {
This template gives a picture of the overall async-io done by page servers.
   * [AioDirtyCount > AioDirtyCount Statistic] by [combining > Main Menu Combine Item] all [page servers > Pgsvr Type].
   * [AioCkptCount > AioCkptCount Statistic] by [combining > Main Menu Combine Item] all [page servers > Pgsvr Type].
   * [LocalDirtyPageCount > LocalDirtyPageCount Statistic] for each [shrpc > Shrpc Type].

See [AIO page servers] for more information.
}

{SpaceFree Template} {
This template gives you the statistics that allow you to determine how much of a resource is available. Currently the only resources supported by this template are the shared page cache and the object repository.
   * [FreeFrameCount > FreeFrameCount Statistic] for each [shrpc > Shrpc Type].
   * [FreePages > FreePages Statistic] for each [stone > Stn Type] on the [Right Y Axis].

See [Shared Page Cache Health] for help on shared page cache sizing. 
}

{CPU Template} {
This template gives a picture of overall CPU usage. It shows one set of statistics for Solaris, and another for NT.
!Solaris
   * [UserTime > UserTime Statistic] by [combining > Main Menu Combine Item] all instances.
   * [PercentCpuActive > PercentCpuActive Statistic] for each [Solaris system > SolarisSystem Type] on the [Right Y Axis].
   * [PercentCpuWaiting > PercentCpuWaiting Statistic] for each [Solaris system > SolarisSystem Type] on the [Right Y Axis].
!Windows NT
   * [SysTime > SysTime Statistic] by [combining > Main Menu Combine Item] all instances.
   * [TotalProcessorTime > TotalProcessorTime Statistic] for each [NT system > NtSystem Type].
   * [ProcessorQueueLength > ProcessorQueueLength Statistic] for each [NT system > NtSystem Type] on the [Right Y Axis].
}

{CacheMix Template} {
The intent of this template is to give a picture of the overall [Shared Page Cache Health]. When you bring up this template, the following stats are displayed:
   * [FreeFrameCount > FreeFrameCount Statistic] for each [shrpc > Shrpc Type] on the [Right Y Axis].
   * [LocalDirtyPageCount > LocalDirtyPageCount Statistic] for each [shrpc > Shrpc Type]
   * [FreeFrameLimit > FreeFrameLimit Statistic] for each [shrpc > Shrpc Type]
   * [BitlistPagesWrittenByGem > BitlistPagesWrittenByGem Statistic] for each [shrpc > Shrpc Type]
   * [BitlistPagesWrittenByStone > BitlistPagesWrittenByStone Statistic] for each [shrpc > Shrpc Type]
   * [BmInternalPagesWrittenByGem > BmInternalPagesWrittenByGem Statistic] for each [shrpc > Shrpc Type]
   * [BmInternalPagesWrittenByStone > BmInternalPagesWrittenByStone Statistic] for each [shrpc > Shrpc Type]
   * [BmLeafPagesWrittenByGem > BmLeafPagesWrittenByGem Statistic] for each [shrpc > Shrpc Type]
   * [BmLeafPagesWrittenByStone > BmLeafPagesWrittenByStone Statistic] for each [shrpc > Shrpc Type]
   * [CommitRecordPagesWrittenByGem > CommitRecordPagesWrittenByGem Statistic] for each [shrpc > Shrpc Type]
   * [CommitRecordPagesWrittenByStone > CommitRecordPagesWrittenByStone Statistic] for each [shrpc > Shrpc Type]
   * [DataPagesWrittenByGem > DataPagesWrittenByGem Statistic] for each [shrpc > Shrpc Type]
   * [OtInternalPagesWrittenByGem > OtInternalPagesWrittenByGem Statistic] for each [shrpc > Shrpc Type]
   * [OtInternalPagesWrittenByStone > OtInternalPagesWrittenByStone Statistic] for each [shrpc > Shrpc Type]
   * [OtLeafPagesWrittenByGem > OtLeafPagesWrittenByGem Statistic] for each [shrpc > Shrpc Type]
   * [OtLeafPagesWrittenByStone > OtLeafPagesWrittenByStone Statistic] for each [shrpc > Shrpc Type]
}

{Shared Page Cache} {
The SPC serves three types of data to the processes attached to the cache:

   * data pages
      * [DataPagesWrittenByGem > DataPagesWrittenByGem Statistic]
   * object table pages
      * [OtInternalPagesWrittenByGem > OtInternalPagesWrittenByGem Statistic]
      * [OtLeafPagesWrittenByGem > OtLeafPagesWrittenByGem Statistic]
   * commit record pages
      * [BitlistPagesWrittenByGem > BitlistPagesWrittenByGem Statistic]
      * [BmInternalPagesWrittenByGem > BmInternalPagesWrittenByGem Statistic]
      * [BmLeafPagesWrittenByGem > BmLeafPagesWrittenByGem Statistic]
      * [CommitRecordPagesWrittenByGem > CommitRecordPagesWrittenByGem Statistic]

There is a smattering of other types of data in the cache, but the types listed above cover 99% of the cases.

If you create a VSD chart from the [CacheMix Template], you can see the mix of these different types of pages in the cache as it performs various operations.

In a healthy cache, [DataPagesWrittenByGem > DataPagesWrittenByGem Statistic] will dominate. If you have a large number of objects in the repository, then you will start to see a sizable number of object table pages ([OtInternalPagesWrittenByGem > OtInternalPagesWrittenByGem Statistic] and [OtLeafPagesWrittenByGem > OtLeafPagesWrittenByGem Statistic]). Other page types may rise and fall within cache while certain maintenance operations are being performed.

!How big should I make my shared page cache?

The optimal cache size should be able to handle the working set of data pages, object table pages and commit record pages during your most time critical system operating periods.

!If your shared page cache is too small:

Your sessions will be performing too many [LocalPageCacheMisses > LocalPageCacheMisses Statistic]. Before taking any action, compare the [LocalPageCacheMisses > LocalPageCacheMisses Statistic] for the session with the [ObjsReadCount > ObjsReadCount Statistic]. 

   * If they are equal, then every time your session references an object that has not been loaded into the vm's object memory, you are being forced to load the page that that object resides on from disk into the shared page cache. You can double check by comparing [LocalPageCacheMisses > LocalPageCacheMisses Statistic] to the [PagesPreempted > PagesPreempted Statistic] stat in the [shrpc > Shrpc Type] - these two stats should be roughly equivalent. You can probably benefit from a larger cache size.

   * If the [LocalPageCacheMisses > LocalPageCacheMisses Statistic] is a small percentage of your [ObjsReadCount > ObjsReadCount Statistic], then your cache is pretty close to the right size. 

   * If [ObjsReadCount > ObjsReadCount Statistic] is a very small percentage of the [LocalPageCacheMisses > LocalPageCacheMisses Statistic], yet the absolute number of [LocalPageCacheMisses > LocalPageCacheMisses Statistic] is very high, then you may be taking hits on object table page references or a commit record backlog. First check your stone's [CommitRecordCount > CommitRecordCount Statistic]. If it is in the 1000's, then you have a commit record backlog problem. Finally, take a look at [ObjTablePageReads > ObjTablePageReads Statistic]. If they are roughly equal then you'll need to increase the cache size. 

An alternative to increasing the size of the shared page cache is to increase the size of the POM Cache in the vm. If the cache misses are due to object reads, then this technique could reduce the need to increase the size of the shared page cache.

!If your shared page cache is too large:

See also: [Shared Page Cache Health], [Writing]
}

{AIO page servers} {
!How many AIO page servers do I need?
The system will not let you allocate more than one page server per extent. I have heard that two or three extents per aio page server is a good rule of thumb.

You can tell you need more if:
   * [LocalDirtyPageCount > LocalDirtyPageCount Statistic] is taking up close to a third or more of the frames in the cache.
AND
   * The [AioWakeupInterval > AioWakeupInterval Statistic] for page servers named <b>aioWriter</b> (the aio threads in the [SAP]) is spending noticeable time at 0. When [AioWakeupInterval > AioWakeupInterval Statistic] is at zero the thread is scanning the cache and writing pages as fast as it can.

Each page server thread has 4 thresholds of interest:
   *  [LocalDirtyPageCount > LocalDirtyPageCount Statistic] < 1% of cache
idle. [AioWakeupInterval > AioWakeupInterval Statistic] threshold equal to 1000 milliseconds.
   *  1% of cache < [LocalDirtyPageCount > LocalDirtyPageCount Statistic] < 50% of cache
1 cache scan per second. [AioWakeupInterval > AioWakeupInterval Statistic] threshold equal to 1000 milliseconds.
   *  50% of cache < [LocalDirtyPageCount > LocalDirtyPageCount Statistic] > 75% of cache
1 cache scan per 1/2 second. [AioWakeupInterval > AioWakeupInterval Statistic] threshold equal to 500 milliseconds.
   *  75% of cache < [LocalDirtyPageCount > LocalDirtyPageCount Statistic]
continuous cache scans. [AioWakeupInterval > AioWakeupInterval Statistic] threshold equal to 0 milliseconds.

See also: [Extents and Tranlogs], [Shared Page Cache Health]
}

{Extents and Tranlogs} {
!What's the skinny on Raw Partitions?
Put your tranlogs on raw partitions

   * Tranlog i/o is the number one limiting factor in commit performance.
   * If you don't put your tranlogs on a raw partition, then at least make sure that your tranlog directory is not on the same spindle as your extents.
   * Try to alternate tranlogs across two spindles and archive one while the other is active.

Put extents on raw partitions

   * Since GemStone does random access to the extents, it is not as important to put your extents on raw partitions. In fact, because of the disk i/o buffering done by the os, file-based extents may lead to better performance.

Always put separate extents on separate spindles
   * If/when you add more [AIO page servers], you will get the optimal i/o performance by having each extent on a separate spindle.

!How many extents should I have?

You can tell if you need more extents if:
   * Your [AIO page servers] are maxed out and dirty pages are dominating your [shared page cache > Shared Page Cache Health].
OR
   * You are running out of space on your current disk partition.

!How big should I allow my extents to be?

!Which allocation mode should I use?
   * [Extent Allocation Modes]
}

{Extent Allocation Modes} {
   * Sequential Allocation Mode
   * Weighted Allocation Mode
}

{Writing} {
!Scenario Description:

In this scenario we are imagining that you are loading your repository with initial data. There is minimal repository reading going on and the primary activity is the creation of new objects that are to be stored in the repository (The extent stat [ExtentReadKBytes > ExtentReadKBytes Statistic] will be very, very low, if not zero and the extent stat [ExtentWriteKBytes > ExtentWriteKBytes Statistic] will be very high).

!Principle
The goal is to mazimize the [ObjsCommitted > ObjsCommitted Statistic] per second as this will be your true measure of performance. 

!System Parameter Settings:

   * Reduce the size of the [shared page cache > Shared Page Cache]

With a minimum amount of reading going on the primary purpose of the cache is to provide a home for dirty pages until the [AIO page servers] are able to write the dirty pages to disk. The cache is also holding onto the active commit records. Use a large cache until you have maximized your commit rate and i/o rate, then reduce the size of the cache until The stone and/or sessions start getting [LocalPageCacheMisses > LocalPageCacheMisses Statistic]. 

Also keep an eye on the [WriteKBytes > WriteKBytes Statistic] stat for the disk volume where the tranlogs are being written. The stat should be fairly steady, so if you see swings in the write rate, take a look at the health of the stone.

!VM Parameter Settings:

   * Increase the [private page cache size > PrivatePageCacheSize Statistic] to eliminate any [FramesAddedToFreeList > FramesAddedToFreeList Statistic] activiy for the [sessions > Session Type] doing the writes.
   * Maximize the number of objects per commit. There is a fixed overhead per commit, so it is advantageous to commit as many objects per commit as possible. The primary limiting factor in this case is the amount of java heap ([ObjMemSize > ObjMemSize Statistic]) used by the session - the objects are kept in java object memory until the commit at which time the persistent objects can be gc'ed freeing up object memory for more new objects.

See also: [Extent Allocation Modes], [Shared Page Cache]
}

{Shared Page Cache Health} {
To check you shared page cache's heath bring up a chart using the [CacheMix Template] and take a look at the following three statistics:
   * [FreeFrameCount > FreeFrameCount Statistic]
   * [LocalDirtyPageCount > LocalDirtyPageCount Statistic]
   * [DataPagesWrittenByGem > DataPagesWrittenByGem Statistic]

[FreeFrameCount > FreeFrameCount Statistic] should be ratcheting along between 0 and 2000 frames. If [FreeFrameCount > FreeFrameCount Statistic] is flat-lined at zero, your working-set of pages may be larger than the cache. First check that the [sessions > Session Type] are not doing excessive [FramesAddedToFreeList > FramesAddedToFreeList Statistic], then consider increasing the size of the [Shared Page Cache].

[LocalDirtyPageCount > LocalDirtyPageCount Statistic] should be way less than a third of the cache. If there are lots of dirty pages in the cache, then take a look at adding more [AIO page servers].

The bulk of the pages in the cache should be [DataPagesWrittenByGem > DataPagesWrittenByGem Statistic]. 

If you see a large number of [CommitRecordPagesWrittenByGem > CommitRecordPagesWrittenByGem Statistic], [BitlistPagesWrittenByGem > BitlistPagesWrittenByGem Statistic], [BmInternalPagesWrittenByGem > BmInternalPagesWrittenByGem Statistic], or [BmLeafPagesWrittenByGem > BmLeafPagesWrittenByGem Statistic], you may be suffering from a high commit record backlog and you should take steps to alleviate that situation.

See also: [AIO page servers], [Shared Page Cache]
}

{Chart Menu Add From Template SubMenu} {
This submenu has an item for every template.\
Selecting one of these items causes that template to be [expanded > Template Expansion]\
and every line the expansion produces is added to this chart.

[Selection Key > Keyboard Selection Keys]: <tt>Alt-a</tt>

This menu can be [torn off > Tear Off Menus].

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Save Template Item} {
Selecting this menu item causes all of the lines on the chart to be\
saved as a template.
The saved template is written to the [template file > VSD Files].

The name of the template will be based upon the chart window's name.
You can rename the template by editing the [template file > VSD Files] and [reloading > Template Menu Reload Template File Item] it

Each line on the chart is used as a pattern when saving it to the template.\
Exact information on the instances is no recorded in the template.\
This is so when the template is used later, with another file, it should\
be able to match some of its instances. In some case the saved template\
can be made more useful by editing the [template file > VSD Files].\
Also some template features can only be used by directly editing the file.

[Selection Key > Keyboard Selection Keys]: <tt>Alt-s</tt>

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Paste Item} {
Selecting this menu item causes the last item that was cut or copied\
to be added to this chart as one or more lines. If it finds something\
on the clipboard to paste it will remove that item from the clipboard.\
A paste operation does nothing if the clipboard is empty.

A paste can also be done with a host dependent <em>Paste</em> key.

[Accelerator Key > Keyboard Accelerators]: <tt>control-v</tt>

See [How to Cut, Copy, and Paste] for more information.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Print Item} {
Selecting this menu item causes the chart to be printed. This is only supported on Unix platforms. The command name stored in the <tt>vsd(exec:lpr)</tt> variable is executed with the contents of a postscript file. The default value of this variable is <tt>lpr</tt> and can be customized in the [config file > VSD Files].

The temporary postscript file is written to VSD's working directory. Use [Main Menu Change Directory... Item] to change this directory.

[Accelerator Key > Keyboard Accelerators]: <tt>control-p</tt>

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Snapshot Item} {
Selecting this menu item causes a picture of the chart to be taken and written to the file <tt>snapshot.gif</tt>. The file is always written to VSD's working directory and any existing file will be overwritten. Use [Main Menu Change Directory... Item] to change the working directory.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Help... Item} {
Selecting this menu item causes a [help window > Help Window Features] to\
popup with a description of the [chart window > Chart Window Features].

[Selection Key > Keyboard Selection Keys]: <tt>Alt-h</tt>

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Zoom In Item} {
Selecting this menu item begins a zoom in operation on the chart's\
graph. A zoom in consists of the following steps:
   1 Click in the graph at the point you wish to be the upper left hand corner.
   1 Click in the graph at the point you wish to be the lower right hand corner.

Once the operation has begun it can be canceled at any time with\
a right click of the mouse.

See [How to Zoom] for more information.

[Accelerator Key > Keyboard Accelerators]: <tt>control-z</tt>

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Zoom Out Item} {
Selecting this menu item does a zoom out operation on the chart's\
graph. A zoom out will reverse the effects of the most recent zoom in.\
A zoom out does nothing unless the graph is zoomed in at least\
once.

A right click of the mouse over the graph will also do a zoom out.

See [How to Zoom] for more information.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Compare Two Points Item} {
This operation item allows you to [log > Log Window] information obtained\
by comparing two points. Unlike the [Line Menu <b>Log Delta</b> Item] the\
two points can be from any of the lines on the chart's [graph > Graph Display].

Once the operation has begun it can be canceled at any time with\
a right click of the mouse.

!Usage
   1 Select the item.
   1 [Select > Selecting a Point for an Operation] the first point.
   1 [Select > Selecting a Point for an Operation] the second point. A thin black line will be drawn between the\
first point and the mouse cursor to remind you of what you are comparing.
   1 View the [logged > Log Window] information.

!Logged Information
The following information is logged by this operation:
   * A description of the lines the points were on.
   * The exact coordinates of the two points.
   * <b>time delta</b>: the absolute difference between the two point's X coordinates.
   * <b>value delta</b>: the difference between the two point's Y coordinates.\
This is done by subtracting the first point's Y value from the second point's\
Y value.
   * <b>value/time delta</b>: the result of dividing the <em>value delta</em>\
by the <em>time delta</em>.\
This delta is only shown if the <em>time delta</em> is not zero.
   * <b>data statistics</b>: [statistics > Data Statistics] for the data points\
on each line. The data points of interest are the ones in the range defined\
by the X values of the two selected points.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Data Statistics} {
The following statistics on sets of data values are supported by VSD:
   * <b>count</b>: the number of points in the data set.
   * <b>min</b>: the minimum Y value of the points in the data set.
   * <b>max</b>: the maximum Y value of the points in the data set.
   * <b>mean</b>: the average Y value of all the points in the data set.
   * <b>stddev</b>: the standard deviation of all the Y values in the data set.\
Larger standard deviation values mean that more values far away from the\
average exist.
}

{Selecting a Point for an Operation} {
Various chart operations require that you select one or more points on a\
chart's graph. In most of these cases the mouse cursor changes to cross hairs\
to tell you that the graph is in a special mode. Once the mouse cursor is\
over a valid point that can be selected the it changes to a target.\
If you click when its a target the point will be selected.

Note that during this process the mouse will automatically highlights the\
line its closest to and display the coordinates of the line point its\
closest to. See [How to Get Information About a Location] for more information.

In some cases the point must be on a certain line. If another line is\
nearby you may have trouble with its point always being selected instead\
the line you need. Move the line to its own chart or rescale it or change\
its Y axis to remedy this problem.
}

{Chart Menu Compute Scale All Item} {
Selecting this menu item causes every line on the chart to have an\
[optimal scale > Line Menu Compute Scale Item] computed for it.

[Accelerator Key > Keyboard Accelerators]: <tt>control-S</tt>

For more information on scaling see [Display Scaling a Line].

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Unscale All Item} {
Selecting this menu item causes every line on the chart to be\
[unscaled > Line Menu Compute Scale Item].

[Accelerator Key > Keyboard Accelerators]: <tt>control-N</tt>

For more information on scaling see [Display Scaling a Line].

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Show Legend Item} {
If this item is on then the [chart window > Chart Window Features] will have a [legend > Graph Legend] control.\
Screen space can be saved by turning it off. If it is turned off then\
a description of the selected line will be printed in the  upper left corner of\
the [graph > Graph Display].

Use [Main Chart Menu <b>Show Legend</b> Item] to control the initial state\
of this item.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Time Format SubMenu} {
This submenu controls what format a timestamp will be displayed in.\
It allows any one, and only one, of the following formats to be selected:
   * [Elapsed Time in Seconds > Elapsed Time in Seconds Format] 
   * [Hour:Minute:Second > Hour:Minute:Second Format]
   * [Month/Day Hour:Minute:Second > Month/Day Hour:Minute:Second Format]

[Selection Key > Keyboard Selection Keys]: <tt>Alt-t</tt>

This menu can be [torn off > Tear Off Menus].

Use [Main Chart Menu <b>Time Format</b> SubMenu] to control the initial state\
of this item.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Elapsed Time in Seconds Format} {
Use this format to get the least amount of information printed about the timestamp.

If the time stamp is [relative > Main Menu Absolute TimeStamps Item]\
then this is the number of seconds since the first sample in the file\
it is from. The exact format is <u><em>num</em><b>s</b></u> where:
   * <em>num</em> is a sequence of digits
   * <b>s</b> stands for seconds

If the time stamp is [absolute > Main Menu Absolute TimeStamps Item]\
then just the time of day in hours, minutes, and seconds is printed.\
This is exactly the same as the [Hour:Minute:Second Format].
}

{Hour:Minute:Second Format} {
If the time stamp is [relative > Main Menu Absolute TimeStamps Item]\
then this is the number of hours, minutes, and seconds\
since the first sample in the file it is from.\
Only non-zero counts are show.\
The exact format is\
<u><em>num</em><b>h</b><em>num</em><b>m</b><em>num</em><b>s</b></u> where:
   * <em>num</em> is a sequence of digits
   * <b>h</b> stands for hours
   * <b>m</b> stands for minutes
   * <b>s</b> stands for seconds

If the time stamp is [absolute > Main Menu Absolute TimeStamps Item]\
then just the time of day in hours, minutes, and seconds is printed.\
The exact format is <u><em>hours</em><b>:</b><em>minutes</em><b>:</b><em>seconds</em></u> where:
   * <em>hours</em> is a value in the range 0..23; two digits are always printed.
   * <em>minutes</em> is a value in the range 0..59.
   * <em>seconds</em> is a value in the range 0..61;\
the value 60 allows for the occasional leap second;\
the value 61 allows for the occasional double leap second.
}

{Month/Day Hour:Minute:Second Format} {
If the time stamp is [relative > Main Menu Absolute TimeStamps Item]\
then this is the elapsed number of days, hours, minutes, and seconds\
since the first sample in the file it is from.\
Only non-zero counts are show.\
The exact format is\
<u><em>num</em><b>d</b><em>num</em><b>h</b><em>num</em><b>m</b><em>num</em><b>s</b></u> where:
   * <em>num</em> is a sequence of digits
   * <b>h</b> stands for days
   * <b>h</b> stands for hours
   * <b>m</b> stands for minutes
   * <b>s</b> stands for seconds

If the time stamp is [absolute > Main Menu Absolute TimeStamps Item]\
then the month, day of the month, and  the time of day in hours, minutes, and seconds is printed.\
The exact format is <u><em>month</em><b>/</b><em>day</em> <em>hours</em><b>:</b><em>minutes</em><b>:</b><em>seconds</em></u> where:
   * <em>month</em> is a value in the range 1..12; two digits are always printed.
   * <em>day</em> is a value in the range 1..31; two digits are always printed.
   * <em>hours</em> is a value in the range 0..23; two digits are always printed.
   * <em>minutes</em> is a value in the range 0..59.
   * <em>seconds</em> is a value in the range 0..61;\
the value 60 allows for the occasional leap second;\
the value 61 allows for the occasional double leap second.
}

{Chart Menu Show Time Axis Title Item} {
If this item is on then the [chart window > Chart Window Features] will display a title under the graph's [X Axis].
Screen space can be saved by turning it off.

Use [Main Chart Menu <b>Show Time Axis Title</b> Item] to control the initial state\
of this item.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Show Left Axis Title Item} {
If this item is on then the [chart window > Chart Window Features] will display a title next to the graph's [Left Y Axis].
Screen space can be saved by turning it off.

Use [Main Chart Menu <b>Show Left Axis Title</b> Item] to control the initial state\
of this item.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Show Right Axis Title Item} {
If this item is on then the [chart window > Chart Window Features] will display a title next to the graph's [Right Y Axis].
Screen space can be saved by turning it off.

Use [Main Chart Menu <b>Show Right Axis Title</b> Item] to control the initial state\
of this item.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Show Current Values Item} {
If this item is on then the [chart window > Chart Window Features] will have\
[X: > Chart Window X: Display] and [Y: > Chart Window Y: Display] controls
Screen space can be saved by turning it off.

Use [Main Chart Menu <b>Show Current Values</b> Item] to control the initial state\
of this item.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Show Min and Max Item} {
If this item is on then the [chart window > Chart Window Features]\
will have [Min: > Chart Window Min: Display] and [Max: > Chart Window Max: Display] controls.
Screen space can be saved by turning it off.

Use [Main Chart Menu <b>Show Min and Max</b> Item] to control the initial state\
of this item.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Show Line Stats Item} {
If this item is on then the [chart window > Chart Window Features]\
will display [line statistics > Data Statistics] in the upper left corner of its [graph > Graph Display].
Turning it off saves the cost of computing these statistics and can make it easier to view lines with points in the upper left corner.

Use [Main Chart Menu <b>Show Line Stats</b> Item] to control the initial state\
of this item.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Show CrossHairs Item} {
If this item is on then the [chart window > Chart Window Features] will draw cross hair lines on its [graph > Graph Display].

Use [Main Chart Menu <b>Show CrossHairs</b> Item] to control the initial state\
of this item.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Show Grid Lines Item} {
If this item is on then the [chart window > Chart Window Features] will draw dotted grid lines on its [graph > Graph Display].

Use [Main Chart Menu <b>Show Grid Lines</b> Item] to control the initial state\
of this item.

This item is part of the [chart menu > Chart Window Chart Menu].
}

{Chart Menu Close Item} {
Selecting this item causes the chart window to no longer exist.\
This can also be done using the native window manager.

To close all your chart windows use the [Main Chart Menu <b>Close All Charts</b> Item].

This item is part of the [chart menu > Chart Window Chart Menu].
}


{Chart Window Line Menu} {
This menu is disable until a [line is selected > How to Select a Line].
Operations on this menu apply to the selected line.

[Selection Key > Keyboard Selection Keys]: <tt>Alt-l</tt>

This menu can be [torn off > Tear Off Menus].

This menu is on each [chart window > Chart Window Features].

!Items
   * [Log Info > Line Menu Log Info Item]
   * [Log Delta > Line Menu Log Delta Item]
   * [Compute Scale > Line Menu Compute Scale Item]
   * [Unscale > Line Menu Unscale Item]
   * [Graph on Left Axis > Line Menu Graph on Left Axis Item]
   * [Symbol > Line Menu Symbol SubMenu]
   * [Style > Line Menu Style SubMenu]
   * [Update > Line Menu Update Item]
   * [Add Lines > Line Menu Add Lines Item]
   * [Diff Lines > Line Menu Diff Lines Item]
   * [Divide Lines > Line Menu Divide Lines Item]
   * [Normalize > Line Menu Normalize Item]
   * [Trim Left > Line Menu Trim Left Item]
   * [Trim Right > Line Menu Trim Right Item]
   * [Untrim Left > Line Menu Untrim Left Item]
   * [Untrim Right > Line Menu Untrim Right Item]
   * [Copy > Line Menu Copy Item]
   * [Cut > Line Menu Cut Item]
   * [Delete > Line Menu Delete Item]
}

{Line Menu Log Info Item} {
Selecting this item causes information on the current line to be written to the [log window >Log Window]. The information includes:
   * A description of the line's instances and statistic
   * the line's [value scale > Value Scaling a Line] if any
   * the line's [offset > Offsetting a Line] if any
   * the line's filter. The prefix <tt>filter:</tt> is used.
   * the line's units. The prefix <tt>units:</tt> is used.
   * an indicator if the line was normalized. The keyword <tt>normalized</tt> is used.
   * the line's files. The prefix <tt>file:</tt> or <tt>files:</tt> is used.
   * if the line is a [combination > Main Menu Combine Item] of more than one instance then a list of each of the instances. The keyword <tt>dataSources:</tt> heads this section.
   * if the line was created using [arithmetic > Line Arithmetic] then full information, except for line statistics, is given on each of the derived lines. Also the operator used is show.
   * the line's statistics which include:
      * the statistic range. This consists of the times of the first and last sample used to compute the statistics
      * the minimum value in the statistic range
      * the maximum value in the statistic range
      * the average of all the values in the statistic range
      * the standard deviation of all the values in the statistic range

[Selection Key > Keyboard Selection Keys]: <tt>Alt-i</tt>

This item is part of the [line menu > Chart Window Line Menu].
}

{Line Menu Log Delta Item} {
This operation item allows you to [log > Log Window] information obtained\
by comparing two points on the selected line.

[Accelerator Key > Keyboard Accelerators]: <tt>control-d</tt>

Once the operation has begun it can be canceled at any time with\
a right click of the mouse.

!Usage
   1 Select the line the two points are on.
   1 Select the item.
   1 [Select > Selecting a Point for an Operation] the first point.
   1 [Select > Selecting a Point for an Operation] the second point. A thin black line will be drawn between the\
first point and the mouse cursor to remind you of what you are comparing.
   1 View the [logged > Log Window] information.

!Logged Information
The following information is logged by this operation:
   * A description of the line the points were on.
   * The exact coordinates of the two points.
   * <b>time delta</b>: the absolute difference between the two point's X coordinates.
   * <b>value delta</b>: the difference between the two point's Y coordinates.\
This is done by subtracting the first point's Y value from the second point's\
Y value.
   * <b>value/time delta</b>: the result of dividing the <em>value delta</em>\
by the <em>time delta</em>.
   * <b>data statistics</b>: [statistics > Data Statistics] for all the data points\
on the line between the two selected points.

This item is part of the [line menu > Chart Window Line Menu].
}

{Line Menu Compute Scale Item} {
Selecting this item sets the current lines [display scale > Display Scaling a Line] to a value such that the lines maximum value will display at the top of the Y axis its plotted on.

[Accelerator Key > Keyboard Accelerators]: <tt>control-s</tt>

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Unscale Item} {
Selecting this item sets the current line's [display scale > Display Scaling a Line] to one.

[Accelerator Key > Keyboard Accelerators]: <tt>control-n</tt>

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Graph on Left Axis Item} {
If this item is checked then the current line is plotted on the [left axis > Left Y Axis]. Otherwise its plotted on the [right axis > Right Y Axis]. If you have two lines whose values differ greatly then plotting them on seperate axis can help in comparing the two lines visually.

[Accelerator Key > Keyboard Accelerators]: <tt>control-a</tt>

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Symbol SubMenu} {
This submenu lets you select the symbol that will be used to display the data points of the current line. By default no symbol is used to the data points blend in with the lines that connect them. Using a symbol lets you see the actual data points. Symbols tend to blend together if you have a large number of data points so only use this feature when you have [zoomed > How to Zoom] in to a smaller region. The symbols are:
   * <b>scross</b>: a simple X
   * <b>splus</b>: a simple +
   * <b>square</b>: a square
   * <b>triangle</b>: a triangle
   * <b>circle</b>: a circle
   * <b>diamond</b>: a diamond
   * <b>plus</b>: a fancy +
   * <b>cross</b>: a fancy X

[Selection Key > Keyboard Selection Keys]: <tt>Alt-s</tt>

This menu can be [torn off > Tear Off Menus].

This submenu is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Style SubMenu} {
This submenu lets you select the style used to connect the data points when displaying the current line. The default style is <b>linear</b>. The style does not change the actual data points just the lines drawn between them. The available styles are:
   * <b>linear</b>: a simple line segment is drawn between each pair of data points.
   * <b>step</b>: two line segments are drawn between each pair of data points. The first is a horizontal line segment that steps to the next X-coordinate. The second is a vertical line that steps to the next Y-coordinate.
   * <b>natural</b>: multiple line segments, generated using a cubic spline, are drawn between each pair of data points.
   * <b>quadratic</b>: multiple line segments, generated using a quadratic spline, are drawn between each pair of data points.

[Selection Key > Keyboard Selection Keys]: <tt>Alt-t</tt>

This menu can be [torn off > Tear Off Menus].

This submenu is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Update Item} {
Selecting this item will cause all the files used by the current line to be [updated > How to Update the View of a Data File] which may result in the line becoming longer.

[Accelerator Key > Keyboard Accelerators]: <tt>control-u</tt>

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Add Lines Item} {
Selecting this item starts the process of adding another line to the current line. Vsd will prompt you to select the other line. You can <em>left click</em> on either the line or its [legend > Graph Legend] entry to select it. You can <em>right click</em> to cancel the operation. If you do select another line then a new line is produced which is the result of adding the first two lines together. See [line arithmetic > Line Arithmetic] for more information.

[Accelerator Key > Keyboard Accelerators]: <tt>control-+</tt>

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Diff Lines Item} {
Selecting this item starts the process of subtracting another line from the current line. Vsd will prompt you to select the other line. You can <em>left click</em> on either the line or its [legend > Graph Legend] entry to select it. You can <em>right click</em> to cancel the operation. If you do select another line then a new line is produced which is the result of subtracting the first line from the second. See [line arithmetic > Line Arithmetic] for more information.

[Accelerator Key > Keyboard Accelerators]: <tt>control--</tt>

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Divide Lines Item} {
Selecting this item starts the process of dividing the current line by another line. Vsd will prompt you to select the other line. You can <em>left click</em> on either the line or its [legend > Graph Legend] entry to select it. You can <em>right click</em> to cancel the operation. If you do select another line then a new line is produced which is the result of dividing the first line by the second. See [line arithmetic > Line Arithmetic] for more information.

[Accelerator Key > Keyboard Accelerators]: <tt>control-/</tt>

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Normalize Item} {
If this item is checked then the line will be [normalized > Normalizing a Line]. Its renormalized any time its data points change.
If its not checked then you are free to set the line's [offset > Offsetting a Line] to any value.

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Trim Left Item} {
Selecting this item start a trim left operation. You can either select a data point on the current line or <em>right click</em> to cancel the operation. To select a data point move the mouse over the line. The cursor will turn into a circle when its over a valid trim point. If you want to ignore all the data to the left of this trim point then <em>left click</em>.

See [File Trimming] for more information.

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Trim Right Item} {
Selecting this item start a trim right operation. You can either select a data point on the current line or <em>right click</em> to cancel the operation. To select a data point move the mouse over the line. The cursor will turn into a circle when its over a valid trim point. If you want to ignore all the data to the right of this trim point then <em>left click</em>.

See [File Trimming] for more information.

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Untrim Left Item} {
Selecting this item causes any left trims done to the current line's files to be undone. See [File Trimming] for more information.

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Untrim Right Item} {
Selecting this item causes any right trims done to the current line's files to be undone. See [File Trimming] for more information.

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Copy Item} {
Selecting this item makes a copy of the currently selected line and puts it on the paste clipboard. For more information see [How to Cut, Copy, and Paste].

[Accelerator Key > Keyboard Accelerators]: <tt>control-c</tt> or a host dependent <em>Copy</em> key.

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Cut Item} {
Selecting this item removes the currently selected line from the graph and puts it on the paste clipboard. For more information see [How to Cut, Copy, and Paste].

[Accelerator Key > Keyboard Accelerators]: <tt>control-x</tt> or a host dependent <em>Cut</em> key.

This item is part of the [line menu > Chart Window Line Menu].
}
{Line Menu Delete Item} {
Selecting this item deletes the currently selected line. Once its deleted it can not be undeleted.

You can also delete a line by middle clicking the mouse on its [legend > Graph Legend] entry.

[Accelerator Key > Keyboard Accelerators]: <tt>Del</tt>

This item is part of the [line menu > Chart Window Line Menu].
}

{Display Scaling a Line} {
You usually want to change the scale of a line because it looks like a\
flat line due to another line with very large values. The easiest thing\
you can do is graph the line on the other y axis. This will cause the\
line to be scaled independently of lines on the other axis.
The next easiest thing is to use the [Line Menu <b>Compute Scale</b> Item]. This will\
compute a scale value for the current line that make it visable on the\
current graph. You can quickly undo this with the [Line Menu <b>Unscale</b> Item].
You can also manually change the scale using the up or down arrow\
by the [number entry > Chart Window Number Entry] in the upper right corner of a chart. First click\
on the [button > Chart Window Operator MenuButton] next the the number entry and pick <b>S</b> from the dropdown.\
Each click doubles or halves the scale.
You can also enter any scale you want by clicking on the existing value and\
changing it using the keyboard.
The default scale is one. Changing the\
scale just causes the line to be drawn differently, it does not modify\
the actual values of the data points.
}

{Value Scaling a Line} {
The data points of a line can all be multiplied (or divided) by a constant. This is done\
by adding (or subtracting) a constant value from every data point on the line.
To specify a multiplier constant select a line and then click on the [button > Chart Window Operator MenuButton] next\
to the the number entry in the upper right corner of a chart window. Pick <b>*</b>\
or <b>/</b> from the dropdown and then enter the constant into the [number entry > Chart Window Number Entry].\
Each click of the up or down arrow doubles or halves the constant.
Multiplier constants are always done after the data is filtered and\
before an offset constant and scale constant are applied.
Note that unlike a scale, which is for display purposes only, a multiplier\
actually changes the y values of the line's data points. A common use\
is to change the units of a line. For example kilobytes can be changed to\
bytes by multiplying by 1024.
}

{Offsetting a Line} {
The data points of a line can all be offset by a constant. This is done\
by adding (or subtracting) a constant value from every data point on the line.
To specify an offset constant select a line and then click on the [button > Chart Window Operator MenuButton] next\
to the the number entry in the upper right corner of a chart window. Pick <b>+</b>\
or <b>-</b> from the dropdown and then enter the constant into the [number entry > Chart Window Number Entry].\
Each click of the up or down arrow change the offset constant by one.
Offset constants are always done after a multiplier constant is applied\
and before a scale constant is applied.
Note that the normalization feature automatically computes the offset so if\
a line is normalized then a user supplied constant is ignored.
}

{Normalizing a Line} {
If a line is normalized then an offset is computed so that its\
minimum data point will have a value of zero.\
The normalization offset is recomputed any time the data for the line changes.
If a line is normalized then it can not be offset by a constant value\
other than the one computed by the normalization code. 
Normalization is ignored unless the filter is "none".
}

{Tear Off Menus} {
If you find yourself constantly going back to the same menu item time\
after time you may find turning the menu into a button box helpful.\
If the menu has a dashed line at its top this indicates that the menu\
can be torn off. Once you do this it will be a box of buttons in its own\
window. Now you can just click on these buttons. For a nested menu you\
keep using this can be a real win.
The only way to get rid of a torn off menu is the use your window manager's\
window close or kill operation.
}

{List Multiple Selection} {
Some list items allow more than one item in the list to be selected.
   * A single item can be selected by clicking on it.
   * Multiple disjoint items can be selected by holding the <tt>Control</tt>\
key down when clicking on the items.
   * Multiple contiguous items can be selected by holding the <tt>Shift</tt> key down\
or by drag selecting.
   * A selected item can be deselected by holding the <tt>Control</tt>\
key down and clicking on it.
}

{String Entry Editing} {
When entering a string the following  special editing operations are available:
   * <tt>Control-a</tt> or the <em>Home</em> moves the cursor to the beginning of the string. If the shift modifier is used with the <em>Home</em> key then the selection is also extended to the beginning.
   * <tt>Control-e</tt> or the <em>End</em> key moves the cursor to the end of the string. If the shift modifier is used with the <em>End</em> key then the selection is also extended to the end.
   * <tt>Control-b</tt> moves the cursor back one character.
   * <tt>Control-f</tt> moves the cursor forward one character.
   * <tt>Control-t</tt> reverses the order of the two characters to the left of the cursor.
   * <tt>Control-k</tt> deletes all the characters to the right of the cursor.
   * <tt>Control-d</tt> or the <em>Delete</em> key deletes a single character to the right of the cursor.
   * <tt>Meta-d</tt> deletes a single word to the right of the cursor.
   * <tt>Control-/</tt> selects all the text.
   * <tt>Control-\</tt> clears any selection.
   * <tt>Control-h</tt> or the <em>Backspace</em> key deletes a single character to the left of the cursor if nothing is selected. Otherwise they delete the selection.
   * <tt>Meta-w</tt>, <tt>F16</tt>, or the <em>Copy</em> key copies the selection to the clipboard. Does nothing if no selection.
   * <tt>Control-w</tt>, <tt>F20</tt>, or the <em>Cut</em> key copies the selection to the clipboard and deletes the selection. Does nothing if no selection.
   * <tt>Control-y</tt>, <tt>F18</tt>, or the <em>Paste</em> key inserts the contents of the clipboard at the position of the cursor.
}

{Mouse Help} {
If you hold the mouse pointer over a widget explanatory text will appear\
in the [status box > Main Window Status Display].
}

{Bell Messages} {
If vsd ever beeps this indicates a warning or error.\
Look for the reason why in the [status box > Main Window Status Display].
Bell messages timeout after 10 seconds.
}

{Keyboard Selection Keys} {
Many menus, menu items, and buttons have a selection key. Selection keys are\
indicated by underlining a letter in the name of the control.\
Its used by holding down the <tt>Alt</tt> key and pressing the selection key.\
Using the selection key is equivalent to clicking the mouse on the control.
Keyboard selection keys are case-insensitive.
Keyboard selection keys only work if the control the selection key is bound\
to is visible on the screen and its window is selected.
}

{Keyboard Accelerators} {
Some menu items have keyboard accelerators.\
Accelerators allow you to quickly invoke a menu item.\
Accelerators are displayed next to the name of the menu item.\
Using the accelerator is equivalent to clicking the mouse on the item.
Keyboard accelerators are case-sensitive.
Keyboard accelerators work as long as the window the menu belongs to is selected.
}

{General Interface Features} {
   * [Tear Off Menus]
   * [List Multiple Selection]
   * [String Entry Editing]
   * [Mouse Help]
   * [Context Sensitive Help]
   * [Bell Messages]
   * [Keyboard Selection Keys]
   * [Keyboard Accelerators]
}

{Context Sensitive Help} {
A [help window > Help Window Features] containing context sensitive help can be created by pressing the <tt>F1</tt> key or your keyboard dependent <em>Help</em> key.
The help text will pertain to the window and widget that has keyboard focus.
}

{How to Load a Data File} {
[Type > String Entry Editing] in the full path in the [File: > Main Window File ComboBox] control and hit return.
The [Main Menu <b>Load Data File...</b> Item] can be used to browse for a file to load.
The command line can specify files to load when [vsd is started > How to Start VSD].
While a file is loading you can interrupt that load by clicking on\
the <b>Interrupt</b> button in the progress window. All the data already read\
will be available and the load can be continued later with the [File Menu <b>Update</b> Item].
You can also switch to a data file you already have loaded by dropping\
down the [File: > Main Window File ComboBox] control's list and selecting it.
You can get some information about a loaded data file with the [File Menu <b>Info...</b> Item].
For more information related to loaded files see [Controlling the Enabled Files].
}

{How to Update the View of a Data File} {
The [File Menu <b>Update</b> Item] will reread the current data file if it has\
changed since the last time vsd read it. It can also be used to continue\
the loading of a data file that was interrupted.\
Any charts displaying data from that file will also be updated.
If the [File Menu <b>Auto Update</b> Item] is turned on then vsd will keep doing the update\
operation everytime the file changes. The auto update interval is based\
on the sample interval of the data file.
}

{How to Create a Data File} {
Data files are created by a [statmonitor]. You can run the <tt>statmonitor</tt> command directly\
from the command line or you can use the [Main Menu <b>Monitor...</b> Item].
The [Monitor Window] will show you all the statistic sources on the local machine\
that you can monitor. Click on the sources you want stats for, adjust\
any of the startup parameters, and then click on Start.\
Vsd will automatically load the data file once it has some samples in it.
When you are done click on Stop. Vsd will shutdown any monitors it started\
when you exit vsd.
}

{How to Compare Files} {
In many cases vsd is used to compare multiple runs of the same load under\
different configurations or versions of the product.\
The following features facilitate comparsion of files:
   * Turn off the [Main Menu <b>Single File Mode</b> Item] so that more than one file can be loaded.
   * Turn on the [Main Menu <b>Combine</b> Item] and turn off the [Main Menu <b>Combine Across Files</b> Item]. This way\
you select a large group of object instances and get a line for each file\
being compared.
   * Turn off the [Main Menu <b>Absolute TimeStamps</b> Item] so that vsd will act as if each data\
run started at the same time.

Many data runs have a startup period at the beginning and a shutdown period at\
the end which are usually misleading for comparison purposes. To get rid\
of these do the following:
   * Chart a good representative line from each file.
   * Then for each line use the [Line Menu <b>Trim Left</b> Item] to get rid of all the data from the\
file's startup period and the [Line Menu <b>Trim Right</b> Item] to get rid of all the data from the\
file's shutdown period.
See [File Trimming] for more information.

If you want to compute the difference between two data runs then try this:
   * Chart a line from each data run's file.
   * Then select one of the lines and pick the [Line Menu <b>Diff Lines</b> Item] and\
then select the other line.
The result will be a third line whose values\
are the difference between the two original lines.\
See [Line Arithmetic] for more information.
}
 
{How to Merge Files} {
In some cases you may have multiple data files that you want to treat as\
a single file. If the files are in chronological order and have data for the same processes then you can simply concatenate them together into a single file. Just do it in the correct order. If they are compressed then you need to uncompress them before they can be concatenated.

A better way of concatenating a bunch of chronological files is to use vsd's append features. It can be done when vsd is started with the [-a > append load command line switch] switch. It can also be done interactively with the [Append Data File... > File Menu Append Data File... Item] menu item.

Another way is to use the external <tt>statmerge</tt> tool which reads multiple files a writes all their data to a single new file. Its best to use <tt>statmerge</tt> when you have multiple files with samples that need to be woven together because they took place at the same time on different machines.

The following features facilitate merging of files without using any of the above techniques:
   * Turn off the [Main Menu <b>Single File Mode</b> Item] so that more than one file can be loaded.
   * Turn on the [Main Menu <b>Combine Across Files</b> Item] so that when a combined line is created\
it will combine all the selected instances into a single line.
   * Turn on the [Main Menu <b>Absolute TimeStamps</b> Item] so that vsd will show the actual times\
each data sample was taken in each file.
}
{Statmonitor Output Format} {
Files written by [statmonitor] have a simple text format. Vsd allows the files to be compressed using the standard gzip format.
Vsd also allows files to be concatenated. You should only concatenate files which do not overlap in time and they should be ordered by time when concatenated.

The first line of the file must be of the form:
   * <tt>STATMON "</tt><em>digits</em><tt>"</tt>
where <em>digits</em> is one or more digits. This number represents the format version used in writing the rest of the file. The following describes version <b>2</b> which is used by the current statmonitor and vsd.

A <em>propertyDefinition</em> has the form:
   * <em>propertyName</em><tt> = "</tt><em>propertyValue</em><tt>"</tt>
where <em>propertyName</em> is a name and <em>propertyValue</em> is a string.
The next four lines are <em>propertyDefinitions</em> with these names:
   1 <tt>Platform</tt>  the value describes the operating system that the file was generated on.
   1 <tt>GemStoneVersion</tt>  the value describes the version of statmonitor's product.
   1 <tt>Machine</tt>  the value describes specific details about the machine the file was generated on.
   1 <tt>Time</tt>  the value describes the time, including timezone, that the first sample was written.

The next item in the format is a definition of the instance types used. The form is:
   * <tt>StatTypes = &#91;</tt><em>typeList</em><tt>]</tt>
where a <em>typeList</em> is zero or more comma seperated <em>typeDefinitions</em>. A <em>typeDefinition</em> has the form:
   * <em>typeName</em><tt> ( </tt><em>statNames</em><tt> ) </tt><em>typeId</em>
where <em>typeName</em> is the name of the type, <em>typeId</em> is a number used to identity this type, and <em>statNames</em> is five or more names representing the type's statistics. These names define what the fields in each instance snapshot (see the following) is. The first five <em>statNames</em> must always be:
   1 <tt>StatTypeNum</tt>  the numeric id of the snapshot's type
   1 <tt>Time</tt>  the time the snapshot was taken
   1 <tt>ProcessName</tt>  a string describing the snapshot's instance
   1 <tt>ProcessId</tt>  a number describing the process associated with the snapshot's instance. Zero if no associated process.
   1 <tt>SessionId</tt>  a number uniquely identifying the snapshot's instance. Zero if not applicable.

The next line has the form:
   * <tt>%%%%Generated by the statistics monitor</tt>
The next line has the form:
   * <tt>ENDHEADER</tt>
The next line is a blank line.
After this each line is an instance snapshot. Each instance snapshot is a list of whitespace seperated strings. A string must be provided for each of the snapshot's type's statNames. Most of the strings are unsigned numbers.
}
{How to Start VSD} {
Vsd can be started with one or more command line arguments. Unless the argument is a switch its expected to be the name of a [statmonitor] output file to load.
!Switches
   * [-a       > append load command line switch]
   * [-b color > set master background color]
   * [-n       > normal load command line switch]
   * [-u       > update command line switch]
}
{append load command line switch} {
The <tt>-a</tt> command line switch causes any file loaded from the command line to be concatenated together. This is done by loading the first one after the <tt>-a</tt> normally and then [appending > File Menu Append Data File... Item] the rest of the files to it. Only files up to the next [-n > normal load command line switch] switch will be appended.
}
{set master background color} {
The <tt>-b color</tt> command line switch causes the master background color to be set to color.  The color may be specified by name (e.g.: white) or by RGB value (e.g.: #d3d3ff).  The master background color may also be set in the environment variable <tt>VSD_MASTER_BG_COLOR</tt>.  The following web page shows a complete list of colors accepted by VSD: <tt><u>http://www.tcl.tk/man/tcl8.4/TkCmd/colors.htm</u></tt>
}
{normal load command line switch} {
The <tt>-n</tt> command line switch causes any file loaded from the command line to be loaded normally. It turns off and previous [-a > append load command line switch] switch.
}
{update command line switch} {
The <tt>-u</tt> command line switch causes the previously loaded file to have [auto update > File Menu Auto Update Item] turned on.
}
{How to Select} {
Statistics are kept for a fixed number of [instances > Instance Definition]. The [types > Instance Type Definition] of the instances are defined by the data file but in most cases the well known types are used.

To graph a line you need to select the instances and statistic name of interest. The following links tell you how to control what instances and statistics will be available to select and how to do the actual selection.
   * [Controlling the Enabled Files]
   * [Controlling the Listed Object Instances]
   * [Controlling the Listed Statistic Names]
   * [How to Select Object Instances]
   * [How to Select Statistics]
}
 
{Controlling the Enabled Files} {
The main window will only let you see object instances from enabled files.\
Before a file can be enabled it first must be loaded.
If the [Main Menu <b>Single File Mode</b> Item] is checked then only one loaded file can be\
enabled at a time. In this mode each time a file is loaded it will enabled\
and the previous file disabled. If an already loaded file is picked from\
the [File: > Main Window File ComboBox] control then it becomes the enabled file.
If the [Main Menu <b>Single File Mode</b> Item] is unchecked then more than one loaded file can be\
enabled. Object instances for all the enabled files will be shown in the\
main window. The [File: > Main Window File ComboBox] control will show the current selected loaded file.\
The [Main Window File Menu] item's operate on this file. Each file can be\
explicitly enabled or disabled with the [File Menu <b>Enabled</b> Item].
}
 
{Controlling the Listed Object Instances} {
The order the instances are listed on can be controlled by clicking on\
the column header. The primary sort key will be the clicked on column.\
Click on the same column again to reverse the order.
If the [Main Menu <b>Single File Mode</b> Item] is checked then only instances from the\
most currently selected file will be listed. Otherwise the instances\
from every enabled file are listed. You can control which files are\
enabled by selecting the file with the [File: > Main Window File ComboBox] control and\
then using the [File Menu <b>Enabled</b> Item].
}
 
{Controlling the Listed Statistic Names} {
The statistics list will only contain the name of statistics that\
all of the selected instances have in common. If no instances are\
selected then all known statistics are listed.
If the [Main Menu <b>No Flatlines</b> Item] is unchecked then statistics whose values\
are all zero have names show in a light font.\
Otherwise these statistic names are not listed.
The [Main Menu <b>Statistic Level</b> SubMenu] lets you select what level of statistics\
are listed. Any statistics that belong to a level higher than the selected one\
will not be listed.
}
 
{How to Select Object Instances} {
If you are interested in just one instance select it by clicking on it.
If you are interested in all of the instances of a certain type then\
select them all. Only statistics the selected instances all have in common will be show.\
If the [Main Menu <b>Combine</b> Item] is checked then all the data for the selected instances\
will be added together when a line is created. Otherwise each instance\
will get its own line.\
If [Main Menu <b>Combine Across Files</b> Item] is checked then it will cause combine\
to ignore what file an instance is from. If its unchecked then only instances\
from the same file will be combined together.
To search for an instance enter <tt>control-s</tt>. A search window will popup\
in which you can type. Enter <tt>control-s</tt> or <tt>tab</tt> to find the next match.\
Enter <tt>return</tt> to get rid of the search window. If you enter a number then\
the search will be based on the process id field. Otherwise the name field\
is used.
Right clicking over the instance list gets a [popup menu > Instance List PopupMenu]. If you pick\
[Select > Instance List PopupMenu Select SubMenu] submenu you can then do one of the following:
   * The <b>Clear</b> item unselects all the instances.
   * The <b>All</b> item selects all the instances.
   * The <b>by Statistic</b> item will select all of the instances that support\
the currently selected statistics. This gives you an easy way to find\
what instances support a statistic you are interested in.
   * The <b>by Type</b> item will select instances whose type is the same as the\
type of a currently selected instance. So if you want all 'Sessions'\
selected just select one and then pick <b>by Type</b>.
}
 
{How to Select Statistics} {
Click on the statistic you want to select.
If you select [more than one > List Multiple Selection] statistic you get a line for each one.

To search for a statistic whose name starts with a known prefix simply\
type the letters of that prefix and the first statistic with that\
prefix will be shown.

To find a statistic whose name contains a known substring do a [search > List Search Control] by typing <tt>control-s</tt>.
}

{List Search Control} {
This control allows a list to be searched. The search always finds the next item in the list that has a substring containing the text being searched for. As text is typed in the search is done automatically. The control contains the text from the last search.

When doing an [instance > Main Window Instance Table] search if you just type in a number then only the <b>Pid</b> column is searched and vsd beeps when it finds a completely matching pid. Otherwise the search is done on the <b>Name</b> column. If you want to search for a number in the name column then you must also include a non-numeric prefix. For example to search for a session id prefix it with the <tt>-</tt> character.

!Bindings
   * [standard editing > String Entry Editing]
   * <tt>control-s</tt> or <tt>tab</tt> to find the next matching list element
   * <tt>control-r</tt> to find the previous matching list element
   * <tt>return</tt> or click somewhere else to terminate the search

The following controls support this control:
   * [Main Window Instance Table]
   * [Main Window Statistic List]
   * [Chart Window Statistic ComboBox]
   * [Statistic Window Name ComboBox]
}
 
{How to Get Statistic Information} {
If the [Main Menu <b>Show Statistic Info</b> Item] is checked then a\
[seperate window > Statistic Information Window]\
will be created that will be kept updated with information on the most\
currently selected statistic.
In the [statistic information window > Statistic Information Window] you can browse all the available statistics\
and modify the statistic's level and/or the statistic's default filter.\
Any modification will be saved when you exit vsd.
}
 
{How to Filter Statistics} {
The filters are: Default, None, PerSecond, PerSample, Smooth, and Aggregate.
<b>Default</b> gets you None if the statistic represents a snapshot of a value.\
It gets you PerSecond if the statistic represents a value that always increases.
<b>None</b> shows you the raw values for the statistic with no filtering at all.
<b>PerSample</b> shows you the difference between two consecutive samples\
of the statistic.
<b>PerSecond</b> is the same as PerSample except it divides the difference by the number\
of elapsed seconds between the two samples.
<b>Smooth</b> is like none except any values much larger or smaller than the average are smoothed out.
<b>Aggregate</b> shows you a running total of per sample deltas for the statistic.\
The running total is reset to zero when the current delta is zero or\
changes direction. For example if the last couple of delta where positive\
then a change in direction would be a delta with a negative value.
When a line is added to a chart the default filter is used.\
The default filter for a statistic can be redefined using the [Default Filter MenuButton].
Once the line is added you can change its filter using the [Chart Window Filter MenuButton].
}
 
{How to Create a New Chart} {
Select the [instances > How to Select Object Instances]\
and [statistics > How to Select Statistics]\
to display in the new chart and click on the\
[Main Window New Chart Button].
You can let VSD generate a name for the new chart or enter one yourself\
in the [Chart: > Main Window Chart ComboBox] control.
The new chart will be configured based on options found in the [Main Window Chart Menu].\
If you change these options they will be saved and used the next time\
you start vsd.

A chart window can be created with the following controls:
   * [Add Line > Main Window Add Line Button]
   * [New Chart > Main Window New Chart Button]
   * [Add To Chart > Main Chart Menu Add To Chart Item]
   * [New Template Chart > Template Menu New Template Chart SubMenu]

To learn more about what can be done with a chart see [Chart Window Features].
}
 
{How to Add a Line to an Existing Chart} {
Select the [instances > How to Select Object Instances]\
and [statistics > How to Select Statistics]\
to add and click on the [Main Window <b>Add Line</b> Button].\
The line will be added to the chart shown in the [Chart: > Main Window Chart ComboBox] control.
}
 
{How to Cut, Copy, and Paste} {
You can copy or cut the selected line from a chart.\
Once this is done it can be pasted once to a chart.\
This allows you to easily move lines from one chart to another and\
to create a copy of a line to modify without changing the orignal.
You can copy and paste the current object instance and statistic selection\
from the main window to a chart window. This allows for easier chart\
targeting in cases that you have a large number of charts.
A copy or cut puts an item on the clipboard and deletes any item that was\
already on the clipboard.
A paste causes the clipboard to be emptied.

!Keyboard Bindings
   * <b>Copy</b> is done with <tt>control-c</tt> or a host dependent <em>Copy</em> key.
   * <b>Cut</b> is done with <tt>control-x</tt> or a host dependent <em>Cut</em> key.
   * <b>Paste</b> is done with <tt>control-v</tt> or a host dependent <em>Paste</em> key.

!Related Menu Items
   * [copy selection > Main Menu Copy Selection Item]
   * [copy selected line > Line Menu Copy Item]
   * [cut selected line > Line Menu Cut Item]
   * [paste selection or line > Chart Menu Paste Item]
}
 
{How to Select a Line} {
Move the mouse onto the line you want to select. Once the line\
is highlighted click on it.
You can also select a line by clicking on it in the legend.
Deselect a line by clicking on it again.
}
 
{How to Get Information About a Location} {
Move the mouse in the graph itself.\
If the mouse gets close to a line it will be highlighted. Also if the\
mouse is close to an actual data point its X and Y values will be displayed.
}
 
{How to Delete a Line} {
Select the line and then use the [Line Menu <b>Delete</b> Item].
Or move the mouse over the line's [legend > Graph Legend] entry\
and click on the middle mouse button.
}
 
{How to Zoom} {
Zooming allows you see details in a particular area of a chart.\
It also removes some visual lossage that occurs when lots of samples\
are displayed on a finite sized chart. Multiple zoom levels are supported\
for each chart. Note that when a chart is zoomed data points that lie\
outside the zoom window will not be visible. Also the stats displayed for\
the selected line will exclude data points to the left or right of the zoom window.

A zoom in can be done in a number of ways.
<b>Time Zooms:</b> The easiest is to middle click the mouse in the area you want to\
see better. This only zooms the time (x) axis so it lets you easily focus\
on a point in time without any loss of value (y) axis in that time period.
<b>Box Zooms:</b> You can also zoom in using the [Chart Menu <b>Zoom In</b> Item].\
First start a zoom using the menu item.\
Then set the first point of the zoom by clicking on it with the left button.\
Now move the mouse to the other point and click again.\
A zoom can be cancelled by clicking the right mouse button.\
This zooms both the x and y axis so some data in the time period might\
not be visible on the graph.

You can adjust a zoom level by using the left or right arrow keys.\
This time shifts the zoom level by one sample. If you use the <tt>control</tt> key\
with the left or right arrow keys then the time shift is by however many\
time samples are in the zoom level.

To zoom out one level click the right mouse button over the graph or use
the [Chart Menu <b>Zoom Out</b> Item].
}
 
{How to Change a Line} {
First select the line. Then you can change its:
   * <b>statistic</b> using the [Chart Window Statistic ComboBox].
   * <b>filter</b> using the [Chart Window Filter MenuButton].
   * <b>data set</b> using [File Trimming].
   * <b>adder</b> using the [Chart Window Operator MenuButton] and the [Chart Window Number Entry]. See [Normalizing a Line] and [Offsetting a Line] for more information.
   * <b>muliplier</b> using the [Chart Window Operator MenuButton] and the [Chart Window Number Entry]. See [Value Scaling a Line] for more information.
   * <b>scale</b> using the [Chart Window Operator MenuButton] and the [Chart Window Number Entry]. See [Display Scaling a Line] for more information.
   * <b>display symbol</b> using the [Line Menu <b>Symbol</b> SubMenu].
   * <b>display axis</b> using the [Line Menu <b>Graph on Left Axis</b> Item].
}
 
{How to Compare Data} {
   * To see the difference between two points on the same line use the [Line Menu <b>Log Delta</b> Item].
   * To see the difference between any two points on a chart use the [Chart Menu <b>Compare Two Points</b> Item].
   * To see the difference between all the points on two lines use the [Line Menu <b>Diff Lines</b> Item].
}

{How to Customize a Chart} {
Many menu items exist in the [Chart Window Chart Menu] that allow the chart display\
to be customized. Feel free to play with these; they will only change\
the current chart.
}

{Help Links} {
Help links are show in blue and underlined.\
If you click on a link then the link will be followed\
to the new help topic which will be displayed in the current window.\
If you <tt>control</tt> click or right click on a link then the new help\
topic will be shown in a new help window.
}

{Help Window Features} {
Any number of help windows can exist.

!How to Use A Help Window
   * [General Interface Features]
   * [Help Links]

!Keyboard Bindings
   * <tt>control-b</tt> goes back to the previous help view.
   * <tt>control-f</tt> goes forward after a back.
   * <tt>control-s</tt> pops up a [search window > Help Search Control].

!Help Controls
   * <b>Back</b> goes back to the previous help topic
   * <b>Forward</b> returns to a help topic left by going back.
   * <b>Search...</b> pops up a [search window > Help Search Control].
   * <b>Dismiss</b> closes the help window.
}

{Help Search Control} {
This control allows the text of help topics to be searched. Type in the text you are interested in finding. You will hear a beep if the text can not be found in the current help topic. By default the search is done on the help topic in the current window. You can search all topics by clicking on the <b>All Topics</b> button.
Searches are case-insensitive.

!Bindings
   * [standard editing > String Entry Editing]
   * <tt>control-s</tt>, <tt>tab</tt>, or the <b>Next</b> button to find the next match in the current help topic.
   * <tt>control-r</tt> or the <b>Prev</b> button to find the previous match in the curreent help topic.
   * the <b>All Topics</b> button causes a search to be done on all help topics. The help window's contents will change to a results topic which is a list of links to all the topics that contain the text.
   * <tt>return</tt> or click somewhere else to terminate the search
}

{Font Window} {
This dialog window lets you pick a font its used by the following:
   * [Choose Chart Font... > Main Chart Menu Choose Chart Font... Item]
   * [Choose Text Font... > Help Menu Choose Text Font... Item]
Its a modal dialog so it needs to be closed before the rest of vsd will respond to the mouse.
!Menus
This dialogs menu are used to pick the font. Any font you pick will be show immediately with some sample text in this dialog. If you want to see it in an actual window use the <b>Apply</b> button.
   * [File > Font File Menu]
   * [Font > Font Menu]
   * [Size > Font Size Menu]
   * [Format > Font Format Menu]
!Buttons
   * <b>Ok</b> causes any font picked to be used and the dialog to be closed.
   * <b>Apply</b> causes the font picked to be used temporarily. This allows you to see what it looks like in an actual window and then change it again, accept it with the <b>Ok</b> button, or reject it with the <b>Cancel</b> button.
   * <b>Cancel</b> causes any changes made to be rejected and the dialog to be closed.
}
{Font File Menu} {
!Items
   * <b>Reset</b>: causes the dialog's font to go back to the one it started with.
   * <b>Apply</b>: causes the font picked to be used temporarily. This allows you to see what it looks like in an actual window and then change it again, accept it with the <b>Ok</b> button, or reject it with the <b>Cancel</b> button.
   * <b>OK</b>: causes any font picked to be used and the dialog to be closed.
   * <b>Cancel</b>: causes any changes made to be rejected and the dialog to be closed.
This menu is part of the [font dialog > Font Window].
}
{Font Menu} {
This menu allows a single font to be selected. It has an item for every font that vsd could find on your system.

This menu can be [torn off > Tear Off Menus].

This menu is part of the [font dialog > Font Window].
}
{Font Size Menu} {
This menu allows the size of the font to be selected. A number of predefined sizes are offered. If no of those do what you want then select <b>Other...</b> which causes the font dialog window to have a numeric entry field.

This menu can be [torn off > Tear Off Menus].

This menu is part of the [font dialog > Font Window].
}
{Font Format Menu} {
This menu allows you to select any number of the following font modifiers:
   * <b>Bold</b>: makes the font look darker.
   * <b>Italic</b>: makes the font look slanted.
   * <b>Underline</b>: draws a line under the font.
   * <b>Overstrike</b>: draws a line through the font.

This menu can be [torn off > Tear Off Menus].

This menu is part of the [font dialog > Font Window].
}

{Log Window} {
Vsd has at most a single log window. Information is written to it and it can be cut and paste from it to your favorite text editor. If you close the log window then any information written to it is deleted. 
The operations that write to the log window are:
   * [Log... button > File Info Log... Button]
   * [Log Info menu item > Line Menu Log Info Item]
   * [Log Delta menu item > Line Menu Log Delta Item]
   * [Compare Two Points menu item > Chart Menu Compare Two Points Item]
}
{File Information Window} {
This window is created/updated when the [file info... item > File Menu Info... Item] is selected. It shows the following information on the current file:
   * the product version of the [statmonitor] that generated the file
   * a description of the machine and operating system that [statmonitor] ran on when generating the file
   * the time that the first data sample in the file was taken and an estimate of the interval.

You can get even more information about the file by clicking on the [Log...button > File Info Log... Button].
You can get rid of this window by clicking on the <b>Dismiss</b> button.
}

{File Info Log... Button} {
Clicking on this button causes the following information to be [logged > Log Window]:
   * the absolute file name
   * the product version of the [statmonitor] that generated the file
   * a description of the machine and operating system that [statmonitor] ran on when generating the file
   * the time that the first data sample in the file was taken and an estimate of the interval.
   
This button is on the [File Information Window].
}

{Monitor Window} {
Vsd has at most one monitor window. It allows you to easily run a [statmonitor] whose output will be automatically loaded into vsd. Its created or brought to the front by selecting the [Monitor... > Main Menu Monitor... Item] item.
The main display in this window shows a list of valid statistic sources. You can select any one of these. For each source the following is shown:
   * <b>Cache Name</b>:  this is either the name of an existing cache on the local machine or <tt>none</tt> which allows you to collect operating system statistics only.
   * <b>StatMon</b>:  this will be <tt><none></tt> if this vsd does not have a [statmonitor] running on this source. Otherwise its the process id of the monitor. Each vsd can have at most one monitor per source.
   * <b>Version</b>:  if the source is a product's statistic cache then this is the version of that product. Otherwise its the version of the operating system.
   * <b>Creator</b>:  if the source is a product's statistic cache then this is the name of the user who started that product's servers. Otherwise its the host name of the machine.

![Controls > Statmonitor Option Controls]

!Buttons
   * <b>Refresh</b>:  updates the list of statistic sources
   * <b>Start</b>:  starts a [statmonitor] on the selected statistic source. This button is disabled until a valid statistic source is selected. The start will use the values of the [statmonitor options > Statmonitor Option Controls].
   * <b>Status</b>:  shows the status of a running [statmonitor]. This button is disabled until a statistic source with a running statmonitor is selected.
   * <b>Stop</b>:  stops a running [statmonitor]. This button is disabled until a statistic source with a running statmonitor is selected.
   * <b>Dismiss</b>:  closes the monitor window.
}
{Statmonitor Option Controls} {
The following controls both show how a running [statmonitor] is configured and how you want to configure one you are starting. When starting a statmonitor first set the options you desire then click on the <b>Start</b> button.
   * <b>StatMon Output:</b> shows the name of the running statmonitor's output file. If left blank when starting then vsd will generate a unique name. You can type in any file name you desire before starting.
   * <b>Sample Interval:</b> specifies the sampling interval in seconds.
   * <b>Write Interval:</b> tells statmonitor how long to buffer samples internally before flushing them to the output file. Setting this to zero causes the <b>Sample Interval</b> to be used.
   * <b>Level:</b>  tells statmonitor how many operating system statistics it should collect. If you look at the [operating system types > Instance Type Definition] each one documents what the level must be for it to get collected. The default level is one. If the level is zero then no operating system statistics will be collected. Increasing the level causes additional statistics and instance types to be collected. On Windows NT setting the level higher than two can causes an ever increasing number of [thread instances > NtThread Type] to be collected which vsd will not handle well so only collect at this level for short periods of time. On Solaris setting the level higher than three can cause statmonitor to consume a great deal more CPU so it should only be done if the [SystemPages Type] is really needed.
   * <b>AppStat Count:</b>  tells statmonitor how many shared counter statistics to collect from the shared cache. By default it doesn't collect any. If its told to collect one or more then you will see a single [AppStat Type] instance and it will have statistics named <tt>sharedCounter</tt><em>id</em> where <em>id</em> is a number starting at zero. The number of statistics it will have is determined by the <em>numAppStats</em> argument. By default the value of all shared counters is zero. You must instrument your code if you want change their values. The Java methods to use are <tt>initSharedCounter</tt> and <tt>incrementSharedCounter</tt> on the <tt>StatisticAccess</tt> interface in the <tt>gemstone.services</tt> package.
   * <b>Compress</b>  if checked causes the output file to be compressed saving a significant amount of disk space.
   * <b>Pids:</b>  given a list of process ids tells statmonitor to collect additional processes. For each process id given statmonitor will collect a [Process Type] instance.
   * <b>Sessions:</b> given a list of session ids causes statmonitor to only collect cache statistics for the specified [sessions > Session Type].
}

{Statistic Information Window} {
Vsd has at most one statistic information window. Its purpose is to display information on the most recently selected statistic. It can also be used to customize the default filter and the level of any statistic. Its created by checking the [Show Statistic Info > Main Menu Show Statistic Info Item] checkbox.

!Controls
   * [statistic name selector > Statistic Window Name ComboBox]
   * [Default Filter MenuButton]
   * [Level MenuButton]
   * [Statistic Help Button]
!Displays
   * <b>Kind:</b> shows what kind of statistic it is. It will be one of the following:
      * <b>counter</b>: a statistic whose value always increases
      * <b>svalue</b>: a statistic whose value is a signed 32 bit integer.
      * <b>uvalue</b>: a statistic whose value is an unsigned 32 bit integer.
      * <b>float</b>: a statistic whose value is a floating point number
   * <b>Types:</b> shows which [instance types > Instance Type Definition] are known to support this statistic. If none are known then <tt>unknown</tt> is shown. Until a file is loaded vsd has no idea of which types support a statistic.
   * <b>Statistic Description</b> show a textual description of the statistic.
   * <b>Units:</b> shows the units that the statistic's value represents. Some of the more common unit strings are:
      * <b>none</b>
      * <b>minutes</b>
      * <b>seconds</b>
      * <b>milliseconds</b>
      * <b>items</b>
      * <b>bytes</b>
      * <b>kilobytes</b>
      * <b>megabytes</b>
      * <b>pages</b>
      * <b>locks</b>
      * <b>frames</b>
      * <b>commit records</b>
      * <b>log records</b>
      * <b>objects</b>
      * <b>sessions</b>
      * <b>vms</b>
      * <b>messages</b>
      * <b>signals</b>
      * <b>symbols</b>
      * <b>methods</b>
      * <b>threads</b>
      * <b>packets</b>
      * <b>segments</b>
      * <b>connections</b>
      * <b>extents</b>
      * <b>processes</b>
      * <b>events</b>
      * <b>semaphores</b>
      * <b>mutexes</b>
      * <b>sections</b>
      * <b>%</b>:  the value is a percentage
      * <b>false</b> or <b>true</b>:  the value is 0 (false) or 1 (true). 
      * <b>priority</b>
      * <b>enumeration</b>:  the value is a fixed set of values each of which has a specific meaning.
      * <b>id</b>:  the value is just a numeric identifier.
      * <b>bits/sec</b>:  bits per second.
      * <b>ios/sec</b>:  input/output operations per second.
      * <b>operations</b>
      * <b>aborts</b>
      * <b>commits</b>
      * <b>reclaims</b>
      * <b>checkpoints</b>
      * <b>scavenges</b>
}
{Level MenuButton} {
Shows and sets the level of the current statistic. The level can be used to limit the number of statistics [shown > Main Menu Statistic Level SubMenu] by vsd. The level will be one of the following:
   * <b>common</b>  the most useful statistics.
   * <b>advanced</b>  statistic is only of interest to advanced users
   * <b>wizard</b>  statistic is meant for internal developers
If you change the level with this menu button then it will be remembered in [memory file > VSD Files].

This button is on the [statistic information window > Statistic Information Window].
}
{Statistic Help Button} {
Clicking on this button creates a [help window > Help Window Features] containing the topic that describes the current statistic.

This button is on the [statistic information window > Statistic Information Window].
}
{Default Filter MenuButton} {
Shows and sets the default filter of the current statistic. The default filter is the one that will be used when a line is created for this statistic. It can be any of the following:
   * <b>Default</b>
   * <b>None</b>
   * <b>PerSecond</b>
   * <b>PerSample</b>
   * <b>Smooth</b>
   * <b>Aggregate</b>
See [How to Filter Statistics] for a description of the various filters.

This button is on the [statistic information window > Statistic Information Window].
}
{Statistic Window Name ComboBox} {
This control displays the current statistic. It also will let you change it.
!Bindings
   * Clicking on a name with the <em>mouse</em> both selects it and causes it to become the current statistic.
   * The <em>down</em> arrow key selects the next statistic.
   * The <em>up</em> arrow key selects the previous statistic.
   * The <em>letter keys</em> select the next statistic whose first letter matches the key.
   * <tt>control-s</tt> starts a [search > List Search Control] which results in selecting a statistic.
   * <em>Return</em> causes the selected statistic to become the current statistic.
   * <em>Esc</em> cancels the change leaving the current statistic unchanged.

This control is on the [statistic information window > Statistic Information Window].
}
{Main Window Features} {
Vsd only has a single main window and it always exists. If this window\
is closed or killed then vsd will terminate.

!How to Use The Main Window
   * [General Interface Features]
   * [How to Load a Data File]
   * [How to Update the View of a Data File]
   * [How to Create a Data File]
   * [How to Compare Files]
   * [How to Merge Files]
   * [How to Select]
   * [Controlling the Enabled Files]
   * [Controlling the Listed Object Instances]
   * [Controlling the Listed Statistic Names]
   * [How to Select Object Instances]
   * [How to Select Statistics]
   * [How to Get Statistic Information]
   * [How to Create a New Chart]
   * [How to Add a Line to an Existing Chart]

!Main Menus
   * [Main > Main Window Main Menu]
   * [File > Main Window File Menu]
   * [Chart > Main Window Chart Menu]
   * [Template > Main Window Template Menu]
   * [Help > Main Window Help Menu]

!Main Controls
   * [File: > Main Window File ComboBox]
   * [Instance Table > Main Window Instance Table]
   * [Statistic List > Main Window Statistic List]
   * [Chart: > Main Window Chart ComboBox]
   * [Add Line > Main Window Add Line Button]
   * [New Chart > Main Window New Chart Button]
   * [Status Display > Main Window Status Display]
}

{Main Window Main Menu} {
!Items
   * [Load Data File... > Main Menu Load Data File... Item]
   * [Monitor... > Main Menu Monitor... Item]
   * [Change Directory... > Main Menu Change Directory... Item]
   * [Change Time Offset... > Main Menu Change Time Offset... Item]
   * [Copy Selection > Main Menu Copy Selection Item]
   * [Show Statistic Info > Main Menu Show Statistic Info Item]
   * [Combine > Main Menu Combine Item]
   * [Combine Across Files > Main Menu Combine Across Files Item]
   * [No Flatlines > Main Menu No Flatlines Item]
   * [Single File Mode > Main Menu Single File Mode Item]
   * [Absolute TimeStamps > Main Menu Absolute TimeStamps Item]
   * [Copy Referenced Lines > Main Menu Copy Referenced Lines Item]
   * [Statistic Level > Main Menu Statistic Level SubMenu]
   * [Dump Statistic Info > Main Menu Dump Statistic Info Item]
   * [Confirm Exit > Main Menu Confirm Exit Item]
   * [Exit > Main Menu Exit Item]
   * [Trace API Calls > Main Menu Trace API Calls Item]
   * [ForceError > Main Menu ForceError Item]
   * [Restart > Main Menu Restart Item]
   * [Debug > Main Menu Debug Item]

[Selection Key > Keyboard Selection Keys]: <tt>Alt-m</tt>

This menu is on the [main window > Main Window Features].
}

{Main Menu Load Data File... Item} {
Pops up file selection dialog which can be used to pick the data file to load.
See [How to Load a Data File] for more information.

[Selection Key > Keyboard Selection Keys]: <tt>Alt-l</tt>

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Monitor... Item} {
Pops up the [Monitor Window].
See [How to Create a Data File] for more information.

[Accelerator Key > Keyboard Accelerators]: <tt>control-m</tt>

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Change Directory... Item} {
Pops up a dialog that asks for the directory VSD should use as its working directory. Initially this is the directory VSD was started from but it can be changed using this item.
The operations that use the VSD working directory are:
   * [Chart Menu Print Item]
   * [Chart Menu Snapshot Item]

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Change Time Offset... Item} {
Pops up a spinbox that allows the time offset to be altered.  The time offset represents a value (in hours) that is added to all timestamps in all stat files loaded by VSD.  The default value is zero and the valid range runs from -23 to +23 hours.  Time Offset settings are not saved and the value will be reset to zero each time VSD is started.

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Copy Selection Item} {
Copies the currently selected [instances > How to Select Object Instances] and [statistics > How to Select Statistics] to the clipboard.
See [How to Cut, Copy, and Paste] for more information.

[Accelerator Key > Keyboard Accelerators]: <tt>control-c</tt>

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Show Statistic Info Item} {
Controls whether the [statistic information window > Statistic Information Window] is displayed.
See [How to Get Statistic Information] for more information.

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Combine Item} {
Controls what is done with a [multiple > List Multiple Selection] [instance > How to Select Object Instances] selection when a line is [created > How to Add a Line to an Existing Chart].
If this item is checked then all the data for the selected instances\
will be added together into a single line. Otherwise a line is created for each  instance.

The [Combine Across Files > Main Menu Combine Across Files Item] item modifies how many of the selected instances are combined. 

This can also be done using the [Instance List PopupMenu <b>Combine</b> Item].

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Combine Across Files Item} {
Controls what is done with a [multiple > List Multiple Selection] [instance > How to Select Object Instances] selection when a line is [created > How to Add a Line to an Existing Chart].
If this item is checked then when a [combine > Main Menu Combine Item] is done all the instances are combined into a single line.\
Otherwise instances are only combined if they are from the same file. So you end up with a line for each selected file.

This can also be done using the [Instance List PopupMenu <b>Combine Across Files</b> Item].

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu No Flatlines Item} {
If checked then:
   * the names of statistics with all zero raw values for the selected instances will not be displayed.
   * lines will not be created if all their filtered values are zero. A [bell message > Bell Messages] will be displayed if this causes no lines to be created. Note that this option is ignored when creating a line using [line arithmetic > Line Arithmetic].

If unchecked then:
   * the names of statistics with all zero raw values for the selected instances will be displayed in a faint font.

See [Controlling the Listed Statistic Names] for more information.

This can also be done using the [Instance List PopupMenu <b>No Flatlines</b> Item].

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Single File Mode Item} {
In general you want to check this item if you want to work with more than one file at a time. See the following for examples:
   * [How to Compare Files]
   * [How to Merge Files]

If checked then:
   * only one loaded file can be [enabled > Controlling the Enabled Files] at a time.

If unchecked then:
   * more than one loaded file can be [enabled > Controlling the Enabled Files].

See the following for more information:
   * [Controlling the Enabled Files]
   * [Controlling the Listed Object Instances]
   * [Main Window File ComboBox]

This can also be done using the [Instance List PopupMenu <b>Single File Mode</b> Item].

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Absolute TimeStamps Item} {
If checked then:
   * Created lines will use absolute timestamps which can be useful when [merging > How to Merge Files] files.

If unchecked then:
   * Created lines will use relative timestamps which can be useful when [comparing > How to Compare Files] files.

Once a line is created its timestamps can not be changed. If you want to change them just set this item and recreate the line.

Absolute and relative timestamps have different display formats. For more on this see [Chart Menu Time Format SubMenu].

This can also be done using the [Instance List PopupMenu <b>Absolute TimeStamps</b> Item].

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Copy Referenced Lines Item} {
If checked then:
   * copies of the source lines are made when [line arithmetic > Line Arithmetic] is done. This prevents subsequent changes to the sources lines effecting the result line.

If unchecked then:
   * references of the source lines are used when [line arithmetic > Line Arithmetic] is done. This allows subsequent changes to the sources lines to also change the result line.

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Statistic Level SubMenu} {
This submenu lets you select what level of statistics\
are listed. Any statistics that belong to a level higher than the selected one\
will not be listed.

Each statistic name belongs to one of three levels. You can customize the level by using the [Level MenuButton] on the [Statistic Information Window].

!Items
   * [Common Statistics Only > Common Statistics Only Item]
   * [Advanced & Common Statistics > Advanced & Common Statistics Item]
   * [All Statistics > All Statistics Item]

See [Controlling the Listed Statistic Names] for more information.

This item is part of the [main menu > Main Window Main Menu].
}

{Common Statistics Only Item} {
Causes only those statistics whose level is <em>common</em> to be shown in statistic lists.

This item is part of the [statistic level submenu > Main Menu Statistic Level SubMenu].
}

{Advanced & Common Statistics Item} {
Causes only those statistics whose level is <em>common</em> or <em>advanced</em> to be shown in statistic lists.

This item is part of the [statistic level submenu > Main Menu Statistic Level SubMenu].
}

{All Statistics Item} {
Causes all statistics to be shown in statistic lists.

This item is part of the [statistic level submenu > Main Menu Statistic Level SubMenu].
}

{Main Menu Dump Statistic Info Item} {
Causes information on all known statistics to be dumped to a log window.

This item will only appear if vsd is run in [Wizard Mode].
This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Confirm Exit Item} {
If checked then:
   * vsd will ask for confirmation before it completes an [exit > Main Menu Exit Item] operation.

If unchecked then:
    * vsd will perform an [exit > Main Menu Exit Item] operation without asking the user for confirmation.

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Exit Item} {
Causes vsd to terminate. Before terminating vsd will:
   * confirm with the user that the exit was intended if the [Main Menu Confirm Exit Item] is checked.
   * kill off any monitors left running. See [Monitor Window] for more information.
   * writes the <u><tt>~/.vsdrc</tt></u> <em>memory file</em>. See [VSD Files] for more information.

If the window manager closes the main window then these same actions are taken. If you want to exit vsd without performing any of these actions then kill the vsd process.

This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Trace API Calls Item} {
If checked then:
   * any call by vsd to its lower level C APIs will result in a trace message written to its stderr. This is intended to help debug crashes that are hard to reproduce.

If unchecked then:
   * API calls are not traced.

This item will only appear if vsd is run in [Wizard Mode].
This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu ForceError Item} {
Picking this item forces an error. This allows vsd developers to make sure the error catching logic is functioning correctly.

This item will only appear if vsd is run in [Wizard Mode].
This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Restart Item} {
Picking this item causes vsd to reread its [Tcl > Tcl Language] [source file > VSD Files]. This allows vsd developers to make changes to vsd and then apply the changes without exiting and restarting vsd.

This item will only appear if vsd is run in [Wizard Mode].
This item is part of the [main menu > Main Window Main Menu].
}

{Main Menu Debug Item} {
Picking this item causes vsd to source "tkcon.tcl" from the same directory the ".vsdrc" is located in. In a vsd developers environment "tkcon.tcl" is a debugger that allows inspection of vsd's internal state.

This item will only appear if vsd is run in [Wizard Mode].
This item is part of the [main menu > Main Window Main Menu].
}

{Wizard Mode} {
Wizard mode enables certain advanced vsd features intended for vsd developers.

Wizard mode can be enabled either of the following:
   * Setting the <b>VSD_WIZARD</b> enviroment variable in the environment that starts vsd.
   * Setting the Tcl variable <b>vsd(wizard)</b> in <u><tt>~/.vsdconfig</tt></u>. See [VSD Files] for more information.
}

{Main Window File Menu} {
All of the items on this menu operate on the [<em>current file</em> > Main Window File ComboBox].
If no [<em>current file</em> > Main Window File ComboBox] exists then all the items will be disabled.

!Items
   * [Append Data File... > File Menu Append Data File... Item]
   * [Info... > File Menu Info... Item]
   * [Update > File Menu Update Item]
   * [Update All > File Menu Update All Item]
   * [Auto Update > File Menu Auto Update Item]
   * [Enabled > File Menu Enabled Item]
   * [Untrim Left > File Menu Untrim Left Item]
   * [Untrim Right > File Menu Untrim Right Item]
   * [Dump > File Menu Dump Item]

[Selection Key > Keyboard Selection Keys]: <tt>Alt-f</tt>

This menu is on the [main window > Main Window Features].
}

{File Menu Append Data File... Item} {
Pops up file selection dialog which can be used to pick a data file to append to the currently loaded file. This allows you to easily concatenate multiple physical files. Data will no longer be read from the current file location. Instead it will only be read from the new appended location. You should only append files that are newer than the current data.
This operation will fail if the current file load has been interrupted. You need to do an [update > File Menu Update Item] to finish the load before an append can be done.
See [How to Load a Data File] for more information.

This item is part of the [file menu > Main Window File Menu].
}

{File Menu Info... Item} {
Causes the [File Information Window] to be loaded with information on the [<em>current file</em> > Main Window File ComboBox].

This item is part of the [file menu > Main Window File Menu].
}

{File Menu Update All Item} {
Causes any data not already read from any [enabled > Controlling the Enabled Files] file to be read now. This can be used on files that [statmonitor] is still writing data to or on files whose load was interrupted.

[Accelerator Key > Keyboard Accelerators]: <tt>control-U</tt>

This item is part of the [file menu > Main Window File Menu].
}

{File Menu Update Item} {
Causes any data not already read from the [<em>current file</em> > Main Window File ComboBox] to be read now. This can be used on files that [statmonitor] is still writing data to or on files whose load was interrupted.

[Accelerator Key > Keyboard Accelerators]: <tt>control-u</tt>

This item is part of the [file menu > Main Window File Menu].
}

{File Menu Auto Update Item} {
If checked causes an automatic update to be done on the [<em>current file</em> > Main Window File ComboBox] whenever it should have changed. The interval of the first couple of timestamps in a file are used to estimate when a file should have changed.

This item is part of the [file menu > Main Window File Menu].
}

{File Menu Enabled Item} {
This item is only useful in [multi-file mode > Main Menu Single File Mode Item]. Checking this item causes the [<em>current file</em> > Main Window File ComboBox] to be one of those whose instances are [displayed > Main Window Instance Table]. Unchecking this item causes vsd to act as if the [<em>current file</em> > Main Window File ComboBox] was never loaded.

This item is part of the [file menu > Main Window File Menu].
}

{File Menu Untrim Left Item} {
This item is only enabled if the [<em>current file</em> > Main Window File ComboBox] was trimmed left. Selecting it undoes all left trims to the file.
See [File Trimming] for more information.

This item is part of the [file menu > Main Window File Menu].
}

{File Menu Untrim Right Item} {
This item is only enabled if the [<em>current file</em> > Main Window File ComboBox] was trimmed right. Selecting it undoes all right trims to the file.
See [File Trimming] for more information.

This item is part of the [file menu > Main Window File Menu].
}

{File Menu Dump Item} {
Causes vsd to write to its stdout details in the internal data structures its using to contain the data read from the [<em>current file</em> > Main Window File ComboBox].

This item will only appear if vsd is run in [Wizard Mode].
This item is part of the [file menu > Main Window File Menu].
}

{Main Window Chart Menu} {
!Items
   * [Add To Chart > Main Chart Menu Add To Chart Item]
   * [New Chart... > Main Chart Menu New Chart... Item]
   * [Show Legend > Main Chart Menu Show Legend Item]
   * [Time Format > Main Chart Menu Time Format SubMenu]
   * [Default Line Style > Main Chart Menu Default Line Style SubMenu]
   * [Show Time Axis Title > Main Chart Menu Show Time Axis Title Item]
   * [Show Left Axis Title > Main Chart Menu Show Left Axis Title Item]
   * [Show Right Axis Title > Main Chart Menu Show Right Axis Title Item]
   * [Show Current Values > Main Chart Menu Show Current Values Item]
   * [Show Min and Max > Main Chart Menu Show Min and Max Item]
   * [Show Line Stats > Main Chart Menu Show Line Stats Item]
   * [Show CrossHairs > Main Chart Menu Show CrossHairs Item]
   * [Show Grid Lines > Main Chart Menu Show Grid Lines Item]
   * [Selected Line Color... > Main Chart Menu Selected Line Color... Item]
   * [Choose Chart Font... > Main Chart Menu Choose Chart Font... Item]
   * [Close All Charts > Main Chart Menu Close All Charts Item]

[Selection Key > Keyboard Selection Keys]: <tt>Alt-c</tt>

This menu can be [torn off > Tear Off Menus].

This menu is on the [main window > Main Window Features].
}

{Main Chart Menu Add To Chart Item} {
Does the same thing as the [Add Line > Main Window Add Line Button] button.
This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu New Chart... Item} {
Does the same thing as the [New Chart > Main Window New Chart Button] button.
This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Show Legend Item} {
This item determines if a new [chart window > Chart Window Features] will have  a [legend > Graph Legend] control.

The value its set to will be remembered by vsd in its [memory file > VSD Files].

Use [Chart Menu <b>Show Legend</b> Item] to change this item for a particular chart.

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Time Format SubMenu} {
This submenu determines the default time format for a new chart.

The value its set to will be remembered by vsd in its [memory file > VSD Files].

Use [Chart Menu <b>Time Format</b> SubMenu] to change this item for a particular chart.

[Selection Key > Keyboard Selection Keys]: <tt>Alt-t</tt>

This menu can be [torn off > Tear Off Menus].

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Default Line Style SubMenu} {
This submenu determines the default line style used when creating lines.

The value its set to will be remembered by vsd in its [memory file > VSD Files].

See [line styles > Line Menu Style SubMenu] to learn more.

This menu can be [torn off > Tear Off Menus].

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Show Time Axis Title Item} {
This item determines if a new [chart window > Chart Window Features] will display a title string under the graph's [X Axis].

The value its set to will be remembered by vsd in its [memory file > VSD Files].

Use [Chart Menu <b>Show Time Axis Title</b> Item] to change this item for a particular chart.

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Show Left Axis Title Item} {
This item determines if a new [chart window > Chart Window Features] will display a title string next to the graph's [Left Y Axis].

The value its set to will be remembered by vsd in its [memory file > VSD Files].

Use [Chart Menu <b>Show Left Axis Title</b> Item] to change this item for a particular chart.

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Show Right Axis Title Item} {
This item determines if a new [chart window > Chart Window Features] will display a title string next to the graph's [Right Y Axis].

The value its set to will be remembered by vsd in its [memory file > VSD Files].

Use [Chart Menu <b>Show Right Axis Title</b> Item] to change this item for a particular chart.

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Show Current Values Item} {
This item determines if a new [chart window > Chart Window Features] will have  [X: > Chart Window X: Display] and [Y: > Chart Window Y: Display] controls.

The value its set to will be remembered by vsd in its [memory file > VSD Files].

Use [Chart Menu <b>Show Current Values</b> Item] to change this item for a particular chart.

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Show Min and Max Item} {
This item determines if a new [chart window > Chart Window Features] will have  [Min: > Chart Window Min: Display] and [Max: > Chart Window Max: Display] controls.

The value its set to will be remembered by vsd in its [memory file > VSD Files].

Use [Chart Menu <b>Show Min and Max</b> Item] to change this item for a particular chart.

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Show Line Stats Item} {
This item determines if a new [chart window > Chart Window Features] will display [line statistics > Data Statistics] in the upper left corner of its [graph > Graph Display].

The value its set to will be remembered by vsd in its [memory file > VSD Files].

Use [Chart Menu <b>Show Line Stats</b> Item] to change this item for a particular chart.

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Show CrossHairs Item} {
This item determines if a new [chart window > Chart Window Features] will draw cross hair lines on its [graph > Graph Display].

The value its set to will be remembered by vsd in its [memory file > VSD Files].

Use [Chart Menu <b>Show CrossHairs</b> Item] to change this item for a particular chart.

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Show Grid Lines Item} {
This item determines if a new [chart window > Chart Window Features] will draw dotted grid lines on its [graph > Graph Display].

The value its set to will be remembered by vsd in its [memory file > VSD Files].

Use [Chart Menu <b>Show Grid Lines</b> Item] to change this item for a particular chart.

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Selected Line Color... Item} {
Selecting this item will cause a color chooser dialog window to popup.\
Use it to pick the color to use for the selected line.\
You will not be able to do anything else until you finish or cancel the color choice.\
Your choice will be recorded in the [memory file > VSD Files].

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Choose Chart Font... Item} {
Selecting this item will cause the [font chooser > Font Window] to pop up.\
Use it to pick the chart font. You will not be able to do anything else until\
you finish or cancel the font choice.\
Your choice will be recorded in the [memory file > VSD Files].

The chart font is used for most everything that displays text in a font window. The only exception are the menus.

Font changes will appear immediately in any existing chart. In some cases you need to reselect the active line and [unshow/show > Chart Menu Show Legend Item] the [legend > Graph Legend] to get the new font to display.

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Chart Menu Close All Charts Item} {
Selecting this item causes all the existing chart windows to no longer exist.

To close just a single chart window use the [Chart Menu <b>Close</b> Item].

This item is part of the [main chart menu > Main Window Chart Menu].
}

{Main Window Template Menu} {
!Items
   * [Reload Template File > Template Menu Reload Template File Item]
   * [New Template Chart > Template Menu New Template Chart SubMenu]
   * [Templates Use Selection > Template Menu Templates Use Selection Item]

[Selection Key > Keyboard Selection Keys]: <tt>Alt-t</tt>

This menu can be [torn off > Tear Off Menus].

This menu is on the [main window > Main Window Features].
}

{Template Menu Reload Template File Item} {
Causes the [template file > VSD Files] to be reloaded. Use this if you have edited the template file and want the changes to be used immediately.

[Selection Key > Keyboard Selection Keys]: <tt>Alt-r</tt>

This item is part of the [main template menu > Main Window Template Menu].
}

{Template Menu New Template Chart SubMenu} {
Each item on this submenu represents a template from the [template file > VSD Files]. Selecting an item from this submenu causes a [new chart > Chart Window Features] to be created. The [contents > Template Syntax] of the template [determines what lines > Template Expansion] will be added to the created chart.

Vsd has a set of [predefined templates > Predefined Templates]. Each one of these will show up as an item on this submenu. Also any [user defined templates > Chart Menu Save Template Item] will show up.

[Selection Key > Keyboard Selection Keys]: <tt>Alt-c</tt>

This menu can be [torn off > Tear Off Menus].

This item is part of the [main template menu > Main Window Template Menu].
}

{Predefined Templates} {
The following are template definitions that come with VSD. They are stored in the [template file > VSD Files] and can be used from the [New Template Chart > Template Menu New Template Chart SubMenu] menu or the [Add From Template > Chart Menu Add From Template SubMenu].
   * [CPU > CPU Template]
   * [CacheMix > CacheMix Template]
   * [CacheTooSmall > CacheTooSmall Template]
   * [CommitInfo > CommitInfo Template]
   * [EpochSweeps > EpochSweeps Template]
   * [Garbage > Garbage Template]
   * [PageServer > PageServer Template]
   * [SpaceFree > SpaceFree Template]

<b>NOTE:</b> If you get an updated VSD release the definitions of these templates may have changed and new definitions may exist. Your old [template file > VSD Files] will still contain the definitions from an older VSD release. The way to get the new definitions is to delete or rename you template file. This will cause VSD to write a new default template file. You can then edit it and copy any of your own template definitions to it.
}

{Template Menu Templates Use Selection Item} {
If unselected then the [selected instances > Main Window Instance Table] are ignored when a template is used.
If selected then the [selected instances > Main Window Instance Table] will be the only ones that match general patterns in the template.

This item is part of the [main template menu > Main Window Template Menu].
}

{Main Window Help Menu} {
!Items
   * [How to... > Help Menu How to... Item]
   * [Main Window... > Help Menu Main Window... Item]
   * [Chart Window... > Help Menu Chart Window... Item]
   * [All Topics... > Help Menu All Topics... Item]
   * [All Help Text... > Help Menu All Help Text... Item]
   * [Choose Text Font... > Help Menu Choose Text Font... Item]
   * [About VSD... > Help Menu About VSD... Item]

[Selection Key > Keyboard Selection Keys]: <tt>Alt-h</tt>

This menu is on the [main window > Main Window Features].
}

{Help Menu How to... Item} {
Selecting this item creates a [help window > Help Window Features] containing links to all the help topics that tell you how to do something.

This item is part of the [main chart menu > Main Window Help Menu].
}

{Help Menu Main Window... Item} {
Selecting this item creates a [help window > Help Window Features] containing the help topic that describes vsd's [main window > Main Window Features].

This item is part of the [main chart menu > Main Window Help Menu].
}

{Help Menu Chart Window... Item} {
Selecting this item creates a [help window > Help Window Features] containing the help topic that describes vsd's [chart windows > Chart Window Features].

This item is part of the [main chart menu > Main Window Help Menu].
}

{Help Menu All Topics... Item} {
Selecting this item creates a [help window > Help Window Features] containing links to all the help topics. The links are sorted alphabetically.

This item is part of the [main chart menu > Main Window Help Menu].
}

{Help Menu All Help Text... Item} {
Selecting this item creates a [help window > Help Window Features] containing the contents of all the help topics. The contents are sorted by topic name. Creation of this help window can take a long time.

This item is part of the [main chart menu > Main Window Help Menu].
}

{Help Menu Choose Text Font... Item} {
This item allows the font used by vsd to display help text to be customized.
Selecting it brings up a [font dialog > Font Window].

This item is part of the [main chart menu > Main Window Help Menu].
}

{Help Menu About VSD... Item} {
Selecting this item brings up a window that displays various information about vsd. This information includes:
   * version numbers
   * file locations
   * home page

This item is part of the [main chart menu > Main Window Help Menu].
}

{Main Window Add Line Button} {
Creates one or more lines from the selected [instances > How to Select Object Instances]\
and [statistics > How to Select Statistics] and then adds them to the current chart window. If a chart window does not exist then a new one will be created.

The current chart's name is displayed in the [Chart: > Main Window Chart ComboBox] control.

If a new chart window is created then its name can be entered in the [Chart: > Main Window Chart ComboBox] control before this operation is started. Otherwise a default name is used.

For details on how the selection is used to create lines see [Line Creation].

This operation can also be done by double clicking when selecting a\
[instance > How to Select Object Instances]\
or [statistic > How to Select Statistics].

[Accelerator Key > Keyboard Accelerators]: <tt>control-a</tt>
This control is on the [main window > Main Window Features].
}
{Line Creation} {
For a line to be created at least one [instance > How to Select Object Instances] and one [statistic > How to Select Statistics] must be selected.

If more than one instance is selected then vsd needs to decide how to combine them. See [combine > Main Menu Combine Item] and [combine across files > Main Menu Combine Across Files Item] for a description of how this is done.

If [no flatlines > Main Menu No Flatlines Item] is true, and you are not using [line arithmetic > Line Arithmetic], then the line will not be created if all its values are zero. 

The default filter for the statistic on the line is used when creating the line.

A unique color and dash style for the line is picked based on what lines the chart already contains.

!Operations That Create Lines
   * [New Chart > Main Window New Chart Button]
   * [Add Line > Main Window Add Line Button]
   * [copy & paste > How to Cut, Copy, and Paste]
   * [Add Lines > Line Menu Add Lines Item]
   * [Diff Lines > Line Menu Diff Lines Item]
   * [Divide Lines > Line Menu Divide Lines Item]
   * [New Template Chart > Template Menu New Template Chart SubMenu]
   * [Add From Template > Chart Menu Add From Template SubMenu]
}
{Main Window New Chart Button} {
Does the same thing as the [Add Line > Main Window Add Line Button] button with the following exceptions:
   * It will never use an existing chart.
   * An empty chart window is created if no lines are created. So this is the operation to use to get an empty chart that you plan to [paste > How to Cut, Copy, and Paste] a line to.

[Accelerator Key > Keyboard Accelerators]: <tt>control-n</tt>
This control is on the [main window > Main Window Features].
}

{Main Window File ComboBox} {
The file control has the following functions:
   * display name of current file
   * display names of all loaded files
   * display a history of files loaded in the past
   * change the current file
   * load a new file

!Drop Down List
The file control's drop down list contains three types of elements:
   * The first element is always <u><tt>Browse For File...</tt></u> which if selected will do the same thing as the [Main Menu <b>Load Data File...</b> Item].
   * The names of files loaded in the past are always at the bottom of the list. Vsd [remembers > VSD Files] the last ten loaded files. These entries are always displayed as full absolute path names. Selecting one will cause it to be loaded.
   * Currently loaded files are always in the middle of the list. They are displayed with the same [syntax > Loaded File Description Syntax] as that used for the <em>current file</em>. Selecting one causes it to become the <em>current file</em>.

!Current File
The <em>current file</em> is a loaded file whose [description > Loaded File Description Syntax] is displayed in the file control's string entry. It is the one that can be operated on by the [Main Window <b>File</b> Menu]. If [single file mode > Main Menu Single File Mode Item] is on then it is also the only one whose instances will be displayed.

!Loading a New File
See [How to Load a Data File].

This control is on the [main window > Main Window Features].
}

{Main Window Instance Table} {
This table lists all the [instances > Instance Definition] from each [enabled > Controlling the Enabled Files] [file > Main Window File ComboBox].

Its main purpose it to allow instances to be [selected > How to Select Object Instances] so that lines can be [created > Line Creation] for the selected instance's [statistics > Main Window Statistic List].

For each instance in the list the following items are displayed:
   * <b>Name</b>: a string of characters that somewhat uniquely identifies the instance.
   * <b>Type</b>: see [Instance Type Definition].
   * <b>Pid</b>: The id of the process associated with this instance. This item is optional.
   * <b>StartTime</b>: The time the very first sample was taken for this instance.
   * <b>File</b>: the [id > Loaded File Description Syntax] of the file the instance's samples where read from.
   * <b>Samples</b>: The number of samples taken so far for this instance. This can change if data is still being collected the file is [updated > How to Update the View of a Data File]. A green font is used to show that more samples are still possible.

!Sorting
The instance list is sorted. You can tell which column is the primary sort key by looking at the column headers. The one with an extra decoration drawn around its name is the primary sort key. If the decoration is raised then the sort order is increasing. If the decoration is sunken then the sort order is descreasing.
Click on a header to make it the primary sort key. Click on the same header to toggle its sort order.

!Selecting Instances
See [How to Select Object Instances].

!Bindings
   * <tt>control-s</tt> starts an instance [search > List Search Control].
   * <tt>right mouse button</tt> accesses the [popup menu > Instance List PopupMenu].
   * [List Multiple Selection]
   * <tt>double click</tt> on an item does an [add line operation > Main Window Add Line Button].

This control is on the [main window > Main Window Features].
}

{Main Window Statistic List} {
This control lists all the statistics for the selected [instances > Main Window Instance Table]. If no instances are selected then all known statistics will be shown. The statistics are sorted in alphabetic order.

See [How to Select Statistics] for more information on how to use this control.

!Bindings
   * <tt>control-s</tt> starts a statistic [search > List Search Control].
   * [List Multiple Selection]
   * <tt>double click</tt> on an item does an [add line operation > Main Window Add Line Button].

This control is on the [main window > Main Window Features].
}

{Main Window Status Display} {
This control, located at the bottom of the main window, is used to display all [messages > Bell Messages] and [mouse help > Mouse Help].
}

{Instance List PopupMenu} {
Most of the items on this menu can also be found the [Main Window <b>Main</b> Menu]. The unique item is [Select > Instance List PopupMenu Select SubMenu]. They are duplicated here for easy use while working with instances.

!Items
   * [Search... > Instance List PopupMenu Search... Item]
   * [Select > Instance List PopupMenu Select SubMenu]
   * [Combine > Instance List PopupMenu Combine Item]
   * [Combine Across Files > Instance List PopupMenu Combine Across Files Item]
   * [No Flatlines > Instance List PopupMenu No Flatlines Item]
   * [Single File Mode > Instance List PopupMenu Single File Mode Item]
   * [Absolute TimeStamps > Instance List PopupMenu Absolute TimeStamps Item]

This menu can be [torn off > Tear Off Menus].

This popmenu is on the [Main Window Instance Table] control.
}

{Instance List PopupMenu Search... Item} {
Starts an instance [search > List Search Control] operation.

[Accelerator Key > Keyboard Accelerators]: <tt>control-s</tt>
This item is part of the [instance list popup menu > Instance List PopupMenu].
}

{Instance List PopupMenu Select SubMenu} {
See [How to Select Object Instances] for more information.

!Items
   * <b>Clear</b>: unselects every instance in the list.
   * <b>by Statistic</b>: select every instance that support the currently selected statistics.
   * <b>by Type</b>: for every currently selected instance; select all other instances of the same type.
   * <b>All</b>: select every instance in the list.

This menu can be [torn off > Tear Off Menus].

This menu is part of the [instance list popup menu > Instance List PopupMenu].
}

{Instance List PopupMenu Combine Item} {
Does the same thing as the [Main Menu Combine Item].

This item is part of the [instance list popup menu > Instance List PopupMenu].
}

{Instance List PopupMenu Combine Across Files Item} {
Does the same thing as the [Main Menu Combine Across Files Item].

This item is part of the [instance list popup menu > Instance List PopupMenu].
}

{Instance List PopupMenu No Flatlines Item} {
Does the same thing as the [Main Menu No Flatlines Item].

This item is part of the [instance list popup menu > Instance List PopupMenu].
}

{Instance List PopupMenu Single File Mode Item} {
Does the same thing as the [Main Menu Single File Mode Item].

This item is part of the [instance list popup menu > Instance List PopupMenu].
}

{Instance List PopupMenu Absolute TimeStamps Item} {
Does the same thing as the [Main Menu Absolute TimeStamps Item].

This item is part of the [instance list popup menu > Instance List PopupMenu].
}

{Instance Definition} {
The term <b>instance</b> is used to refer to a logical identifiable entity which has associated with it a set of statistics. A finite number of data samples exist for each instance. Each sample is a snapshot of all the instances statistic values at a particular point in time.

An instance's identity is determined by the following properties:
   * a name
   * a [type > Instance Type Definition]
   * an optional process id
   * the file the instance's samples where read from
}

{Instance Type Definition} {
Each [instance > Instance Definition] has a type. Each type has:
   * a name
   * a version number
   * a set of statistic names

The type is identified by its name and version number. Vsd automatically generates version numbers when it finds two types with the same name but different static names. This only happens when vsd loads more than one file. The first type loaded by vsd is always version one. Vsd shows other version numbers as a suffix on the type name.

!Well Known Instance Types
[statmonitor] is the standard generator of vsd data files and it defines the following well known types in its output. They fall into two main categories:
   * <b>Cache Instance Types</b>
      * [Vm Type]
      * [Shrpc Type]
      * [Pgsvr Type]
      * [Stn Type]
      * [Extent Type]
      * [Session Type]
      * [Statmon Type]
      * [AppStat Type]
   * <b>Operating System Instance Types</b>
      * [Process Type]
      * [TCP Type]
      * [SolarisSystem Type]
      * [Disk Type]
      * [SimpleNetwork Type]
      * [ComplexNetwork Type]
      * [Partition Type]
      * [SystemPages Type]
      * [NtSystem Type]
      * [NtMemory Type]
      * [NtObjects Type]
      * [NtPagingFile Type]
      * [NtNetwork Type]
      * [NtLogicalDisk Type]
      * [NtThread Type]

If data files are generated with other tools they are free to define their own types.
}

{SAP} {
SAP stands for system agent process. Physically its a Java VM. Each stone has a primary SAP and can have any number of optional remote SAPs. SAPs are started and stopped when the stone is started and stopped. The SAP manages all communication with the stone. In vsd its represented by:
   * a [Vm > Vm Type] and whose name ends with <tt>sap</tt>
   * a [shared page cache monitor > Shrpc Type]
   * a [pageService > Pgsvr Type]
   * one or more [aioWriters > Pgsvr Type]
}

{Vm Type} {
Represents a Java virtual machine. This type has a great number of statistics.
They include:
   * OS [Process Type] statistics
   * statistics for vm internals
   * statistics for Java code that may be executed in this VM. Examples of these are ORB, EJB, OTS, and Activator statistics.

!Vm Type Versions
}

{Session Type} {
Represents a single GemStone session. Sessions are always associated with a single VM process but a VM can have more than one session.

!Session Type Versions
}

{Pgsvr Type} {
Represents two different kinds of threads that run in the [SAP] VM.
   * Each SAP has a single pgsvr thread named <u><tt>pageService</tt></u>. Its services the pages in the shared page cache frames. It removes pages that are no longer needed and preempts pages when frames are in high demand.
   * Each SAP can have one or more threads named <u><tt>aioWriter</tt><em>x</em></u>. These threads scan the pages in the shared page cache and writing dirty ones as fast as they can to the extents.

!Pgsvr Type Versions
}

{Extent Type} {
Represents a single [stone > Stn Type] extent file. Stones can have one or more extents. The statistics measure how much the extent is being used and how much of it is in use.

!Extent Type Versions
}

{Shrpc Type} {
Represents the shared page cache manager. Each [SAP] VM has a single instance of this type. The statistics measure how the frames in the shared cache are being used.
!Shrpc Type Versions
}

{Stn Type} {
Represents the stone service. This is a single process that each GemStone system has. In addition to the standard [process > Process Type] statistics, its statistics measure extent and tranlog usage and transaction performance.

!Stn Type Versions
}

{Statmon Type} {
Represents the [statmonitor] process that collected the data. The only statistic this type has, other than the standard [process > Process Type] ones, is the [TimeWritingStats Statistic].

!Statmon Type Versions
}

{AppStat Type} {
Represents the application statistics collected by [statmonitor]. Statmonitor can be told when it starts to collection a certain number of appstats by using the <tt>-n</tt> command line switch. These shared counter statistics will always be zero unless application code has been written to change their values.

!AppStat Type Versions
}

{Process Type} {
Represents a single operating system process. Many of the other types include the process type's statistics. If [statmonitor] is started from vsd a instance of this type will be collected for vsd.
Also each <tt>-P</tt> [statmonitor] command line argument will result in an instance of this type.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than zero.

!Process Type Versions
}

{SolarisSystem Type} {
Represents a single Solaris machine. These statistics are the best ones to look at first to see overall resource usage on a machine.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than zero.

!SolarisSystem Type Versions
}

{Solaris_x86_System Type} {
Represents a single Solaris machine on the x86_64 architecture. These statistics are the best ones to look at first to see overall resource usage on a machine.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than zero.

!Solaris_x86_System Type Versions
}


{NtSystem Type} {
Represents a single Windows NT machine. These statistics are the best ones to look at first to see overall resource usage on a machine.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than zero.

!NtSystem Type Versions
}
{NtMemory Type} {
Represents the memory management subsystem of a Windows NT machine. These statistics let you determine how much paging your machine is doing.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than zero.

!NtMemory Type Versions
}
{NtObjects Type} {
Represents the resource tracking subsystem of a Windows NT machine. These statistics are just counts of a number of system objects.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than zero.

!NtObjects Type Versions
}
{NtPagingFile Type} {
Represents a single Windows NT paging file. Paging files are used to provide virtual memory swap space. If it fills up you will start to get out of memory errors.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than one.

!NtPagingFile Type Versions
}
{NtNetwork Type} {
Represents a Windows NT network subsystem.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than one.

!NtNetwork Type Versions
}
{NtLogicalDisk Type} {
Represents a single formatted Windows NT file system. More than one of these can exist.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than one.

!NtLogicalDisk Type Versions
}
{NtThread Type} {
Represents a single Windows NT native thread. Each process can have one or more native threads. This type lets you see process like statistics for each thread. However a huge number of thread instances can exist so collecting at this level should only be done for short periods of time.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than two.

!NtThread Type Versions
}

{Disk Type} {
Represents a single operating system disk. Disks represent the physical device. They can be partioned into one or more [partitions > Partition Type].

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than one.

!Disk Type Versions
}

{TCP Type} {
Represents a machines TCP networking subsystem.

On Solaris only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than one.
On Windows NT only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than zero.

!TCP Type Versions
}

{SimpleNetwork Type} {
Represents a machines simple network adaptors. Typically this is the loopback adaptor. The loopback adapter is used when inter-process communication is done with sockets on the same machine.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than two.

!SimpleNetwork Type Versions
}

{ComplexNetwork Type} {
Represents a machines complex network adaptors. Typically this is any adaptor except for loopback.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than two.

!ComplexNetwork Type Versions
}

{Partition Type} {
Represents a single partition on an operating system disk. Each file system is usually on a single partition.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than two.

!Partition Type Versions
}

{SystemPages Type} {
Represents advanced Solaris memory management statistics. These statistics are expensive to collect and in most cases statistics on [SolarisSystem Type] are adequate.

Only collected by [statmonitor] if it started with a <tt>-s</tt> level greater than three.

!SystemPages Type Versions
}

{Loaded File Description Syntax} {
For loaded files vsd displays a short descriptive string to identify the file.
The exact syntax is <u><em>id</em><tt>. </tt><em>name os host version</em></u> where:
   * <em>id</em> is a unique number. Its used in the [instance table's > Main Window Instance Table] <b>File</b> column.
   * <em>name</em> is a trimmed form of the absolute file name. It will only be trimmed if the trimmed name differs from all other loaded file trimmed names.
   * <em>os</em> the operating system that the file's data was collected on.
   * <em>host</em> the host name of the machine the file's data was collected on.
   * <em>version</em> the version of the product the file's data was collected on.
}

{Main Window Chart ComboBox} {
The chart control has the following functions:
   * display name of current chart
   * display names of all existing charts
   * enter name for a new chart
   * pick the current chart

!Current Chart
The last [chart window > Chart Window Features] that was selected is the current chart. Its name is displayed in this control.
To change the current chart just click on that chart window or drop down the chart control's combobox and pick it from the list. The drop down list contains the names of all existing chart windows.

!Naming a New Chart
Any time a [chart window > Chart Window Features] is created it must be given an name. By default the name is <u><tt>Chart </tt><em>x</em></u> where <em>x</em> is a number. You can use the chart control to enter your own name by clicking on it and [typing > String Entry Editing] in the new name. After the name has been entered create the new chart and it should have the entered name.

This control is on the [main window > Main Window Features].
}

{Version History} {
Please visit the following web page for a history of VSD versions: http://gemtalksystems.com/products/vsd/history/

}

{File Trimming} {
Trimming data causes vsd to act as if that data does not exist.\
Each loaded file can have a two sequences of its data trimmed.
The <em>Left</em> sequence always starts with the file's first data sample.
The <em>Right</em> sequence always ends with the file's last data sample.
Trimming is always done with a single line even though it will cause the\
entire file to be trimmed. Using a line gives the trimmer a graphical\
display to pick the most meaningful trim point.
Trimming can be done more than once to a sequence making the sequence
larger each time.\
Untrimming totally reverses all trim operations on the sequence.

The menu items that support file trimming are:
   * Line [Trim Left > Line Menu Trim Left Item]
   * Line [Trim Right > Line Menu Trim Right Item]
   * Line [Untrim Left > Line Menu Untrim Left Item]
   * Line [Untrim Right > Line Menu Untrim Right Item]
   * File [Untrim Left > File Menu Untrim Left Item]
   * File [Untrim Right > File Menu Untrim Right Item]
}

{Line Arithmetic} {
Two source lines on the same chart can be used to produce a new result line.\
The values in the result line are the result of adding, subtracting, or\
dividing the values of the source lines.\
The menu items that support line arithmetic are:
   * [Add Lines > Line Menu Add Lines Item]
   * [Diff Lines > Line Menu Diff Lines Item]
   * [Divide Lines > Line Menu Divide Lines Item]

The resulting line will only have data in the time period the two original lines had in common. Line arithmetic can not be done on disjoint lines. You can [combine > Main Menu Combine Item] disjoint statistics which is much like adding lines.

If a [copy > Main Menu Copy Referenced Lines Item] of the source lines\
is made then subsequent changes to the sources lines will have no effect\
on the result line.

If the result line has a [reference > Main Menu Copy Referenced Lines Item]\
to the source lines then subsequent changes in the source lines will be\
propogated the the result line.
}
{Multiple Files} {
Vsd now has much better support for working with multiple files:
   * The [instance table > Main Window Instance Table] shows the file id the instance was loaded from. You can [control > Controlling the Enabled Files] which files instances will be displayed.
   * [Template expansion > Template Expansion] will create a chart for each file making it easy to compare files.
   * Some other options have been added allowing files to be [compared > How to Compare Files] and [merged > How to Merge Files].
}
{statmonitor} {
The statistic monitor is a process that periodically samples statistics and writes their values to a file. The source of the statistics can be a shared cache created by a [stone > Stn Type] or the operating system. For both sources they must reside on the machine the statistic monitor is running on. By default statmonitor will be monitoring both a shared cache and the operating system.

The executable to run to create a statistic monitor is <tt>statmonitor</tt>. Its located in the <tt>bin</tt> subdirectory. Its important to use the statmonitor executable that was distributed with the product whose shared cache you wish to monitor. If you don't then its likely your statmonitor will fail to start with a version mismatch error.

Statmonitor will keep running until its interrupted or its reached the limit set by <tt>-h</tt> or <tt>-t</tt>.

Statmonitor requires a single argument when you start it. That is the name of the [stone > Stn Type] whose cache statistics will be monitored. If you only want to monitor operating system statistics then use the string <tt>none</tt> as the stone name.

For a description of the format of the files written by statmonitor see [Statmonitor Output Format].

Statmonitor accepts a large number of optional switches after the required stone name. They fall into one of the following categories.

!Input Control Switches
   * <tt>-i</tt> <em>interval</em>:  specifies the sampling interval in seconds. The default is twenty seconds. The minimum is one second. Overrides any previous <tt>-i</tt> or <tt>-I</tt> switches.
   * <tt>-I</tt> <em>msInterval</em>:  specifies the sampling interval in milliseconds (thousandths of a second). The default is twenty seconds. The current minimum is 100 milliseconds. Subsecond sampling intervals cause an actual timestamp to not be written to the output file for each sample. Instead a simple counter is written and the analyzer running vsd needs to remember the actual interval used. Overrides any previous <tt>-i</tt> or <tt>-I</tt> switches.
   * <tt>-m</tt> <em>stoneHost</em>:  if the cache you will monitor is remote from the stone then in addition to the required stone name you must also specify the host the stone is running on.
   * <tt>-n</tt> <em>numAppStats</em>:  tells statmonitor how many shared counter statistics to collect from the shared cache. By default it doesn't collect any. If its told to collect one or more then you will see a single [AppStat Type] instance and it will have statistics named <tt>sharedCounter</tt><em>id</em> where <em>id</em> is a number starting at zero. The number of statistics it will have is determined by the <em>numAppStats</em> argument. By default the value of all shared counters is zero. You must instrument your code if you want change their values. The Java methods to use are <tt>initSharedCounter</tt> and <tt>incrementSharedCounter</tt> on the <tt>StatisticAccess</tt> interface in the <tt>gemstone.services</tt> package.
   * <tt>-p</tt> <em>sessionId</em>:  causes statmonitor to only collect cache statistics for the specified [sessions > Session Type]. This switch can be repeated if you want to monitor more than one session. By default statmonitor will collect cache statistics on all sessions. This switch exists for historical reasons. Its not clear if it serves any useful purpose.
   * <tt>-P</tt> <em>processId</em>: This switch can be repeated if you want to monitor more than one additional [process > Process Type]. By default statmonitor collects statistics for all the processes that have cache statistics. This switch lets you collect process statistics for processes that don't have cache statistics. For example your web server.
   * <tt>-s</tt> <em>level</em>:  tells statmonitor how many operating system statistics it should collect. If you look at the [operating system types > Instance Type Definition] each one documents what the level must be for it to get collected. The default level is one. If the level is zero then no operating system statistics will be collected. Increasing the level causes additional statistics and instance types to be collected. On Windows NT setting the level higher than two can causes an ever increasing number of [thread instances > NtThread Type] to be collected which vsd will not handle well so only collect at this level for short periods of time. On Solaris setting the level higher than three can cause statmonitor to consume a great deal more CPU so it should only be done if the [SystemPages Type] is really needed.
   * <tt>-v</tt> <em>vsdPid</em>: Used by vsd when it is starting statmonitor. This causes statmonitor to collect [process > Process Type] statistics automatically on the vsd that started it.

!Output Control Switches
   * <tt>-f</tt> <em>fileName</em>:  specifies the name of the file statmonitor will write its output to. If not specified defaults to <u><tt>statmon</tt><em>id</em><tt>.out</tt></u>. If you want statmonitor to write to its standard output, instead of a file, then use the string <tt>stdout</tt> as the <em>fileName</em> argument.
   * <tt>-z</tt>:  causes statmonitor's output file to be compressed. Vsd is able to read these files transparently. If you want to uncompress use the gunzip executable.
   * <tt>-r</tt>:  causes statmonitor to restart a new output file when the current one completes. The <tt>-h</tt> or <tt>-t</tt> switches control when a restart is done. The base name of each file is given a unique suffix. Note that the generated files can be concatenated together and treated by vsd as a single file.
   * <tt>-h</tt> <em>hours</em>: causes statmonitor to only write to its output file for the given number of hours. Once that time is up statmonitor exits or restarts a new file (see <tt>-r</tt>). By default statmonitor writes until its interrupted or killed.
   * <tt>-t</tt> <em>times</em>: causes statmonitor to only write to its output file the given number of samples. Once that limits has been reached statmonitor exits or restarts a new file (see <tt>-r</tt>). By default statmonitor writes until its interrupted or killed.
   * <tt>-u</tt> <em>seconds</em>: tells statmonitor how long to buffer samples internally before flushing them to the output file. By default it will buffer for 60 seconds. Setting this to zero causes the interval (<tt>-i</tt> or <tt>-I</tt>) value to be used.
}
{Template Expansion} {
A template is made up of a list of [<em>lineSpecs</em> > Template Syntax]. Each lineSpec can end up [creating > Line Creation] zero or more lines on a chart. If you want all the lines generated by the expansion to go to a single chart window then use [Add From Template > Chart Menu Add From Template SubMenu]. Otherwise a chart is created for each unique file in the selected instances.

!Operations that Expand Templates
   * [New Template Chart > Template Menu New Template Chart SubMenu]
   * [Add From Template > Chart Menu Add From Template SubMenu]
}
{Statistic Aliases} {
Statistic aliases can be added to the [config file > VSD Files].
A statistic alias causes vsd to always use an existing statistic definition when it sees an aliased name. Aliases can be used to map older non-existent names to an existing statistic.
For each alias you want to define add a line of the following form:
   * <tt>sl_stat -alias</tt> <em>oldname newname</em>
where <em>oldname</em> is the statistic name you want mapped to <em>newname</em>.
}
{Statistic Definitions} {
Statistic definitions can be added to the [config file > VSD Files].
Each statistic definition must have the following attributes defined:
   * <b>name:</b> Names the statistic. This attribute is required. Should be an alphanumeric string.
   * <b>kind:</b> See [Statistic Information Window]'s <b>Displays</b> section for a description. This attribute is optional and defaults to <tt>uvalue</tt>. Legal values are:
      * <tt>counter</tt>
      * <tt>uvalue</tt>
      * <tt>svalue</tt>
      * <tt>float</tt>
   * <b>level:</b> See [Level MenuButton] for a description. This attribute is optional and defaults to <tt>common</tt>. Legal values are:
      * <tt>common</tt>
      * <tt>advanced</tt>
      * <tt>wizard</tt>
   * <b>units:</b> Describes the units that the statistic's value represents. This attribute is optional and defaults to <tt>none</tt>. Can be any string. See [Statistic Information Window]'s <b>Displays</b> section for list of common unit strings. 
   * <b>isOSStat:</b> Use a true value to indicate that the statistic value is generated by the operating system. This attribute is optional and defaults to <tt>false</tt>. Must be a boolean value.
   * <b>filter:</b> See [Default Filter MenuButton] for a description. This attribute is optional and defaults to <tt>default</tt>. Legal values are:
      * <tt>default</tt>
      * <tt>none</tt>
      * <tt>persecond</tt>
      * <tt>persample</tt>
      * <tt>smooth</tt>
      * <tt>aggregate</tt>
   * <b>description:</b> Documents the statistic. This attribute is optional and defaults to an empty string. Can be any string. To start a new paragraph in the description use an end of line. When refering to another statistic in the description text use this form to make it a hyper-link:
      * <tt> &#91;</tt><em>SN</em><tt> > </tt><em>SN</em><tt> Statistic]</tt> where <em>SN</em> is the name of the other statistic. Note that if your description string is enclosed in quotes <tt>""</tt> instead of curly brackets <tt>{}</tt> then you will need to escape the first square bracket with a backslash <tt>\</tt>.
Any user defined statistics will override definitions shipped with vsd.
For each statistic you want to define add a line of this form:
   * <tt>set statdef(</tt><em>name</em><tt>) {</tt><em>type level units isOSStat filter description</em><tt>}</tt>
To leave an optional attribute empty use an empty pair of curly brackets <tt>{}</tt>.
}
{Template Syntax} {
The contents of the [template file > VSD Files] must be [tcl code > Tcl Language]. The code in this file should define templates. Each template definition consists of a <em>name</em> and a <em>templateSpec</em>. To define a template an element must be added to the Tcl array named <b>vsdtemplates</b> and the index of the element must be the templates <em>name</em>.

The standard format of a template definition is: <tt>set vsdtemplates(</tt><em>name</em><tt>) </tt><em>templateSpec</em>.

What follows is the syntax for <em>templateSpecs</em>.
Square brackets <tt>[[]</tt> are used in the syntax descriptions to designate\
an optional element.

A <em>list</em> starts with an open curly brace <b>{</b> and is terminated\
by a matching close curly brace <b>}</b>. Whitespace is use to seperate\
elements in a <em>list</em>. The curly braces are not required for single element lists.

A <em>templateSpec</em> is a <em>list</em> of <em>lineSpec</em>.
A <em>lineSpec</em> is either a <em>namesLineSpec</em>, a <em>simpleLineSpec</em> or an <em>operatorLineSpec</em>.
A <em>namesLineSpec</em> is a <em>list</em> in the following format:
   * <b>@</b> <em>nameList</em>
The <em>nameList</em> is a <em>list</em> of zero or more template names. A <em>namesLineSpec</em> is treated as the collection of all the named templates.

A <em>simpleLineSpec</em> is a <em>list</em> in the following format: 
   * <b>{</b><em>typeList namePattern stat scale filter axis</em> <tt>[[</tt><em>divider offset normalize</em><tt>] [[</tt><em>statFilter</em><tt>]</tt><b>}</b>
An <em>operatorLineSpec</em> is a <em>list</em> in the following format: 
   * <b>{</b><em>operator lineSpec1 lineSpec2 scale filter axis</em> <tt>[[</tt><em>divider offset normalize</em><tt>] [[</tt><em>statFilter</em><tt>]</tt><b>}</b>

The <em>typeList</em>, <em>namePattern</em>, and <em>stat</em> are used to select the data that will be plotted.
The <em>typeList</em> is a <em>list</em> of zero or more object type strings and/or file numbers.\
Examples of object type strings are Stn, Shrpc, Vm, Session, Extent and Pgsvr.\
Each type in the list will be selected.
File numbers can be used to limit the spec to the numbered file.
If no types are specified then all the types that support <em>stat</em> will be selected.
If no file numbers are specified then all files enabled will be selected.
An optional plus character <b>+</b> can be appended to the last type in the\
list. This will cause all of the instances that match this <em>lineSpec</em>\
to be [combined > Main Menu Combine Item].

The <em>namePattern</em> can be used to restrict which instances of the\
 types should be selected. It can be a simple name or a [pattern > Glob Style Pattern Syntax]. Use the pattern <b>*</b> if you don't care about the name.

The <em>stat</em> must be a valid statistic name for the given <em>typeList</em>.

The <em>operator</em> field must be one of the following strings:
   * <b>plus</b>
   * <b>diff</b>
   * <b>divide</b>

Both <em>lineSpec1</em> and <em>lineSpec2</em> are a <em>lineSpec</em>.\
The lines produced by these specs are combined together using the <em>operator</em>\
to produce the visible line. If one spec produces more lines than the\
other than the final line from the lessor spec is used repeatedly.

The <em>scale</em> must be a number. See [Display Scaling a Line] to learn what this number will do.

The <em>filter</em> must be one of the following strings:
  <b>none</b>, <b>persecond</b>, <b>persample</b>, <b>smooth</b>, or <b>aggregate</b>.
See [How to Filter Statistics] to learn what this string will do.

The <em>axis</em> must be the string <b>y</b> or <b>y2</b>.\
This [controls what Y axis > Line Menu Graph on Left Axis Item] the line will be graphed on

The <em>divider</em> must be a number. See [Value Scaling a Line]\
to learn what this number will do.

The <em>offset</em> must be a number. See [Offsetting a Line]\
to learn what this number will do.
The <em>offset</em> number is ignored if <em>normalize</em> is not zero.

The <em>normalize</em> must be the number zero or one.\
See [Normalizing a Line] to learn what this number will do.

!Statistic Filters
The optional <em>statFilter</em> is a <em>list</em> that lets you exclude lines\
based on their stat values. Its format is:
   <b>{</b><em>count min max mean stddev</em><b>}</b>
Each line produced by a template's lineSpec is checked against this filter before its added to the chart. Each line's values must pass each of the constraints imposed by the non-empty items in the filter.
Any statFilter item can be an empty string <b>{}</b>,
a single number, or a list of two numbers.

If an item is the empty string <b>{}</b> it is ignored.

If an item is a list of two numbers (i.e. <b>{36 100}</b>) then\
the first number must be less than the second number and\
if the stat is less than the first or greater than the second\
then it is excluded.

If an item is a number then it is used as follows:
   * If <em>count</em> >= 0 then any line with less samples than the filter is excluded.
   * If <em>count</em> < 0 then any line with more samples than the absolute value\
of the filter is excluded.
   * If <em>min</em> >= 0 then any line whose min is less than the filter is excluded.
   * If <em>min</em> < 0 then any line whose min is greater than the filter is excluded.
   * If <em>max</em> >= 0 then any line whose max is less than the filter is excluded.
   * If <em>max</em> < 0 then any line whose max is greater than the absolute value of the filter is excluded.
   * If <em>mean</em> >= 0 then any line whose mean is less than the filter is excluded.
   * If <em>mean</em> < 0 then any line whose mean is greater than the absolute value of the filter is excluded.
   * If <em>stddev</em> >= 0 then any line whose stddev is less than the filter is excluded.
   * If <em>stddev</em> < 0 then any line whose stddev is greater than the absolute value of the filter is excluded.

!Filter examples:
   * <tt>{100}</tt> only includes stats who have at least 100 samples.
   * <tt>{{} {} 100}</tt> only includes stats whose max is >= 100.
   * <tt>{{} 20 {} {} -5}</tt> only includes stats whose min >= 20\
and whose standard deviation is less than 5.
   * <tt>{{100 200} {} {-500} {120 240}}</tt> only includes stats who have\
at least 100 samples but no more than 200 samples\
and whose maximum value is less than 500\
and whose average value is between 120 and 240.
}
{Glob Style Pattern Syntax} {
   * <b>*</b> Matches any sequence of characters including a null string.
   * <b>?</b> Matches any single character.
   * <b>[[</b><em>chars</em><b>]</b> Matches any character in the set given by\
<em>chars</em>. If a sequence of the form <em>x</em><b>-</b><em>y</em> appears\
in <em>chars</em>, then any character between <em>x</em> and <em>y</em>,\
inclusive, will match.
   * <b>\</b><em>x</em> Matches the single character <em>x</em>.\
This provides a way of avoiding the special\
interpretation of the characters <b>*?[[]\</b> in the pattern.
}
}

#!Vector Operations
#<em>not yet documented</em>
#!Instance Operations
#<em>not yet documented</em>

############################# Start the program #########################
if {![info exists vsdIsRunning]} {
    global vsd
    set vsdIsRunning 1
    tix initstyle
    wm withdraw .
    set w .vsd
    toplevel $w  
    set vsd(version) "5.0.0"
    set vsd(svn_revision)  "36642"
    set vsd(svn_url) "https://svn.gemtalksystems.com/repos/smalltalk/server/vsd/trunk"
    set vsd(build_date) "Thu Jun 11 10:57:53 PDT 2015"

# Request 44952 - Make F12 a hot-key to find and show the main window.
    bind all <F12> {
      global vsd
      set w $vsd(w)
      focus $w
      raise $w
      wm deiconify $w
    }

# Bug 43692 - Close current sub-window with Alt-F4 key sequence
    if {$isWindows} {
      bind all <Alt-F4> { 
        global vsd
        set xxx [winfo toplevel %W]
        if { $xxx == $vsd(w) } {
          # Alt-F4 on main window: call exit routine
          ExitVSD 
        } else {
          # Alt-F4 NOT on main window: destroy the window
          destroy $xxx 
        }     
      }
    }
    RunVSD $w
}
