#!/bin/sh
# the exec restarts using tclsh which in turn ignores
# the command because of this backslash: \
exec mash-VERSION "$0" -name bin/mgamon -- "$@"

#
# Copyright (c) 1993-1996 The Regents of the University of California.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
#    must display the following acknowledgement:
#	This product includes software developed by the University of
#	California, Berkeley and the Network Research Group at
#	Lawrence Berkeley Laboratory.
# 4. Neither the name of the University nor of the Laboratory may be used
#    to endorse or promote products derived from this software without
#    specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# @(#) $Header: /usr/src/mash/repository/mash/mash-1/head.tcl,v 1.3 1997/08/15 07:23:36 mccanne Exp $ (LBL)
#
Class Log
Log proc name s {
	Log set name_ $s
}
Log proc warn s {
	Log instvar name_
	puts stderr "$name_: $s"
}
Log proc fatal s {
	Log warn $s
	exit 1
}
Class Application
Application public init name {
	$self next
	$self instvar name_ class_
	set name_ $name
	$self add_option appname $name
	Log set name_ $name
	set class_ [string toupper [string index $name_ 0]][string \
		range $name_ 1 end]
	catch "tk appname $name"
	Application set instance_ $self
}
Application proc instance {} {
	return [Application set instance_]
}
Application proc name {} {
	return [[Application instance] set name_]
}
Application proc class {} {
	return [[Application instance] set class_]
}
Application proc toplevel w {
	Application instvar visual_ colormap_
	if [info exists visual_] {
		toplevel $w -class [Application class] \
			-visual $visual_ -colormap $colormap_
	} else {
		toplevel $w -class [Application class]
	}
}
global font
set font(helvetica10) {
	normal--*-100-75-75-*-*-*-*
	normal--10-*-*-*-*-*-*-*
	normal--11-*-*-*-*-*-*-*
	normal--*-100-*-*-*-*-*-*
	normal--*-*-*-*-*-*-*-*
}
set font(helvetica12) {
	normal--*-120-75-75-*-*-*-*
	normal--12-*-*-*-*-*-*-*
	normal--14-*-*-*-*-*-*-*
	normal--*-120-*-*-*-*-*-*
	normal--*-*-*-*-*-*-*-*
}
set font(helvetica14) {
	normal--*-140-75-75-*-*-*-*
	normal--14-*-*-*-*-*-*-*
	normal--*-140-*-*-*-*-*-*
	normal--*-*-*-*-*-*-*-*
}
set font(times14) {
	normal--*-140-75-75-*-*-*-*
	normal--14-*-*-*-*-*-*-*
	normal--*-140-*-*-*-*-*-*
	normal--*-*-*-*-*-*-*-*
}
Application instproc search_font { foundry style weight points slant } {
	global font tcl_version tcl_platform
 	if {$tcl_version >= 8} {
 		if {$slant == "r"} {
 			set slant ""
 		} elseif {$slant == "o"} {
 			set slant "italic"
 		}
		if {$weight == "medium"} {
			set weight ""
		}
 		return "$style -$points $weight $slant"
 	}
	foreach f $font($style$points) {
		set fname -$foundry-$style-$weight-$slant-$f
		if [havefont $fname] {
			return $fname
		}
	}
	$self instvar name_
	puts stderr "$name_: can't find $weight $fname font (using fixed)"
	if ![havefont fixed] {
		puts stderr "$name_: can't find fixed font"
		exit 1
	}
	return fixed
}
Application public init_local {} {
	$self instvar name_
	set f ~/.$name_.tcl
	if [file exists $f] {
		uplevel #0 "source $f"
	}
	set script [$self resource startupScript]
	if { $script != "" } {
		uplevel #0 "source $script"
	}
}
Application instproc user_hook {} {
}
Object instproc options {} {
	$self instvar options_
	if ![info exists options_] {
		Object instvar options_
		if ![info exists options_] {
			set options_ [new Configuration]
			global tcl_platform
			if {"$tcl_platform(platform)"=="windows"} {
				$options_ add_default \
					background SystemButtonFace
				$options_ add_default \
					infoHighlightColor SystemHighlightText
			}
		}
	}
	$options_ add_default appname mash
	return $options_
}
Object instproc optionsFrom o {
	$self set options_ $o
}
Class instproc configuration a {
 	$self instvar options_
	if ![info exists options_] {
		set options_ [new Configuration]
	}
	foreach { option value } $a {
		$options_ add_default $option $value
	}
}
Object instproc get_option r {
	set v [[$self options] get_option $r]
	if { $v != "" } {
		return $v
	}
	set cl [$self info class]
	foreach cl "$cl [$cl info heritage]" {
		$cl instvar options_
		if [info exists options_] {
			set v [$options_ get_option $r]
			if { $v != "" } {
				return $v
			}
		}
	}
	return ""
}
Object instproc resource r {
	return [$self get_option $r]
}
Object instproc add_option { r v } {
	return [[$self options] add_option $r $v]
}
Object instproc add_default { r v } {
	return [[$self options] add_default $r $v]
}
Object instproc yesno r {
	set v [$self get_option $r]
	if [string match \[0-9\]* $v] {
		return $v
	}
	if [string match \[tT\]* $v] {
		return 1
	}
	return 0
}
Object instproc debug s {
	if [$self yesno debug] {
		Log warn $s
	}
}
Object instproc warn s {
	Log warn $s
}
Object instproc fatal s {
	Log fatal $s
}
Class Configuration
Configuration public get_option r {
	$self instvar table_ default_
	if [info exists table_($r)] {
		return $table_($r)
	}
	if [info exists default_($r)] {
		return $default_($r)
	}
	return ""
}
Configuration public add_option { r v } {
	$self instvar table_
	set table_($r) $v
}
Configuration public add_default { r v } {
	$self set default_($r) $v
}
Configuration public register_option  { flag option args } {
	$self instvar arg_option_ usage_
	set arg_option_($flag) $option
	set usage_($flag) $args
}
Configuration public register_boolean_option  { flag option args } {
	$self instvar arg_bool_ arg_bool_val_
	set arg_bool_($flag) $option
	if { $args == "" } {
		set args 1
	}
	set arg_bool_val_($flag) $args
}
Configuration public register_list_option {flag option args} {
	$self instvar arg_list_option_
	set arg_list_option_($flag) $option
	set usage_($flag) $args
}
Configuration private is_arg argv {
	if { $argv != "" } {
		return [string match -* [lindex $argv 0]]
	}
	return 0
}
Configuration instproc parse_args argv {
	$self instvar arg_resource_ bool_resource_ 
	$self instvar arg_option_ arg_bool_ arg_bool_val_ arg_list_option_
	if { [info exists arg_resource_] || [info exists bool_resource_] } {
		puts stderr "your application class needs to be fixed"
		exit 1
	}
	while 1 {
		if ![$self is_arg $argv] {
			break
		}
		set arg [lindex $argv 0]
		set argv [lrange $argv 1 end]
		set val [lindex $argv 0]
		if { $arg == "-help" } {
			$self usage
			exit
		}
		if { $arg == "-X" } {
			set L [split $val =]
			if { [llength $L] != 2 } {
				puts stderr "malformed -X argument"
				exit 1
			}
			$self add_option [lindex $L 0] [lindex $L 1]
			set argv [lrange $argv 1 end]
			continue
		}
		if [info exists arg_option_($arg)] {
			$self add_option $arg_option_($arg) $val
			set argv [lrange $argv 1 end]
			continue
		}
		if [info exists arg_bool_($arg)] {
			$self add_option $arg_bool_($arg) $arg_bool_val_($arg)
			continue
		}
		if [info exists arg_list_option_($arg)] {
			set o $arg_list_option_($arg)
			set l [$self get_option $o]
			lappend l $val
			$self add_option $o $l
			set argv [lrange $argv 1 end]
			continue
		}
		$self usage
		$self fatal "unknown command option: $arg"
	}
	return $argv
}
Configuration public usage {} {
	set display_args_on_single_line 0
	if { $display_args_on_single_line } {
		puts "usage: [Application name] [join [$self arg_info]]"
	} else {
		puts "usage: [Application name]" 
		foreach arg [$self arg_info] {
			puts $arg
		}
	}
}
Configuration private arg_info {} {
	$self instvar arg_option_ arg_bool_ usage_
	foreach arg [array names arg_option_] {
		set r $arg_option_($arg)
		set d [$self get_option $r]
		if { $d != "" || $usage_($arg) != "required"} {
			lappend opt "\[$arg $r ($d)\]"
		} else {
			lappend req "$arg $r"
		}
	}
	foreach arg [array names arg_bool_] {
		set r $arg_bool_($arg)
		set d [$self get_option $r]
		if { $d != "" } {
		        lappend opt "\[$arg ($d)\]"
		} else {
			lappend opt "\[$arg\]"
		}
	}
	if [info exists opt] {
		if [info exists req] {
			return [concat $opt $req]
		} else {
			return $opt
		}
	} else {
		if [info exists req] {
			return $req
		} else {
			return ""
		}
	}
}
Configuration public load_preferences suffixList {
	set mash [glob ~]/.mash
	if [file isdirectory $mash] {
		$self load_file $mash/prefs
		foreach suffix $suffixList {
			$self load_file $mash/prefs-$suffix
		}
	}
}
Configuration private load_file fname {
	if ![file readable $fname] {
		return
	}
	set f [open $fname r]
	set count 0
	while 1 {
		incr count
		if [eof $f] {
			close $f
			return
		}
		set line [string trim [gets $f]]
		if { $line == {} || [string index $line 0]=="#" } {
			continue
		}
		set colon [string first ":" $line]
		if { $colon==-1 } {
			puts stderr "Invalid line $count in $fname:\
					Must be of the form \"key: value\""
			continue
		}
		set option [string trim [string range $line 0 [expr $colon-1]]]
		set value [string trim [string range $line \
				[expr $colon+1] end]]
		$self add_option $option $value
	}
}
proc isWidgetObject { cl } {
	if { [$cl info heritage WidgetObject] != {} || $cl=="WidgetObject" } {
		return 1
	} else {
		return 0
	}
}
Class WidgetClass -superclass Class
WidgetClass proc unknown { cl args } {
	set private_options(-configspec) ""
	set private_options(-default) ""
	set private_options(-alias) ""
	set len [llength $args]
	for { set idx 0 } { $idx < $len } { incr idx 2 } {
		if { [info exists private_options([lindex $args $idx])] } {
			set private_options([lindex $args $idx]) \
					[lindex $args [expr $idx+1]]
			set args [lreplace $args $idx [expr $idx+1]]
			incr idx -2
		}
	}
	set idx [lsearch $args "-superclass"]
	if { $idx!=-1 } {
		incr idx
		if { [llength $args] <= $idx } {
			error "missing argument for option '-superclass'"
		}
		set superclasses [lindex $args $idx]
		set need_WidgetObject 1
		foreach superclass $superclasses {
			if { [$superclass info heritage WidgetObject]!="" } {
				set need_WidgetObject 0
				break
			}
		}
		if { $need_WidgetObject && $cl!="WidgetObject"} {
			lappend superclasses WidgetObject
			set args [lreplace $args $idx $idx $superclasses]
		}
	} else {
		if { $cl!="WidgetObject" } {
			lappend args -superclass WidgetObject
		}
	}
	eval [list $self] next [list $cl] $args
	$cl heritage_defaults
	foreach option [array names private_options] {
		set arg $private_options($option)
		$cl set_[string range $option 1 end] $arg
	}
}
WidgetClass proc set_widget_default { } {
	set count 0
	while [winfo exists .dummy_${count}__] { incr count }
	set dummy .dummy_${count}__
	button $dummy
	$self set_widget_default_ $dummy { -background -foreground \
			-activebackground -activeforeground -borderwidth \
			-cursor -disabledforeground -highlightbackground\
			-highlightcolor -highlightthickness -takefocus \
			{-boldfont -font} }
	destroy $dummy
	entry $dummy
	$self set_widget_default_ $dummy { -font -selectbackground \
			-selectforeground -selectborderwidth }
	destroy $dummy
}
WidgetClass proc set_widget_default_ { path options } {
	$self instvar widget_defaults_
	foreach option $options {
		if { [llength $option]==1 } {
			set option [lindex $option 0]
			set widget_defaults_($option) [$path cget $option]
		} else {
			set widget_defaults_([lindex $option 0]) \
					[$path cget [lindex $option 1]]
		}
	}
}
WidgetClass proc widget_default { option } {
	$self instvar widget_defaults_
	if { [info exists widget_defaults_($option) ] } {
		return $widget_defaults_($option)
	} else {
		error "no such default option \"$option\""
	}
}
WidgetClass proc translate_default { option value } {
	if { ![string compare $value "WidgetDefault"] } {
		return [WidgetClass widget_default $option]
	} elseif { [regexp {WidgetDefault\((.*)\)} $value dummy \
			defaultOption] } {
		return [WidgetClass widget_default $defaultOption]
	}
	return $value
}
WidgetClass set_widget_default
WidgetClass instproc heritage_defaults { } {
	set heritage [$self info heritage]
	set len [expr [llength $heritage]-1]
	while { $len >= 0 } {
		set cl [lindex $heritage $len]
		incr len -1
		if { [isWidgetObject $cl] } {
			$self configspec_ [$cl info configspec] 1
			$self default_ [$cl info default]
		}
	}
}
WidgetClass instproc set_configspec { specs } {
	$self configspec_ $specs 0
}
WidgetClass instproc configspec_ { specs {isAncestor} } {
	$self instvar configspec_
	foreach spec $specs {
		if { ! $isAncestor } {
			set option  [lindex $spec 0]
			set default [lindex $spec 3]
			set spec [lreplace $spec 3 3 [WidgetClass \
					translate_default $option $default]]
			set configspec_($option) $spec
		}
		option add *$self.[lindex $spec 1] \
				[lindex $spec 3] widgetDefault
	}
}
WidgetClass instproc set_alias { aliases } {
	$self instvar configspec_
	foreach alias $aliases {
		set al   [lindex $alias 0]
		set orig [lindex $alias 1]
		if { ![info exists configspec_($orig)] } {
			error "no configspec $orig (specified in alias list)"
		}
		set configspec_($al) $configspec_($orig)
	}
}
WidgetClass instproc set_default { defaults } {
	$self default_ $defaults
	$self set defaults_ $defaults
}
WidgetClass instproc default_ { defaults } {
	foreach default $defaults {
		set option [lindex $default 0]
		set star [string last "*" $option]
		set dot  [string last "." $option]
		if { $star < $dot } {
			set idx [expr $dot+1]
		} else {
			set idx [expr $star+1]
		}
		option add *${self}$option [WidgetClass translate_default \
				-[string tolower [string range $option $idx \
				end]] [lindex $default 1]] widgetDefault
	}
}
WidgetClass instproc create { widget args } {
	eval [list $self] next [list _o$widget] [list $widget] $args
	return $widget
}
WidgetClass instproc info { option args } {
	if { $option == "default" } {
		if { $args != "" } {
			error "extra arguments in call to 'info $option'"
		}
		return [$self set defaults_]
	} elseif { $option == "configspec" } {
		$self instvar configspec_
		set len [llength $args]
		if { $len == 0 } {
			set list {}
			foreach el [array names configspec_] {
				lappend list $configspec_($el)
			}
			return $list
		}
		if { [llength $args] != 1 } {
			error "extra arguments in call to 'info $option'"
		}
		if { [info exists configspec_($args)] } {
			return $configspec_($args)
		} else {
			return ""
		}
		return [eval [list $self] next [list $option] $args]
	} else {
		return [eval [list $self] next [list $option] $args]
	}
}
WidgetClass WidgetObject -configspec {
	{-options options Options {} widget_options widget_options}
}
WidgetObject instproc init { widget args } {
	$self next
	$self instvar path_ widget_proc_
	set path_ $widget
	$self create_root_widget $widget
	if { ![winfo exists $widget] } {
		error "must create a widget $widget inside\
				[$self info class]::create_root_widget"
	}
	$self instvar widget_proc_
	set widget_proc_ "proc_$self"
	rename $widget $widget_proc_
	proc ::$widget { args } "return \[uplevel [list $self] \$args\]"
	$self build_widget $widget
	set heritage [[$self info class] info heritage]
	set idx 0
	for { set idx [expr [llength $heritage]-1] } {$idx>=0} {incr idx -1} {
		set cl [lindex $heritage $idx]
		if { [isWidgetObject $cl] } {
			$self configure_default $cl
		}
	}
	$self configure_default [$self info class]
	if { $args!="" } {
		eval [list $self] configure $args
	}
	if { [winfo toplevel $path_]==$path_ } {
		bind $widget <Destroy> "if \{\"%W\"==\"$path_\"\} \
				\{delete $self\}"
	} else {
		bind $widget <Destroy> "delete $self"
	}
}
WidgetObject instproc create_root_widget { path } {
	frame $path -class [$self info class]
}
WidgetObject instproc build_widget { path } {
}
WidgetObject instproc info { option args } {
	switch $option {
		"path" {
			if { $args != "" } {
				error "extra arguments in call to 'info $option'"
			}
			return [$self set path_]
		}
		"self" { return $self }
		default {
			return [eval [list $self] next [list $option] $args]
		}
	}
}
WidgetObject instproc unknown { method args } {
	return [eval [list $self] widget_proc [list $method] $args]
}
WidgetObject instproc widget_proc { args } {
	$self instvar widget_proc_
	return [eval [list $widget_proc_] $args]
}
WidgetObject instproc config { args } {
	return [eval [list $self] configure $args]
}
WidgetObject instproc configure_default { cl } {
	set path [$self info path]
	set widget_class [winfo class $path]
	if { $widget_class == [$self info class] } {
		foreach spec [$cl info configspec] {
			set optVal [option get $path [lindex $spec 1] $cl]
			$self configure [lindex $spec 0] $optVal
		}
	} else {
		foreach spec [$cl info configspec] {
			$self configure [lindex $spec 0] [lindex $spec 3]
		}
	}
}
WidgetObject instproc configure { args } {
	set len [llength $args]
	switch $len {
		0 { return [$self configure_all] }
		1 { return [$self configure_one $args] }
		default {
			if { $len % 2 != 0 } {
				error "odd number of arguments for configure"
			}
			for { set i 0 } { $i < $len } { incr i 2 } {
				$self configure_one [lindex $args $i] \
						[lindex $args [expr $i+1]]
			}
		}
	}
}
WidgetObject instproc configure_one { args } {
	set option [lindex $args 0]
	if { [string index $option 0] != "-" } {
		error "invalid option $option: must start with -"
	}
	set option [string range $option 1 end]
	set spec [[$self info class] info configspec -$option]
	if { $spec!="" } {
		set config_proc [lindex $spec 4]
		set cget_proc   [lindex $spec 5]
		if { $cget_proc=={} } { set cget_proc $config_proc }
		if { [llength $args] < 2 } {
			return [lreplace $spec 4 end [$self $cget_proc \
					"-$option"]]
		} else {
			return [$self $config_proc "-$option" [lindex $args 1]]
		}
	}
	foreach cl [[$self info class] info heritage] {
		if { [isWidgetObject $cl] } {
			set spec [$cl info configspec -$option]
			if { $spec!="" } {
				set config_proc [lindex $spec 4]
				set cget_proc   [lindex $spec 5]
				if { $cget_proc=={} } {
					set cget_proc $config_proc
				}
				if { [llength $args] < 2 } {
					return [lreplace $spec 4 end \
							[$self $cget_proc \
							"-$option"]]
				} else {
					return [$self $config_proc "-$option" \
							[lindex $args 1]]
				}
			}
		}
	}
	return [eval [list $self] widget_proc configure $args]
}
WidgetObject instproc configure_all { } {
	set result [$self configure_all_ [$self info class]]
	foreach cl [[$self info class] info heritage] {
		if { [isWidgetObject $cl] } {
			set result [concat $result [$self configure_all_ $cl]]
		}
	}
	set result [concat $result [$self widget_proc configure]]
	return $result
}
WidgetObject instproc configure_all_ { cl } {
	set result ""
	foreach spec [$cl info configspec] {
		set option [lindex $spec 0]
		if { $option != "-options" } {
			lappend result [$self configure $option]
		}
	}
	return $result
}
WidgetObject instproc cget { option } {
	return [lindex [$self configure_one $option] 4]
}
WidgetObject instproc widget_options { option args } {
	if { [llength $args]==0 } {
		error "options has no value; cannot read it"
	}
	set root [$self info path]
	foreach option [lindex $args 0] {
		set opt [string trim [lindex $option 0]]
		set arg [lindex $option 1]
		set lastdot [string last . $opt]
		if { $lastdot <= 0 } {
			set path $root
		} else {
			set firstdot  [string first . $opt]
			set path [string range $opt 0 [expr $firstdot-1]]
			set path [$self subwidget $path]
			if { $firstdot < $lastdot } {
				set path $path.[string range $opt \
						[expr $firstdot+1] \
						[expr $lastdot -1]]
			}
		}
		set opt [string range $opt [expr $lastdot+1] end]
		$path configure -$opt $arg
	}
}
WidgetObject instproc subwidget { widget args } {
	set path "[$self info path].$widget"
	if { ![winfo exists $path] } {
		$self instvar subwidgets_
		if { ![info exists subwidgets_($widget)] } {
			error "no subwidget $widget inside [$self info path]"
		}
		set path $subwidgets_($widget)
	}
	if { [llength $args]==0 } {
		return $path
	}
	return [eval [list $path] $args]
}
WidgetObject instproc set_subwidget { name path } {
	$self instvar subwidgets_
	$self set subwidgets_($name) $path
}
WidgetObject instproc ignore_args { args } {
}
WidgetObject instproc do_when_idle { command } {
	$self instvar do_idle_ids_
	set command [string trim $command]
	if ![info exists do_idle_ids_($command)] {
		set do_idle_ids_($command) \
				[after idle "WidgetObject do_idle_ \
				[list $self] [list $command]"]
	}
}
WidgetObject proc do_idle_ { o command } {
	$o instvar do_idle_ids_
	catch {unset do_idle_ids_($command)}
	if { [info command $o]!=$o } {
		return
	}
	set w [$o info path]
	if {![winfo exists $w] || [string compare [winfo class $w] \
			[$o info class]] != 0} {
		return
	} else {
		uplevel #0 $command
	}
}
WidgetClass proc transparent_gif { {color {}} } {
	global TRANSPARENT_GIF_COLOR
	if { $color!={} } {
		set TRANSPARENT_GIF_COLOR $color
	} else {
		set TRANSPARENT_GIF_COLOR [$self widget_default -background]
	}
}
WidgetClass proc EntryBindings { tag } {
	bind $tag <FocusIn>  "$self EntryBindings_FocusIn %W"
	bind $tag <FocusOut> "$self EntryBindings_FocusOut %W"
}
WidgetClass proc EntryBindings_FocusIn { entry } {
	if [string compare [$entry get] ""] {
		$entry selection from 0
		$entry selection to   end
		$entry icursor end
	} else {
		$entry selection clear
	}
}
WidgetClass proc EntryBindings_FocusOut { entry } {
    $entry selection clear
}
WidgetClass EntryBindings Entry
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\26\134\43\24\134\43\302\134\43\134\43\330\330\330\370\374\370\134\43\134\43\134\43\70\370\60\200\200\200\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\26\134\43\24\134\43\134\43\3\123\10\272\334\376\120\205\40\142\234\103\20\142\33\316\133\267\174\202\306\111\323\103\232\47\20\14\231\367\146\354\70\233\50\134\134\156\255\13\203\234\17\260\347\323\155\204\73\142\21\106\100\326\74\277\201\223\247\212\106\223\112\211\125\367\204\314\176\130\221\134\43\334\355\224\302\242\5\57\224\146\120\333\360\106\2\134\43\73"]
image create photo Icons(check) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\24\134\43\24\134\43\302\134\43\134\43\330\330\330\370\374\370\134\43\134\43\134\43\370\24\100\200\200\200\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\24\134\43\24\134\43\134\43\3\126\10\272\274\21\55\212\366\306\210\312\116\27\354\330\214\47\154\225\46\20\215\367\1\345\167\22\250\43\12\235\11\303\114\255\332\67\266\153\267\230\157\367\22\16\211\306\43\21\263\370\251\100\251\31\21\232\231\265\134\134\306\347\253\64\352\125\261\267\116\327\13\340\305\36\305\344\70\31\214\264\335\311\5\216\331\110\134\43\134\43\73"]
image create photo Icons(cross) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\22\134\43\22\134\43\302\134\43\134\43\330\330\330\134\43\134\43\134\43\370\374\370\270\274\270\70\370\60\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\22\134\43\22\134\43\134\43\3\112\10\272\334\376\360\205\71\243\232\42\347\52\363\40\104\60\154\116\40\14\50\50\242\103\320\230\254\312\266\14\34\207\63\175\11\140\357\343\256\335\357\47\12\2\114\224\200\52\251\73\236\156\53\226\321\11\235\115\251\51\234\264\44\235\154\45\121\24\47\222\274\132\42\11\134\43\73"]
image create photo Icons(plus) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\22\134\43\22\134\43\302\134\43\134\43\330\330\330\134\43\134\43\134\43\370\374\370\270\274\270\70\370\60\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\22\134\43\22\134\43\134\43\3\101\10\272\334\376\360\205\71\243\232\42\347\52\363\370\337\346\4\2\150\202\101\103\236\147\272\254\154\373\12\104\155\337\301\340\2\344\355\23\271\35\211\102\44\352\146\61\31\62\171\144\300\222\273\27\63\352\314\231\70\221\242\145\273\110\134\43\134\43\73"]
image create photo Icons(minus) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\24\134\43\24\134\43\302\134\43\134\43\330\330\330\120\124\120\134\43\134\43\134\43\270\274\270\370\374\370\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\24\134\43\24\134\43\134\43\3\134\134\10\272\334\356\41\312\327\242\270\170\104\32\260\317\301\43\175\327\4\21\232\44\15\32\24\14\4\312\6\162\272\274\132\254\301\173\72\53\253\330\13\365\122\205\30\64\42\257\270\71\11\227\273\143\5\106\30\106\233\225\130\25\152\312\52\225\105\21\325\212\303\42\265\270\136\13\302\222\105\164\153\27\153\116\224\162\214\166\212\276\221\134\43\134\43\73"]
image create photo Icons(trashcan) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\50\134\43\50\134\43\302\134\43\134\43\330\330\330\170\174\134\43\370\374\134\43\270\274\270\134\43\134\43\134\43\170\174\170\134\43\134\43\134\43\134\43\134\43\134\43\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\50\134\43\50\134\43\134\43\3\270\10\272\334\376\60\312\111\253\275\70\353\27\372\316\201\40\14\304\147\205\342\110\24\346\204\246\53\333\162\151\112\26\362\314\274\165\254\357\265\332\55\247\343\5\175\77\143\160\230\264\21\236\3\30\256\330\173\76\235\323\26\317\172\225\22\65\106\56\101\210\334\204\271\307\54\70\50\20\57\313\30\145\300\252\204\237\330\52\50\233\31\307\267\273\154\166\56\176\2\163\112\42\174\25\207\210\4\121\176\202\20\213\60\204\52\152\22\222\224\75\226\221\231\44\215\204\211\234\224\150\204\220\13\230\42\244\176\241\15\250\171\216\245\233\100\231\264\136\137\247\265\265\103\267\270\271\240\61\262\73\142\303\304\303\70\307\24\307\312\313\314\315\301\17\316\321\316\77\324\325\326\327\330\11\134\43\73"]
image create photo Icons(warning) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\20\134\43\12\134\43\241\134\43\134\43\330\330\330\370\374\370\134\43\134\43\134\43\200\200\200\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\20\134\43\12\134\43\134\43\2\35\204\217\171\301\355\201\202\230\264\212\21\155\35\70\153\256\134\43\322\326\205\343\125\206\42\252\266\356\133\134\43\134\43\73"]
image create photo Icons(minimize) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\20\134\43\12\134\43\241\134\43\134\43\330\330\330\370\374\370\134\43\134\43\134\43\200\200\200\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\20\134\43\12\134\43\134\43\2\35\204\217\251\26\273\41\206\103\120\304\11\252\275\157\173\231\150\236\5\62\343\131\2\303\312\266\51\226\24\134\43\73"]
image create photo Icons(maximize) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\24\134\43\17\134\43\362\134\43\134\43\330\330\330\177\177\177\377\377\134\43\377\377\377\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\24\134\43\17\134\43\134\43\3\101\10\272\334\276\41\306\367\2\20\27\130\12\63\306\222\344\4\103\151\236\145\100\64\344\347\171\52\73\274\56\270\62\55\15\337\320\134\134\277\61\334\340\127\13\366\164\56\243\42\107\274\50\65\241\150\210\267\40\130\257\130\54\147\313\110\134\43\134\43\73"]
image create photo Icons(folder) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\24\134\43\17\134\43\302\134\43\134\43\330\330\330\170\174\170\370\374\370\270\274\270\370\374\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\24\134\43\17\134\43\134\43\3\105\10\272\334\316\41\306\367\202\270\67\120\50\6\361\203\40\111\216\365\235\41\46\26\215\5\242\150\300\56\143\75\22\62\247\356\362\220\323\35\330\253\20\231\1\137\110\331\17\50\104\21\215\114\344\111\6\125\330\154\205\252\42\313\355\166\67\340\105\2\134\43\73"]
image create photo Icons(folderopen) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\24\134\43\17\134\43\362\134\43\134\43\330\330\330\177\177\177\377\377\134\43\377\377\377\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\24\134\43\17\134\43\134\43\3\105\10\272\334\276\41\306\367\2\20\27\130\12\63\306\222\344\4\103\151\236\145\100\64\344\27\174\236\312\16\227\4\203\53\323\206\157\234\103\64\220\47\43\323\15\134\134\267\332\117\101\42\362\160\263\344\255\10\341\131\43\113\5\141\313\355\166\71\140\106\2\134\43\73"]
image create photo Icons(folderup) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\17\134\43\17\134\43\241\134\43\134\43\330\330\330\170\174\170\370\374\370\134\43\134\43\134\43\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\17\134\43\17\134\43\134\43\2\62\204\217\151\301\315\12\202\230\263\51\111\205\113\222\325\66\40\130\126\205\107\347\224\42\111\5\346\242\245\332\33\261\352\31\67\67\154\273\242\3\244\1\6\304\242\21\202\64\24\134\43\134\43\73"]
image create photo Icons(textfile) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\22\134\43\22\134\43\204\134\43\134\43\330\330\330\170\174\170\134\43\370\360\360\370\360\134\43\134\43\134\43\360\374\360\134\43\374\360\134\43\370\370\360\370\370\134\43\170\170\134\43\374\370\370\370\360\134\43\174\170\134\43\134\43\360\134\43\134\43\170\134\43\134\43\370\134\43\134\43\160\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\22\134\43\22\134\43\134\43\5\144\40\40\216\144\151\212\101\32\234\145\52\14\57\101\260\100\134\43\303\205\220\317\147\140\14\277\327\141\300\153\275\4\210\237\62\121\34\331\24\260\5\122\260\140\64\121\57\45\20\310\64\331\250\103\341\300\332\313\231\165\344\336\21\361\142\60\257\43\31\143\156\45\64\32\360\270\214\340\160\30\356\171\47\16\2\200\64\45\203\17\170\206\44\20\177\201\47\62\213\64\41\134\43\73"]
image create photo Icons(browse) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\11\134\43\10\134\43\241\134\43\134\43\330\330\330\370\374\370\134\43\134\43\134\43\200\200\200\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\11\134\43\10\134\43\134\43\2\25\204\21\247\41\243\50\242\63\54\112\150\355\10\134\134\217\11\150\17\360\115\5\134\43\73"]
image create photo Icons(up) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\11\134\43\10\134\43\241\134\43\134\43\330\330\330\370\374\370\134\43\134\43\134\43\200\200\200\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\11\134\43\10\134\43\134\43\2\24\4\202\141\33\342\143\222\23\3\266\71\55\246\54\257\310\175\6\264\24\134\43\73"]
image create photo Icons(down) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\11\134\43\10\134\43\241\134\43\134\43\330\330\330\370\374\370\134\43\134\43\134\43\200\200\200\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\11\134\43\10\134\43\134\43\2\25\204\43\143\213\222\354\242\152\321\215\200\321\330\12\320\356\125\17\125\15\5\134\43\73"]
image create photo Icons(fastup) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\11\134\43\10\134\43\241\134\43\134\43\330\330\330\134\43\134\43\134\43\200\200\200\370\374\370\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\11\134\43\10\134\43\134\43\2\23\104\216\41\60\251\134\43\333\131\154\330\27\335\144\216\362\15\145\136\1\134\43\73"]
image create photo Icons(fastdown) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\34\134\43\24\134\43\245\134\43\134\43\370\370\370\340\340\370\230\230\340\150\150\300\370\340\370\134\43\134\43\300\134\43\134\43\230\134\43\134\43\150\300\230\150\370\370\300\250\300\370\340\300\134\43\300\300\230\300\300\134\43\150\134\43\300\340\340\300\370\370\340\150\150\150\250\254\230\150\134\43\150\340\340\134\43\370\370\230\150\150\340\230\150\134\43\150\150\134\43\300\300\340\340\340\150\300\230\134\43\370\370\150\340\370\370\230\150\150\370\370\134\43\134\43\150\340\230\150\300\340\340\340\300\300\150\370\340\134\43\150\150\230\230\230\300\134\43\150\300\150\134\43\230\340\340\230\134\43\134\43\340\230\230\230\300\230\300\230\230\134\43\340\300\150\300\230\340\370\340\150\370\340\230\370\340\300\340\300\230\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\34\134\43\24\134\43\134\43\6\375\100\200\160\110\54\32\217\110\100\100\60\150\22\222\120\245\240\140\60\34\14\210\104\62\200\124\120\253\13\206\241\241\65\6\12\216\7\244\50\250\32\42\15\111\141\102\131\263\251\207\205\135\330\256\322\37\163\13\25\106\26\125\27\30\24\104\31\137\6\13\11\4\31\32\203\154\125\33\21\33\223\112\214\15\34\104\1\4\35\240\134\43\213\6\33\36\21\211\103\205\206\37\103\113\5\5\40\5\41\42\124\227\245\231\1\156\215\166\147\273\6\27\43\206\300\44\104\253\300\235\232\225\45\140\46\156\164\173\134\43\3\156\15\223\175\33\15\206\44\47\156\202\105\323\225\203\276\36\15\124\320\137\325\204\156\50\51\1\40\277\245\51\52\324\107\35\214\6\367\273\124\36\53\125\54\134\134\105\2\230\30\200\342\300\204\26\54\340\35\150\341\202\24\76\21\107\136\344\203\127\5\226\241\124\256\346\255\243\270\353\340\2\30\321\134\43\264\271\320\300\205\206\30\51\144\244\170\200\62\305\14\15\51\122\304\110\20\122\110\134\43\21\20\152\106\51\22\4\134\43\73"]
image create photo Icons(cal) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\67\141\15\134\43\24\134\43\360\134\43\134\43\377\377\377\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\15\134\43\24\134\43\134\43\2\55\204\217\11\301\235\254\240\11\152\322\145\35\306\162\172\172\65\20\10\162\143\145\155\110\130\256\254\232\225\127\105\242\134\134\344\314\250\356\255\221\377\113\341\64\207\2\134\43\73"]
image create photo Icons(ear) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\67\141\20\134\43\20\134\43\360\134\43\134\43\377\377\377\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\20\134\43\20\134\43\134\43\2\51\204\17\21\310\271\353\40\202\312\120\106\157\332\107\147\316\171\226\3\116\326\327\164\222\324\150\151\7\277\343\374\262\45\326\246\166\154\352\271\121\134\43\134\43\73"]
image create photo Icons(hand) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\24\134\43\24\134\43\367\134\43\134\43\330\330\330\370\374\370\71\370\61\134\43\134\43\134\43\200\200\200\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\341\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\341\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\341\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\43\341\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\43\341\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\45\341\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\52\341\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\217\200\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\142\200\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\43\200\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\45\200\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\45\200\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\43\201\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\45\201\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\21\134\43\134\43\134\43\45\201\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\21\134\43\134\43\134\43\45\201\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\21\134\43\134\43\134\43\67\201\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\21\134\43\134\43\134\43\246\200\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\21\134\43\134\43\134\43\222\200\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\26\134\43\134\43\134\43\223\200\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\26\134\43\134\43\134\43\315\200\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\26\134\43\134\43\134\43\105\341\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\247\247\247\134\43\57\134\43\117\134\43\134\43\21\251\134\43\370\43\134\43\134\43\270\134\43\236\134\43\254\254\254\134\43\255\255\255\134\43\256\256\256\134\43\257\257\257\134\43\260\260\260\134\43\261\261\261\134\43\263\263\263\134\43\264\264\264\134\43\265\265\265\134\43\266\266\266\134\43\267\267\267\134\43\270\270\270\134\43\271\271\271\134\43\272\272\272\134\43\273\273\273\134\43\274\274\274\134\43\275\275\275\134\43\276\276\276\134\43\300\300\300\134\43\301\301\301\134\43\302\302\302\134\43\303\303\303\134\43\304\304\304\134\43\305\305\305\134\43\306\306\306\134\43\307\307\307\134\43\310\310\310\134\43\311\311\311\134\43\312\312\312\134\43\314\314\314\134\43\315\315\315\134\43\316\316\316\134\43\41\371\4\1\134\43\134\43\1\134\43\54\134\43\134\43\134\43\134\43\24\134\43\24\134\43\100\10\135\134\43\3\10\34\110\260\240\301\201\2\22\52\134\134\230\320\320\101\2\20\43\22\70\150\160\41\105\212\14\5\30\232\146\110\42\304\213\40\53\146\24\20\62\300\110\205\33\73\116\44\330\220\243\307\225\45\143\312\304\110\162\246\300\214\62\117\46\4\251\23\345\107\226\43\71\116\223\130\160\241\320\227\7\247\171\31\352\61\144\123\233\62\3\2\134\43\73"]
image create photo VcrIcons(play) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\24\134\43\24\134\43\367\134\43\134\43\330\330\330\370\374\370\71\370\61\134\43\134\43\134\43\200\200\200\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\341\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\341\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\341\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\43\341\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\43\341\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\45\341\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\52\341\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\217\200\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\142\200\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\43\200\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\45\200\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\45\200\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\43\201\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\45\201\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\21\134\43\134\43\134\43\45\201\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\21\134\43\134\43\134\43\45\201\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\21\134\43\134\43\134\43\67\201\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\21\134\43\134\43\134\43\246\200\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\21\134\43\134\43\134\43\222\200\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\26\134\43\134\43\134\43\223\200\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\26\134\43\134\43\134\43\315\200\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\14\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\26\134\43\134\43\134\43\105\341\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\247\247\247\134\43\101\134\43\117\134\43\134\43\21\251\134\43\300\134\43\236\134\43\300\134\43\236\134\43\254\254\254\134\43\255\255\255\134\43\256\256\256\134\43\257\257\257\134\43\260\260\260\134\43\261\261\261\134\43\263\263\263\134\43\264\264\264\134\43\265\265\265\134\43\266\266\266\134\43\267\267\267\134\43\270\270\270\134\43\271\271\271\134\43\272\272\272\134\43\273\273\273\134\43\274\274\274\134\43\275\275\275\134\43\276\276\276\134\43\300\300\300\134\43\301\301\301\134\43\302\302\302\134\43\303\303\303\134\43\304\304\304\134\43\305\305\305\134\43\306\306\306\134\43\307\307\307\134\43\310\310\310\134\43\311\311\311\134\43\312\312\312\134\43\314\314\314\134\43\315\315\315\134\43\316\316\316\134\43\41\371\4\1\134\43\134\43\1\134\43\54\134\43\134\43\134\43\134\43\24\134\43\24\134\43\100\10\173\134\43\3\10\34\110\260\240\301\201\2\22\52\134\134\50\134\43\32\1\2\7\13\302\103\207\356\241\305\210\5\27\42\203\130\220\134\134\105\213\14\5\30\172\210\261\144\311\220\11\35\162\24\10\340\41\112\205\43\127\112\244\150\221\100\302\215\62\115\6\134\43\200\16\34\134\43\235\100\117\212\4\247\63\44\50\2\330\16\276\114\170\124\46\277\245\12\161\22\4\200\15\44\312\230\6\301\221\43\127\123\43\111\214\133\271\76\204\206\25\50\134\43\217\125\311\5\215\30\20\134\43\73"]
image create photo VcrIcons(reverse) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\24\134\43\24\134\43\302\134\43\134\43\330\330\330\370\374\370\270\274\270\134\43\134\43\134\43\200\200\200\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\24\134\43\24\134\43\134\43\3\111\10\272\334\376\360\205\31\26\255\60\210\75\224\346\331\46\14\4\361\215\245\163\222\246\310\252\156\271\246\315\334\162\64\143\333\60\176\243\204\36\220\127\213\375\136\105\37\121\147\134\134\132\232\306\307\140\372\242\42\35\245\254\42\233\153\160\203\200\157\144\114\56\3\22\134\43\73"]
image create photo VcrIcons(pause) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\20\134\43\24\134\43\302\134\43\134\43\330\330\330\134\43\134\43\134\43\270\274\270\120\124\120\370\374\370\200\200\200\134\43\134\43\134\43\134\43\134\43\134\43\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\20\134\43\24\134\43\134\43\3\74\10\272\334\376\60\262\100\253\15\142\216\315\73\321\135\110\24\205\22\204\42\151\242\236\12\234\354\66\226\157\54\273\160\74\257\366\136\367\70\333\300\47\40\30\217\110\237\202\304\154\62\31\316\50\115\102\255\132\1\11\134\43\73"]
image create photo VcrIcons(stop) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\24\134\43\20\134\43\200\134\43\134\43\134\43\134\43\134\43\277\277\277\41\371\4\1\134\43\134\43\1\134\43\54\134\43\134\43\134\43\134\43\24\134\43\20\134\43\134\43\2\34\214\217\251\313\355\17\27\230\224\276\212\57\266\156\363\346\115\232\67\156\145\326\205\321\312\266\114\1\134\43\73"]
image create photo VcrIcons(sstop) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\24\134\43\20\134\43\200\134\43\134\43\134\43\134\43\134\43\277\277\277\41\371\4\1\134\43\134\43\1\134\43\54\134\43\134\43\134\43\134\43\24\134\43\20\134\43\134\43\2\35\214\217\251\313\355\17\27\210\12\130\172\254\306\272\307\16\76\140\330\214\227\110\102\36\67\141\356\213\24\134\43\73"]
image create photo VcrIcons(splay) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\20\134\43\24\134\43\302\134\43\134\43\330\330\330\134\43\134\43\134\43\270\274\270\370\24\100\370\374\370\200\200\200\134\43\134\43\134\43\134\43\134\43\134\43\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\20\134\43\24\134\43\134\43\3\74\10\272\334\376\60\262\100\253\15\142\216\315\73\321\135\110\24\205\22\204\42\151\242\236\12\234\354\66\226\157\54\273\160\74\257\366\136\367\70\333\300\47\40\30\217\110\237\202\304\154\62\31\316\50\115\102\255\132\1\11\134\43\73"]
image create photo VcrIcons(record) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\12\134\43\12\134\43\302\134\43\134\43\330\330\330\370\140\100\370\134\43\134\43\370\244\134\43\260\40\40\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\134\43\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\12\134\43\12\134\43\134\43\3\32\10\272\334\276\41\10\27\106\234\320\136\262\304\25\2\247\200\44\41\216\241\351\230\347\263\44\134\43\73"]
image create photo VcrIcons(redbullet) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\12\134\43\12\134\43\302\134\43\134\43\330\330\330\134\43\374\134\43\370\134\43\134\43\230\370\230\60\314\60\50\210\120\134\43\134\43\134\43\134\43\134\43\134\43\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\12\134\43\12\134\43\134\43\3\32\10\272\334\276\41\10\27\106\44\254\306\100\312\42\27\321\175\242\130\170\344\211\62\352\343\44\134\43\73"]
image create photo VcrIcons(greenbullet) -data $imageObject__
set imageObject__ [new Image/GIF "\107\111\106\70\71\141\12\134\43\12\134\43\302\134\43\134\43\330\330\330\170\174\170\134\43\374\370\370\374\370\134\43\134\43\134\43\134\43\174\170\134\43\134\43\370\134\43\134\43\134\43\41\371\4\1\134\43\134\43\134\43\134\43\54\134\43\134\43\134\43\134\43\12\134\43\12\134\43\134\43\3\40\10\20\254\276\142\10\362\102\214\205\252\40\145\166\226\367\71\104\141\22\32\211\12\106\372\134\43\254\373\260\157\235\134\43\134\43\73"]
image create photo VcrIcons(browse_small) -data $imageObject__
WidgetClass ScrolledWidget -configspec {
	{ -scrollbar scrollbar Scrollbar {none} config_scroll cget_scroll }
}
ScrolledWidget instproc build_widget { path } {
	$self instvar main_
	frame  $path.dummy -borderwidth 0 -relief flat
	set main_ [$self create_main_widget $path]
	scrollbar $path.vscroll -command "$main_ yview" -orient vertical
	scrollbar $path.hscroll -command "$main_ xview" \
			-orient horizontal
	$main_ configure -yscrollcommand "$path.vscroll set"
	$main_ configure -xscrollcommand "$path.hscroll set"
	pack $path.dummy -side top -fill both -expand 1
	pack $main_ -side left -anchor nw -fill both -expand 1 \
			-in $path.dummy
}
ScrolledWidget instproc create_main_widget { path } {
	error "cannot create object of class [$self info class];\
			every subclass MUST redefine the create_main_widget\
			method"
}
ScrolledWidget instproc config_scroll { option scroll } {
	$self instvar main_
	set path [$self info path]
	catch {
		pack forget $path.vscroll
		pack forget $path.hscroll
	}
	switch $scroll {
		horizontal {
			pack $path.hscroll -side bottom -fill x \
					-before $path.dummy
		}
		vertical {
			pack $path.vscroll -side right -fill y \
					-in $path.dummy -before $main_
		}
		both {
			pack $path.hscroll -side bottom -fill x \
					-before $path.dummy
			pack $path.vscroll -side right -fill y \
					-in $path.dummy -before $main_
		}
		auto {
			error "function not implemented"
		}
		default {
			set scroll none
		}
	}
	$self set scroll_ $scroll
}
ScrolledWidget instproc cget_scroll { option } {
	$self instvar scroll_
	if [info exists scroll_] { return $scroll_ } else { return none }
}
WidgetClass ScrolledCanvas -superclass ScrolledWidget
ScrolledCanvas instproc create_main_widget { path } {
	return [canvas $path.bbox]
}
WidgetClass ScrolledText -superclass ScrolledWidget
ScrolledText instproc create_main_widget { path } {
	return [text $path.text]
}
WidgetClass ScrolledWindow -superclass ScrolledCanvas
ScrolledWindow instproc build_widget { path } {
	$self next $path
	frame $path.bbox.window
	$path.bbox create window 0 0 -anchor nw -window $path.bbox.window
	$self set_subwidget window $path.bbox.window
	bind $path.bbox.window <Configure> "+$self ev_window_resize %w %h"
}
ScrolledWindow instproc ev_window_resize { width height } {
	[$self subwidget bbox] configure -scrollregion "0 0 $width $height"
}
WidgetClass ScrolledWindow/Expand -superclass ScrolledWindow
ScrolledWindow/Expand instproc build_widget { path } {
	$self next $path
	set dummy [frame [$self subwidget bbox].dummy_ -width 0 -height 0 \
			-relief flat -bg [[$self subwidget window] cget -bg]]
	pack $dummy -side top -in [$self subwidget window]
	bind [$self subwidget bbox] <Configure> "+$self ev_bbox_resize_ %w %h"
}
ScrolledWindow/Expand instproc ev_bbox_resize_ { w h } {
	set window [$self subwidget window]
	set bbox   [$self subwidget bbox]
	$bbox.dummy_ configure \
			-width [expr $w - ([$bbox cget -bd] + \
			[$window cget -bd] + [$bbox cget -highlightthickness] \
			+ [$window cget -highlightthickness]) * 2]
}
WidgetClass ListLabelItem -configspec {
	{ -value       value       Value       {}            config_value }
	{ -select      select      Select      0             config_option }
	{ -highlight   highlight   Highlight   0             config_option }
	{ -relief relief Relief flat config_relief cget_relief }
	{ -normalbackground normalBackground NormalBackground \
			WidgetDefault(-background) config_option }
	{ -normalforeground normalForeground NormalForeground \
			WidgetDefault(-foreground) config_option }
	{ -normalrelief normalRelief NormalRelief flat config_option }
	{ -selectbackground selectBackground SelectBackground WidgetDefault \
			config_option }
	{ -selectforeground selectForeground SelectForeground WidgetDefault \
			config_option }
	{ -selectrelief selectRelief SelectRelief sunken config_option }
	{ -highlightrelief highlightRelief HighlightRelief raised \
			config_option }
}
ListLabelItem instproc init { args } {
	$self instvar config_
	set config_(-value) {}
	set config_(-select) 0
	set config_(-highlight) 0
	set config_(-normalbackground) Black
	set config_(-normalforeground) Black
	set config_(-normalrelief)     flat
	set config_(-selectbackground) Black
	set config_(-selectforeground) Black
	set config_(-selectrelief)     sunken
	set config_(-highlightrelief)  raised
	eval [list $self] next $args	
}
ListLabelItem instproc create_root_widget { path } {
	label $path -anchor w
	if { [option get $path padX Label]=="" } {
		$path configure -padx 1
	}
	if { [option get $path padX Label]=="" } {
		$path configure -pady 1
	}
}
ListLabelItem instproc config_value { option args } {
	$self instvar config_
	if { [llength $args]==0 } {
		return [$self widget_proc cget -text]
	} else {
		$self widget_proc configure -text [lindex $args 0]
	}
}
ListLabelItem instproc config_option { option args } {
	$self instvar config_
	if { [llength $args]==0 } {
		return $config_($option)
	} else {
		set value [lindex $args 0]
		set config_($option) $value
		$self config_[string range $option 1 end] $value
	}
}
ListLabelItem instproc config_relief { option value } {
	$self widget_proc configure -relief $value
}
ListLabelItem instproc cget_relief { option } {
	$self widget_proc cget -relief
}
ListLabelItem instproc config_normalbackground { value } {
	if { ![$self set config_(-select)] } {
		$self widget_proc configure -bg $value
	}
}
ListLabelItem instproc config_normalforeground { value } {
	if { ![$self set config_(-select)] } {
		$self widget_proc configure -fg $value
	}
}
ListLabelItem instproc config_normalrelief { value } {
	if { ![$self set config_(-select)] && \
			![$self set config_(-highlight)] } {
		$self widget_proc configure -relief $value
	}
}
ListLabelItem instproc config_selectbackground { value } {
	if { [$self set config_(-select)] } {
		$self widget_proc configure -bg $value
	}
}
ListLabelItem instproc config_selectforeground { value } {
	if { [$self set config_(-select)] } {
		$self widget_proc configure -fg $value
	}
}
ListLabelItem instproc config_selectrelief { value } {
	if { [$self set config_(-select)] && \
		![$self set config_(-highlight)] } {
		$self widget_proc configure -relief $value
	}
}
ListLabelItem instproc config_highlightrelief { value } {
	if { [$self set config_(-highlight)] } {
		$self widget_proc configure -relief $value
	}
}
ListLabelItem instproc config_select { value } {
	$self instvar config_
	if { $value } {
		$self widget_proc configure -bg $config_(-selectbackground)
		$self widget_proc configure -fg $config_(-selectforeground)
		if { !$config_(-highlight) } {
			$self widget_proc configure \
					-relief $config_(-selectrelief)
		}
	} else {
		$self widget_proc configure -bg $config_(-normalbackground)
		$self widget_proc configure -fg $config_(-normalforeground)
		if { !$config_(-highlight) } {
			$self widget_proc configure \
					-relief $config_(-normalrelief)
		}
	}
}
ListLabelItem instproc config_highlight { value } {
	$self instvar config_
	if { $value } {
		$self widget_proc configure -relief $config_(-highlightrelief)
	} else {
		if { $config_(-select) } {
			$self widget_proc configure \
					-relief $config_(-selectrelief)
		} else {
			$self widget_proc configure \
					-relief $config_(-normalrelief)
		}
	}
}
WidgetClass ScrolledListbox -superclass ScrolledWindow -configspec {
	{ -itemclass itemClass ItemClass ListLabelItem config_option }
	{ -browsecmd browseCmd BrowseCmd "" config_option }
	{ -command command Command "" config_option }
	{ -selectmode selectMode SelectMode single config_selectmode }
} -default {
	{ *window.takeFocus 1 }
	{ *window.highlightThickness 0 }
}
ScrolledListbox instproc build_widget { path } {
	$self next $path
	set window [$self subwidget window]
	frame $window.dummy_ -width 0 -height 0 -relief flat \
			-bg [$window cget -bg]
	pack $window.dummy_ -side top
	$self create_bindtag
	$self set count_ 0
	$self set highlight_ ""
}
ScrolledListbox instproc create_bindtag { } {
	bind [$self subwidget bbox] <Configure> "+$self ev_bbox_resize_ %w %h"
	set window [$self subwidget window]
	bind $window <KeyPress-Up> "$self ev_key_up_"
	bind $window <KeyPress-Down> "$self ev_key_down_"
	bind $window <KeyPress-space> "$self ev_key_space_"
	bind Bindings_$self <ButtonPress-1> "+$self selection.toggle -widget \
			\[$self root_widget_ %W\]; $self browse \
			\[$self widget_to_id_ \[$self root_widget_ %W\]\]"
	bind Bindings_$self <Double-1> "+$self invoke \
			\[$self widget_to_id_ \[$self root_widget_ %W\]\]"
	bind Bindings_$self <Enter> "+if \{ \[$self root_widget_ %W\] == \
			\"%W\" \} \{ $self highlight.set -widget %W \}"
	bind Bindings_$self <Leave> "+if \{ \[$self root_widget_ %W\] == \
			\"%W\" \} \{ $self highlight.clear -widget %W \}"
}
ScrolledListbox instproc ev_bbox_resize_ { w h } {
	set window [$self subwidget window]
	set bbox   [$self subwidget bbox]
	$window.dummy_ configure \
			-width [expr $w - ([$bbox cget -bd] + \
			[$window cget -bd] + [$bbox cget -highlightthickness] \
			+ [$window cget -highlightthickness]) * 2]
}
ScrolledListbox instproc ev_key_up_ { } {
	set highlight [$self highlight.get]
	if { $highlight != "" } {
		set list [$self widget_list_]
		set idx [lsearch $list [$self id_to_widget_ $highlight]]
		if { $idx <= 0 } {
			return
		}
		incr idx -1
	} else {
		set idx 0
	}
	$self see $idx
	$self highlight.set $idx
}
ScrolledListbox instproc ev_key_down_ { } {
	set highlight [$self highlight.get]
	if { $highlight != "" } {
		set list [$self widget_list_]
		set idx [lsearch $list [$self id_to_widget_ $highlight]]
		if { $idx < 0 || $idx >= [expr [llength $list]-1] } {
			return
		}
		incr idx 1
	} else {
		set idx 0
	}
	$self see $idx
	$self highlight.set $idx
}
ScrolledListbox instproc ev_key_space_ { } {
	set highlight [$self highlight.get]
	if { $highlight != "" } {
		$self selection.toggle -id $highlight
		$self browse $highlight
	}
}
ScrolledListbox instproc root_widget_ { path } {
	set window [$self subwidget window]
	set widget $path
	while { $widget!="" && [winfo parent $widget] != $window } {
		set widget [winfo parent $widget]
	}
	if { $widget=="" } {
		error "invalid widget $path"
	}
	return $widget
}
ScrolledListbox instproc widget_list_ { } {
	set list [pack slaves [$self subwidget window]]
	return [lrange $list 1 end]
}
ScrolledListbox instproc config_option { option args } {
	$self instvar config_
	if { [llength $args]==0 } {
		return $config_($option)
	} else {
		set config_($option) [lindex $args 0]
	}
}
ScrolledListbox instproc config_selectmode { option args } {
	$self instvar config_
	if { [llength $args]==0 } {
		return $config_(-selectmode)
	}
	set value [lindex $args 0]
	switch -exact -- $value {
		single {
			set config_(-selectmode) "single"
			set selection [lindex [$self selection.get all] 0]
			$self selection.clear all
			if { $selection!="" } {
				$self selection.set -id $selection
			}
		}
		multiple {
			set config_(-selectmode) "multiple"
		}
		none {
			set config_(-selectmode) "none"
			$self selection.clear all
		}
		default {
			error "invalid selectmode \"$value\". must be one of\
					\"single\", \"multiple\", or \"none\""
		}
	}
}
ScrolledListbox instproc browse { id } {
	set browsecmd [$self cget -browsecmd]
	if { $browsecmd!="" } {
		uplevel #0 $browsecmd [list $id]
	}
}
ScrolledListbox instproc invoke { id } {
	set command [$self cget -command]
	if { $command!="" } {
		uplevel #0 $command [list $id]
	}
}
ScrolledListbox instproc ID { idVar arguments { idx 0 } } {
	upvar $idVar id
	if { [llength $arguments] <= $idx } {
		error "missing arguments"
	}
	set arg [lindex $arguments $idx]
	switch -exact -- $arg {
		-id {
			set end [expr $idx+2]
			if { [llength $arguments] < $end } {
				error "missing argument for \"-id\""
			}
			set id [lindex $arguments [expr $idx+1]]
			return $end
		}
		-widget {
			set end [expr $idx+2]
			if { [llength $arguments] < $end } {
				error "missing argument for \"-widget\""
			}
			set widget [lindex $arguments [expr $idx+1]]
			set id [$self widget_to_id_ $widget]
			return $end
		}
		-value {
			set end [expr $idx+2]
			if { [llength $arguments] < $end } {
				error "missing argument for \"-value\""
			}
			set widget [lindex $arguments [expr $idx+1]]
			set id [$self value_to_id_ $widget]
			return $end
		}
		default {
			set id [$self index_to_id_ $arg]
			return [expr $idx+1]
		}
	}
}
ScrolledListbox instproc widget_to_id_ { widget } {
	$self instvar widget_to_id_
	if [info exists widget_to_id_($widget)] {
		return $widget_to_id_($widget)
	} else {
		error "invalid widget \"$widget\""
	}
}
ScrolledListbox instproc value_to_id_ { value } {
	foreach widget [self widget_list_] {
		if { $value == [$self info.value -widget $widget] } {
			return $id
		}
	}
	error "invalid value \"$value\""
}
ScrolledListbox instproc index_to_id_ { index } {
	set widget [lindex [$self widget_list_] $index]
	if { $widget=="" } {
		error "invalid index \"$index\""
	}
	return [$self widget_to_id_ $widget]
}
ScrolledListbox instproc id_to_widget_ { id } {
	$self instvar id_to_widget_
	if [info exists id_to_widget_($id)] {
		return $id_to_widget_($id)
	} else {
		error "invalid id \"$id\""
	}
}
ScrolledListbox instproc id_to_value_ { id } {
	set widget [$self id_to_widget_ $id]
	return [$widget cget -value]
}
ScrolledListbox instproc insert { where args } {
	$self instvar count_ id_to_widget_ widget_to_id_
	switch -exact -- $where {
		end {
			set where ""
		}
		after {
			set idx [$self ID where_id $args]
			set where "-after [$self id_to_widget_ $where_id]"
			set args [lrange $args $idx end]
		}
		before {
			set idx [$self ID where_id $args]
			set where "-before [$self id_to_widget_ $where_id]"
			set args [lrange $args $idx end]
		}
		default {
			error "invalid argument \"$where\". must be one of\
					\"end\", \"after\", or \"before\""
		}
	}
	set window [$self subwidget window]
	set item_class [$self cget -itemclass]
	if { $item_class=="" } {
		error "must configure -itemclass before inserting any elements"
	}
	foreach arg $args {
		if { [lindex $arg 0] == "-id" } {
			if { [llength $arg] <= 1 } {
				error "missing argument for \"-id\""
			}
			set id [lindex $arg 1]
			set arg [lrange $arg 2 end]
		} else {
			set id #$count_
		}
		if { [info exists id_to_widget_($id)] } {
			error "id \"$id\" already exists"
		}
		set widget $window.item_$count_
		incr count_
		$item_class $widget -value $arg
		$self bindtag_recursive_ $widget
		if { $where=="" } {
			pack $widget -side top -fill x -expand 1
		} else {
			eval pack [list $widget] -side top -fill x -expand 1 \
					$where
		}
		set id_to_widget_($id) $widget
		set widget_to_id_($widget) $id
	}
}
ScrolledListbox instproc delete { args } {
	$self instvar id_to_widget_ widget_to_id_ selection_ highlight_
	if { [lindex $args 0]=="all" } {
		if { [llength $args]!=1 } {
			error "extra arguments starting at argument 2"
		}
		foreach widget [$self widget_list_] {
			destroy $widget
		}
		catch {
			unset id_to_widget_
			unset widget_to_id_
			unset selection_
		}
		set highlight_ ""
	} else {
		set id [eval [list $self] info.id $args]
		set widget [$self id_to_widget_ $id]
		destroy $widget
		catch {
			unset id_to_widget_($id)
			unset widget_to_id_($widget)
			unset selection_($id)
		}
		if { $highlight_==$id } {
			set highlight_ ""
		}
	}
}
ScrolledListbox instproc bindtag_recursive_ { widget } {
	$self bindtag_ $widget
	foreach path [winfo children $widget] {
		$self bindtag_recursive_ $path
	}
}
ScrolledListbox instproc bindtag_ { widget } {
	set tags [bindtags $widget]
	if {[lsearch -exact $tags Bindings_$self] == -1} {
		bindtags $widget [concat [list Bindings_$self] $tags]
	}
}
ScrolledListbox instproc see { args } {
	set id [eval [list $self] info.id $args]
	set widget [$self id_to_widget_ $id]
	set y1 [winfo y $widget]
	set y2 [expr $y1 + [winfo height $widget] - 1]
	set viewable [$self subwidget bbox yview]
	set scrollregion [$self subwidget bbox cget -scrollregion]
	set height [expr [lindex $scrollregion 3] - [lindex $scrollregion 1]]
	set bbox_y1 [expr $height * [lindex $viewable 0] + \
			[lindex $scrollregion 1]]
	set bbox_y2 [expr $height * [lindex $viewable 1] + \
			[lindex $scrollregion 1]]
	if { $y1 < $bbox_y1 } {
		set bbox_y1 $y1
		$self subwidget bbox yview moveto \
				[expr double($bbox_y1)/double($height)]
	} elseif { $y2 > $bbox_y2 } {
		set bbox_y1 [expr $y2 - ($bbox_y2 - $bbox_y1)]
		$self subwidget bbox yview moveto \
				[expr double($bbox_y1)/double($height)]
	}
}
ScrolledListbox instproc info { method args } {
	if { [$class info instprocs info.$method] == "info.$method" } {
		return [eval [list $self] [list info.$method] $args]
	} else {
		return [eval [list $self] next [list $method] $args]
	}
}
ScrolledListbox instproc info.id { args } {
	set idx [$self ID id $args]
	if { [llength $args] > $idx } {
		error "extra arguments starting with argument $idx"
	}
	return $id
}
ScrolledListbox instproc info.widget { args } {
	set id [eval [list $self] info.id $args]
	return [$self id_to_widget_ $id]
}
ScrolledListbox instproc info.value { args } {
	set id [eval [list $self] info.id $args]
	return [$self id_to_value_ $id]
}
ScrolledListbox instproc info.all { {what {}} } {
	switch -exact -- $what {
		{} -
		-id {
			set ids {}
			foreach widget [$self widget_list_] {
				lappend ids [$self widget_to_id_ $widget]
			}
			return $ids
		}
		-widget {
			return [$self widget_list_]
		}
		-value {
			set values
			foreach widget [$self widget_list_] {
				set id [$self widget_to_id_ $widget]
				lappend values [$self id_to_value_ $id]
			}
			return $values
		}
		default {
			error "invalid argument \"$what\". must be one of\
					\"-id\", \"-widget\", or \"-value\""
		}
	}
}
ScrolledListbox instproc info.exists { args } {
	set len [llength $args]
	if { $len > 2 } {
		error "extra arguments"
	}
	switch -exact -- [lindex $args 0] {
		-id {
			if { $len < 2 } {
				error "missing argument for \"-id\""
			}
			return [info exists id_to_widget_([lindex $args 1])]
		}
		-widget {
			if { $len < 2 } {
				error "missing argument for \"-widget\""
			}
			return [info exists widget_to_id_([lindex $args 1])]
		}
		-value {
			if { $len < 2 } {
				error "missing argument for \"-widget\""
			}
			return ![catch {$self value_to_id_ [lindex $args 1]}]
		}
		default {
			if { $len > 1 } {
				error "extra arguments"
			}
			return ![catch {$self index_to_id_ [lindex $args 1]}]
		}
	}
}
ScrolledListbox instproc info.numelems { } {
	return [llength [$self widget_list_]]
}
ScrolledListbox instproc selection { method args } {
	eval [list $self] [list selection.$method] $args
}
ScrolledListbox instproc selection.set { args } {
	$self instvar selection_
	set selectmode [$self cget -selectmode]
	if { $selectmode=="none" } {
		return
	}
	if { [lindex $args 0]=="all" } {
		if { [llength $args] > 1 } {
			error "extra arguments starting at argument 2"
		}
		foreach widget [$self widget_list_] {
			$self selection.set -widget $widget
		}
	}
	set id [eval [list $self] info.id $args]
	if { [info exists selection_($id)] } {
		return
	}
	if { [$self cget -selectmode]=="single" } {
		$self selection.clear all
	}
	set selection_($id) 1
	set widget [$self id_to_widget_ $id]
	$widget configure -select 1
}
ScrolledListbox instproc selection.get { args } {
	$self instvar selection_
	if { [llength $args]==0 } {
		return [array names selection_]
	}
	if { [lindex $args 0]=="all" } {
		if { [llength $args] > 1 } {
			error "extra arguments starting at argument 2"
		}
		return [array names selection_]
	}
	set id [eval [list $self] info.id $args]
	if { [info exists selection_($id)] } {
		return $id
	} else {
		return ""
	}
}
ScrolledListbox instproc selection.clear { args } {
	$self instvar selection_
	if { [llength $args]==0 } {
		$self selection.clear_all_
		return
	}
	if { [lindex $args 0]=="all" } {
		if { [llength $args] > 1 } {
			error "extra arguments starting at argument 2"
		}
		$self selection.clear_all_
		return
	}
	set id [eval [list $self] info.id $args]
	if { [info exists selection_($id)] } {
		unset selection_($id)
		[$self id_to_widget_ $id] configure -select 0
	} else {
		return
	}
}
ScrolledListbox instproc selection.clear_all_ { } {
	$self instvar selection_
	foreach id [array names selection_] {
		unset selection_($id)
		[$self id_to_widget_ $id] configure -select 0
	}
}
ScrolledListbox instproc selection.toggle { args } {
	set id [eval [list $self] info.id $args]
	if { [$self selection.get -id $id]=="" } {
		$self selection.set -id $id
	} else {
		$self selection.clear -id $id
	}
}
ScrolledListbox instproc highlight { method args } {
	eval [list $self] [list highlight.$method] $args
}
ScrolledListbox instproc highlight.set { args } {
	$self instvar highlight_
	set id [eval [list $self] info.id $args]
	if { $id == $highlight_ } {
		return
	}
	if { $highlight_!="" } {
		[$self id_to_widget_ $highlight_] configure -highlight 0
	}
	set highlight_ $id
	[$self id_to_widget_ $id] configure -highlight 1
}
ScrolledListbox instproc highlight.get { args } {
	$self instvar highlight_
	if { [llength $args]==0 } {
		return $highlight_
	}
	set id [eval [list $self] info.id $args]
	if { $highlight_==$id } {
		return $id
	} else {
		return ""
	}
}
ScrolledListbox instproc highlight.clear { args } {
	$self instvar highlight_
	if { [llength $args]==0 } {
		[$self id_to_widget_ $highlight_] configure -highlight 0
		set highlight_ ""
	} else {
		set id [eval [list $self] info.id $args]
		if { $highlight_==$id } {
			[$self id_to_widget_ $highlight_] configure \
					-highlight 0
			set highlight_ ""
		}
	}
}
ScrolledListbox instproc highlight.toggle { args } {
	$self instvar highlight_
	if { [llength $args]==0 } {
		$self highlight.clear
	} else {
		set id [eval [list $self] info.id $args]
		if { $id == $highlight_ } {
			$self highlight.clear
		} else {
			$self highlight.set -id $id
		}
	}
}
WidgetClass HierarchicalListboxItem -configspec {
	{ -value       value       Value       {}            config_value }
	{ -select      select      Select      0             config_option }
	{ -highlight   highlight   Highlight   0             config_option }
	{ -normalbackground normalBackground NormalBackground \
			WidgetDefault(-background) config_option }
	{ -normalforeground normalForeground NormalForeground \
			WidgetDefault(-foreground) config_option }
	{ -normalrelief normalRelief NormalRelief flat config_option }
	{ -selectbackground selectBackground SelectBackground WidgetDefault \
			config_option }
	{ -selectforeground selectForeground SelectForeground WidgetDefault \
			config_option }
	{ -selectrelief selectRelief SelectRelief sunken config_option }
	{ -highlightrelief highlightRelief HighlightRelief raised \
			config_option }
} -default {
	{ .borderWidth WidgetDefault }
	{ *font WidgetDefault }
	{ *Label.padX 1 }
	{ *Label.padY 0 }
	{ *Label.borderWidth 0 }
}
HierarchicalListboxItem instproc init { args } {
	$self instvar config_
	set config_(-value) {}
	set config_(-select) 0
	set config_(-highlight) 0
	set config_(-normalbackground) Black
	set config_(-normalforeground) Black
	set config_(-normalrelief)     flat
	set config_(-selectbackground) Black
	set config_(-selectforeground) Black
	set config_(-selectrelief)     sunken
	set config_(-highlightrelief)  raised
	eval [list $self] next $args	
}
HierarchicalListboxItem instproc build_widget { path } {
	label $path.padding
	label $path.image
	label $path.text -anchor w
	pack $path.padding -side left
	pack $path.image -side left
	pack $path.text  -side left -fill x -anchor w
}
HierarchicalListboxItem instproc config_value { option args } {
	$self instvar config_
	if { [llength $args]==0 } {
		if [info exists config_(-value)] {
			return $config_(-value)
		} else {
			return ""
		}
	} else {
		set value [lindex $args 0]
		set image [lindex $value 0]
		set config_(-value) [lindex $value 1]
		set split [split $config_(-value) "/"]
		if { $config_(-value)=="/" || [llength $split] <= 1 } {
			set level 0
			set label $config_(-value)
		} else {
			set level [llength $split]
			set label [lindex $split [expr $level-1]]
		}
		$self subwidget padding configure -padx [expr $level * 4]
		$self subwidget image   configure -image $image
		$self subwidget text    configure -text  $label
	}
}
HierarchicalListboxItem instproc config_option { option args } {
	$self instvar config_
	if { [llength $args]==0 } {
		return $config_($option)
	} else {
		set value [lindex $args 0]
		$self config_[string range $option 1 end] $value
		set config_($option) $value
	}
}
HierarchicalListboxItem instproc config_background { value } {
	set path [$self info path]
	$path configure -bg $value
	foreach label [winfo children $path] {
		$label configure -bg $value
	}
}
HierarchicalListboxItem instproc config_foreground { value } {
	foreach label [winfo children [$self info path]] {
		$label configure -fg $value
	}
}
HierarchicalListboxItem instproc config_relief { value } {
	[$self info path] configure -relief $value
}
HierarchicalListboxItem instproc config_normalbackground { value } {
	if { ![$self set config_(-select)] } {
		$self config_background $value
	}
}
HierarchicalListboxItem instproc config_normalforeground { value } {
	if { ![$self set config_(-select)] } {
		$self config_foreground $value
	}
}
HierarchicalListboxItem instproc config_normalrelief { value } {
	if { ![$self set config_(-select)] && \
			![$self set config_(-highlight)] } {
		$self config_relief $value
	}
}
HierarchicalListboxItem instproc config_selectbackground { value } {
	if { [$self set config_(-select)] } {
		$self config_background $value
	}
}
HierarchicalListboxItem instproc config_selectforeground { value } {
	if { [$self set config_(-select)] } {
		$self config_foreground $value
	}
}
HierarchicalListboxItem instproc config_selectrelief { value } {
	if { [$self set config_(-select)] && \
		![$self set config_(-highlight)] } {
		$self config_relief $value
	}
}
HierarchicalListboxItem instproc config_highlightrelief { value } {
	if { [$self set config_(-highlight)] } {
		$self config_relief $value
	}
}
HierarchicalListboxItem instproc config_select { value } {
	$self instvar config_
	if { $value } {
		$self config_background $config_(-selectbackground)
		$self config_foreground $config_(-selectforeground)
		if { !$config_(-highlight) } {
			$self config_relief $config_(-selectrelief)
		}
	} else {
		$self config_background $config_(-normalbackground)
		$self config_foreground $config_(-normalforeground)
		if { !$config_(-highlight) } {
			$self config_relief $config_(-normalrelief)
		}
	}
}
HierarchicalListboxItem instproc config_highlight { value } {
	$self instvar config_
	if { $value } {
		$self config_relief $config_(-highlightrelief)
	} else {
		if { $config_(-select) } {
			$self config_relief $config_(-selectrelief)
		} else {
			$self config_relief $config_(-normalrelief)
		}
	}
}
WidgetClass MultiColumnListbox -superclass ScrolledCanvas -configspec {
	{ -browsecmd browseCmd BrowseCmd "" config_option }
	{ -command command Command "" config_option }
	{ -selectbackground selectBackground SelectBackground #a0a0ff \
			config_option }
	{ -font font Font WidgetDefault	config_option }
} -default {
	{ .scrollbar horizontal }
	{ *hscroll.highlightThickness 0 }
	{ *hscroll.takeFocus 0 }
	{ *bbox.borderWidth 2 }
	{ *bbox.width 400 }
	{ *bbox.height 120 }
}
MultiColumnListbox instproc config_option { option args } {
	$self instvar data
	if { [llength $args] == {} } {
		return $data($option)
	} else {
		set data($option) [lindex $args 0]
	}
}
MultiColumnListbox instproc build_widget { path } {
	$self instvar data
	$self next $path
	set data(canvas) [$self subwidget bbox]
	set data(sbar) [$self subwidget hscroll]
	set data(maxIW) 1
	set data(maxIH) 1
	set data(maxTW) 1
	set data(maxTH) 1
	set data(numItems) 0
	set data(curItem)  {}
	set data(noScroll) 1
	bind $data(canvas) <Configure> "+$self arrange"
	bind $data(canvas) <1>         "$self btn1 %x %y"
	bind $data(canvas) <B1-Motion> "$self motion1 %x %y"
	bind $data(canvas) <Double-1>  "$self double1 %x %y"
	bind $data(canvas) <ButtonRelease-1> "tkCancelRepeat"
	bind $data(canvas) <B1-Leave>  "$self leave1 %x %y"
	bind $data(canvas) <B1-Enter>  "tkCancelRepeat"
	bind $data(canvas) <Up>        "$self up_down -1"
	bind $data(canvas) <Down>      "$self up_down  1"
	bind $data(canvas) <Left>      "$self left_right -1"
	bind $data(canvas) <Right>     "$self left_right  1"
	bind $data(canvas) <Return>    "$self return_key"
	bind $data(canvas) <KeyPress>  "$self key_press %A"
	bind $data(canvas) <Control-KeyPress> ";"
	bind $data(canvas) <Alt-KeyPress>  ";"
	bind $data(canvas) <FocusIn>   "$self focus_in"
}
MultiColumnListbox instproc auto_scan { } {
	$self instvar data
	global tkPriv
	set x $tkPriv(x)
	set y $tkPriv(y)
	if $data(noScroll) {
		return
	}
	if {$x >= [winfo width $data(canvas)]} {
		$data(canvas) xview scroll 1 units
	} elseif {$x < 0} {
		$data(canvas) xview scroll -1 units
	} elseif {$y >= [winfo height $data(canvas)]} {
	} elseif {$y < 0} {
	} else {
		return
	}
	$self motion1 $x $y
	set tkPriv(afterId) [after 50 $self auto_scan]
}
MultiColumnListbox instproc delete_all {} {
	$self instvar data
	$self instvar itemList
	$data(canvas) delete all
	catch {unset data(selected)}
	catch {unset data(rect)}
	catch {unset data(list)}
	catch {unset itemList}
	set data(numItems) 0
	set data(curItem)  {}
}
MultiColumnListbox instproc add {image text} {
	$self instvar data
	$self instvar itemList
	$self instvar textList
	set iTag [$data(canvas) create image 0 0 -image $image -anchor nw]
	set tTag [$data(canvas) create text  0 0 -text  $text  -anchor nw \
			-font $data(-font)]
	set rTag [$data(canvas) create rect  0 0 0 0 -fill "" -outline ""]
	set b [$data(canvas) bbox $iTag]
	set iW [expr [lindex $b 2]-[lindex $b 0]]
	set iH [expr [lindex $b 3]-[lindex $b 1]]
	if {$data(maxIW) < $iW} {
		set data(maxIW) $iW
	}
	if {$data(maxIH) < $iH} {
		set data(maxIH) $iH
	}
	set b [$data(canvas) bbox $tTag]
	set tW [expr [lindex $b 2]-[lindex $b 0]]
	set tH [expr [lindex $b 3]-[lindex $b 1]]
	if {$data(maxTW) < $tW} {
		set data(maxTW) $tW
	}
	if {$data(maxTH) < $tH} {
		set data(maxTH) $tH
	}
	lappend data(list) [list $iTag $tTag $rTag $iW $iH $tW $tH \
			$data(numItems)]
	set itemList($rTag) [list $iTag $tTag $text $data(numItems)]
	set textList($data(numItems)) [string tolower $text]
	incr data(numItems)
}
MultiColumnListbox instproc arrange {} {
	$self instvar data
	if ![info exists data(list)] {
		if {[info exists data(canvas)] && \
				[winfo exists $data(canvas)]} {
			set data(noScroll) 1
			$data(sbar) config -command ""
		}
		return
	}
	set W [winfo width  $data(canvas)]
	set H [winfo height $data(canvas)]
	set pad [expr [$data(canvas) cget -highlightthickness] + \
			[$data(canvas) cget -bd]]
	incr W -[expr $pad*2]
	incr H -[expr $pad*2]
	set dx [expr $data(maxIW) + $data(maxTW) + 4]
	if {$data(maxTH) > $data(maxIH)} {
		set dy $data(maxTH)
	} else {
		set dy $data(maxIH)
	}
	set shift [expr $data(maxIW) + 4]
	set x [expr $pad * 2]
	set y [expr $pad * 1]
	set usedColumn 0
	foreach pair $data(list) {
		set usedColumn 1
		set iTag [lindex $pair 0]
		set tTag [lindex $pair 1]
		set rTag [lindex $pair 2]
		set iW   [lindex $pair 3]
		set iH   [lindex $pair 4]
		set tW   [lindex $pair 5]
		set tH   [lindex $pair 6]
		set i_dy [expr ($dy - $iH)/2]
		set t_dy [expr ($dy - $tH)/2]
		$data(canvas) coords $iTag $x                 [expr $y + $i_dy]
		$data(canvas) coords $tTag [expr $x + $shift] [expr $y + $t_dy]
		$data(canvas) coords $tTag [expr $x + $shift] [expr $y + $t_dy]
		$data(canvas) coords $rTag $x $y [expr $x+$dx] [expr $y+$dy]
		incr y $dy
		if {[expr $y + $dy] >= $H} {
			set y [expr $pad * 1]
			incr x $dx
			set usedColumn 0
		}
	}
	if {$usedColumn} {
		set sW [expr $x + $dx]
	} else {
		set sW $x
	}
	if {$sW < $W} {
		$data(canvas) config -scrollregion "$pad $pad $sW $H"
		$data(sbar) config -command ""
		$data(canvas) xview moveto 0
		set data(noScroll) 1
	} else {
		$data(canvas) config -scrollregion "$pad $pad $sW $H"
		$data(sbar) config -command "$data(canvas) xview"
		set data(noScroll) 0
	}
	set data(itemsPerColumn) [expr ($H-$pad)/$dy]
	if {$data(itemsPerColumn) < 1} {
		set data(itemsPerColumn) 1
	}
	if {$data(curItem) != {}} {
		$self select [lindex [lindex $data(list) $data(curItem)] 2] 0
	}
}
MultiColumnListbox instproc invoke {} {
	$self instvar data
	if {[string compare $data(-command) ""] && \
			[info exists data(selected)]} {
		eval $data(-command) [list $data(selected)]
	}
}
MultiColumnListbox instproc see {rTag} {
	$self instvar data
	$self instvar itemList
	if $data(noScroll) {
		return
	}
	set sRegion [$data(canvas) cget -scrollregion]
	if ![string compare $sRegion {}] {
		return
	}
	if ![info exists itemList($rTag)] {
		return
	}
	set bbox [$data(canvas) bbox $rTag]
	set pad [expr [$data(canvas) cget -highlightthickness] + \
			[$data(canvas) cget -bd]]
	set x1 [lindex $bbox 0]
	set x2 [lindex $bbox 2]
	incr x1 -[expr $pad * 2]
	incr x2 -[expr $pad * 1]
	set cW [expr [winfo width $data(canvas)] - $pad*2]
	set scrollW [expr [lindex $sRegion 2]-[lindex $sRegion 0]+1]
	set dispX [expr int([lindex [$data(canvas) xview] 0]*$scrollW)]
	set oldDispX $dispX
	if {[expr $x2 - $dispX] >= $cW} {
		set dispX [expr $x2 - $cW]
	}
	if {[expr $x1 - $dispX] < 0} {
		set dispX $x1
	}
	if {$oldDispX != $dispX} {
		set fraction [expr double($dispX)/double($scrollW)]
		$data(canvas) xview moveto $fraction
	}
}
MultiColumnListbox instproc select_at_XY {x y} {
	$self instvar data
	$self select [$data(canvas) find closest \
			[$data(canvas) canvasx $x] [$data(canvas) canvasy $y]]
}
MultiColumnListbox instproc select {rTag {callBrowse 1}} {
	$self instvar data
	$self instvar itemList
	if ![info exists itemList($rTag)] {
		return
	}
	set iTag   [lindex $itemList($rTag) 0]
	set tTag   [lindex $itemList($rTag) 1]
	set text   [lindex $itemList($rTag) 2]
	set serial [lindex $itemList($rTag) 3]
	if ![info exists data(rect)] {
		set data(rect) [$data(canvas) create rect 0 0 0 0 \
				-fill $data(-selectbackground) \
				-outline $data(-selectbackground)]
	}
	$data(canvas) lower $data(rect)
	set bbox [$data(canvas) bbox $tTag]
	eval $data(canvas) coords $data(rect) $bbox
	set data(curItem) $serial
	set data(selected) $text
	if {$callBrowse} {
		if [string compare $data(-browsecmd) ""] {
			eval $data(-browsecmd) [list $text]
		}
	}
}
MultiColumnListbox instproc unselect {} {
	$self instvar data
	if [info exists data(rect)] {
		$data(canvas) delete $data(rect)
		unset data(rect)
	}
	if [info exists data(selected)] {
		unset data(selected)
	}
	set data(curItem)  {}
}
MultiColumnListbox instproc get {} {
	$self instvar data
	if [info exists data(selected)] {
		return $data(selected)
	} else {
		return ""
	}
}
MultiColumnListbox instproc btn1 {x y} {
	$self instvar data
	focus $data(canvas)
	$self select_at_XY $x $y
}
MultiColumnListbox instproc motion1 {x y} {
	global tkPriv
	set tkPriv(x) $x
	set tkPriv(y) $y
	$self select_at_XY $x $y
}
MultiColumnListbox instproc double1 {x y} {
	$self instvar data
	if {$data(curItem) != {}} {
		$self invoke
	}
}
MultiColumnListbox instproc return_key {} {
	$self invoke
}
MultiColumnListbox instproc leave1 {x y} {
	global tkPriv
	set tkPriv(x) $x
	set tkPriv(y) $y
	$self auto_scan
}
MultiColumnListbox instproc focus_in {} {
	$self instvar data
	if ![info exists data(list)] {
		return
	}
	if {$data(curItem) == {}} {
		set rTag [lindex [lindex $data(list) 0] 2]
		$self select $rTag
	}
}
MultiColumnListbox instproc up_down {amount} {
	$self instvar data
	if ![info exists data(list)] {
		return
	}
	if {$data(curItem) == {}} {
		set rTag [lindex [lindex $data(list) 0] 2]
	} else {
		set oldRTag [lindex [lindex $data(list) $data(curItem)] 2]
		set rTag [lindex [lindex $data(list) [expr \
				$data(curItem)+$amount]] 2]
		if ![string compare $rTag ""] {
			set rTag $oldRTag
		}
	}
	if [string compare $rTag ""] {
		$self select $rTag
		$self see $rTag
	}
}
MultiColumnListbox instproc left_right {amount} {
	$self instvar data
	if ![info exists data(list)] {
		return
	}
	if {$data(curItem) == {}} {
		set rTag [lindex [lindex $data(list) 0] 2]
	} else {
		set oldRTag [lindex [lindex $data(list) $data(curItem)] 2]
		set newItem [expr $data(curItem)+($amount*\
				$data(itemsPerColumn))]
		set rTag [lindex [lindex $data(list) $newItem] 2]
		if ![string compare $rTag ""] {
			set rTag $oldRTag
		}
	}
	if [string compare $rTag ""] {
		$self select $rTag
		$self see $rTag
	}
}
MultiColumnListbox instproc key_press {key} {
	global tkPriv
	set w [$self info path]
	append tkPriv(ILAccel,$w) $key
	$self goto $tkPriv(ILAccel,$w)
	catch {
		after cancel $tkPriv(ILAccel,$w,afterId)
	}
	set tkPriv(ILAccel,$w,afterId) [after 500 $self reset]
}
MultiColumnListbox instproc goto {text} {
	$self instvar data
	$self instvar textList
	global tkPriv
	if ![info exists data(list)] {
		return
	}
	if {[string length $text] == 0} {
		return
	}
	if {$data(curItem) == {} || $data(curItem) == 0} {
		set start  0
	} else {
		set start  $data(curItem)
	}
	set text [string tolower $text]
	set theIndex -1
	set less 0
	set len [string length $text]
	set len0 [expr $len-1]
	set i $start
	while 1 {
		set sub [string range $textList($i) 0 $len0]
		if {[string compare $text $sub] == 0} {
			set theIndex $i
			break
		}
		incr i
		if {$i == $data(numItems)} {
			set i 0
		}
		if {$i == $start} {
			break
		}
	}
	if {$theIndex > -1} {
		set rTag [lindex [lindex $data(list) $theIndex] 2]
		$self select $rTag 0
		$self see $rTag
	}
}
MultiColumnListbox instproc reset { } {
	global tkPriv
	set w [$self info path]
	catch {unset tkPriv(ILAccel,$w)}
}
Class SDPParser
Class SDPMedia
Class SDPTime
Class SDPMessage 
SDPParser instproc init { {ordered_syntax 1} } {
	$self next
	$self instvar nextsym_ ordered_syntax_ parse_error_
	set nextsym_(start) "v"
	set nextsym_(v) "o"
	set nextsym_(o) "s"
	set nextsym_(s) "i u e p c b t"
	set nextsym_(i) "u e p c b t"
	set nextsym_(u) "e p c b t"
	set nextsym_(e) "e p c b t"
	set nextsym_(p) "e p c b t"
	set nextsym_(c) "b t "
	set nextsym_(b) "t"
	set nextsym_(t) "t r z k a m"
	set nextsym_(r) "t z k a m"
	set nextsym_(z) "k a m"
	set nextsym_(k) "a m"
	set nextsym_(a) "a m"
	set nextsym_(m) "m i:m c:m b:m k:m a:m v"
	set nextsym_(i:m) "m c:m b:m k:m a:m v"
	set nextsym_(c:m) "m b:m k:m a:m v"
	set nextsym_(b:m) "m k:m a:m v"
	set nextsym_(k:m) "m a:m v"
	set nextsym_(a:m) "m a:m v"
	set ordered_syntax_ $ordered_syntax
	set parse_error_ ""
}
SDPParser instproc check_syntax { last cur media } {
	$self instvar nextsym_
	if ![info exists nextsym_($last)] {
		return ""
	}
	foreach s $nextsym_($last) {
		set t [split $s :]
		if { [lindex $t 0] == $cur } {
			return $s
		}
	}
	return ""
}
SDPParser instproc parse { announcement } {
	$self instvar parse_error_ ordered_syntax_
	set media ""
	set allmsgs ""
	set lasttag "start"
	set lines [split $announcement "\n"]
	set parse_error_ ""
	set lnum 0
	foreach line $lines {
		incr lnum
		if { $line=={} } continue
		set sline [split $line =]
		set tag [lindex $sline 0]
		set value [join [lrange $sline 1 end]]
		set ret [$self check_syntax $lasttag $tag $media]
		if { $ret == "" && $ordered_syntax_==1 } {
			set parse_error_ "$class: syntax error between\
					$lasttag and $tag in line $lnum."
			foreach m $allmsgs {
				delete $m
			}
			return ""
		}
		set lasttag $ret
		switch $tag {
		v { 
			set media ""
			set msg [new SDPMessage]
			lappend allmsgs $msg
			$msg set version_ $value
		}
		o {
			$msg set creator_ [lindex $value 0]
			$msg set createtime_ [lindex $value 1]
			$msg set modtime_  [lindex $value 2]
			$msg set nettype_ [lindex $value 3]	
			$msg set addrtype_ [lindex $value 3]
			$msg set createaddr_ [lindex $value 5]
		}
		s {	
			$msg set session_name_ $value 
		}
		i {	
			if { $media != "" } {
				$media set session_info_ $value 
			} else {
				$msg set session_info_ $value 
			}
		}
		p {
			set tmp "" 
			catch { set tmp [$msg set phonelist_] }
			lappend tmp $value
			$msg set phonelist_ $tmp
		}
		e { 
			set tmp "" 
			catch { set tmp [$msg set emaillist_] }
			lappend tmp $value
			$msg set emaillist_ $tmp
		}
		u { 
			$msg set uri_ $value
		} 
		c {
			if { $media != "" } {
				$media set nettype_ [lindex $value 0]
				$media set addrtype_ [lindex $value 1]
				$media set caddr_ [lindex $value 2]
			} else {
				$msg set nettype_ [lindex $value 0]
				$msg set addrtype_ [lindex $value 1]
				$msg set caddr_ [lindex $value 2]
			}
		}
		b {
			set bwspec [split $value :]
			if { $media != "" } {
				$media set bwmod_ [lindex $bwspec 0]
				$media set bwval_ [lindex $bwspec 1]
			} else {
				$msg set bwmod_ [lindex $bwspec 0]
				$msg set bwval_ [lindex $bwspec 1]
			}
		}
		t {
			set tdes [new SDPTime]
			$tdes set fields_(t) $value
			$tdes set starttime_ [lindex $value 0]
			$tdes set endtime_ [lindex $value 1]
			set tmp [$msg set alltimedes_]
			lappend tmp $tdes
			$msg set alltimedes_ $tmp
		}
		r {
			$tdes set fields_(r) $value
			$tdes set repeat_interval_ [lindex $value 0]
			$tdes set active_duration_ [lindex $value 1]
			$tdes set offlist_ [lrange $value 2 end]
		}
		z {
			set nval [llength $value]
			if [expr 2 * ($nval / 2) != $nval] {
				foreach m $allmsgs {
					delete $m
				}
				return ""
			}
			$self instvar zoneinfo_
			for { set n 0 } { $n < $nval } { incr n } {
				set adjtime [lindex $value $n]
				incr n
				set offset [lindex $value $n]
				lappend zoneinfo_ "$adjtime $offset"
			}
		}
		k {
			set tmp [split $value :]
			if { $media != "" } {
				$media set crypt_method_ [lindex $tmp 0]
				$media set crypt_key_ [lindex $tmp 1]
			} else {
				$msg set crypt_method_ [lindex $tmp 0]
				$msg set crypt_key_ [lindex $tmp 1]
			}
		}
		a {
			set attribute [split $value ":"]
			set attname [lindex $attribute 0]
			set attval [join [lrange $attribute 1 end] ":"]
			if { $media != "" } {
				set target $media
			} else {
				set target $msg
			}
			if [catch {$target set attributes_($attname)}] {
				$target set attributes_($attname) {}
			}
			$target set attributes_($attname) \
			    [concat [$target set attributes_($attname)] \
				 [list $attval]]
		}
		m {
			set media [new SDPMedia $msg]
			set mt [lindex $value 0]
			$media set mediatype_ $mt
			$media set port_  [lindex $value 1]
			$media set proto_ [lindex $value 2]
			$media set fmt_ [lrange $value 3 end]
			set tmp ""
			catch { set tmp [$msg set media_array_($mt)] }
			lappend tmp $media
			$msg set media_array_($mt) $media
			set tmp [$msg set allmedia_]
			lappend tmp $media
			$msg set allmedia_ $tmp
		}
		default {
			set parse_error_ "$class: error unknown modifier $tag."
			foreach m $allmsgs {
				delete $m
			}
			return ""
		}
		}
		set tmp [$msg set msgtext_]
		lappend tmp $line
		$msg set msgtext_ $tmp
		if { $media != "" } {
			$media set fields_($tag) $value
		} else {
			$msg set fields_($tag) $value
		}
	}
	foreach msg $allmsgs {
		set tmp [$msg set msgtext_]
		set tmp [join $tmp \n]
		append tmp \n
		$msg set msgtext_ $tmp
	}
	return $allmsgs
}
SDPParser instproc parse_error { } {
	return [$self set parse_error_]
}
SDPMessage instproc init {} {
	$self next
	$self instvar allmedia_ alltimedes_ msgtext_
	set allmedia_ ""
	set alltimedes_ ""
	set msgtext_ ""
}
SDPMessage instproc destroy {} {
	$self instvar allmedia_ alltimedes_
	foreach m $allmedia_ {
		delete $m
	}
	foreach t $alltimedes_ {
		delete $t
	}
	$self next
}
SDPMessage instproc media { media_type } {
	$self instvar media_array_
	if [info exists media_array_($media_type)] {
		return $media_array_($media_type)
	} else {
		return ""
	}
}
SDPMessage instproc have_field { field } {
	$self instvar fields_
	return [info exists fields_($field)]
}
SDPMessage instproc field_value { field } {
	$self instvar fields_
	if [info exists fields_($field)] {
		return $fields_($field)
	} else {
		return ""
	}
}
SDPMessage instproc attributes {} {
	$self instvar attributes_
	if [info exists attributes_] {
		return [array names attributes_]
	} else {
		return ""
	}
}
SDPMessage instproc have_attr { name } {
	$self instvar attributes_
	return [info exists attributes_($name)]
}
SDPMessage instproc attr_value { name } {
    $self instvar attributes_
    if [info exists attributes_($name)] {
	    return $attributes_($name)
    } else {
	    return ""
    }
}
SDPMessage instproc obj2str {} {
	$self instvar attributes_ alltimedes_ allmedia_
	set o "v=[$self field_value v]"
	foreach f { o s i u } {
		if [$self have_field $f] {
			set n "$f=[$self field_value $f]"
			set o $o\n$n
		}
	}
	$self instvar phonelist_ emaillist_
	if [info exists phonelist_] {
		foreach e $phonelist_ {
			set n "p=$e"
			set o $o\n$n
		}
	}
	if [info exists emaillist_] {
		foreach e $emaillist_ {
			set n "e=$e"
			set o $o\n$n
		}
	}
	foreach f { c b } {
		if [$self have_field $f] {
			set n "$f=[$self field_value $f]"
			set o $o\n$n
		}
	}
	foreach t $alltimedes_ {
		set n [$t obj2str]
		set o $o\n$n
	}
	foreach f { z k } {
		if [$self have_field $f] {
			set n "$f=[$self field_value $f]"
			set o $o\n$n
		}
	}
	foreach a [$self attributes] {
		if { $attributes_($a) == "" } {
			set n "a=$a"
		} else {
			set n "a=$a:$attributes_($a)"
		}
		set o $o\n$n
	}
	foreach m $allmedia_ {
		set n [$m obj2str]
		set o $o\n$n
	}
	return $o
}
SDPMessage public unique_key {} {
    if ![$self have_field o] {
	$self warn "in SDPMessage::unique_key without o= field"
	return ""
    }
    set l [split [$self field_value o]]
    set l [lreplace $l 2 2]
    set key [join $l :]
    return $key
}
SDPMessage instproc htmlify_media { } {
    set html {}
    foreach media [$self set allmedia_] {
	append html [$media create_dynamic_html \
		[DynamicHTMLifier set html_(media)]]
    }
    return $html
}
SDPMessage instproc htmlify_times { } {
    set html {}
    foreach time [$self set alltimedes_] {
	set repeat [string tolower [$time readable_repeat]]
	if { [$time set starttime_] != 0 } {
	    append html [$time create_dynamic_html \
		    [DynamicHTMLifier set html_(time_$repeat)]]
	} else {
	    append html "Unbounded session"
	}
    }
    return $html
}
SDPMessage instproc htmlify_url { } {
    $self instvar uri_
    if [info exists uri_] {
	return "<a href=\"$uri_\">$uri_</a>"
    } else {
	return ""
    }
}
SDPMessage instproc htmlify_list { varname } {
    set list {}
    foreach elt [$self get $varname] {
	if { $list!={} } {
	    append list ", $elt"
	} else {
	    append list $elt
	}
    }
    return $list
}
SDPMessage instproc get { varname } {
    $self instvar $varname
    if [info exists $varname] {
	return [set $varname]
    } else {
	return ""
    }
}
SDPMedia instproc htmlify_mediatype { } {
    return "[$self set mediatype_]"
}
SDPMedia instproc get { varname } {
    $self instvar $varname
    if [info exists $varname] {
	return [set $varname]
    } else {
	return ""
    }
}
SDPMedia instproc init {{msg ""}} {
	$self next
	if {$msg == ""} { return }
	$self instvar attributes_ fields_
	set alist [$msg attributes]
	foreach a $alist {
		set attributes_($a) [$msg set attributes_($a)]
	}
	set vlist [$msg info vars]
	foreach f { session_info_ nettype_ addrtype_ caddr_ bwmod_ bwval_ 
		crypt_method_ crypt_key_ } {
		if { [lsearch -exact $vlist $f] >= 0 } {
			$self set $f [$msg set $f]
		}
	}
	foreach f { i c b k a } {
		if [$msg have_field $f] {
			set fields_($f) [$msg field_value $f]
		}
	}
}
SDPMedia instproc have_field { field } {
	$self instvar fields_
	return [info exists fields_($field)]
}
SDPMedia instproc field_value { field } {
	$self instvar fields_
	if [info exists fields_($field)] {
		return $fields_($field)
	} else {
		return ""
	}
}
SDPMedia instproc have_attr { name } {
	$self instvar attributes_
	return [info exists attributes_($name)]
}
SDPMedia instproc attr_value { name } {
    $self instvar attributes_
    if [info exists attributes_($name)] {
	    return $attributes_($name)
    } else {
	    return ""
    }
}
SDPMedia instproc attributes {} {
	$self instvar attributes_
	if [info exists attributes_] {
		return [array names attributes_]
	} else {
		return ""
	}
}
SDPMedia instproc obj2str {} {
	$self instvar attributes_
	set o "m=[$self field_value m]"
	foreach f { i c b k } {
		if [$self have_field $f] {
			set n "$f=[$self field_value $f]"
			set o $o\n$n
		}
	}
	foreach a [array names attributes_] {
		if { $attributes_($a) == "" } {
			set n "a=$a"
		} else {
			set n "a=$a:$attributes_($a)"
		}
		set o $o\n$n
	}
	return $o
}
SDPTime instproc have_field { field } {
	$self instvar fields_
	return [info exists fields_($field)]
}
SDPTime instproc field_value { field } {
	$self instvar fields_
	if [info exists fields_($field)] {
		return $fields_($field)
	} else {
		return ""
	}
}
SDPTime instproc obj2str {} {
	set o "t=[$self field_value t]"
	if [$self have_field r] {
		set n "r=[$self field_value r]"
		set o $o\n$n
	}
	return $o
}
SDPTime public get { varname } {
    $self instvar $varname
    if [info exists $varname] {
	return [set $varname]
    } else {
	return ""
    }
}
SDPTime public sec_until_current { time_type } {
    set sdp_time [ntp_to_unix [$self get $time_type]]
    set current [clock seconds]
    return [expr $sdp_time - $current]
}
SDPTime public current_in_interval { start end } {
    set current [unix_to_ntp [clock seconds]]
    if { [expr $start == 0 && $end == 0] } {
	return 1
    } elseif { $start == 0 } {
	return [expr $end > $current]
    } elseif { $end == 0 } {
	return [expr $start <= $current]
    } else {
	return [expr $start <= $current && $end > $current]
    }
}
SDPTime public readable_time { time_type } {
    set sec [ntp_to_unix [$self get $time_type]]
    if { $sec == 0 } {
	return *unbounded*
    } else {
	return [clock format $sec -format {%H:%M}]
    }
}
SDPTime public readable_duration { } {
    set duration [$self get active_duration_]
    set hours [expr $duration / 3600]
    if { $hours < 24 } {
	return "$hours hour(s)"
    }
    set days [expr $hours / 24]
    if { $days < 7 } {
	return "$days day(s)"
    }
    set weeks [expr $days / 7]
    return "$weeks week(s)"
}
SDPTime public readable_date { time_type } {
    set sec [ntp_to_unix [$self get $time_type]]
    if { $sec == 0 } {
	return *unbounded*
    } else {
	return [clock format $sec -format {%B %d, %Y}]
    }
}
SDPTime public readable_day { time_type } {
    set sec [ntp_to_unix [$self get $time_type]]
    if { $sec == 0 } {
	return *unbounded*
    } else {
	return [clock format $sec -format {%a}]
    }
}
SDPTime public readable_day_full { time_type } {
    set sec [ntp_to_unix [$self get $time_type]]
    if { $sec == 0 } {
	return *unbounded*
    } else {
	return [clock format $sec -format {%A}]
    }
}
SDPTime public readable_zone { time_type } {
    set sec [ntp_to_unix [$self get $time_type]]
    return [clock format $sec -format {%Z}]
}
SDPTime public readable_repeat { } {
    set interval [$self get repeat_interval_]
    if { $interval == 86400 } {
	return Daily
    } elseif { $interval == 604800 } {
	return Weekly
    } else {
	return None
    }
}
WidgetClass ASMonitorUI -default {
	{ *ScrolledListbox*Canvas.relief sunken }
	{ *ScrolledListbox*Canvas.borderWidth 1 }
	{ *ScrolledListbox.scrollbar both }
	{ *ScrolledListbox.bbox.highlightThickness 1 }
	{ *ScrolledListbox.Scrollbar.borderWidth 1 }
	{ *ScrolledListbox.Scrollbar.borderWidth 1 }
	{ *ScrolledListbox.Scrollbar.highlightThickness 1 }
	{ *ScrolledListbox.Scrollbar.width 10 }
	{ *ScrolledListbox*Canvas.width 170 }
	{ *ScrolledListbox*Canvas.height 140 }
	{ *HierarchicalListboxItem.borderWidth 1 }
	{ *HierarchicalListboxItem*font WidgetDefault(-boldfont) }
	{ *Button.borderWidth 1 }
	{ *Button.pady 0 }
}
ASMonitorUI proc.invoke {} {
	$self instvar atype_map_ atype_clr_
	set atype_map_(hm) "Host Managers"
	set atype_map_(srv) "Servents"
	set atype_map_(client) "Clients"
	set atype_map_(all) "All Agents"
	set atype_clr_(hm) blue
	set atype_clr_(srv) red
	set atype_clr_(client) darkgreen
	set atype_clr_(all) black
}
ASMonitorUI public destroy {} {
	$self instvar sdp_ agent_info_ agent_list_
	delete $sdp_
	foreach name [array names agent_info_] {
		delete $agent_info_($name)
	}
	foreach name [array names agent_list_] {
		delete $agent_list_($name)
	}
	$self next
}
ASMonitorUI public build_widget {path} {
	$self instvar sdp_
	set sdp_ [new SDPParser]
	global mash
	set toplevel [winfo toplevel $path]
	wm title $toplevel "Active Service Monitor v$mash(version)"
	frame $path.bottom
	label $path.asctrl -text "Control Address: [$self get_option asCtrl]"\
			-anchor w
	button $path.quit -text "Quit" -command "exit" -font \
			[WidgetClass widget_default -boldfont]
	pack $path.asctrl -fill both -expand 1 -anchor w -side left \
			-in $path.bottom
	pack $path.quit -fill y -anchor w -side left -in $path.bottom
	pack $path.bottom -side bottom -fill x
	ASInfoWindow $path.default_info -relief sunken -borderwidth 1 \
			-width 200
	pack $path.default_info -fill both -expand 1 -side right
	ScrolledListbox $path.agenttypes -itemclass HierarchicalListboxItem \
			-browsecmd "$self select_agent_list"
	pack $path.agenttypes -fill both -expand 1 -side top
	label $path.death_label -text "Send death packet to:" -anchor w
	button $path.death -text "All Agents" -command \
			"$self send_death_pkt" -anchor w
	pack $path.death_label -fill x -side top -anchor w
	pack $path.death -fill x -side top
	frame $path.frame
	pack $path.frame -fill x -expand 1 -side top
	$self agent_list hm ""
	$self agent_list srv ""
	$self agent_list client ""
	$self agent_list all ""
	$self instvar agentlists_
	$agentlists_(all) browse_me
	$path.agenttypes selection set -id all
	set o [$self get_option doLog]
	if { $o != "" } {
		$self instvar log_
		foreach a [split $o :] {
			set log_($a) 1
		}
	}
}
ASMonitorUI public application {a} {
	$self set appl_ $a
}
ASMonitorUI private send_death_pkt {} {
	$self instvar appl_
	set l [$self info path].agenttypes
	set sel [lindex [$l selection get] 0]
	if {$sel != {}} {
		set sel [split $sel ,]
		set atype [lindex $sel 0]
		set srv_name [lindex $sel 1]
		if { $atype != "client" } {
			if { [string match "MeGa*" $srv_name] } {
				set srv_name [string range $srv_name 6 end]
				$appl_ build_death $srv_name
			} elseif { $atype=="srv" } {
				if { $srv_name!="" } {
					$appl_ build_death srv
				} else {
					foreach m {audio video sdp mb srv} {
						$appl_ build_death $m
					}
				}
			} elseif { $atype=="hm" } {
				$appl_ build_death hm
			} elseif { $atype=="all" } {
				foreach m {audio video sdp mb hm srv} {
					$appl_ build_death $m
				}
			}
		}
	}
}
ASMonitorUI private select_agent_list {id} {
	$self instvar agentlists_
	if [info exists agentlists_($id)] {
		$agentlists_($id) browse_me
	}
	set button [$self subwidget death]
	if [string match "client*" $id] {
		$button configure -state disabled -text "Client"
	} else {
		switch -exact -- $id {
			hm { set text "All Host Managers" }
			srv { set text "All Servents" }
			all { set text "All Agents" }
			default {
				if [string match "srv,MeGa: *" $id] {
					set text [string tolower [string range\
							$id 10 end]]
					set text "[string toupper [string \
							index $text 0]][string\
							range $text 1 end]\
							Agents"
				} else {
					set text "All Non-MeGa Agents"
				}
			}
		}
		$button configure -state normal -text $text
	}
}
ASMonitorUI public recv_msg {atype aspec addr srv_name srv_loc srv_inst \
		ssg_port agent_data delta} {
	$self instvar sdp_
	if {$srv_name=="MeGa"} {
		set sdp [$sdp_ parse $agent_data]
		set media [lindex [$sdp set allmedia_] 0]
		if { $media == "" } {return}
		set qualified_srv_name "$srv_name: [$media set mediatype_]"
	} else {
		set qualified_srv_name $srv_name
		set sdp ""
	}
	set a [$self agent_info $aspec $atype $qualified_srv_name]
	$a update $atype $aspec $addr $qualified_srv_name $srv_loc $srv_inst \
			$ssg_port $agent_data $sdp $delta
	if {$srv_name=="MeGa"} {
		delete $sdp
	}
}
ASMonitorUI public register {atype aspec addr srv_name srv_inst agent_data} {
	$self recv_msg $atype $aspec $addr $srv_name "" $srv_inst - \
			$agent_data ""
	$self instvar log_
	if [info exists log_($atype)] {
		puts "register: [gettimeofday] + $aspec $atype\
				$qualified_srv_name $addr"
	}
}
ASMonitorUI public unregister {atype aspec addr srv_name srv_inst agent_data} {
	$self instvar sdp_
	if {$srv_name=="MeGa"} {
		set agent_data [$sdp_ parse $agent_data]
		set media [lindex [$agent_data set allmedia_] 0]
		if { $media == "" } {
			delete $agent_data
			return
		}
		append srv_name ": [$media set mediatype_]"
		delete $agent_data
	}
	set a [$self agent_info $aspec $atype $srv_name]
	delete $a
	$self instvar log_
	if [info exists log_($atype)] {
		puts "unregister: [gettimeofday] + $aspec $atype\
				$srv_name $addr"
	}
}
ASMonitorUI public agent_info {aspec atype srv_name} {
	$self instvar agent_info_
	if ![info exists agent_info_($aspec)] {
		set agent_info_($aspec) [new ASAgentInfo $self $aspec $atype \
				$srv_name]
	}
	return $agent_info_($aspec)
}
ASMonitorUI public agent_list {atype srv_name} {
	$self instvar agent_list_
	if ![info exists agent_list_($atype,$srv_name)] {
		set agent_list_($atype,$srv_name) [new ASAgentList $self \
				$atype $srv_name]
	}
	return $agent_list_($atype,$srv_name)
}
Class ASAgentInfo
ASAgentInfo public init {ui aspec atype srv_name} {
	$self next
	$self instvar name_ ui_ windows_
	ASMonitorUI instvar atype_clr_
	set windows_ {}
	set ui_ $ui
	set name_(aspec) $aspec
	set name_(atype) $atype
	set name_(srv_name) $srv_name
	set list [$ui agent_list $atype $srv_name]
	$list insert $self $aspec $atype_clr_($atype)
	set glist [$ui agent_list $atype ""]
	if { $glist != $list } {
		$glist insert $self "$srv_name: $aspec" $atype_clr_($atype)
	}
	set glist [$ui agent_list all ""]
	if { $srv_name!={} } {
		set label "${srv_name}($atype): $aspec"
	} else { set label "$atype: $aspec" }
	$glist insert $self $label $atype_clr_($atype)
	if { [$ui_ subwidget default_info current]=={} } {
		$glist browse_agent $self
	}
}
ASAgentInfo public destroy {} {
	$self instvar ui_ name_ windows_ name_
	if { [lsearch $windows_ [$ui_ subwidget default_info info self]]!=-1} {
		$ui_ subwidget default_info attach {}
	}
	set list [$ui_ agent_list $name_(atype) $name_(srv_name)]
	$list delete $self
	if { $name_(srv_name)!={} } {
		if [$list is_empty] {
			delete $list
		}
	}
	set glist [$ui_ agent_list $name_(atype) ""]
	if { $glist != $list } {
		$glist delete $self
	}
	set glist [$ui_ agent_list all ""]
	$glist delete $self
	$ui_ instvar agent_info_
	unset agent_info_($name_(aspec))
	$self next
}
ASAgentInfo public attach {window} {
	$self instvar windows_
	lappend windows_ $window
}
ASAgentInfo public detach {window} {
	$self instvar windows_
	set idx [lsearch -exact $windows_ $window]
	if { $idx!=-1 } { set windows_ [lreplace $windows_ $idx $idx] }
}
ASAgentInfo public update {atype aspec addr srv_name srv_loc srv_inst ssg_port\
		agent_data sdp delta} {
	$self instvar fields_ prv_fields_
	set fields_(srv_loc) $srv_loc
	set fields_(srv_inst) $srv_inst
	set fields_(ssg_port) $ssg_port
	set fields_(agent_data) $agent_data
	set fields_(delta) $delta
	set fields_(last_heard) [gettimeofday ascii]
	set fields_(heard_from) $addr
	if { $sdp=={} } {
		set fields_(sdp) 0
	} else {
		set fields_(sdp) 1
		if { $atype=="srv" } {
			set prv_fields_(o) [join [$sdp field_value o] :]
			set prv_fields_(s) [join [$sdp field_value s] :]
			set prv_fields_(toolname) [$sdp attr_value tool]
			set prv_fields_(sessions) ""
			foreach media [$sdp set allmedia_] {
				set tmp [split [$media set caddr_] /]
				set caddr [lindex $tmp 0]/[$media set \
						port_]/[lindex $tmp 1]
				append prv_fields_(sessions) "\n$caddr"
			}
			set prv_fields_(sessions) [string range \
					$prv_fields_(sessions) 1 end]
		} elseif { $atype=="client" } {
			set prv_fields_(o) [join [$sdp field_value o] :]
			set prv_fields_(s) [join [$sdp field_value s] :]
			set prv_fields_(toolname) [$sdp attr_value tool]
			set prv_fields_(global) [$sdp set caddr_]
			set prv_fields_(local) [[$sdp set allmedia_] set \
					caddr_]
			set prv_fields_(bw) ""
			if [$sdp have_field b] {
				set bwval [$sdp set bwval_]
				set bwval [$self format_bps $bwval]
				set prv_fields_(bw) $bwval
			}
		}
	}
	$self instvar windows_
	foreach w $windows_ {
		$w update
	}
}
ASAgentInfo private format_bps b {
	set bps $b
	if { $bps < 1 } {
		set bps "0 bps"
	} elseif { $bps < 1000 } {
		set bps [format "%3.0f bps" $bps]
	} elseif { $bps < 1000000 } {
		set bps [format "%3.0f kb/s" [expr $bps / 1000.]]
	} else {
		set bps [format "%.1f Mb/s" [expr $bps / 1000000.]]
	}
	return $bps
}
Class ASAgentList
ASAgentList public init {ui atype srv_name} {
	$self next
	$self instvar widget_ ui_ agentlists_id_
	$ui instvar agentlists_
	set n [ASMonitorUI set atype_map_($atype)]
	set clr [ASMonitorUI set atype_clr_($atype)]
	if { $srv_name != "" } {
		append n "/$srv_name"
		$ui subwidget agenttypes insert after -id $atype \
				[list -id $atype,$srv_name {} $n]
		set agentlists_($atype,$srv_name) $self
		set agentlists_id_ $atype,$srv_name
	} else {
		$ui subwidget agenttypes insert end [list -id $atype \
				Icons(minimize) $n]
		set agentlists_($atype) $self
		set agentlists_id_ $atype
	}
	set w [$ui subwidget agenttypes info widget -id $agentlists_id_]
	$w configure -normalforeground $clr -selectforeground $clr
	set ui_ $ui
	option add *agentlist$self*borderWidth 1
	set widget_ [ScrolledListbox [$ui info path].agentlist$self -options \
			{ { bbox.height 140 } } \
			-browsecmd "$self browse_agent" \
			-command "$self browse_agent_new_window"]
}
ASAgentList public destroy {} {
	$self instvar ui_ agentlists_id_
	$ui_ instvar agent_list_
	unset agent_list_($agentlists_id_)
	$ui_ subwidget agenttypes delete -id $agentlists_id_
	$self next
}
ASAgentList public insert {info label clr} {
	$self instvar widget_
	$widget_ insert end "-id $info $label"
	set w [$widget_ info widget -id $info]
	$w configure -normalforeground $clr -selectforeground $clr
}
ASAgentList public delete {info} {
	$self instvar widget_
	$widget_ delete -id $info
}
ASAgentList public is_empty {} {
	$self instvar widget_
	if { [$widget_ info numelems] <= 0 } { return 1 } else { return 0 }
}
ASAgentList public browse_me { } {
	$self instvar ui_ widget_
	pack forget [pack slaves [$ui_ info path].frame]
	pack $widget_ -in [$ui_ info path].frame -fill both -expand 1
	if { [$widget_ info numelems] > 0 } {
		$self browse_agent [$widget_ info id 0]
	}
}
ASAgentList public browse_agent {id} {
	$self instvar widget_ ui_
	if { [lindex [$widget_ selection get] 0] != $id } {
		$widget_ selection set -id $id
	}
	$ui_ subwidget default_info attach $id $self
}
ASAgentList public browse_agent_new_window {id} {
	$self instvar widget_
	set w .agent_info_$id
	if [winfo exists $w] {
		wm deiconify $w
		return
	}
	$id instvar name_
	toplevel $w
	wm title $w "Agent Info: $name_(aspec) ($name_(atype):\
			$name_(srv_name))"
	ASInfoWindow $w.info
	pack $w.info -side top -fill both -expand 1
	button $w.dismiss -bd 1 -pady 0 -text "Dismiss" \
			-command "destroy $w"
	pack $w.dismiss -side right
	$w.info attach $id
	after "2000" delete $id
}
WidgetClass ASInfoWindow -default {
	{ *ScrolledWindow*Canvas.width 200 }
	{ *ScrolledWindow.scrollbar both }
	{ *ScrolledWindow.bbox.highlightThickness 1 }
	{ *ScrolledWindow.Scrollbar.borderWidth 1 }
	{ *ScrolledWindow.Scrollbar.borderWidth 1 }
	{ *ScrolledWindow.Scrollbar.highlightThickness 1 }
	{ *ScrolledWindow.Scrollbar.width 10 }
}
ASInfoWindow proc.invoke {} {
	$self instvar labels_
	set labels_(srv_loc)      "Service location"
	set labels_(srv_inst)     "Service instance"
	set labels_(ssg_port)     "SSG port"
	set labels_(last_heard)   "Last heard"
	set labels_(heard_from)   "Heard from"
	set labels_(delta)        "Delta"
	set labels_(agent_data)   "Agent data"
	set labels_(o)            "Agent ID"
	set labels_(s)            "Session ID"
	set labels_(toolname)     "Tool"
	set labels_(sessions)     "Sessions"
	set labels_(global)       "Global addr"
	set labels_(local)        "Local addr"
	set labels_(bw)           "Bandwidth"
}
ASInfoWindow public build_widget path {
	ScrolledWindow $path.scroll
	pack $path.scroll -fill both -expand 1
	set path [$path.scroll subwidget window]
	label $path.name -bd 1 -relief sunken -anchor w -foreground \
			[WidgetClass widget_default -disabledforeground] \
			-text "No agent exists"
	pack $path.name -fill x -side top
	frame $path.labels
	frame $path.values
	$self create_label srv_loc
	$self create_label srv_inst
	$self create_label ssg_port
	$self create_label last_heard
	$self create_label heard_from
	$self create_label delta
	$self create_label agent_data
	pack $path.labels -side left -anchor n
	pack $path.values -fill x -expand 1 -side left -anchor n
}
ASInfoWindow public destroy {} {
	$self instvar obj_
	if {[info exists obj_] && [ASAgentInfo info instances $obj_]==$obj_} {
		$obj_ detach $self
	}
	$self next
}
ASInfoWindow public create_label { name {after_id {}} } {
	ASInfoWindow instvar labels_
	set path [[$self info path].scroll subwidget window]
	label $path.labels.$name -text "$labels_($name):" -anchor w \
			-justify left -font [WidgetClass widget_default -font]
	label $path.$name -anchor w -justify left \
			-font [WidgetClass widget_default -font]
	if { $after_id=={} } {
		pack $path.labels.$name -fill x -anchor n -expand 1
		pack $path.$name -in $path.values -fill x -anchor n -expand 1
	} else {
		pack $path.labels.$name -fill x -anchor n -expand 1 \
				-before $path.labels.$after_id
		pack $path.$name -in $path.values -fill x -anchor n -expand 1\
				-before $path.$after_id
	}
}
ASInfoWindow public current {} {
	$self instvar obj_
	if [info exists obj_] { return $obj_ }  else { return {} }
}
ASInfoWindow public attach {obj {list {}}} {
	$self instvar obj_ list_
	if { [info exists list_] && $list_!={} && ($list_!=$list || \
			$obj_!=$obj) } {
		if { $list_!=$list } { [$list_ set widget_] selection clear }
		$obj_ instvar prv_fields_
		set path [[$self info path].scroll subwidget window]
		foreach name [array names prv_fields_] {
			if [winfo exists $path.$name] {
				destroy $path.labels.$name
				destroy $path.$name
			}
		}
	}
	if [info exists obj_] { $obj_ detach $self }
	if { $obj=={} } {
		set path [[$self info path].scroll subwidget window]
		$path.name configure -text "No agent exists" -foreground \
				[WidgetClass widget_default \
				-disabledforeground]
		$obj_ instvar fields_
		foreach name  [array names fields_] {
			if [winfo exists $path.$name] {
				$path.$name configure -text ""
			}
		}
		unset obj_
		unset list_
	} else {
		$obj attach $self
		set obj_ $obj
		set list_ $list
		$self update
	}
}
ASInfoWindow public update {} {
	$self instvar obj_
	$obj_ instvar name_ fields_ prv_fields_
	set path [$self info path]
	set path [$path.scroll subwidget window]
	if { $name_(srv_name)!={} } {
		set text "$name_(srv_name)($name_(atype)): $name_(aspec)"
	} else {
		set text "$name_(atype): $name_(aspec)"
	}
	$path.name configure -text $text -foreground \
			[ASMonitorUI set atype_clr_($name_(atype))]
	foreach name [array names fields_] {
		if [winfo exists $path.$name] {
			$path.$name configure -text $fields_($name)
		}
	}
	foreach name [array names prv_fields_] {
		if ![winfo exists $path.$name] {
			$self create_label $name delta
		}
		$path.$name configure -text $prv_fields_($name)
	}
}
Class AddressBlock -configuration {
	defaultTTL 1
	maxbw -1
}
Class AddressBlock/RTP -superclass AddressBlock
Class AddressBlock/Simple -superclass AddressBlock
AddressBlock instproc init spec {
	$self next
	$self set nchan_ 0
	foreach s [split $spec ,] {
		set err [$self parse $s]
		if { $err != "" } {
			$self fatal $err
		}
	}
}
AddressBlock instproc data-port p {
	return [expr $p &~ 1]
}
AddressBlock instproc ctrl-port p {
	return [expr [$self data-port $p] + 1]
}
AddressBlock instproc addr {{k 0}} {
	return [$self set addr_($k)]
}
AddressBlock instproc sport {{k 0}} {
	return [$self set sport_($k)]
}
AddressBlock instproc rport {{k 0}} {
	return [$self set rport_($k)]
}
AddressBlock instproc ttl {{k 0}} {
	return [$self set ttl_($k)]
}
AddressBlock instproc nchan {} {
	return [$self set nchan_]
}
AddressBlock instproc parse s {
	set dst [split $s /]
	set n [llength $dst]
	if { $n < 2 } {
		return "must specify both address and port in the form addr/port"
	}
	set addr [lindex $dst 0]
	set ports [split [lindex $dst 1] :]
	set sport [lindex $ports 0]
	if { [llength $ports] == 1 } {
		set rport $sport
	} else {
		set rport [lindex $ports 1]
	}
	set firstchar [string index $addr 0]
	if [string match \[a-zA-Z\] $firstchar] {
		set s [gethostbyname $addr]
		if { $s == "" } {
			return "cannot lookup host name: $addr"
		}
		set addr $s
	}
	foreach port "$sport $rport" {
		if { ![string match \[0-9\]* $port] || $port >= 65536 } {
			$self fatal "illegal port '$port'"
		}
	}
	set ttl [$self get_option defaultTTL]
	set cnt 1
	if { $n >= 3 } {
		set fmt [lindex $dst 2]
		if { $n >= 4 } {
			set ttl [lindex $dst 3]
			if { $n > 4 } {
				set cnt [lindex $dst 4]
				if { ![string match \[0-9\]* $cnt] ||
				     $cnt >= 20 } {
					return "$dst: bad layered addr count"
					exit 1
				}
				if { $n > 5 } {
					return "$dst: malformed address"
				}
			}
		}
	}
	if { $ttl < 0 || $ttl > 255 } {
		return "$dst: invalid ttl ($ttl)"
	}
	set oct [split $addr .]
	set base [lindex $oct 0].[lindex $oct 1].[lindex $oct 2]
	set off [lindex $oct 3]
	$self instvar addr_ sport_ rport_ ttl_ nchan_
	set i 0
	while { $i < $cnt } {
		set sp [$self data-port $sport]
		set rp [$self data-port $rport]
		set addr_($nchan_) $base.$off
		set sport_($nchan_) $sp
		set rport_($nchan_) $rp
		set ttl_($nchan_) $ttl
		if [in_multicast $addr] {
			incr off
		}
		incr sport 2
		incr rport 2
		incr i
		incr nchan_
	}
	if { [info exists fmt] && $fmt != "" && $fmt != "1" } {
		$self add_option videoFormat $fmt
		$self add_option audioFormat $fmt
	}	
	if [info exists confid] {
		$self add_option confid $confid
	}	
	if [info exists ttl] {
		$self add_option defaultTTL $ttl
	}
	$self bandwidth_heuristic
}
AddressBlock instproc bandwidth_heuristic {} {
	$self instvar nchan_ addr_ ttl_ maxbw_
	set i 0
	while { $i < $nchan_ } {
		set maxbw [$self get_option maxbw]
		if { $maxbw <= 0 } {
			set ttl $ttl_($i)
			if { $ttl <= 16 || ![in_multicast $addr_($i)] } {
				set maxbw 3072000
			} elseif { $ttl <= 64 } {
				set maxbw 1024000
			} elseif  { $ttl <= 128 } {
				set maxbw 128000
			} elseif { $ttl <= 192 } {
				set maxbw 53000
			} else {
				set maxbw 32000
			}
		}
		set maxbw_($i) $maxbw
		incr i
	}
}
AddressBlock/Simple instproc data-port p {
	return $p
}
AddressBlock/RTP instproc data-port p {
	return [expr $p &~ 1]
}
set rlm_param(alpha) 4
set rlm_param(alpha) 2
set rlm_param(beta) 0.75
set rlm_param(init-tj) 1.5
set rlm_param(init-tj) 10
set rlm_param(init-tj) 5
set rlm_param(init-td) 5
set rlm_param(init-td-var) 2
set rlm_param(max) 600
set rlm_param(max) 60
set rlm_param(g1) 0.25
set rlm_param(g2) 0.25
Class MMG
MMG instproc init { levels } {
	$self next
	$self instvar debug_ env_ maxlevel_
	set debug_ 0
	set env_ [lindex [split [$self info class] /] 1]
	set maxlevel_ $levels
	global rlm_debug_flag
	if [info exists rlm_debug_flag] {
		set debug_ $rlm_debug_flag
	}
	$self instvar TD TDVAR state_ subscription_
	global rlm_param
	set TD $rlm_param(init-td)
	set TDVAR $rlm_param(init-td-var)
	set state_ /S
	$self instvar layer_ layers_
	set i 1
	while { $i <= $maxlevel_ } {
		set layer_($i) [$self create-layer [expr $i - 1]]
		lappend layers_ $layer_($i)
		incr i
	}
	set subscription_ 0
	$self add-layer
	set state_ /S
	$self set_TJ_timer
}
MMG instproc set-state s {
	$self instvar state_
	set old $state_
	set state_ $s
	$self debug "FSM: $old -> $s"
}
MMG instproc drop-layer {} {
	$self dumpLevel
	$self instvar subscription_ layer_
	set n $subscription_
	if { $n > 0 } {
		$self debug "DRP-LAYER $n"
		$layer_($n) leave-group 
		incr n -1
		set subscription_ $n
	}
	$self dumpLevel
}
MMG instproc add-layer {} {
	$self dumpLevel
	$self instvar maxlevel_ subscription_ layer_
	set n $subscription_
	if { $n < $maxlevel_ } {
		$self debug "ADD-LAYER"
		incr n
		set subscription_ $n
		$layer_($n) join-group
	}
	$self dumpLevel
}
MMG instproc current_layer_getting_packets {} {
	$self instvar subscription_ layer_ TD
	set n $subscription_
	if { $n == 0 } {
		return 0
	}
	set l $layer_($subscription_)
	$self debug "npkts [$l npkts]"
	if [$l getting-pkts] {
		return 1
	}
	set delta [expr [$self now] - [$l last-add]]
	if { $delta > $TD } {
		set TD [expr 1.2 * $delta]
	}
	return 0
}
MMG instproc mmg_loss {} {
	$self instvar layers_
	set loss 0
	foreach l $layers_ {
		incr loss [$l nlost]
	}
	return $loss
}
MMG instproc mmg_pkts {} {
	$self instvar layers_
	set npkts 0
	foreach l $layers_ {
		incr npkts [$l npkts]
	}
	return $npkts
}
MMG instproc check-equilibrium {} {
	global rlm_param
	$self instvar subscription_ maxlevel_ layer_
	set n [expr $subscription_ + 1]
	if { $n >= $maxlevel_ || [$layer_($n) timer] >= $rlm_param(max) } {
		set eq 1
	} else {
		set eq 0
	}
	$self debug "EQ $eq"
}
MMG instproc backoff-one { n alpha } {
	$self debug "BACKOFF $n by $alpha"
	$self instvar layer_
	$layer_($n) backoff $alpha
}
MMG instproc backoff n {
	$self debug "BACKOFF $n"
	global rlm_param
	$self instvar maxlevel_ layer_
	set alpha $rlm_param(alpha)
	set L $layer_($n)
	$L backoff $alpha
	incr n
	while { $n <= $maxlevel_ } {
		$layer_($n) peg-backoff $L
		incr n
	}
	$self check-equilibrium
}
MMG instproc highest_level_pending {} {
	$self instvar maxlevel_
	set m ""
	set n 0
	incr n
	while { $n <= $maxlevel_ } {
		if [$self level_pending $n] {
			set m $n
		}
		incr n
	}
	return $m
}
MMG instproc rlm_update_D  D {
	global rlm_param
	$self instvar TD TDVAR
	set v [expr abs($D - $TD)]
	set TD [expr $TD * (1 - $rlm_param(g1)) \
				+ $rlm_param(g1) * $D]
	set TDVAR [expr $TDVAR * (1 - $rlm_param(g2)) \
		       + $rlm_param(g2) * $v]
}
MMG instproc exceed_loss_thresh {} {
	$self instvar h_npkts h_nlost
	set npkts [expr [$self mmg_pkts] - $h_npkts]
	if { $npkts >= 10 } {
		set nloss [expr [$self mmg_loss] - $h_nlost]
		set loss [expr double($nloss) / ($nloss + $npkts)]
		$self debug "H-THRESH $nloss $npkts $loss"
		if { $loss > 0.25 } {
			return 1
		}
	}
	return 0
}
MMG instproc enter_M {} {
	$self set-state /M
	$self set_TD_timer_wait
	$self instvar h_npkts h_nlost
	set h_npkts [$self mmg_pkts]
	set h_nlost [$self mmg_loss]
}
MMG instproc enter_D {} {
	$self set-state /D
	$self set_TD_timer_conservative
}
MMG instproc enter_H {} {
	$self set_TD_timer_conservative
	$self set-state /H
}
MMG instproc log-loss {} {
	$self debug "LOSS [$self mmg_loss]"
	$self instvar state_ subscription_ pending_ts_
	if { $state_ == "/M" } {
		if [$self exceed_loss_thresh] {
			$self cancel_timer TD
			$self drop-layer
			$self check-equilibrium
			$self enter_D
		}
		return
	}
	if { $state_ == "/S" } {
		$self cancel_timer TD
		set n [$self highest_level_pending]
		if { $n != "" } {
			$self backoff $n
			if { $n == $subscription_ } {
				set ts $pending_ts_($subscription_)
				$self rlm_update_D [expr [$self now] - $ts]
				$self drop-layer
				$self check-equilibrium
				$self enter_D
				return
			}
			if { $n == [expr $subscription_ + 1] } {
				$self cancel_timer TJ
				$self set_TJ_timer
			}
		}
		if [$self our_level_recently_added] {
			$self enter_M
			return
		}
		$self enter_H
		return
	}
	if { $state_ == "/H" || $state_ == "/D" } {
		return
	}
	puts stderr "rlm state machine botched"
	exit -1
}
MMG instproc relax_TJ {} {
	$self instvar subscription_ layer_
	if { $subscription_ > 0 } {
		$layer_($subscription_) relax
		$self check-equilibrium
	}
}
MMG instproc trigger_TD {} {
	$self instvar state_
	if { $state_ == "/H" } {
		$self enter_M
		return
	}
	if { $state_ == "/D" || $state_ == "/M" } {
		$self set-state /S
		$self set_TD_timer_conservative
		return
	}
	if { $state_ == "/S" } {
		$self relax_TJ
		$self set_TD_timer_conservative
		return
	}
	puts stderr "trigger_TD: rlm state machine botched $state)"
	exit -1
}
MMG instproc set_TJ_timer {} {
	global rlm_param
	$self instvar subscription_ layer_
	set n [expr $subscription_ + 1]
	if ![info exists layer_($n)] {
		return
	}
	set I [$layer_($n) timer]
	set d [expr $I / 2.0 + [trunc_exponential $I]]
	$self debug "TJ $d"
	$self set_timer TJ $d
}
MMG instproc set_TD_timer_conservative {} {
	$self instvar TD TDVAR
	set delay [expr $TD + 1.5 * $TDVAR]
	$self set_timer TD $delay
}
MMG instproc set_TD_timer_wait {} {
	$self instvar TD TDVAR
	$self instvar subscription_
	set k [expr $subscription_ / 2. + 1.5]
	$self set_timer TD [expr $TD + $k * $TDVAR]
}
MMG instproc is-recent { ts } {
	$self instvar TD TDVAR
	set ts [expr $ts + ($TD + 2 * $TDVAR)]
	if { $ts > [$self now] } {
		return 1
	}
	return 0
}
MMG instproc level_pending n {
	$self instvar pending_ts_
	if { [info exists pending_ts_($n)] && \
		 [$self is-recent $pending_ts_($n)] } {
		return 1
	}
	return 0
}
MMG instproc level_recently_joined n {
	$self instvar join_ts_
	if { [info exists join_ts_($n)] && \
		 [$self is-recent $join_ts_($n)] } {
		return 1
	}
	return 0
}
MMG instproc pending_inferior_jexps {} {
	set n 0
	$self instvar subscription_
	while { $n <= $subscription_ } { 
		if [$self level_recently_joined $n] {
			return 1
		}
		incr n
	}
	$self debug "NO-PEND-INF"
	return 0
}
MMG instproc trigger_TJ {} {
	$self debug "trigger-TJ"
	$self instvar state_ ctrl_ subscription_
	if { ($state_ == "/S" && ![$self pending_inferior_jexps] && \
		  [$self current_layer_getting_packets])  } {
		$self add-layer
		$self check-equilibrium
		set msg "add $subscription_"
		$ctrl_ send $msg
		$self local-join
	}
	$self set_TJ_timer
}
MMG instproc our_level_recently_added {} {
	$self instvar subscription_ layer_
	return [$self is-recent [$layer_($subscription_) last-add]]
}
MMG instproc recv-ctrl msg {
	$self instvar join_ts_ pending_ts_ subscription_
	$self debug "X-JOIN $msg"
	set what [lindex $msg 0]
	if { $what != "add" } {
		return
	}
	set level [lindex $msg 1]
	set join_ts_($level) [$self now]
	if { $level > $subscription_ } {
		set pending_ts_($level) [$self now]
	}
}
MMG instproc local-join {} {
	$self instvar subscription_ pending_ts_ join_ts_
	set join_ts_($subscription_) [$self now]
	set pending_ts_($subscription_) [$self now]
}
MMG instproc debug { msg } {
	$self instvar debug_ subscription_ state_
	if {$debug_} {
		puts stderr "[gettimeofday] layer $subscription_ $state_ $msg"
	}
}
MMG instproc dumpLevel {} {
}
Class Layer
Layer instproc init { mmg } {
	$self next
	$self instvar mmg_ TJ npkts_
	global rlm_param
	set mmg_ $mmg
	set TJ $rlm_param(init-tj)
	set npkts_ 0
}
Layer instproc relax {} {
	global rlm_param
	$self instvar TJ
	set TJ [expr $TJ * $rlm_param(beta)]
	if { $TJ <= $rlm_param(init-tj) } {
		set TJ $rlm_param(init-tj)
	}
}
Layer instproc backoff alpha {
	global rlm_param
	$self instvar TJ
	set TJ [expr $TJ * $alpha]
	if { $TJ >= $rlm_param(max) } {
		set TJ $rlm_param(max)
	}
}
Layer instproc peg-backoff L {
	$self instvar TJ
	set t [$L set TJ]    
	if { $t >= $TJ } {
		set TJ $t
	}
}
Layer instproc timer {} {
	$self instvar TJ
	return $TJ
}
Layer instproc last-add {} {
	$self instvar add_time_
	return $add_time_
}
Layer instproc join-group {} {
	$self instvar npkts_ add_time_ mmg_
	set npkts_ [$self npkts]
	set add_time_ [$mmg_ now]
}
Layer instproc leave-group {} {
}
Layer instproc getting-pkts {} {
	$self instvar npkts_
	return [expr [$self npkts] != $npkts_]
}
set rlm_debug_flag 1
Class Layer/mash -superclass Layer
Layer/mash instproc init {mmg net n} {
	$self next $mmg
	$self instvar net_ l_ n_
	set net_ $net
	set n_ $n
	set l_ [$net_ set net_($n)]
}
Layer/mash instproc join-group {} {
	$self instvar mmg_ net_
	set level [expr [$mmg_ set subscription_] - 1]
	$net_ set-subscription-level $level
	$self next
}
Layer/mash instproc leave-group {} {
	$self instvar mmg_ net_
	set level [expr [$mmg_ set subscription_] - 1]
	$net_ set-subscription-level $level
	$self next
}
Layer/mash instproc nlost {} {
	$self instvar l_
	return [$l_ nlost]
}
Layer/mash instproc npkts {} {
	$self instvar l_ n_
	return [$l_ npkts $n_]
}
Class MMG/mash -superclass MMG
MMG/mash instproc init {net caddr} {
	$self instvar net_
	set net_ $net
	$self next [$net set nchan_]
	proc ctrl$self {args} { puts "ctrl: $args" }
	$self set ctrl_ ctrl$self
}
MMG/mash instproc create-layer {layerNo} {
	$self instvar net_
	return [new Layer/mash $self $net_ $layerNo]
}
MMG/mash instproc now {} {
	return [gettimeofday]
}
MMG/mash instproc set_timer {which delay} {
	$self instvar timers_
	if [info exists timers_($which)] {
		puts "timer botched ($which)"
		exit 1
	}
	set delay [expr int($delay * 1000)]
	set timers_($which) [after $delay "$self trigger_timer $which"]
}
MMG/mash instproc trigger_timer {which} {
	$self instvar timers_
	unset timers_($which)
	$self trigger_$which
}
MMG/mash instproc cancel_timer {which} {
	$self instvar ns_ timers_
	if [info exists timers_($which)] {
		after cancel $timers_($which)
		unset timers_($which)
	}
}
MMG/mash instproc debug { msg } {
	$self instvar debug_
	if {!$debug_} { return }
	$self instvar subscription_ state_
	set time [format %.05f [$self now]]
	puts stderr "$time layer $subscription_ $state_ $msg"
}
proc uniform01 {} {
    return [expr double(([random] % 10000000) + 1) / 1e7]
}
proc uniform { a b } {
	return [expr ($b - $a) * [uniform01] + $a]
}
proc exponential mean {
	return [expr - $mean * log([uniform01])]
}
proc trunc_exponential lambda {
	while 1 {
		set u [exponential $lambda]
		if { $u < [expr 4 * $lambda] } {
			return $u
		}
	}
}
Class Network/IP -superclass Network
Network/IP instproc init args {
	puts stderr "Network/IP called... change to Network"
	eval $self next $args
}
Network instproc port args {
	eval $self sport $args
}
proc in_multicast addr {
	return [expr ([lindex [split $addr .] 0] & 0xf0) == 0xe0]
}
Class NetworkLayer
Class NetworkManager
NetworkManager instproc graphics-init n {
	if {$n == 1 || [winfo exists .l]} { return }
	$self instvar nchan_
	set nchan_ $n
	toplevel .l
	set k 0
	while { $k < $nchan_ } {
		radiobutton .l.b$k -command "$self set-subscription-level $k" \
			-text "Level $k" \
			-variable nLayers -value $k
		pack .l.b$k
		incr k
	}
	wm withdraw .l
	bind . <l> { 
		if [winfo ismapped .l] {
			wm withdraw .l
		} else {
			wm deiconify .l
		}
	}
}
NetworkManager instproc set-subscription-level n {
	$self instvar agent_ nchan_ session_ net_
	$agent_ set_maxchannel $n
	$session_ set loopbackLayer_ [expr $n + 1]
	set i 0
	while { $i <= $n } {
		$net_($i) enable
		incr i
	}
	while { $i < $nchan_ } {
		$net_($i) disable
		incr i
	}
	global nLayers
	set nLayers $n
}
NetworkLayer instproc init { session addr sport rport ttl channel } {
	$self next
	$self instvar session_ addr_ port_ ttl_ dn_ cn_ channel_ active_
	set addr_ $addr
	set sport_ $sport
	set rport_ $rport
	set session_ $session
	set ttl_ $ttl
	set channel_ $channel
	set dn_ [new Network]
	$dn_ open $addr_ $sport_ $rport_ $ttl_
	set cn_ [new Network]
	$cn_ open $addr_ [expr $sport_ + 1] [expr $rport + 1] $ttl_
	$cn_ loopback 1
	$session_ data-net $dn_ $channel_
	$session_ ctrl-net $cn_ $channel_
	set active_ 0
	$dn_ drop-membership
	$cn_ drop-membership
	$self set tloss_ 0
}
NetworkLayer instproc destroy {} {
	$self instvar dn_ cn_
	delete $dn_
	delete $cn_
	$self next
}
NetworkLayer instproc data-net {} {
	return [$self set dn_]
}
NetworkLayer instproc ctrl-net {} {
	return [$self set cn_]
}
NetworkLayer instproc enable-send {} {
	$self instvar dn_ cn_ session_ channel_
	$session_ data-net $dn_ $channel_
	$session_ ctrl-net $cn_ $channel_
}
NetworkLayer instproc disable-send {} {
	$self instvar dn_ cn_ session_ channel_
	$session_ data-net "" $channel_
	$session_ ctrl-net "" $channel_
}
NetworkLayer instproc enable {} {
	$self instvar active_ dn_ cn_ session_ channel_
	if !$active_ {
		set active_ 1
		$dn_ add-membership
		$cn_ add-membership
		$session_ data-net $dn_ $channel_
		$session_ ctrl-net $cn_ $channel_
	}
}
NetworkLayer instproc disable {} {
	$self instvar dn_ cn_ active_ session_ channel_
	if $active_ {
		set active_ 0
		$dn_ drop-membership
		$cn_ drop-membership
	}
}
NetworkLayer instproc notify-loss {src} {
	$self instvar loss_ tloss_
	if ![info exists loss_($src)] {
		set loss_($src) 0
	}
	set nloss [$src missing]
	incr tloss_ [expr $nloss - $loss_($src)]
	set loss_($src) $nloss
}
NetworkLayer instproc nlost {} {
	$self instvar tloss_
	return $tloss_
}
NetworkLayer instproc npkts {n} {
	$self instvar agent_
	set npkts 0
	foreach s [$agent_ set sources_] {
		set l [lindex [$s set layers_] $n]
		incr npkts [$l set np_]
	}
	return $npkts
}
NetworkLayer instproc crypt { dc cc } {
	$self instvar dn_ cn_
	$dn_ crypt $dc
	$cn_ crypt $cc
}
NetworkManager instproc init { ab session agent } {
	$self next
	$self instvar session_ agent_ encrypt_ key_ fmt_
	set session_ $session
	set agent_ $agent
	set encrypt_ 0
	set key_ ""
        set fmt_ ""
	$self allocate $ab $session
}
NetworkManager instproc allocate { ab session } {
	$self instvar nchan_ net_ mmg_
	if [info exists nchan_] {
		set oldnchan $nchan_
	} else {
		set oldnchan 0
	}
	set nchan_ 0
	while { $nchan_ < [$ab nchan] } {
		set addr [$ab addr $nchan_]
		set sport [$ab sport $nchan_]
		set rport [$ab rport $nchan_]
		set ttl [$ab ttl $nchan_]
		if [info exists net_($nchan_)] {
			delete $net_($nchan_)
		}
		set net_($nchan_) [new NetworkLayer $session $addr \
					$sport $rport $ttl $nchan_]
		$self instvar agent_
		$net_($nchan_) set agent_ $agent_
		incr nchan_
	}
	set n $nchan_
	while {$n < $oldnchan} {
		if [info exists net_($n)] {
			delete $net_($n)
		}
		incr n
	}
	if [info exists mmg_] {
		delete $mmg_
	}
	$self set-subscription-level 0
	if {$nchan_ == 1} { return }
	if [$self yesno useLayersWindow] {
		$self graphics-init $nchan_
	}
	if [$self get_option useRLM] {
		set caddr ""
		set mmg_ [new MMG/mash $self $caddr]
	}
}
NetworkManager instproc nchan {} {
	return [$self set nchan_]
}
NetworkManager instproc reset ab {
	$self instvar session_
	$self allocate $ab $session_
}
NetworkManager instproc data-net args {
	if { $args == "" } {
		set k 0
	} else {
		set k $args
	}
	$self instvar net_
	return [$net_($k) data-net]
}
NetworkManager instproc ctrl-net args {
	if { $args == "" } {
		set k 0
	} else {
		set k $args
	}
	$self instvar net_
	return [$net_($k) ctrl-net]
}
NetworkManager public loopback enable {
	$self instvar nchan_ net_
	set i 0
	while { $i < $nchan_ } {
		set net $net_($i)
		set dn [$net data-net]
		set cn [$net ctrl-net]
		$dn loopback $enable
		$cn loopback $enable
		incr i
	}
}
NetworkManager instproc install-key key {
	return [$self set_key $key]
}
NetworkManager instproc crypt_all { dc cc } {
	$self instvar net_
	foreach n [array names net_] {
		$net_($n) crypt $dc $cc
	}
}
NetworkManager instproc destroy {} {
	$self instvar dc_ cc_ net_
	if [info exists dc_] {
		delete $dc_
	}
	if [info exists cc_] {
		delete $cc_
	}
	foreach dn [array names net_] {
		delete $net_($dn)
	}
	$self next
}
NetworkManager instproc usingRLM {} {
	$self instvar mmg_
	return [info exists mmg_]
}
NetworkManager instproc notify-loss {src layer} {
	$self instvar net_
	$net_($layer) notify-loss $src
}
NetworkManager instproc crypt_format { key } {
	set k [string first / $key]
	if { $k < 0 } {
		set fmt DES
	} else {
		set fmt [string range $key 0 [expr $k - 1]]
		set key [string range $key [expr $k + 1] end]
	}
	return "$fmt $key"
}
NetworkManager instproc set_key key {
	if { $key == "" } {
		$self crypt_clear
		return ""
	}
	$self instvar encrypt_ 
	set L [$self crypt_format $key]
	set fmt [lindex $L 0]
	set key [lindex $L 1]
	$self instvar key_
	set key_ $key
	$self instvar dc_ cc_ fmt_
	if { $fmt_ != $fmt } {
		if [info exists dc_] {
			delete $dc_
			unset dc_
		}
		if [info exists cc_] {
			delete $cc_
			unset cc_
		}
		set fmt_ $fmt
	}
	if ![info exists dc_] {
		set clist [Crypt/Data info subclass]
		if { [lsearch -exact $clist Crypt/Data/$fmt] < 0 } {
			return "no $fmt encryption support"
		}
		set dc_ [new Crypt/Data/$fmt]
		set cc_ [new Crypt/Control/$fmt]
	}
	if [$dc_ key $key] {
		$cc_ key $key
		$self crypt_all $dc_ $cc_
		set encrypt_ 1
		return ""
	} else {
		$self crypt_clear
		return "your key is cryptographically weak"
	}
}
NetworkManager instproc crypt_clear {} {
	$self instvar encrypt_ key_
	$self crypt_all "" ""
	set key_ ""
	set encrypt_ 0
}
AnnounceListenManager public init { spec {mtu 1500} } {
	$self next $mtu
	$self instvar data_ snet_ rnet_
	set data_ ""
	set snet_ ""
	set rnet_ ""
	if [regexp {^[0-9]*$} $spec] {
		set rnet_ [new Network]
		$rnet_ open $spec
	} else {
		set ab [new AddressBlock/Simple $spec]
		set addr  [$ab addr]
		set sport [$ab sport]
		set rport [$ab rport]
		set ttl   [$ab ttl]
		delete $ab
		set snet_ [new Network]
		if [in_multicast $addr] {
			$snet_ open $addr $sport $rport $ttl
			set rnet_ $snet_
		} else {
			if { $rport != 0 } {
				set rnet_ [new Network]
				$rnet_ open $rport
			}
			$snet_ open $addr $sport 0 1
		}
	}
	if { $snet_ != "" } {
		$snet_ loopback 1
		$self send_network $snet_
	} 
	if { $rnet_ != "" } {
		$self recv_network $rnet_
	}
}
AnnounceListenManager public destroy {} {
	$self instvar snet_ rnet_ timers_
	if { $rnet_==$snet_ } {
		delete $snet_
	} else {
		if { $snet_ != "" } {
			delete $snet_
		} 
		if { $rnet_ != "" } {
			delete $rnet_
		}
	}
	if [info exists timers_] {
		foreach t [array names timers_] {
			delete $timers_($t)
		}
	}
	$self next
}
AnnounceListenManager public timer {args} {
	$self instvar timers_
	if {[llength $args]==1} {
		set d __default_timer__
		set t [lindex $args 0]
		if {$t!={}} { $t proc timeout { } "$self send_announcement" }
	} else {
		set d [lindex $args 0]
		set t [lindex $args 1]
		if {$t!={}} { $t proc timeout { } \
				[list $self send_announcement $d] }
	}
	if [info exists timers_($d)] {
		set sched [$timers_($d) is_sched]
		delete $timers_($d)
	} else {
		set sched 0
	}
	if {$t!={}} {
		set timers_($d) $t
		if $sched {
			$t start
		}
	} else {
		catch {unset timers_($d)}
	}
	return $t
}
AnnounceListenManager public get_timer {args} {
	$self instvar timers_
	if {[llength $args]==0} {
		set d __default_timer__
	} else {
		set d [lindex $args 0]
	}
	if [info exists timers_($d)] { return $timers_($d) } else { return "" }
}
AnnounceListenManager public start {args} {
	if { [llength $args]==0 } {
		set t [$self get_timer]
	} else {
		set d [lindex $args 0]
		set t [$self get_timer $d]
	}
	if { $t=={} } {
		set t [new Timer/Periodic]
		$t randomize 1
		if [info exists d] { $self timer $d $t } else { $self timer $t}
	}
	if [info exists d] {$self send_announcement $d} \
			else {$self send_announcement}
	$t start
}
AnnounceListenManager public stop {args} {
	$self instvar timers_
	if {[llength $args]==0} {
		foreach d [array names timers_] {
			$timers_($d) cancel
		}
	} else {
		set d [lindex $args 0]
		$timers_($d) cancel
	}
}
AnnounceListenManager public recv_announcement { addr port data len } {
	puts "ALM::recv_announcement $addr/$port \[$len\]: $data"
}
AnnounceListenManager public send_announcement {args} {
	$self instvar data_
	if [llength $args==0] {
		if { $data_!={} } { $self announce $data_ }
	} else {
		$self announce [lindex $args 0]
	}
}
AnnounceListenManager public set_announcement { data } {
	$self set data_ $data
}
AnnounceListenManager public get_announcement { } {
	return [$self set data_]
}
Class Timer
Class Timer/Periodic -superclass Timer
Class Timer/Adaptive -superclass Timer
Class Timer/Adaptive/ConstBW -superclass Timer/Adaptive
Timer public init {} {
	$self next 
	$self randomize 0
	$self set randwt_ 1.0
}
Timer public destroy {} {
	$self cancel
	$self next
}
Timer public randomize { {yesno 1} {randwt {}} } {
	if { $randwt!={} } {
		$self set randwt_ $randwt
	}
	if {$yesno=="yes"} {set yesno 1} elseif {$yesno=="no"} {set yesno 0}
	$self set randomize_ $yesno
}
Timer private sched { t } {
	$self msched $t
}
Timer public msched { t } {
	$self instvar id_ randomize_ randwt_
	if [info exists id_] {
		puts stderr "warning: $self ([$self info class]):\
				overlapping timers"
	}
	if $randomize_ {
		set r [expr [random]/double(0x7fffffff)-0.5]
		set t [expr $t+$t*$r*$randwt_]
	}
	set t [expr int($t+0.5)]
	set id_ [after $t "$self do_timeout"]
}
Timer private do_timeout {} {
	$self instvar id_
	if ![info exists id_] {
		puts stderr "warning: $self ($class) no timer id_"
	} else {
		unset id_
	}
	$self timeout
}
Timer public is_sched { } {
	$self instvar id_
	return [info exists id_]
}
Timer public cancel {} {
	$self instvar id_
	if [info exists id_] {
		after cancel $id_
		unset id_
	}
}
Timer/Periodic public init { {period 5000} } {
	$self next
	$self set period_ $period
}
Timer/Periodic public start { {period {}} } {
	$self instvar period_
	if { $period!={} } { set period_ $period }
	if [$self is_sched] { $self cancel }
	$self msched $period_
}
Timer/Periodic instproc do_timeout {} {
	$self instvar period_
	$self next
	$self msched $period_
}
Timer/Adaptive public init { {interval 5000} } {
	$self next
	$self set interval_ $interval
}
Timer/Adaptive public start {} {
	$self instvar interval_
	if [$self is_sched] { $self cancel }
	set interval_ [$self adapt $interval_]
	$self msched [expr int($interval_+0.5)]
}
Timer/Adaptive public do_timeout {} {
	$self instvar interval_
	$self next
	set interval_ [$self adapt $interval_]
	$self msched [expr int($interval_+0.5)]
}
Timer/Adaptive private adapt {interval} {
	return $interval
}
Timer/Adaptive/ConstBW public init { bw {thresh {}} {size_gain {}} } {
	$self instvar size_gain_ avgsize_ nsrcs_ bw_ thresh_ interval_
	if { $size_gain!={} } {
		set size_gain_ $size_gain
	} else {
		set size_gain_ 0.125
	}
	set avgsize_ 28
	set nsrcs_ 0
	set bw_ $bw
	if { $thresh!={} } {
		set thresh_ 500
	} else {
		set thresh_ $thresh
	}
	$self next $thresh_
}
Timer/Adaptive/ConstBW public threshold { {thresh {}} } {
    $self instvar thresh_
    if {$thresh=={}} {
	return $thresh_
    } else {
	set thresh_ $thresh
    }
}
Timer/Adaptive/ConstBW public sample_size { size } {
	$self instvar avgsize_ size_gain_
	set avgsize_ [expr $avgsize_ + $size_gain_ * ($size + 28 - $avgsize_)]
}
Timer/Adaptive/ConstBW public update_nsrcs { nsrcs } {
	$self set nsrcs_ $nsrcs
}
Timer/Adaptive/ConstBW public nsrcs { nsrcs } {
	return [$self set nsrcs_]
}
Timer/Adaptive/ConstBW public incr_nsrcs { {incr 1} } {
        $self instvar nsrcs_
        incr nsrcs_ $incr
}
Timer/Adaptive/ConstBW private adapt {interval} {
	$self instvar avgsize_ bw_ nsrcs_ thresh_
	set t [expr 1000 * ($nsrcs_ * $avgsize_ * 8) / $bw_]
	if { $t < $thresh_ } {
		return $thresh_
	} else {
		return $t
	}
}
Class AnnounceListenManager/AS -superclass AnnounceListenManager
AnnounceListenManager/AS instproc init { netspec bw atype } {
	random 0
	$self next $netspec 1024
	$self instvar atype_
	set atype_ $atype
	$self instvar agentbytype_
	set agentbytype_(srv) ""
	set agentbytype_(client) ""
	set agentbytype_(hm) ""
	set t [new Timer/Adaptive/ConstBW $bw 3000]
	$t randomize
        $self timer $t
	set o [$self options]
	$o add_default startupWait 60
	$self instvar aliveid_
	set aliveid_ [after [expr [$self get_option startupWait]*1000] "$self check_alive 1"]
}
AnnounceListenManager/AS proc version {} {
	return 2.0
}
AnnounceListenManager/AS public send_announcement {} {
	$self instvar atype_
	set o "ASCP v[$class version]"
	set n $atype_
	set o $o\n$n
	set n [$self agent_instance]
	set o $o\n$n
	set n [$self service_name]
	set o $o\n$n
	set n [$self service_location]
	set o $o\n$n
	set n [$self service_instance]
	set o $o\n$n
	set n [$self ssg_port]
	set o $o\n$n
	set n [$self agent_data]
	set o $o\n$n
	$self announce $o
	$self check_alive 0
}
AnnounceListenManager/AS instproc announce_death {} {
	$self instvar id1_ id2_ atype_
	set o "ASCP v[AnnounceListenManager/AS version]"
	set n $atype_
	set o $o\n$n
	set n [$self agent_instance]
	set o $o\n$n
	set n bye
	set o $o\n$n
	set n -
	set o $o\n$n
	set n -
	set o $o\n$n
	set n -
	set o $o\n$n
	$self announce $o
}
AnnounceListenManager/AS public agent_instance {} {
	return "[pid]@[lookup_host_name [localaddr]]"
}
AnnounceListenManager/AS public agent_data {} {
	return ""
}
AnnounceListenManager/AS public ssg_port {} {
	return "-"
}
AnnounceListenManager/AS instproc service_location {} {
	return "-"
}
AnnounceListenManager/AS instproc destroy {} {
	$self instvar aliveid_
	after cancel $aliveid_
	$self next
}
AnnounceListenManager/AS instproc recv_announcement { addr port data size } {
	$self instvar lastann_ sdp_ agentbytype_ agenttab_ atype_
        set t [$self get_timer]
	$t sample_size $size
	set o [split $data \n]
	if { [lindex $o 0] != "ASCP v[$class version]" } {
		set msg "$self ($class): received non-ASCP v[$class version] announcement from $addr."
		if { $atype_ == "hm" } {
			$self instvar agent_
			$agent_ log $msg
		} else {
			puts stderr $msg
		}
 		return
	}
	set atype [lindex $o 1]
	set aspec [lindex $o 2]
	set srv_name [lindex $o 3]
	set srv_loc [lindex $o 4]
	set srv_inst [lindex $o 5]
	set ssg_port [lindex $o 6]
	set ad [join [lrange $o 7 end] \n]
	if { $srv_name == "DEATH" } {
		set msg "Received death packet from $aspec at $addr - exiting."
		if { $srv_loc == $atype_ } {
			if { $atype_ == "hm" } {
				$self instvar agent_
				$agent_ log $msg
			} else {
				puts stderr $msg
			}
			$self announce_death
			exit 0
		}
		$self recv_msg $atype $aspec $addr DEATH $srv_loc \
			$srv_inst $ssg_port "$ad"
		return
	}
	if { $srv_name == "bye" } {
		$self delete_agent $aspec
		return
	}
	if ![info exists agenttab_($aspec)] {
		$self instvar avgdelta_
		$self register $atype $aspec $addr $srv_name $srv_inst "$ad"
	        $t incr_nsrcs
		set timeout [$self get_option startupWait]
		set avgdelta_($aspec) [expr $timeout / 8]
		lappend agentbytype_($atype) $aspec
	} else {
		set now [gettimeofday]
		set delta [expr $now - $lastann_($aspec,abs)]
		$self instvar avgdelta_
		set avgdelta_($aspec) \
				[expr 0.875*$avgdelta_($aspec)+0.125*$delta]
	}
	set agenttab_($aspec) "$addr {$ad} $atype $srv_name $srv_inst"
	set lastann_($aspec,abs) [gettimeofday]
	set lastann_($aspec,ascii) [gettimeofday ascii]
	$self recv_msg $atype $aspec $addr $srv_name $srv_loc $srv_inst \
			$ssg_port "$ad"
}
AnnounceListenManager/AS instproc advance_timers { delta } {
	$self instvar lastann_ agenttab_ avgdelta_
	set aspecs [array names agenttab_]
	foreach aspec $aspecs {
		set lastann_($aspec,abs) [expr $lastann_($aspec,abs)+$delta]
	}
}
AnnounceListenManager/AS instproc check_alive { timer } {
	$self instvar lastann_ agenttab_ avgdelta_
	set now [gettimeofday]
	set aspecs [array names agenttab_]
	foreach aspec $aspecs {
		set lastann $lastann_($aspec,abs)
		set avgdelta $avgdelta_($aspec)
		set delta [expr $now - $lastann]
		if { $delta > 8 * $avgdelta } {
			$self delete_agent $aspec
		}
	}
	$self instvar aliveid_
	if { $timer } {
		set t [expr [$self get_option startupWait]*1000]
		set aliveid_ [after $t "$self check_alive 1"]
	}
}
AnnounceListenManager/AS instproc delete_agent { aspec } {
 	$self instvar agentbytype_ agenttab_ lastann_ avgdelta_
	if ![info exists agenttab_($aspec)] {
		return 
	}
	set a $agenttab_($aspec)
	set addr [lindex $a 0]
	set ad [lindex $a 1]
	set atype [lindex $a 2]
	set srv_name [lindex $a 3]
	set srv_inst [lindex $a 4]
	unset agenttab_($aspec)
	unset lastann_($aspec,abs)
	unset lastann_($aspec,ascii)
	unset avgdelta_($aspec)
	set t $agentbytype_($atype)
	set i [lsearch -exact $t $aspec]
	set agentbytype_($atype) [lreplace $t $i $i]
	[$self get_timer] incr_nsrcs -1
	$self unregister $atype $aspec $addr $srv_name $srv_inst "$ad"
}
AnnounceListenManager/AS instproc agenttab aspec {
	$self instvar agenttab_
	if [info exists agenttab_($aspec)] {
		return $agenttab_($aspec)
	}
	return ""
}
Class AnnounceListenManager/AS/ASMon -superclass AnnounceListenManager/AS
AnnounceListenManager/AS/ASMon instproc init { agent spec bw } {
	$self next $spec $bw mgamon
	$self instvar agent_
	set agent_ $agent
}
AnnounceListenManager/AS/ASMon instproc build_announcement {} {
	puts stderr "AS Monitor build_announcement called!"
	return ""
}
AnnounceListenManager/AS/ASMon instproc recv_msg { atype aspec addr srv_name\
		srv_loc srv_inst ssg_port agent_data } {
	$self instvar agent_ avgdelta_
	if { $srv_name == "DEATH" } {
		return
	}
	if { $atype=="hm" } { set srv_name "" }
	$agent_ recv_msg $atype $aspec $addr $srv_name $srv_loc $srv_inst\
			$ssg_port $agent_data $avgdelta_($aspec)
}
AnnounceListenManager/AS/ASMon instproc register { atype aspec addr srv_name \
		srv_inst agent_data } {
	$self instvar agent_
	if { $atype=="hm" } { set srv_name "" }
	$agent_ register $atype $aspec $addr $srv_name $srv_inst $agent_data
}
AnnounceListenManager/AS/ASMon instproc unregister { atype aspec addr srv_name\
		srv_inst agent_data } {
	$self instvar agent_
	if { $atype=="hm" } { set srv_name "" }
	$agent_ unregister $atype $aspec $addr $srv_name $srv_inst $agent_data
}
Class MeGa
MeGa instproc init args {
	eval $self next $args
	$self set sdp_ [new SDPParser]
}
MeGa instproc destroy {} {
	$self instvar sdp_
	delete $sdp_
	$self next
}
MeGa proc ctrlchan { media spec } {
	set tmp [split $spec /]
	set addr [lindex $tmp 0]
	if ![in_multicast $addr] {
		return $spec
	}
	set port [lindex $tmp 1]
	switch $media {
	video {
		incr port 2
	}
	audio {
		incr port 4
	}
	mb {
		incr port 6
	}
	sdp {
		incr port 8
	}
	hm {
		incr port 10
	}
	}
	set ttl [lindex $tmp 2]
	return $addr/$port/$ttl
}
Class ASMonApplication -superclass Application
ASMonApplication instproc init argv {
	$self next asmon
	$self instvar ui_
	set o [$self options]
	$self init_args $o
	$self init_resources $o
	$o parse_args $argv
	set ui_ [ASMonitorUI .top]
	pack .top -fill both -expand 1
	.top application $self
	$self init_network .top
}
ASMonApplication instproc init_args o {
	$o register_option -log doLog
	$o register_option -megactrl asCtrl
}
ASMonApplication instproc init_resources o {
	$o add_default defaultTTL 1
	$o add_default asCtrl 224.4.5.24/50000/31
	$o add_default asCtrlBW 20000
}
ASMonApplication instproc init_network { ui } {
	set megaspec [$self get_option asCtrl]
	set bw [$self get_option asCtrlBW]
	$self instvar al_
	foreach m { audio video sdp mb hm srv } {
		set spec [MeGa ctrlchan $m $megaspec]
		set al_($m) [new AnnounceListenManager/AS/ASMon \
				$ui $spec $bw]
	}
}
ASMonApplication instproc build_death { atype } {
	$self instvar al_
	set al $al_($atype)
	set o "ASCP v[AnnounceListenManager/AS version]"
	set n mgamon
	set o $o\n$n
	set n [$al agent_instance]
	set o $o\n$n
	set n "DEATH"
	set o $o\n$n
	set n $atype
	set o $o\n$n
	set n "-"
	set o $o\n$n
	set n "-"
	set o $o\n$n
	$al announce $o
}
new ASMonApplication $argv
