Index: trunk/web/addons/job_monarch/conf.php
===================================================================
--- trunk/web/addons/job_monarch/conf.php	(revision 203)
+++ trunk/web/addons/job_monarch/conf.php	(revision 203)
@@ -0,0 +1,32 @@
+<?php
+// Show hosts in a jobview by default?
+//
+$default_showhosts = 1;
+
+// Path to Ganglia's web frontend root
+//
+$GANGLIA_PATH = "/var/www/ganglia";
+
+// Max size of small clusterimage
+// (250 pixels is same width as Ganglia's pie chart)
+//
+$SMALL_CLUSTERIMAGE_MAXWIDTH = 250;
+
+// The size of a single node in the small clusterimage
+//
+$SMALL_CLUSTERIMAGE_NODEWIDTH = 11;
+
+// How to mark nodes with a job in clusterimage
+//
+$JOB_NODE_MARKING = "J";
+
+// XML Datasource for Toga
+// by default localhost's gmetad
+//
+$DATA_SOURCE = '127.0.0.1:8651';
+
+// Is there a jobarchive?
+//
+$TARCHD = 1;
+
+?>
Index: trunk/web/addons/job_monarch/footer.php
===================================================================
--- trunk/web/addons/job_monarch/footer.php	(revision 203)
+++ trunk/web/addons/job_monarch/footer.php	(revision 203)
@@ -0,0 +1,21 @@
+<?php
+$tpl = new TemplatePower( "templates/footer.tpl" );
+$tpl->prepare();
+$tpl->assign("webfrontend-version",$version["webfrontend"]);
+$tpl->assign("togaweb-version", "0.1");
+$tpl->assign("togaarch-version", "0.1");
+$tpl->assign("togaplug-version", "0.1");
+
+if ($version["gmetad"]) {
+   $tpl->assign("webbackend-component", "gmetad");
+   $tpl->assign("webbackend-version",$version["gmetad"]);
+}
+elseif ($version["gmond"]) {
+   $tpl->assign("webbackend-component", "gmond");
+   $tpl->assign("webbackend-version", $version["gmond"]);
+}
+
+$tpl->assign("parsetime", sprintf("%.4f", $parsetime) . "s");
+
+$tpl->printToScreen();
+?>
Index: trunk/web/addons/job_monarch/graph.php
===================================================================
--- trunk/web/addons/job_monarch/graph.php	(revision 203)
+++ trunk/web/addons/job_monarch/graph.php	(revision 203)
@@ -0,0 +1,443 @@
+<?php
+include_once "./libtoga.php";
+
+if ( !empty( $_GET ) ) {
+        extract( $_GET );
+}
+
+# Graph specific variables
+$size = escapeshellcmd( rawurldecode( $HTTP_GET_VARS["z"] ));
+$graph = escapeshellcmd( rawurldecode( $HTTP_GET_VARS["g"] ));
+$grid = escapeshellcmd( rawurldecode( $HTTP_GET_VARS["G"] ));
+$self = escapeshellcmd( rawurldecode( $HTTP_GET_VARS["me"] ));
+$max = escapeshellcmd( rawurldecode( $HTTP_GET_VARS["x"] ));
+$min = escapeshellcmd( rawurldecode( $HTTP_GET_VARS["n"] ));
+$value = escapeshellcmd( rawurldecode( $HTTP_GET_VARS["v"] ));
+$load_color = escapeshellcmd( rawurldecode( $HTTP_GET_VARS["l"] ));
+$vlabel = escapeshellcmd( rawurldecode( $HTTP_GET_VARS["vl"] ));
+$sourcetime = escapeshellcmd($HTTP_GET_VARS["st"]);
+
+$cluster = $c;
+$metricname = ($g) ? $g : $m;
+$hostname = $h;
+
+# Assumes we have a $start variable (set in get_context.php).
+if ($size == "small") {
+	$height = 40;
+	$width = 130;
+} else if ($size == "medium") {
+	$height = 75;
+	$width = 300;
+} else {
+	$height = 100;
+	$width = 400;
+}
+
+if($command) {
+      $command = '';
+}
+
+//printf( "cluster = %s hostname = %s metric = %s\n", $cluster, $hostname, $metricname );
+
+$trd = new TarchRrdGraph( $cluster, $hostname );
+//$rrd_files = $trd->getRrdFiles( $metricname, $start, $stop );
+
+//print_r( $rrd_files );
+
+$graph = $metricname;
+
+if (isset($graph)) {
+	$rrd_dirs = $trd->getRrdDirs( $period_start, $period_stop );
+	$series = '';
+
+	if($graph == "cpu_report") {
+		$style = "CPU";
+		//printf("ik doe die shit!\n");
+
+		$upper_limit = "--upper-limit 100 --rigid";
+		$lower_limit = "--lower-limit 0";
+
+		$vertical_label = "--vertical-label Percent ";
+
+		$def_nr = 0;
+
+		foreach( $rrd_dirs as $rrd_dir ) {
+
+			if( $def_nr == 0 ) {
+
+				$user_str = ":'User CPU'";
+				$nice_str = ":'Nice CPU'";
+				$system_str = ":'System CPU'";
+				$wio_str = ":'WAIT CPU'";
+				$idle_str = ":'Idle CPU'";
+			} else {
+
+				$user_str = "";
+				$nice_str = "";
+				$system_str = "";
+				$wio_str = "";
+				$idle_str = "";
+			}
+
+			$series .= "DEF:'cpu_user${def_nr}'='${rrd_dir}/cpu_user.rrd':'sum':AVERAGE "
+				."DEF:'cpu_nice${def_nr}'='${rrd_dir}/cpu_nice.rrd':'sum':AVERAGE "
+				."DEF:'cpu_system${def_nr}'='${rrd_dir}/cpu_system.rrd':'sum':AVERAGE "
+				."DEF:'cpu_idle${def_nr}'='${rrd_dir}/cpu_idle.rrd':'sum':AVERAGE "
+				."AREA:'cpu_user${def_nr}'#${cpu_user_color}${user_str} "
+				."STACK:'cpu_nice${def_nr}'#${cpu_nice_color}${nice_str} "
+				."STACK:'cpu_system${def_nr}'#${cpu_system_color}${system_str} ";
+
+			if (file_exists("$rrd_dir/cpu_wio.rrd")) {
+				$series .= "DEF:'cpu_wio${def_nr}'='${rrd_dir}/cpu_wio.rrd':'sum':AVERAGE "
+					."STACK:'cpu_wio${def_nr}'#${cpu_wio_color}${wio_str} ";
+			}
+
+			$series .= "STACK:'cpu_idle${def_nr}'#${cpu_idle_color}${idle_str} ";
+
+			$def_nr++;
+		}
+
+	} else if ($graph == "mem_report") {
+		$style = "Memory";
+
+		$lower_limit = "--lower-limit 0 --rigid";
+		$extras = "--base 1024";
+		$vertical_label = "--vertical-label Bytes";
+
+		$def_nr = 0;
+
+		foreach( $rrd_dirs as $rrd_dir ) {
+
+			if( $def_nr == 0 ) {
+
+				$memuse_str = ":'Memory Used'";
+				$memshared_str = ":'Memory Shared'";
+				$memcached_str = ":'Memory Cached'";
+				$membuff_str = ":'Memory Buffered'";
+				$memswap_str = ":'Memory Swapped'";
+				$total_str = ":'Total In-Core Memory'";
+			} else {
+
+				$memuse_str = "";
+				$memshared_str = "";
+				$memcached_str = "";
+				$membuff_str = "";
+				$memswap_str = "";
+				$total_str = "";
+			}
+
+			$series .= "DEF:'mem_total${def_nr}'='${rrd_dir}/mem_total.rrd':'sum':AVERAGE "
+				."CDEF:'bmem_total${def_nr}'=mem_total${def_nr},1024,* "
+				."DEF:'mem_shared${def_nr}'='${rrd_dir}/mem_shared.rrd':'sum':AVERAGE "
+				."CDEF:'bmem_shared${def_nr}'=mem_shared${def_nr},1024,* "
+				."DEF:'mem_free${def_nr}'='${rrd_dir}/mem_free.rrd':'sum':AVERAGE "
+				."CDEF:'bmem_free${def_nr}'=mem_free${def_nr},1024,* "
+				."DEF:'mem_cached${def_nr}'='${rrd_dir}/mem_cached.rrd':'sum':AVERAGE "
+				."CDEF:'bmem_cached${def_nr}'=mem_cached${def_nr},1024,* "
+				."DEF:'mem_buffers${def_nr}'='${rrd_dir}/mem_buffers.rrd':'sum':AVERAGE "
+				."CDEF:'bmem_buffers${def_nr}'=mem_buffers${def_nr},1024,* "
+				."CDEF:'bmem_used${def_nr}'='bmem_total${def_nr}','bmem_shared${def_nr}',-,'bmem_free${def_nr}',-,'bmem_cached${def_nr}',-,'bmem_buffers${def_nr}',- "
+				."AREA:'bmem_used${def_nr}'#${mem_used_color}${memuse_str} "
+				."STACK:'bmem_shared${def_nr}'#${mem_shared_color}${memshared_str} "
+				."STACK:'bmem_cached${def_nr}'#${mem_cached_color}${memcached_str} "
+				."STACK:'bmem_buffers${def_nr}'#${mem_buffered_color}${membuff_str} ";
+
+			if (file_exists("$rrd_dir/swap_total.rrd")) {
+				$series .= "DEF:'swap_total${def_nr}'='${rrd_dir}/swap_total.rrd':'sum':AVERAGE "
+					."DEF:'swap_free${def_nr}'='${rrd_dir}/swap_free.rrd':'sum':AVERAGE "
+					."CDEF:'bmem_swapped${def_nr}'='swap_total${def_nr}','swap_free${def_nr}',-,1024,* "
+					."STACK:'bmem_swapped${def_nr}'#${mem_swapped_color}${memswap_str} ";
+			}
+
+			$series .= "LINE2:'bmem_total${def_nr}'#${cpu_num_color}${total_str} ";
+
+			$def_nr++;
+		}
+
+	} else if ($graph == "load_report") {
+		$style = "Load";
+
+		$lower_limit = "--lower-limit 0 --rigid";
+		$vertical_label = "--vertical-label 'Load/Procs'";
+
+		$def_nr = 0;
+
+		foreach( $rrd_dirs as $rrd_dir ) {
+
+			if( $def_nr == 0 ) {
+
+				$load_str = ":'1-min Load'";
+				$cpu_str = ":'CPUs'";
+				$run_str = ":'Running Processes'";
+			} else {
+				$load_str = "";
+				$cpu_str = "";
+				$run_str = "";
+			}
+
+			$series .= "DEF:'load_one${def_nr}'='${rrd_dir}/load_one.rrd':'sum':AVERAGE "
+				."DEF:'proc_run${def_nr}'='${rrd_dir}/proc_run.rrd':'sum':AVERAGE "
+				."DEF:'cpu_num${def_nr}'='${rrd_dir}/cpu_num.rrd':'sum':AVERAGE ";
+			$series .="AREA:'load_one${def_nr}'#${load_one_color}${load_str} ";
+			$series .="LINE2:'cpu_num${def_nr}'#${cpu_num_color}${cpu_str} ";
+			$series .="LINE2:'proc_run${def_nr}'#${proc_run_color}${run_str} ";
+
+			$def_nr++;
+		}
+
+	} else if ($graph == "network_report") {
+		$style = "Network";
+
+		$lower_limit = "--lower-limit 0 --rigid";
+		$extras = "--base 1024";
+		$vertical_label = "--vertical-label 'Bytes/sec'";
+
+		$def_nr = 0;
+
+		foreach( $rrd_dirs as $rrd_dir ) {
+
+			if( $def_nr == 0 ) {
+
+				$in_str = ":'In'";
+				$out_str = ":'Out'";
+			} else {
+
+				$in_str = "";
+				$out_str = "";
+			}
+
+			$series .= "DEF:'bytes_in${def_nr}'='${rrd_dir}/bytes_in.rrd':'sum':AVERAGE "
+				."DEF:'bytes_out${def_nr}'='${rrd_dir}/bytes_out.rrd':'sum':AVERAGE "
+				."LINE2:'bytes_in${def_nr}'#${mem_cached_color}${in_str} "
+				."LINE2:'bytes_out${def_nr}'#${mem_used_color}${out_str} ";
+
+			$def_nr++;
+		}
+
+	} else if ($graph == "packet_report") {
+		$style = "Packets";
+
+		$lower_limit = "--lower-limit 0 --rigid";
+		$extras = "--base 1024";
+		$vertical_label = "--vertical-label 'Packets/sec'";
+
+		$def_nr = 0;
+
+		foreach( $rrd_dirs as $rrd_dir ) {
+
+			if( $def_nr == 0 ) {
+
+				$in_str = ":'In'";
+				$out_str = ":'Out'";
+			} else {
+
+				$in_str = "";
+				$out_str = "";
+			}
+
+			$series .= "DEF:'bytes_in${def_nr}'='${rrd_dir}/pkts_in.rrd':'sum':AVERAGE "
+				."DEF:'bytes_out${def_nr}'='${rrd_dir}/pkts_out.rrd':'sum':AVERAGE "
+				."LINE2:'bytes_in${def_nr}'#${mem_cached_color}${in_str} "
+				."LINE2:'bytes_out${def_nr}'#${mem_used_color}${out_str} ";
+
+			$def_nr++;
+		}
+
+	} else {
+		/* Custom graph */
+		$style = "";
+
+		$subtitle = $metricname;
+		if ($context == "host") {
+			if ($size == "small")
+				$prefix = $metricname;
+			else
+				$prefix = $hostname;
+
+			$value = $value>1000 ? number_format($value) : number_format($value, 2);
+		}
+
+		//if ($range=="job") {
+		//	$hrs = intval( -$jobrange / 3600 );
+		//	$subtitle = "$prefix last ${hrs}h (now $value)";
+		//} else
+		//	$subtitle = "$prefix last $range (now $value)";
+
+		if (is_numeric($max))
+			$upper_limit = "--upper-limit '$max' ";
+		if (is_numeric($min))
+			$lower_limit ="--lower-limit '$min' ";
+
+		if ($vlabel)
+			$vertical_label = "--vertical-label '$vlabel'";
+		else {
+			if ($upper_limit or $lower_limit) {
+				$max = $max>1000 ? number_format($max) : number_format($max, 2);
+				$min = $min>0 ? number_format($min,2) : $min;
+
+				$vertical_label ="--vertical-label '$min - $max' ";
+			}
+		}
+
+		$def_nr = 0;
+
+		foreach( $rrd_dirs as $rrd_dir ) {
+
+			if( $def_nr == 0 ) {
+				$title_str = ":'${subtitle}'";
+			} else {
+				$title_str = "";
+			}
+
+			$rrd_file = "$rrd_dir/$metricname.rrd";
+			$series .= "DEF:'sum${def_nr}'='$rrd_file':'sum':AVERAGE "
+				."AREA:'sum${def_nr}'#${default_metric_color}${title_str} ";
+
+			$def_nr++;
+		}
+
+	}
+	if( $series != '' ) {
+		if ($job_start)
+			$series .= "VRULE:${job_start}#${jobstart_color} ";
+		if ($job_stop)
+			$series .= "VRULE:${job_stop}#${jobstart_color} ";
+	}
+}
+
+//$title = "$hostname $style $metricname";
+$title = "$hostname";
+
+//# Set the graph title.
+//if($context == "meta") {
+//	$title = "$self $meta_designator $style last $range";
+//} else if ($context == "grid") {
+//	$title = "$grid $meta_designator $style last $range";
+//} else if ($context == "cluster") {
+//	$title = "$clustername $style last $range";
+//} else {
+//	if ($size == "small") {
+//		# Value for this graph define a background color.
+//		if (!$load_color) $load_color = "ffffff";
+//			$background = "--color BACK#'$load_color'";
+
+//		$title = $hostname;
+//	} else {
+//		if ($style)
+//			$title = "$hostname $style last $range";
+//		else
+//			$title = $metricname;
+//	}
+//}
+
+function determineXGrid( $p_start, $p_stop ) {
+
+	$period = intval( $p_stop - $p_start );
+
+	// Syntax: <minor_grid_lines_time_declr>:<major_grid_lines_time_declr>:<labels_time_declr>:<offset>:<format>
+	//
+	// Where each <*time_declr*> = <time_type>:<time_interval>
+
+	//$my_lines1 = intval( $period / 3.0 );
+	//$my_lines2 = intval( $period / 6.0 );
+
+	//$my_grid = "SECOND:$my_lines2:SECOND:$my_lines1:SECOND:$my_lines1:0:%R";
+
+	//return "--x-grid $my_grid";
+
+	// Less than 1 minute
+	if( $period < 60 ) {
+
+		$tm_formt = "%X";
+		$my_grid = "SECOND:15:SECOND:30:SECOND:30:0:$tm_formt";
+
+	// Less than 10 minutes
+	} else if( $period < 600 ) {
+
+		$tm_formt = "%R";
+		$my_grid = "MINUTE:1:MINUTE:3:MINUTE:3:0:$tm_formt";
+
+	// Less than 1 hour
+	} else if( $period < 3600 ) {
+
+		$tm_formt = "%R";
+		$my_grid = "MINUTE:5:MINUTE:15:MINUTE:15:0:$tm_formt";
+
+	// Less than 15 hour
+	} else if( $period < 3600 ) {
+
+		$tm_formt = "%R";
+		$my_grid = "HOUR:1:HOUR:2:HOUR:2:0:$tm_formt";
+
+	// Less than 1 day
+	//
+	} else if( $period < 86400 ) {
+
+		$tm_formt = "%R";
+		$my_grid = "HOUR:2:HOUR:5:HOUR:5:0:$tm_formt";
+
+	// Less than 15 days
+	//
+	} else if( $period < 1296000 ) {
+
+		$tm_formt = "%e-%m";
+		$my_grid = "HOUR:1:DAY:3:DAY:3:0:'$tm_formt'";
+		
+	// Less than 30 days (a month)
+	//
+	} else if( $period < 2592000 ) {
+
+		$tm_formt = "%e-%m";
+		$my_grid = "DAY:5:DAY:10:DAY:10:0:'$tm_formt'";
+	}
+
+	if( isset( $my_grid ) ) {
+
+		$ret_str = "--x-grid $my_grid";
+		return array($ret_str,$tm_formt);
+
+	} else {
+		return array( "", "" );
+	}
+}
+
+#list( $xgrid, $t_format ) = determineXGrid( $period_start, $period_stop );
+
+#if( $t_format != "" ) {
+#	$prnt_start = strftime( $t_format, $period_start );
+#	$prnt_stop = strftime( $t_format, $period_stop );
+#	$series .= " COMMENT:'     Timescale $prnt_start - $prnt_stop' ";
+#}
+
+$lower_limit = "--lower-limit 0";
+
+#
+# Generate the rrdtool graph command.
+#
+#$command = RRDTOOL . " graph - --start $period_start --end $period_stop ".
+#	"--width $width --height $height $upper_limit $lower_limit ".
+#	"--title '$title' $vertical_label $extras $background $xgrid ".
+#	$series;
+$command = RRDTOOL . " graph - --start $period_start --end $period_stop ".
+	"--width $width --height $height $lower_limit ".
+	"--title '$title' $extras $background ".
+	$series;
+
+$debug=0;
+
+# Did we generate a command?   Run it.
+if($command) {
+	/*Make sure the image is not cached*/
+	header ("Expires: Mon, 26 Jul 1997 05:00:00 GMT");   // Date in the past
+	header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); // always modified
+	header ("Cache-Control: no-cache, must-revalidate");   // HTTP/1.1
+	header ("Pragma: no-cache");                     // HTTP/1.0
+	if ($debug) {
+		header ("Content-type: text/html");
+		print "$command\n\n\n\n\n";
+	} else {
+		header ("Content-type: image/gif");
+		passthru($command);
+	}
+}
+?>
Index: trunk/web/addons/job_monarch/header.php
===================================================================
--- trunk/web/addons/job_monarch/header.php	(revision 203)
+++ trunk/web/addons/job_monarch/header.php	(revision 203)
@@ -0,0 +1,151 @@
+<?php
+# Check if this context is private.
+include_once "$GANGLIA_PATH/auth.php";
+checkcontrol();
+checkprivate();
+
+if ( $context == "control" && $controlroom < 0 )
+      $header = "header-nobanner";
+else
+      $header = "header";
+
+$tpl = new TemplatePower( "templates/header.tpl" );
+$tpl->prepare();
+
+# Maintain our path through the grid tree.
+$me = $self . "@" . $grid[$self][AUTHORITY];
+if ($initgrid)
+   {
+      $gridstack = array();
+      $gridstack[] = $me;
+   }
+else if ($gridwalk=="fwd")
+   {
+      # push our info on gridstack, format is "name@url>name2@url".
+      if (end($gridstack) != $me)
+         {
+            $gridstack[] = $me;
+         }
+   }
+else if ($gridwalk=="back")
+   {
+      # pop a single grid off stack.
+      if (end($gridstack) != $me)
+         {
+            array_pop($gridstack);
+         }
+   }
+$gridstack_str = join(">", $gridstack);
+$gridstack_url = rawurlencode($gridstack_str);
+
+if ($initgrid or $gridwalk)
+   {
+      # Use cookie so we dont have to pass gridstack around within this site.
+      # Cookie values are automatically urlencoded. Expires in a day.
+      setcookie("gs", $gridstack_str, time() + 86400);
+   }
+
+# Invariant: back pointer is second-to-last element of gridstack. Grid stack never
+# has duplicate entries.
+list($parentgrid, $parentlink) = explode("@", $gridstack[count($gridstack)-2]);
+
+# Setup a redirect to a remote server if you choose a grid from pulldown menu. Tell
+# destination server that we're walking foward in the grid tree.
+if (strstr($clustername, "http://"))
+   {
+      $tpl->assign("refresh", "0");
+      $tpl->assign("redirect", ";URL=$clustername?gw=fwd&gs=$gridstack_url");
+      echo "<h2>Redirecting, please wait...</h2>";
+      $tpl->printToScreen();
+      exit;
+   }
+$tpl->assign("refresh", $default_refresh);
+
+$tpl->assign( "date", date("r"));
+$tpl->assign( "page_title", $title );
+
+# The page to go to when "Get Fresh Data" is pressed.
+if (isset($page))
+      $tpl->assign("page",$page);
+else
+      $tpl->assign("page","./");
+
+# Templated Logo image
+$tpl->assign("images","./templates/$template_name/images");
+
+#
+# Used when making graphs via graph.php. Included in most URLs
+#
+$sort_url=rawurlencode($sort);
+$get_metric_string = "m=$metric&r=$range&s=$sort_url&hc=$hostcols";
+if ($jobrange and $jobstart)
+        $get_metric_string .= "&jr=$jobrange&js=$jobstart";
+
+# Set the Alternate view link.
+$cluster_url=rawurlencode($clustername);
+$node_url=rawurlencode($hostname);
+
+# Make some information available to templates.
+$tpl->assign("cluster_url", $cluster_url);
+
+# Build the node_menu
+$node_menu = "";
+
+if ($parentgrid)
+   {
+      $node_menu .= "<B><A HREF=\"$parentlink?gw=back&gs=$gridstack_url\">".
+         "$parentgrid $meta_designator</A></B> ";
+      $node_menu .= "<B>&gt;</B>\n";
+   }
+
+# Show grid.
+$mygrid =  ($self == "unspecified") ? "" : $self;
+$node_menu .= "<B><A HREF=\"./?$get_metric_string\">$mygrid $meta_designator</A> ";
+$node_menu .= "<B>&gt;</B>\n";
+
+if ($physical)
+   $node_menu .= hiddenvar("p", $physical);
+
+if ( $clustername )
+   {
+      $url = rawurlencode($clustername);
+      $node_menu .= "<B><A HREF=\"./?c=$url&$get_metric_string\">$clustername</A></B> ";
+      //$node_menu .= "<B>&gt;</B>\n";
+      $node_menu .= hiddenvar("c", $clustername);
+   }
+else
+   {
+      # No cluster has been specified, so drop in a list
+      $node_menu .= "<SELECT NAME=\"c\" OnChange=\"ganglia_form.submit();\">\n";
+      $node_menu .= "<OPTION VALUE=\"\">--Choose a Source\n";
+      ksort($grid);
+      foreach( $grid as $k => $v )
+         {
+            if ($k==$self) continue;
+            if ($v[GRID])
+               {
+                  $url = $v[AUTHORITY];
+                  $node_menu .="<OPTION VALUE=\"$url\">$k $meta_designator\n";
+               }
+            else
+               {
+                  $url = rawurlencode($k);
+                  $node_menu .="<OPTION VALUE=\"$url\">$k\n";
+               }
+         }
+      $node_menu .= "</SELECT>\n";
+   }
+
+$tpl->assign("node_menu", $node_menu);
+
+# Make sure that no data is cached..
+header ("Expires: Mon, 26 Jul 1997 05:00:00 GMT");    # Date in the past
+header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); # always modified
+header ("Cache-Control: no-cache, must-revalidate");  # HTTP/1.1
+header ("Pragma: no-cache");                          # HTTP/1.0
+
+$tpl->printToScreen();
+
+
+
+?>
Index: trunk/web/addons/job_monarch/host_view.php
===================================================================
--- trunk/web/addons/job_monarch/host_view.php	(revision 203)
+++ trunk/web/addons/job_monarch/host_view.php	(revision 203)
@@ -0,0 +1,171 @@
+<?php
+include_once "./libtoga.php";
+
+//$tpl = new TemplatePower( "templates/host_view.tpl" );
+//$tpl->assignInclude("extra", "templates/host_extra.tpl");
+//$tpl->prepare();
+
+function datetimeToEpoch( $datetime ) {
+
+        //printf("datetime = %s\n", $datetime );
+        $datetime_fields = explode( ' ', $datetime );
+
+        $date = $datetime_fields[0];
+        $time = $datetime_fields[1];
+
+        $date_fields = explode( '-', $date );
+
+        $days = $date_fields[0];
+        $months = $date_fields[1];
+        $years = $date_fields[2];
+
+        //printf( "days = %s months = %s years = %s\n", $days, $months, $years );
+
+        $time_fields = explode( ':', $time );
+
+        $hours = $time_fields[0];
+        $minutes = $time_fields[1];
+        $seconds = $time_fields[2];
+
+        //printf( "hours = %s minutes = %s seconds = %s\n", $hours, $minutes, $seconds );
+
+        $timestamp = mktime( $hours, $minutes, $seconds, $months, $days, $years );
+
+        //printf( "timestamp = %s\n", $timestamp );
+
+        return $timestamp;
+}
+
+function makeHostView() {
+
+	global $tpl, $metrics, $clustername, $hostname;
+	global $cluster_ul, $hosts_up, $get_metric_string;
+	global $cluster, $period_start, $period_stop;
+	global $job_start, $job_stop;
+
+	$metrics = $metrics[$hostname];
+	//print_r( $metrics );
+	$hosts_up = $hosts_up[$hostname];
+	//print_r( $hosts_up );
+
+	$tpl->assign("cluster", $clustername);
+	$tpl->assign("host", $hostname);
+	$tpl->assign("node_image", "../../".node_image($metrics));
+	$tpl->assign("sort",$sort);
+	$tpl->assign("range",$range);
+
+	if( !is_numeric( $period_start ) ) {
+		$period_start = datetimeToEpoch( $period_start );
+	}
+	if( !is_numeric( $period_stop ) ) {
+		$period_stop = datetimeToEpoch( $period_stop );
+	}
+
+	if($hosts_up)
+	      $tpl->assign("node_msg", "This host is up and running."); 
+	else
+	      $tpl->assign("node_msg", "This host is down."); 
+
+	$cluster_url=rawurlencode($clustername);
+	$tpl->assign("cluster_url", $cluster_url);
+	$tpl->assign("graphargs", "h=$hostname&$get_metric_string&st=$cluster[LOCALTIME]&job_start=$job_start&job_stop=$job_stop&period_start=$period_start&period_stop=$period_stop");
+
+	# For the node view link.
+	$tpl->assign("node_view","./?p=2&c=$cluster_url&h=$hostname");
+
+	//# No reason to go on if this node is down.
+	//if ($hosts_down)
+	//   {
+	//      $tpl->printToScreen();
+	//      return;
+	//   }
+
+	$tpl->assign("ip", $hosts_up[IP]);
+
+	foreach ($metrics as $name => $v)
+	   {
+	       if ($v[TYPE] == "string" or $v[TYPE]=="timestamp" or $always_timestamp[$name])
+		  {
+		     # Long gmetric name/values will disrupt the display here.
+		     if ($v[SOURCE] == "gmond") $s_metrics[$name] = $v;
+		  }
+	       elseif ($v[SLOPE] == "zero" or $always_constant[$name])
+		  {
+		     $c_metrics[$name] = $v;
+		  }
+	       else if ($reports[$metric])
+		  continue;
+	       else
+		  {
+		     $graphargs = "c=$cluster_url&h=$hostname&v=$v[VAL]&m=$name"
+		       ."&z=medium&st=$cluster[LOCALTIME]&job_start=$job_start&job_stop=$job_stop&period_start=$period_start&period_stop=$period_stop";
+		     # Adding units to graph 2003 by Jason Smith <smithj4@bnl.gov>.
+		     if ($v[UNITS]) {
+			$encodeUnits = rawurlencode($v[UNITS]);
+			$graphargs .= "&vl=$encodeUnits";
+		     }
+		     $g_metrics[$name][graph] = $graphargs;
+          }
+	   }
+	# Add the uptime metric for this host. Cannot be done in ganglia.php,
+	# since it requires a fully-parsed XML tree. The classic contructor problem.
+	$s_metrics[uptime][TYPE] = "string";
+	$s_metrics[uptime][VAL] = uptime($cluster[LOCALTIME] - $metrics[boottime][VAL]);
+
+	# Add the gmond started timestamps & last reported time (in uptime format) from
+	# the HOST tag:
+	$s_metrics[gmond_started][TYPE] = "timestamp";
+	$s_metrics[gmond_started][VAL] = $hosts_up[GMOND_STARTED];
+	$s_metrics[last_reported][TYPE] = "string";
+	$s_metrics[last_reported][VAL] = uptime($cluster[LOCALTIME] - $hosts_up[REPORTED]);
+
+	# Show string metrics
+	if (is_array($s_metrics))
+	   {
+	      ksort($s_metrics);
+	      foreach ($s_metrics as $name => $v )
+	     {
+		$tpl->newBlock("string_metric_info");
+		$tpl->assign("name", $name);
+		if( $v[TYPE]=="timestamp" or $always_timestamp[$name])
+		   {
+		      $tpl->assign("value", date("r", $v[VAL]));
+		   }
+		else
+		   {
+		      $tpl->assign("value", "$v[VAL] $v[UNITS]");
+		   }
+	     }
+	   }
+
+	# Show constant metrics.
+	if (is_array($c_metrics))
+	   {
+	      ksort($c_metrics);
+	      foreach ($c_metrics as $name => $v )
+	     {
+		$tpl->newBlock("const_metric_info");
+		$tpl->assign("name", $name);
+		$tpl->assign("value", "$v[VAL] $v[UNITS]");
+	     }
+	   }
+
+	# Show graphs.
+	if (is_array($g_metrics))
+	   {
+	      ksort($g_metrics);
+
+	      $i = 0;
+	      foreach ( $g_metrics as $name => $v )
+		 {
+		    $tpl->newBlock("vol_metric_info");
+		    $tpl->assign("graphargs", $v[graph]);
+		    $tpl->assign("alt", "$hostname $name");
+		    if($i++ %2)
+		       $tpl->assign("br", "<BR>");
+		 }
+	   }
+}
+
+	//$tpl->printToScreen();
+?>
Index: trunk/web/addons/job_monarch/image.php
===================================================================
--- trunk/web/addons/job_monarch/image.php	(revision 203)
+++ trunk/web/addons/job_monarch/image.php	(revision 203)
@@ -0,0 +1,73 @@
+<?php
+include_once "./libtoga.php";
+
+if ( !empty( $_GET ) ) {
+        extract( $_GET );
+}
+
+$httpvars = new HTTPVariables( $HTTP_GET_VARS, $_GET );
+$view = $httpvars->getHttpVar( "view" );
+$clustername = $httpvars->getClusterName();
+
+//printf("clustername = %s\n", $clustername );
+if( isset($id) && ($id!='')) $filter[id]=$id;
+if( isset($state) && ($state!='')) $filter[state]=$state;
+if( isset($user) && ($user!='')) $filter[user]=$user;
+if( isset($queue) && ($queue!='')) $filter[queue]=$queue;
+
+function drawSmallClusterImage() {
+
+	global $clustername;
+
+	$ic = new ClusterImage( $clustername );
+	$ic->draw();
+}
+
+function drawBigClusterImage() {
+
+	global $filter, $clustername;
+
+	$ic = new ClusterImage( $clustername );
+	foreach( $filter as $filtername=>$filtervalue ) {
+		//printf("filter %s,%s\n", $filtername, $filtervalue);
+		switch( $filtername ) {
+
+			case "id":
+				$ic->setFilter( 'jobid', $filtervalue );
+				break;
+			case "user":
+				$ic->setFilter( 'owner', $filtervalue);
+				break;
+			case "queue":
+				$ic->setFilter( 'queue', $filtervalue);
+				break;
+			case "state":
+				$ic->setFilter( 'status', $filtervalue);
+				break;
+			default:
+				break;
+		}
+	}
+	$ic->draw();
+}
+
+switch( $view ) {
+
+	case "small-clusterimage":
+
+		drawSmallClusterImage();
+		
+		break;
+
+	case "big-clusterimage":
+
+		drawBigClusterImage();
+	
+		break;
+
+	default:
+
+		break;
+}
+
+?>
Index: trunk/web/addons/job_monarch/index.php
===================================================================
--- trunk/web/addons/job_monarch/index.php	(revision 203)
+++ trunk/web/addons/job_monarch/index.php	(revision 203)
@@ -0,0 +1,417 @@
+<?php
+
+if ( !empty( $_GET ) ) {
+	extract( $_GET );
+}
+
+$my_dir = getcwd();
+
+include_once "./libtoga.php";
+
+global $GANGLIA_PATH;
+chdir( $GANGLIA_PATH );
+
+include_once "./class.TemplatePower.inc.php";
+chdir( $my_dir );
+
+$httpvars = new HTTPVariables( $HTTP_GET_VARS, $_GET );
+$clustername = $httpvars->getClusterName();
+$view = $httpvars->getHttpVar( "view" );
+
+$filter = array();
+
+if( !isset($view) ) $view = "overview";
+if( !isset($sortorder) ) $sortorder = "asc";
+if( !isset($sortby) ) $sortby = "id";
+
+if( isset( $filterorder ) && ($filterorder!='') ) {
+	$myfilter_fields = explode( ",", $filterorder );
+} else {
+	if( isset($queue) && ($queue!='')) $filter[queue]=$queue;
+	if( isset($state) && ($state!='')) $filter[state]=$state;
+	if( isset($user) && ($user!='')) $filter[user]=$user;
+	if( isset($id) && ($id!='')) $filter[id]=$id;
+}
+
+// Fill filter array in order they were picked by user
+foreach( $myfilter_fields as $myfilter ) {
+
+	switch( $myfilter ) {
+
+		case "queue":
+			$filter[queue]=$queue;
+			break;
+		case "state":
+			$filter[state]=$state;
+			break;
+		case "user":
+			$filter[user]=$user;
+			break;
+		case "id":
+			$filter[id]=$id;
+			break;
+	}
+}
+
+//if( isset($queue) && ($queue!='')) $filter[queue]=$queue;
+//if( isset($state) && ($state!='')) $filter[state]=$state;
+//if( isset($user) && ($user!='')) $filter[user]=$user;
+//if( isset($id) && ($id!='')) $filter[id]=$id;
+
+function epochToDatetime( $epoch ) {
+
+        return strftime( "%d-%m-%Y %H:%M:%S", $epoch );
+}
+
+function makeHeader() {
+
+	global $tpl, $grid, $context, $initgrid;
+	global $jobrange, $jobstart, $title;
+	global $page, $gridwalk, $clustername;
+	global $parentgrid, $physical, $hostname;
+	global $self, $filter, $cluster_url, $get_metric_string;
+	global $metrics, $reports, $m, $default_metric;
+	global $default_refresh, $filterorder, $view;
+	global $TARCHD, $period_start, $period_stop, $h, $id;
+	global $job_start, $job_stop;
+	
+	if( isset($default_metric) and !isset($m) )
+		$metricname = $default_metric;
+	else
+		if( isset( $m ) )
+			$metricname = $m;
+		else
+			$metricname = "load_one";
+
+	$header = "header";
+
+	# Maintain our path through the grid tree.
+	$me = $self . "@" . $grid[$self][AUTHORITY];
+
+	$gridstack = array();
+	$gridstack[] = $me;
+
+	if ($gridwalk=="fwd") {
+		# push our info on gridstack, format is "name@url>name2@url".
+		if (end($gridstack) != $me) {
+			$gridstack[] = $me;
+		}
+	} else if ($gridwalk=="back") {
+		# pop a single grid off stack.
+		if (end($gridstack) != $me) {
+			array_pop($gridstack);
+		}
+	}
+
+	$gridstack_str = join(">", $gridstack);
+	$gridstack_url = rawurlencode($gridstack_str);
+
+	if ($initgrid or $gridwalk) {
+		# Use cookie so we dont have to pass gridstack around within this site.
+		# Cookie values are automatically urlencoded. Expires in a day.
+		setcookie("gs", $gridstack_str, time() + 86400);
+	}
+
+	# Invariant: back pointer is second-to-last element of gridstack. Grid stack never
+	# has duplicate entries.
+	list($parentgrid, $parentlink) = explode("@", $gridstack[count($gridstack)-2]);
+
+	# Setup a redirect to a remote server if you choose a grid from pulldown menu. Tell
+	# destination server that we're walking foward in the grid tree.
+	if (strstr($clustername, "http://")) {
+		$tpl->assign("refresh", "0");
+		$tpl->assign("redirect", ";URL=$clustername?gw=fwd&gs=$gridstack_url");
+		echo "<h2>Redirecting, please wait...</h2>";
+		$tpl->printToScreen();
+		exit;
+	}
+
+	if( $view != "search" )
+		$tpl->assign( "refresh", $default_refresh );
+
+	$tpl->assign( "date", date("r") );
+	$tpl->assign( "page_title", $title );
+
+	# The page to go to when "Get Fresh Data" is pressed.
+	$tpl->assign("page","./");
+
+	# Templated Logo image
+	$tpl->assign("images","./templates/$template_name/images");
+
+	#
+	# Used when making graphs via graph.php. Included in most URLs
+	#
+	$sort_url=rawurlencode($sort);
+	$get_metric_string = "m=$metric&r=$range&s=$sort_url&hc=$hostcols";
+
+	if ($jobrange and $jobstart)
+		$get_metric_string .= "&jr=$jobrange&js=$jobstart";
+
+	# Set the Alternate view link.
+	$cluster_url=rawurlencode($clustername);
+	$node_url=rawurlencode($hostname);
+
+	# Make some information available to templates.
+	$tpl->assign("cluster_url", $cluster_url);
+	# Build the node_menu
+	$node_menu = "";
+
+	if ($parentgrid) {
+		$node_menu .= "<B>$parentgrid $meta_designator</B> ";
+		$node_menu .= "<B>&gt;</B>\n";
+	}
+
+	# Show grid.
+	$mygrid =  ($self == "unspecified") ? "" : $self;
+	$node_menu .= "<B><A HREF=\"../..\">$mygrid $meta_designator</A></B> ";
+	$node_menu .= "<B>&gt;</B>\n";
+
+	if ($physical)
+		$node_menu .= hiddenvar("p", $physical);
+
+	if ( $clustername ) {
+		$url = rawurlencode($clustername);
+		$node_menu .= "<B><A HREF=\"../../?c=".rawurlencode($clustername)."\">$clustername</A></B> ";
+		$node_menu .= "<B>&gt;</B>\n";
+		$node_menu .= hiddenvar("c", $clustername);
+	}
+
+	if (!count($metrics)) {
+		echo "<h4>Cannot find any metrics for selected cluster \"$clustername\", exiting.</h4>\n";       echo "Check ganglia XML tree (telnet $ganglia_ip $ganglia_port)\n";
+		exit;
+	}
+	$firsthost = key($metrics);
+	foreach ($metrics[$firsthost] as $m => $foo)
+		$context_metrics[] = $m;
+
+	foreach ($reports as $r => $foo)
+		$context_metrics[] = $r;
+
+	$node_menu .= "<B><A HREF=\"./?c=".rawurlencode($clustername)."\">Joblist</A></B> ";
+
+	if( count( $filter ) > 0 && $view != "search" ) {
+
+		$my_ct = 1;
+		$filter_nr = count( $filter );
+
+		foreach( $filter as $filtername=>$filterval ) {
+
+			$node_menu .= "<B>&gt;</B>\n";
+
+			$href = "<A HREF=\"./?c=".rawurlencode($clustername);
+			$temp_ct = 0;
+			$n_filter = $filter;
+			$my_filterorder = "";
+			$my_filters = array_keys( $filter );
+
+			foreach( $n_filter as $n_filtername=>$n_filterval ) {
+
+				if( $temp_ct < $my_ct ) {
+					$href .= "&". $n_filtername . "=" . $n_filterval;
+
+					if( $my_filterorder == "" )
+						$my_filterorder = $my_filters[$temp_ct];
+					else
+						$my_filterorder .= "," . $my_filters[$temp_ct];
+				}
+
+				$temp_ct++;
+			}
+			$href .= "&filterorder=$my_filterorder\">";
+
+			if( $my_ct < $filter_nr )
+				$node_menu .= "<B>$href$filtername: $filterval</A></B> ";
+			else
+				$node_menu .= "<B>$filtername: $filterval</B> ";
+
+			$my_ct++;
+		}
+	}
+
+	$m = $metricname;
+
+
+	$tpl->gotoBlock( "_ROOT" );
+	$tpl->assignGlobal("view", $view);
+
+	if( array_key_exists( "id", $filter ) or isset($hostname) ) {
+
+		//print_r( $context_metrics );
+
+		if( !isset( $hostname ) ) {
+
+			if (is_array($context_metrics) ) {
+				$metric_menu = "<B>Metric</B>&nbsp;&nbsp;"
+					."<SELECT NAME=\"m\" OnChange=\"".$form_name.".submit();\">\n";
+
+				sort($context_metrics);
+				foreach( $context_metrics as $k ) {
+					$url = rawurlencode($k);
+					$metric_menu .= "<OPTION VALUE=\"$url\" ";
+					if ($k == $metricname )
+						$metric_menu .= "SELECTED";
+					$metric_menu .= ">$k\n";
+				}
+				$metric_menu .= "</SELECT>\n";
+
+			}
+		}
+
+		$tpl->assign("metric_menu", $metric_menu );
+
+		if( $view == "search" or $view == "host" ) {
+			$tpl->newBlock("timeperiod");
+			if( is_numeric( $period_start ) ) {
+				$period_start = epochToDatetime( $period_start );
+			}
+			if( is_numeric( $period_stop ) ) {
+				$period_stop = epochToDatetime( $period_stop );
+			}
+			$tpl->assign("period_start", $period_start );
+			$tpl->assign("period_stop", $period_stop );
+			$tpl->assign("hostname", $hostname );
+
+			if( $view == "host" ) {
+				$tpl->newBlock("hostview");
+				$tpl->assign("job_start", $job_start );
+				$tpl->assign("job_stop", $job_stop );
+			}
+		} 
+
+	}
+
+	if( $view == "search" or $view == "host" ) {
+
+		$node_menu .= "<B>&gt;</B>\n";
+		$node_menu .= "<B>Jobarchive</B> ";
+		$form_name = "archive_search_form";
+		$tpl->assignGlobal("form_name", $form_name );
+
+	} else {
+		$form_name = "toga_form";
+		$tpl->assignGlobal("form_name", $form_name );
+	}
+
+	if( $TARCHD ) {
+		$tpl->newBlock( "search" );
+		$tpl->assignGlobal( "cluster_url", rawurlencode($clustername) );
+		$tpl->assignGlobal( "cluster", $clustername );
+	}
+	$tpl->gotoBlock( "_ROOT" );
+	$tpl->assignGlobal( "cluster", $clustername );
+	$tpl->assign("node_menu", $node_menu);
+
+	# Make sure that no data is cached..
+	header ("Expires: Mon, 26 Jul 1997 05:00:00 GMT");    # Date in the past
+	header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); # always modified
+	header ("Cache-Control: no-cache, must-revalidate");  # HTTP/1.1
+	header ("Pragma: no-cache");                          # HTTP/1.0
+}
+
+function makeFooter() {
+	global $tpl, $version, $parsetime, $monarchversion;
+
+	$tpl->gotoBlock( "_ROOT" );
+	$tpl->assign("webfrontend-version",$version["webfrontend"]);
+	$tpl->assign("monarch-version", $monarchversion);
+
+	if ($version["gmetad"]) {
+		$tpl->assign("webbackend-component", "gmetad");
+		$tpl->assign("webbackend-version",$version["gmetad"]);
+	} else if ($version["gmond"]) {
+		$tpl->assign("webbackend-component", "gmond");
+		$tpl->assign("webbackend-version", $version["gmond"]);
+	}
+
+	$tpl->assign("parsetime", sprintf("%.4f", $parsetime) . "s");
+}
+
+function includeSearchpage() {
+	global $tpl;
+
+	$tpl->assignInclude( "main", "templates/search.tpl" );
+
+}
+
+function includeOverview() {
+	global $tpl;
+
+	$tpl->assignInclude( "main", "templates/overview.tpl" );
+}
+
+function includeHostPage() {
+
+	global $tpl;
+
+	$tpl->assignInclude( "main", "templates/host_view.tpl" );
+}
+
+$tpl = new TemplatePower( "templates/index.tpl" );
+
+$tpl->assignInclude( "header", "templates/header.tpl" );
+
+if( isset( $h ) and $h != '' ) {
+	$hostname = $h;
+	$view = "host";
+}
+
+switch( $view ) {
+
+	case "overview":
+
+		includeOverview();
+		break;
+
+	case "search":
+
+		includeSearchPage();
+		break;
+
+	case "host":
+
+		includeHostPage();
+		break;
+
+	default:
+
+		includeOverview();
+		break;
+}
+
+$tpl->assignInclude( "footer", "templates/footer.tpl" );
+$tpl->prepare();
+
+$title = "Torque Report";
+makeHeader();
+$tpl->assign("cluster_url", rawurlencode($clustername) );
+$tpl->assign("cluster", $clustername );
+
+switch( $view ) {
+
+	case "overview":
+
+		include "./overview.php";
+		makeOverview();
+		break;
+
+	case "search":
+
+		include "./search.php";
+		makeSearchPage();
+		break;
+
+	case "host":
+
+		include "./host_view.php";
+		makeHostView();
+		break;
+
+	default:
+
+		makeOverview();
+		break;
+}
+
+makeFooter();
+$tpl->printToScreen();
+?>
Index: trunk/web/addons/job_monarch/libtoga.js
===================================================================
--- trunk/web/addons/job_monarch/libtoga.js	(revision 203)
+++ trunk/web/addons/job_monarch/libtoga.js	(revision 203)
@@ -0,0 +1,73 @@
+function setSort( sortbyval ) {
+
+	if( sortbyval != document.toga_form.sortby.value ) {
+
+		document.toga_form.sortby.value = sortbyval;
+		document.toga_form.sortorder.value = "asc";
+
+	} else {
+
+		if( document.toga_form.sortorder.value == "desc" )
+			document.toga_form.sortorder.value = "asc";
+		else if( document.toga_form.sortorder.value == "asc" )
+			document.toga_form.sortorder.value = "desc";
+	}
+
+	document.forms['toga_form'].submit();
+}
+
+function setFilter( filtername, filterval ) {
+
+	//document.toga_form.id.value = '';
+	//document.toga_form.queue.value = '';
+	//document.toga_form.state.value = '';
+	//document.toga_form.user.value = '';
+	var myfilterorder = document.toga_form.elements['filterorder'].value;
+
+	if( document.toga_form.elements[filtername] ) {
+		document.toga_form.elements[filtername].value = filterval;
+		if( myfilterorder != '')
+			myfilterorder = myfilterorder + "," + filtername;
+		else
+			myfilterorder = filtername;
+
+	}
+	document.toga_form.elements['filterorder'].value = myfilterorder;
+
+	//setTimeout( "document.forms['toga_form'].submit();", 1000 );
+
+	document.forms['toga_form'].submit();
+}
+
+//function removeFilters( filters ) {
+
+	//var myfilter_fields = filters.split( " " );
+	//for( var i=0; i<myfilter_fields.length; i++ ) {
+		//removeFilter( myfilter_fields[i] );
+		//setTimeout( "removeFilter( "+myfilter_fields[i]+" );", 50 );
+	//}
+	// delay 100 ms before submit or fields might not be set
+	//document.forms['toga_form'].submit();", 100 );
+
+	//setTimeout( "document.forms['toga_form'].submit();", 1000 );
+//}
+
+//function removeFilter( filtername ) {
+
+//      var filterorder_fields = document.toga_form.elements['filterorder'].value.split( "," );
+//      var myfilterorder = '';
+
+//      for( var i=0; i<filterorder_fields.length; i++ ) {
+//              if( filterorder_fields[i] != filtername ) {
+//                      if( myfilterorder != '') {
+//                              myfilterorder = myfilterorder + "," + filterorder_fields[i];
+//                              //alert('myfilterorder = '+myfilterorder);
+//                      } else {
+//                              myfilterorder = filterorder_fields[i];
+//                              //alert('emyfilterorder = '+myfilterorder);
+//                      }
+//              }
+//      }
+//      document.toga_form.elements[filtername].value = '';
+//      document.toga_form.elements['filterorder'].value = myfilterorder;
+//}
Index: trunk/web/addons/job_monarch/libtoga.php
===================================================================
--- trunk/web/addons/job_monarch/libtoga.php	(revision 203)
+++ trunk/web/addons/job_monarch/libtoga.php	(revision 203)
@@ -0,0 +1,973 @@
+<?php
+// If php is compiled without globals
+//
+//if ( !empty( $_GET ) ) {
+//        extract( $_GET );
+//}
+
+class HTTPVariables {
+
+	var $clustername, $metricname;
+	var $restvars, $httpvars;
+
+	function HTTPVariables( $httpvars, $getvars ) {
+
+		$this->restvars = array();
+
+		$this->clustername = $httpvars["c"] ? $httpvars["c"] : null;
+		$this->metricname = $httpvars["m"] ? $httpvars["m"] : null;
+
+		foreach( $httpvars as $httpvar => $httpval ) {
+			
+			if( $httpval ) {
+				$this->restvars[$httpvar] = $httpval;
+			}
+		}
+
+		foreach( $getvars as $getvar => $getval ) {
+
+			if( $getval ) {
+				$this->restvars[$getvar] = $getval;
+			}
+		}
+	}
+
+	function getClusterName() {
+		return $this->clustername;
+	}
+
+	function getMetricName() {
+		return $this->metricname;
+	}
+
+	function getHttpVar( $var ) {
+		if( isset( $this->restvars[$var] ) )
+			return $this->restvars[$var];
+		else
+			return null;
+	}
+}
+
+// Toga's conf
+//
+include_once "./conf.php";
+include_once "./version.php";
+
+global $GANGLIA_PATH;
+
+$my_dir = getcwd();
+
+// Load Ganglia's PHP
+chdir( $GANGLIA_PATH );
+
+include_once "./conf.php";
+include_once "./functions.php";
+include_once "./ganglia.php";
+include_once "./get_context.php";
+unset( $start );
+$context = 'cluster';
+include_once "./get_ganglia.php";
+
+// Back to our PHP
+chdir( $my_dir );
+
+global $SMALL_CLUSTERIMAGE_MAXWIDTH, $SMALL_CLUSTERIMAGE_NODEWIDTH, $DATA_SOURCE, $HTTP_GET_VARS, $_GET;
+$httpvars = new HTTPVariables( $HTTP_GET_VARS, $_GET );
+
+// Set cluster context so that Ganglia will
+// provide us with the correct metrics array
+//
+global $context, $clustername, $reports;
+
+//$clustername = $httpvars->getClusterName();
+
+global $default_metric;
+
+// Ganglia's array of host metrics
+//
+global $metrics, $hosts_up;
+
+class TarchDbase {
+
+	var $ip, $dbase, $conn;
+
+	function TarchDbase( $ip = null, $dbase = 'toga' ) {
+		$this->ip = $ip;
+		$this->dbase = $dbase;
+		$this->conn = null;
+	}
+
+	function connect() {
+
+		if( $this->ip == null and $this->dbase == 'toga' )
+			$this->conn = pg_connect( "dbname=".$this->dbase );
+		else
+			$this->conn = pg_connect( "host=".$this->ip." dbase=".$this->dbase );
+	}
+
+	function searchDbase( $id = null, $queue = null, $user = null, $name = null, $start_from_time = null, $start_to_time = null, $end_from_time = null, $end_to_time = null ) {
+
+		if( $id ) 
+			$query = "SELECT job_id FROM jobs WHERE job_id = '$id' AND job_status = 'F'";
+		else {
+			$query_args = array();
+			
+			if( $queue )
+				$query_args[] = "job_queue ='$queue'";
+			if( $user )
+				$query_args[] = "job_owner ='$user'";
+			if( $name )
+				$query_args[] = "job_name = '$name'";
+			if( $start_from_time )
+				$query_args[] = "job_start_timestamp >= $start_from_time";
+			if( $start_to_time )
+				$query_args[] = "job_start_timestamp <= $start_to_time";
+			if( $end_from_time )
+				$query_args[] = "job_stop_timestamp >= $end_from_time";
+			if( $end_to_time )
+				$query_args[] = "job_stop_timestamp <= $end_to_time";
+
+			$query = "SELECT job_id FROM jobs WHERE job_status = 'F' AND ";
+			$extra_query_args = '';
+
+			foreach( $query_args as $myquery ) {
+
+				if( $extra_query_args == '' )
+					$extra_query_args = $myquery;
+				else
+					$extra_query_args .= " AND ".$myquery;
+			}
+			$query .= $extra_query_args;
+		}
+
+		$ids = $this->queryDbase( $query );
+
+		$ret = array();
+
+		foreach( $ids as $crow)
+			$ret[] = $crow[job_id];
+
+		return $ret;
+	}
+
+	function getNodesForJob( $jobid ) {
+
+		$result = $this->queryDbase( "SELECT node_id FROM job_nodes WHERE job_id = '$jobid'" );
+
+		$nodes = array();
+
+		foreach( $result as $result_row ) 
+
+			$nodes[] = $this->getNodeArray( $result_row[node_id] );
+
+		return $nodes;
+	}
+
+	function getJobsForNode( $nodeid ) {
+
+		$result = $this->queryDbase( "SELECT job_id FROM job_nodes WHERE node_id = '$nodeid'" );
+
+		$jobs = array();
+
+		foreach( $result as $result_row )
+
+			$jobs[] = $this->getJobArray( $result_row[job_id] );
+
+		return $jobs;
+	}
+
+	function getJobArray( $id ) {
+		$result = $this->queryDbase( "SELECT * FROM jobs WHERE job_id = '$id'" );
+
+		return ( $this->makeArray( $result[0] ) );
+	}
+
+	function getNodeArray( $id ) {
+
+		$result = $this->queryDbase( "SELECT * FROM nodes WHERE node_id = '$id'" );
+
+		return ( $this->makeArray( $result[0] ) );
+	}
+
+	function makeArray( $result_row ) {
+
+		$myar = array();
+
+		foreach( $result_row as $mykey => $myval ) {
+
+			$map_key = explode( '_', $mykey );
+
+			$rmap_key = array_reverse( $map_key );
+			array_pop( $rmap_key );
+			$map_key = array_reverse( $rmap_key );
+			
+			$newkey = implode( '_', $map_key );
+			
+			$myar[$newkey] = $result_row[$mykey];
+		}
+
+		return $myar;
+	}
+
+	function queryDbase( $query ) {
+
+		$result_rows = array();
+	
+		if( !$this->conn )
+			$this->connect();
+
+		//printf( "query = [%s]\n", $query );
+		$result = pg_query( $this->conn, $query );
+
+		while ($row = pg_fetch_assoc($result))
+			$result_rows[] = $row;
+
+		return $result_rows;
+	}
+}
+
+class TarchRrdGraph {
+	var $rrdbin, $rrdvalues, $clustername, $hostname, $tempdir, $tarchdir, $metrics;
+
+	function TarchRrdGraph( $clustername, $hostname, $rrdbin = '/usr/bin/rrdtool', $tarchdir = '/data/toga/rrds' ) {
+	
+		$this->rrdbin = $rrdbin;
+		$this->rrdvalues = array();
+		$this->tarchdir = $tarchdir;
+		$this->clustername = $clustername;
+		$this->hostname = $hostname;
+	}
+
+	function doCmd( $command ) {
+
+		printf( "command = %s\n", $command );
+		$pipe = popen( $command . ' 2>&1', 'r' );
+
+		if (!$pipe) {
+			print "pipe failed.";
+			return "";
+		}
+
+		$output = '';
+		while(!feof($pipe))
+			$output .= fread($pipe, 1024);
+
+		pclose($pipe);
+
+		$output = explode( "\n", $output );
+		//print_r( $output );
+		return $output;
+	}
+
+	function dirList( $dir ) {
+
+		$dirlist = array();
+
+		if ($handle = opendir( $dir )) {
+			while (false !== ($file = readdir($handle))) {
+				if ($file != "." && $file != "..") {
+					$dirlist[] = $file;
+				}
+			}
+			closedir($handle);
+		}
+
+		return $dirlist;
+	}
+
+	function getTimePeriods( $start, $end ) {
+
+		//printf("start = %s end = %s\n", $start, $end );
+		$times = array();
+		$dirlist = $this->dirList( $this->tarchdir . '/' . $this->clustername . '/' . $this->hostname );
+
+		//print_r( $dirlist );
+
+		$first = 0;
+		$last = 9999999999999;
+
+		foreach( $dirlist as $dir ) {
+
+			if( $dir > $first and $dir <= $start )
+				$first = $dir;
+			if( $dir < $last and $dir >= $end )
+				$last = $dir;
+		}
+
+		//printf( "first = %s last = %s\n", $first, $last );
+
+		foreach( $dirlist as $dir ) {
+
+			//printf( "dir %s ", $dir );
+
+			if( $dir >= $first and $dir <= $last and !array_key_exists( $dir, $times ) ) {
+			
+				$times[] = $dir;
+				//printf("newtime %s ", $dir );
+
+			}
+		}
+
+		//print_r( $times );
+
+		sort( $times );
+
+		//print_r( $times );
+
+		return $times;
+	}
+
+	function getRrdDirs( $start, $stop ) {
+
+		//printf( "tarchdir = %s\n", $this->tarchdir );
+		$timess = $this->getTimePeriods( $start, $stop );
+		//print_r( $timess );
+
+		$rrd_files = array();
+
+		foreach( $timess as $time ) {
+
+			$rrd_files[] = $this->tarchdir . '/' . $this->clustername . '/' . $this->hostname. '/'.$time;
+		}
+
+		return $rrd_files;
+	}
+
+	function getRrdFiles( $metric, $start, $stop ) {
+
+		$times = $this->getTimePeriods( $start, $stop );
+
+		$rrd_files = array();
+
+		foreach( $times as $time ) {
+
+			$rrd_files[] = $this->tarchdir . '/' . $this->clustername . '/' . $this->hostname . '/' .$time. '/' . $metric. '.rrd';
+		}
+
+		return $rrd_files;
+	}
+
+	function graph( $descr ) {
+//	monitor2:/data/toga/rrds/LISA Cluster/gb-r15n11.irc.sara.nl# rrdtool graph /var/www/ganglia/test1.png --start 1118683231 --end 1118750431 --width 300 --height 400 DEF:'1'='./1118647515/load_one.rrd':'sum':AVERAGE DEF:'2'='./1118690723/load_one.rrd':'sum':AVERAGE DEF:'3'='./1118733925/load_one.rrd':'sum':AVERAGE AREA:1#555555:"load_one" AREA:2#555555 AREA:3#555555
+//	380x461
+//	monitor2:/data/toga/rrds/LISA Cluster/gb-r15n11.irc.sara.nl#
+		//$command = $this->rrdbin . " graph - --start $start --end $end ".
+			"--width $width --height $height $upper_limit $lower_limit ".
+			"--title '$title' $vertical_label $extras $background ". $series;
+
+		//$graph = $this->doCmd( $command );
+
+		//return $graph;
+		return 0;
+	}
+}
+
+class DataSource {
+
+	var $data, $ip, $port;
+
+	function DataSource( $ip = '127.0.0.1', $port = 8649 ) {
+		$this->ip = $ip;
+		$this->port = $port;
+	}
+
+	function getData() {
+
+		$errstr;
+		$errno = 0;
+		$timeout = 3;
+
+		$fp = fsockopen( $this->ip, $this->port, &$errno, &$errstr, $timeout );
+
+		if( !$fp ) {
+			echo 'Unable to connect to '.$this->ip.':'.$this->port; // printf( 'Unable to connect to [%s:%.0f]', $this->ip, $this->port );
+			return;
+		}
+
+		stream_set_timeout( $fp, 30 );
+
+		while ( !feof( $fp ) ) {
+			
+			$data .= fread( $fp, 16384 );
+		}
+
+		fclose( $fp );
+
+		return $data;
+	}
+}
+
+class DataGatherer {
+
+	var $xmlhandler, $data, $httpvars;
+
+	function DataGatherer( $cluster ) {
+
+		global $DATA_SOURCE;
+	
+		//printf("dg cluster = %s\n", $cluster );
+		$ds_fields = explode( ':', $DATA_SOURCE );
+		$ds_ip = $ds_fields[0];
+		$ds_port = $ds_fields[1];
+
+		$this->source = new DataSource( $ds_ip, $ds_port );
+
+		$this->parser = xml_parser_create();
+		$this->httpvars = $httpvars;
+		$this->xmlhandler = new TorqueXMLHandler( $cluster );
+		xml_set_element_handler( $this->parser, array( &$this->xmlhandler, 'startElement' ), array( &$this->xmlhandler, 'stopElement' ) );
+	}
+
+	function parseXML() {
+
+		$src = &$this->source;
+		$this->data = $src->getData();
+
+		if ( !xml_parse( &$this->parser, $this->data ) )
+			$error = sprintf( 'XML error: %s at %d', xml_error_string( xml_get_error_code( &$this->parser ) ), xml_get_current_line_number( &$this->parser ) );
+	}
+
+	function printInfo() {
+		$handler = $this->xmlhandler;
+		$handler->printInfo();
+	}
+
+	function getNodes() {
+		$handler = $this->xmlhandler;
+		return $handler->getNodes();
+	}
+
+	function getCpus() {
+		$handler = $this->xmlhandler;
+		return $handler->getCpus();
+	}
+
+	function getJobs() {
+		$handler = $this->xmlhandler;
+		return $handler->getJobs();
+	}
+
+	function getHeartbeat() {
+		$handler = $this->xmlhandler;
+		return $handler->getHeartbeat();
+	}
+}
+
+class TorqueXMLHandler {
+
+	var $clusters, $heartbeat, $nodes, $jobs, $clustername, $proc_cluster;
+
+	function TorqueXMLHandler( $clustername ) {
+		$jobs = array();
+		$clusters = array();
+		$this->nodes = array();
+		$heartbeat = array();
+		$this->clustername = $clustername;
+		//printf(" cluster set to %s \n", $this->clustername );
+	}
+
+	function getCpus() {
+
+		$cpus = 0;
+
+		foreach( $this->jobs as $jobid=>$jobattrs ) {
+
+			$nodes = count( $jobattrs[nodes] );
+			$ppn = (int) $jobattrs[ppn] ? $jobattrs[ppn] : 1;
+			$mycpus = $nodes * $ppn;
+
+			$cpus = $cpus + $mycpus;
+		}
+	}
+
+	function startElement( $parser, $name, $attrs ) {
+
+		$jobs = &$this->jobs;
+		$nodes = &$this->nodes;
+
+		if ( $attrs[TN] ) {
+
+			// Ignore dead metrics. Detect and mask failures.
+			if ( $attrs[TN] > $attrs[TMAX] * 4 )
+				return;
+		}
+
+		$jobid = null;
+
+		//printf( '%s=%s', $attrs[NAME], $attrs[VAL] );
+
+		//printf( "clustername = %s proc_cluster = %s\n", $this->clustername, $this->proc_cluster );
+
+		if( $name == 'CLUSTER' ) {
+
+			$this->proc_cluster = $attrs[NAME];
+			//printf( "Found cluster %s\n", $attrs[NAME] );
+			//print_r( $attrs );
+
+			//if( !isset( $clusters[$clustername] ) )
+			//	$clusters[$clustername] = array();
+
+		} else if( $name == 'HOST' and $this->proc_cluster == $this->clustername) {
+
+			$hostname = $attrs[NAME];
+			$location = $attrs[LOCATION];
+			//printf( "Found node %s\n", $hostname );
+
+			if( !isset( $nodes[$hostname] ) )
+				$nodes[$hostname] = new NodeImage( $hostname );
+
+		} else if( $name == 'METRIC' and strstr( $attrs[NAME], 'TOGA' ) and $this->proc_cluster == $this->clustername ) {
+
+			if( strstr( $attrs[NAME], 'TOGA-HEARTBEAT' ) ) {
+
+				$this->heartbeat['time'] = $attrs[VAL];
+				//printf( "heartbeat %s\n", $heartbeat['time'] );
+
+			} else if( strstr( $attrs[NAME], 'TOGA-JOB' ) ) {
+
+				sscanf( $attrs[NAME], 'TOGA-JOB-%d', $jobid );
+
+				//printf( "jobid %s\n", $jobid );
+
+				if( !isset( $jobs[$jobid] ) )
+					$jobs[$jobid] = array();
+
+				$fields = explode( ' ', $attrs[VAL] );
+
+				foreach( $fields as $f ) {
+					$togavalues = explode( '=', $f );
+
+					$toganame = $togavalues[0];
+					$togavalue = $togavalues[1];
+
+					//printf( "\t%s\t= %s\n", $toganame, $togavalue );
+
+					if( $toganame == 'nodes' ) {
+
+						if( $jobs[$jobid][status] == 'R' ) {
+						
+							if( !isset( $jobs[$jobid][$toganame] ) )
+								$jobs[$jobid][$toganame] = array();
+
+							$mynodes = explode( ';', $togavalue );
+
+							foreach( $mynodes as $node )
+
+								$jobs[$jobid][$toganame][] = $node;
+
+						} else if( $jobs[$jobid][status] == 'Q' ) {
+
+							$jobs[$jobid][$toganame] = $togavalue;
+						}
+						
+					} else {
+
+						$jobs[$jobid][$toganame] = $togavalue;
+					}
+				}
+
+				if( isset( $jobs[$jobid][domain] ) and isset( $jobs[$jobid][nodes] ) ) {
+			
+					$nr_nodes = count( $jobs[$jobid][nodes] );
+			
+					foreach( $jobs[$jobid][nodes] as $node ) {
+
+						$domain = $jobs[$jobid][domain];
+		                                $domain_len = 0 - strlen( $domain );
+
+						if( substr( $node, $domain_len ) != $domain ) {
+							$host = $node. '.'.$domain;
+						} else {
+							$host = $node;
+						}
+
+						//$host = $node.'.'.$jobs[$jobid][domain];
+				
+						if( !isset( $nodes[$host] ) )
+							$my_node = new NodeImage( $host );
+						else
+							$my_node = $nodes[$host];
+
+						if( !$my_node->hasJob( $jobid ) )
+
+							if( isset( $jobs[$jobid][ppn] ) )
+								$my_node->addJob( $jobid, ((int) $jobs[$jobid][ppn]) );
+							else
+								$my_node->addJob( $jobid, 1 );
+
+						$nodes[$host] = $my_node;
+					}
+				}
+			}
+		}
+		$this->jobs = $jobs;
+		//print_r( $nodes );
+		$this->nodes = $nodes;
+		//print_r( $this->nodes );
+	}
+
+	function stopElement( $parser, $name ) {
+	}
+
+	function printInfo() {
+
+		$jobs = &$this->jobs;
+
+		printf( "---jobs---\n" );
+
+		foreach( $jobs as $jobid => $job ) {
+
+			printf( "job %s\n", $jobid );
+
+			if( isset( $job[nodes] ) ) {
+
+				foreach( $job[nodes] as $node ) {
+
+					$mynode = $this->nodes[$node];
+					$hostname = $mynode->getHostname();
+					$location = $mynode->getLocation();
+
+					printf( "\t- node %s\tlocation %s\n", $hostname, $location );
+					//$this->nodes[$hostname]->setLocation( "hier draait job ".$jobid );
+				}
+			}
+		}
+
+		printf( "---nodes---\n" );
+
+		$nodes = &$this->nodes;
+
+		foreach( $nodes as $node ) {
+
+			$hostname = $node->getHostname();
+			$location = $node->getLocation();
+			$jobs = implode( ' ', $node->getJobs() );
+			printf( "* node %s\tlocation %s\tjobs %s\n", $hostname, $location, $jobs );
+		}
+	}
+
+	function getNodes() {
+		//print_r( $this->nodes );
+		return $this->nodes;
+	}
+
+	function getJobs() {
+		return $this->jobs;
+	}
+
+	function getHeartbeat() {
+		return $this->heartbeat['time'];
+	}
+}
+
+class NodeImage {
+
+	var $image, $x, $y, $hostname, $jobs, $tasks, $showinfo;
+
+	function NodeImage( $hostname ) {
+
+		$this->jobs = array();
+		//$this->image = $image;
+		//$this->x = $x;
+		//$this->y = $y;
+		$this->tasks = 0;
+		$this->hostname = $hostname;
+		$this->cpus = $this->determineCpus();
+		$this->showinfo = 1;
+	}
+
+	function addJob( $jobid, $cpus ) {
+		$jobs = &$this->jobs;
+
+		$jobs[] = $jobid;
+		$this->jobs = $jobs;
+
+		$this->addTask( $cpus );
+	}
+
+	function hasJob( $jobid ) {
+
+		$jobfound = 0;
+
+		if( count( $this->jobs ) > 0 )
+			foreach( $this->jobs as $job )
+
+				if( $job == $jobid )
+					$jobfound = 1;
+
+		return $jobfound;
+	}
+
+	function addTask( $cpus ) {
+
+		$this->tasks = $this->tasks + $cpus;
+	}
+
+	function setImage( $image ) {
+
+		$this->image = $image;
+	}
+
+	function setCoords( $x, $y ) {
+
+		$this->x = $x;
+		$this->y = $y;
+	}
+
+	function colorHex( $color ) {
+	
+		$my_color = imageColorAllocate( $this->image, hexdec( substr( $color, 0, 2 )), hexdec( substr( $color, 2, 2 )), hexdec( substr( $color, 4, 2 )) );
+
+		return $my_color;
+	}
+
+	function setLoad( $load ) {
+		$this->load = $load;
+	}
+
+	function setHostname( $hostname ) {
+		$this->hostname = $hostname;
+	}
+
+	function getHostname() {
+		return $this->hostname;
+	}
+
+	function getJobs() {
+		return $this->jobs;
+	}
+
+	function setShowinfo( $showinfo ) {
+		$this->showinfo = $showinfo;
+	}
+
+	function draw() {
+
+		$this->drawSmall();
+	}
+
+	function drawBig() {
+
+	}
+
+	function drawSmall() {
+
+		global $SMALL_CLUSTERIMAGE_NODEWIDTH;
+		global $JOB_NODE_MARKING;
+
+		$black_color = imageColorAllocate( $this->image, 0, 0, 0 );
+		$size = $SMALL_CLUSTERIMAGE_NODEWIDTH;
+
+		imageFilledRectangle( $this->image, $this->x, $this->y, $this->x+($size), $this->y+($size), $black_color );
+
+		if( $this->showinfo) {
+		
+			$this->load = $this->determineLoad();
+
+			if( !isset( $this->image ) or !isset( $this->x ) or !isset( $this->y ) ) {
+				printf( "aborting\n" );
+				printf( "x %d y %d load %f\n", $this->x, $this->y, $load );
+				return;
+			}
+
+
+			// Convert Ganglias Hexadecimal load color to a Decimal one
+			//
+			$load = $this->determineLoad();	
+			$usecolor = $this->colorHex( load_color($load) );
+			imageFilledRectangle( $this->image, $this->x+1, $this->y+1, $this->x+($size-1), $this->y+($size-1), $usecolor );
+			if( count( $this->jobs ) > 0 )
+				imageString( $this->image, 1, $this->x+(($size/2)-2), $this->y+(($size/2)-3), $JOB_NODE_MARKING, $black_color );
+
+		} else {
+
+			// White
+			$usecolor = imageColorAllocate( $this->image, 255, 255, 255 );
+			imageFilledRectangle( $this->image, $this->x+1, $this->y+1, $this->x+($size-1), $this->y+($size-1), $usecolor );
+		}
+
+
+	}
+
+	function determineCpus() {
+
+		global $metrics;
+
+		$cpus = $metrics[$this->hostname][cpu_num][VAL];
+		if (!$cpus) $cpus=1;
+
+		return $cpus;
+	}
+
+	function determineLoad() {
+
+		global $metrics;
+
+		$load_one = $metrics[$this->hostname][load_one][VAL];
+		$load = ((float) $load_one)/$this->cpus;
+
+		return $load;
+	}
+}
+
+class ClusterImage {
+
+	var $dataget, $image, $clustername;
+	var $filtername, $filters;
+
+	function ClusterImage( $clustername ) {
+
+		//printf( "image cluster = %s\n", $clustername );
+		$this->dataget = new DataGatherer( $clustername );
+		$this->clustername = $clustername;
+		$this->filters = array();
+	}
+
+	function setFilter( $filtername, $filtervalue ) {
+
+		//printf("filter %s = %s\n", $filtername, $filtervalue );
+		//printf( "filter set to %s = %s\n", $filtername, $filtervalue );
+		$this->filters[$filtername] = $filtervalue;
+		//print_r($this->filters);
+	}
+
+	function filterNodes( $jobs, $nodes ) {
+
+		$filtered_nodes = array();
+
+		foreach( $nodes as $node ) {
+
+			$hostname = $node->getHostname();
+
+			$addhost = 1;
+
+			if( count( $this->filters ) > 0 ) {
+
+				$mynjobs = $node->getJobs();
+
+				if( count( $mynjobs ) > 0 ) {
+
+					foreach( $mynjobs as $myjob ) {
+
+						foreach( $this->filters as $filtername => $filtervalue ) {
+
+							//printf("filter bla %s = %s\n", $filtername,$filtervalue );
+
+							if( $filtername!=null && $filtername!='' ) {
+
+								if( $filtername == 'jobid' && !$node->hasJob( $filtervalue) ) {
+									$addhost = 0;
+									//printf("host %s has no job %s\n", $hostname, $filtervalue);
+								} else if( $filtername != 'jobid' ) {
+									//printf("myjob is %s\n", $myjob );
+									if( $jobs[$myjob][$filtername] != $filtervalue ) {
+										//printf("host %s has no job with %s=%s\n", $hostname, $filtername, $filtervalue);
+										$addhost = 0;
+									}
+								}
+							}
+						}
+					}
+				} else
+					$addhost = 0;
+			}
+
+			if( $addhost )
+				$filtered_nodes[] = $hostname;
+		}
+
+		return $filtered_nodes;
+	}
+
+	function draw() {
+
+		//printf("stopt met uitvoer");
+		//return;
+
+		global $SMALL_CLUSTERIMAGE_MAXWIDTH, $SMALL_CLUSTERIMAGE_NODEWIDTH;
+	
+		$mydatag = $this->dataget;
+		$mydatag->parseXML();
+
+		//$max_width = 250;
+		//$node_width = 11;
+
+		$max_width = $SMALL_CLUSTERIMAGE_MAXWIDTH;
+		$node_width = $SMALL_CLUSTERIMAGE_NODEWIDTH;
+
+		//printf( "cmaxw %s nmaxw %s", $SMALL_CLUSTERIMAGE_MAXWIDTH, $SMALL_CLUSTERIMAGE_NODEWIDTH );
+
+		$nodes = $mydatag->getNodes();
+		$nodes_hosts = array_keys( $nodes );
+
+		$nodes_nr = count( $nodes );
+
+		$nodes_size = $nodes_nr*$node_width;
+		$node_rows = 0;
+
+		if( $nodes_size > $max_width ) {
+			$nodes_per_row = ( (int) ($max_width/$node_width) );
+		} else {
+			$nodes_per_row = $nodes_size;
+			$node_rows = 1;
+		}
+
+		if( $nodes_per_row < $nodes_nr ) {
+			$node_rows = ( (int) ($nodes_nr/$nodes_per_row) );
+			$node_rest = fmod( $nodes_nr, $nodes_per_row );
+			//printf( "nodesnr %d noderest %f\n", $nodes_nr, $node_rest );
+			if( $node_rest > 0 ) {
+				$node_rows++;
+				//printf( "noderows %d\n", $node_rows );
+			}
+		}
+
+		//printf( "imagecreate: %dx%d", ($nodes_per_row*$node_width), ($node_rows*$node_width) );
+		//$image = imageCreateTrueColor( ($nodes_per_row*$node_width)+1, ($node_rows*$node_width)+1 );
+		$image = imageCreateTrueColor( $max_width, ($node_rows*$node_width)+1 );
+		$colorwhite = imageColorAllocate( $image, 255, 255, 255 );
+		imageFill( $image, 0, 0, $colorwhite );
+
+		$jobs = $mydatag->getJobs();
+		//printf("filtername = %s\n", $filtername );
+		$filtered_nodes = $this->filterNodes( $jobs, $nodes );
+
+		//print_r($filtered_nodes);
+
+		for( $n = 0; $n < $node_rows; $n++ ) {
+			
+			for( $m = 0; $m < $nodes_per_row; $m++ ) {
+			
+				$x = ($m * $node_width);
+				$y = ($n * $node_width);
+
+				$cur_node = ($n * $nodes_per_row) + ($m);
+				$host = $nodes_hosts[$cur_node];
+
+
+				if( isset( $nodes[$host] ) ) {
+
+					$nodes[$host]->setCoords( $x, $y );
+					$nodes[$host]->setImage( $image );
+
+					if( !in_array( $host, $filtered_nodes ) )
+						$nodes[$host]->setShowinfo( 0 );
+
+					$nodes[$host]->draw();
+				}
+			}
+		}
+		
+		header( 'Content-type: image/png' );
+		imagePNG( $image );
+		imageDestroy( $image );
+	}
+}
+
+//$my_data = new DataGatherer();
+//$my_data->parseXML();
+//$my_data->printInfo();
+
+//$ic = new ClusterImage( "LISA Cluster" );
+//$ic->draw();
+?>
Index: trunk/web/addons/job_monarch/overview.php
===================================================================
--- trunk/web/addons/job_monarch/overview.php	(revision 203)
+++ trunk/web/addons/job_monarch/overview.php	(revision 203)
@@ -0,0 +1,705 @@
+<?php
+global $GANGLIA_PATH, $clustername, $tpl, $filter, $cluster, $get_metric_string, $cluster_url, $sh;
+global $hosts_up, $m, $start, $end, $filterorder;
+
+//$tpl->assign("_ROOT.summary", "" );
+
+$data_gatherer = new DataGatherer( $clustername );
+
+//$tpl->assign( "self", "./index.php" );
+$tpl->assign( "clustername", $clustername );
+
+if( $TARCHD )
+	$tpl->assign( "cluster_url", rawurlencode($clustername) );
+
+$data_gatherer->parseXML();
+
+$heartbeat = $data_gatherer->getHeartbeat();
+$jobs = $data_gatherer->getJobs();
+$gnodes = $data_gatherer->getNodes();
+$cpus = $data_gatherer->getCpus();
+
+$filter_image_url = "";
+
+foreach( $filter as $filtername => $filtervalue ) {
+	$tpl->assign( "f_".$filtername, $filtervalue );
+	$filter_image_url .= "&$filtername=$filtervalue";
+}
+
+$tpl->assign( "clusterimage", "./image.php?c=".rawurlencode($clustername)."&view=big-clusterimage".$filter_image_url );
+$tpl->assign( "f_order", $filterorder );
+
+if( array_key_exists( "id", $filter ) )
+	$piefilter = 'id';
+else if( array_key_exists( "user", $filter ) )
+	$piefilter = 'user';
+else if( array_key_exists( "queue", $filter ) )
+	$piefilter = 'queue';
+
+$pie = drawPie();
+$tpl->assign("pie", $pie );
+
+//if( !array_key_exists( 'id', $filter ) ) {
+
+//	$graph_args = "c=$cluster_url&$get_metric_string&st=$cluster[LOCALTIME]";
+//	$tpl->newBlock( "average_graphs" );
+//	$tpl->assign( "graph_args", $graph_args );
+//}
+
+function timeToEpoch( $time ) {
+
+	$time_fields = explode( ':', $time );
+
+	if( count($time_fields) == 3 ) {
+
+		$hours = $time_fields[0];
+		$minutes = $time_fields[1];
+		$seconds = $time_fields[2];
+
+	} else if( count($time_fields) == 2 ) {
+
+		$hours = 0;
+		$minutes = $time_fields[0];
+		$seconds = $time_fields[1];
+
+	} else if( count($time_fields) == 1 ) {
+
+		$hours = 0;
+		$minutes = 0;
+		$seconds = $time_fields[0];
+	}
+
+	$myepoch = intval( $seconds + (intval( $minutes * 60 )) + (intval( $hours * 3600 )) );
+
+	return $myepoch;
+}
+
+function makeTime( $time ) {
+
+	$days = intval( $time / 86400 );
+	$time = ($days>0) ? $time % ($days * 86400) : $time;
+
+	//printf( "time = %s, days = %s\n", $time, $days );
+
+	$date_str = '';
+	$day_str = '';
+
+	if( $days > 0 ) {
+		if( $days > 1 )
+			$day_str .= $days . ' days';
+		else
+			$day_str .= $days . ' day';
+	}
+
+	$hours = intval( $time / 3600 );
+	$time = $hours ? $time % ($hours * 3600) : $time;
+
+	//printf( "time = %s, days = %s, hours = %s\n", $time, $days, $hours );
+
+	if( $hours > 0 ) {
+		$date_str .= $hours . ':';
+		$date_unit = 'hours';
+	}
+		
+	$minutes = intval( $time / 60 );
+	$seconds = $minutes ? $time % ($minutes * 60) : $time;
+
+	if( $minutes > 0 ) {
+
+		if( $minutes >= 10 )
+			$date_str .= $minutes . ':';
+		else
+			$date_str .= '0' . $minutes . ':';
+
+		$date_unit = (!isset($date_unit)) ? 'minutes' : $date_unit;
+	} else {
+		if($hours > 0 ) {
+			$date_str .= '00:';
+			$date_unit = (!isset($date_unit)) ? 'minutes' : $date_unit;
+		}
+	}
+
+
+	$date_unit = (!isset($date_unit)) ? 'seconds' : $date_unit;
+
+	if( $seconds > 0 ) {
+
+		if( $seconds >= 10 )
+			$date_str .= $seconds . ' ' . $date_unit;
+		else
+			$date_str .= '0' . $seconds . ' ' . $date_unit;
+			
+	} else if ( $hours > 0 or $minutes > 0 )
+
+		$date_str .= '00 ' . $date_unit;
+
+	if( $days > 0) {
+
+		if( $hours > 0 or $minutes > 0 or $seconds > 0 )
+			$date_str = $day_str . ' - ' . $date_str;
+		else
+			$date_str = $day_str;
+	}
+
+	return $date_str;
+}
+
+function makeDate( $time ) {
+	return strftime( "%a %d %b %Y %H:%M:%S", $time );
+}
+
+function colorRed( $color ) {
+	return substr( $color, 0, 2 );
+}
+function colorGreen( $color ) {
+	return substr( $color, 2, 2 );
+}
+function colorBlue( $color ) {
+	return substr( $color, 4, 2 );
+}
+
+function colorDiffer( $first, $second ) {
+
+	// Make sure these two colors differ atleast 50 R/G/B
+	$min_diff = 50;
+
+	$c1r = hexDec( colorRed( $first ) );
+	$c1g = hexDec( colorGreen( $first ) );
+	$c1b = hexDec( colorBlue( $first ) );
+
+	$c2r = hexDec( colorRed( $second ) );
+	$c2g = hexDec( colorGreen( $second ) );
+	$c2b = hexDec( colorBlue( $second ) );
+
+	$rdiff = ($c1r >= $c2r) ? $c1r - $c2r : $c2r - $c1r;
+	$gdiff = ($c1g >= $c2g) ? $c1g - $c2g : $c2g - $c1g;
+	$bdiff = ($c1b >= $c2b) ? $c1b - $c2b : $c2b - $c1b;
+
+	if( $rdiff >= $min_diff or $gdiff >= $min_diff or $bdiff >= $min_diff )
+		return TRUE;
+	else
+		return FALSE;
+}
+
+function randomColor( $known_colors ) {
+
+	$start = "004E00";
+	
+	$start_red = colorRed( $start );
+	$start_green = colorGreen( $start );
+	$start_blue = colorBlue( $start );
+	
+	$end = "FFFFFF";
+
+	$end_red = colorRed( $end );
+	$end_green = colorGreen( $end );
+	$end_blue = colorBlue( $end );
+
+	$change_color = TRUE;
+
+	while( $change_color ) {
+
+		$change_color = FALSE;
+
+		$new_red = rand( hexDec( $start_red ), hexDec( $end_red ) );
+		$new_green = rand( hexDec( $start_green ), hexDec( $end_green ) );
+		$new_blue = rand( hexDec( $start_blue ), hexDec( $end_blue ) );
+
+		$new = decHex( $new_red ) . decHex( $new_green ) . decHex( $new_blue );
+
+		foreach( $known_colors as $old )
+
+			if( !colorDiffer( $new, $old ) )
+
+	 			$change_color = TRUE;
+	}
+
+	// Whoa! Actually found a good color ;)
+	return $new;
+}
+
+function drawJobPie() {
+}
+
+function drawUserPie() {
+
+}
+
+function drawQueuePie() {
+
+}
+
+
+function drawPie() {
+
+	global $jobs, $gnodes, $piefilter, $filter;
+
+	$nodes = $gnodes;
+
+	if( isset($piefilter) )	
+		$pie_args = "title=" . rawurlencode("Cluster ".$piefilter." usage");
+	else
+		$pie_args = "title=" . rawurlencode("Cluster queue usage");
+		
+	$pie_args .= "&size=250x150";
+
+	$queues = array();
+	$nr_jobs = count( $jobs );
+	$nr_nodes = count( $nodes );
+
+	$emptynodes = 0;
+
+	$job_weight = array();
+
+	foreach( $nodes as $node ) {
+
+		$myjobs = $node->getJobs();
+
+		if( count( $myjobs ) == 0 )
+			$emptynodes++;
+	}
+	$used_nodes = $nr_nodes - $emptynodes;
+
+	$empty_percentage = ($emptynodes / $nr_nodes) * 100;
+	$job_percentage = 100 - $empty_percentage; 
+
+	$qcolors = array();
+	$color = randomColor( $qcolors );
+	$qcolors[] = $color;
+	$pie_args .= "&free=$empty_percentage,$color";
+
+	if( isset( $piefilter ) )
+		$filterpie = array();
+
+	foreach( $nodes as $node ) {
+
+		$node_jobs = $node->getJobs();
+		$nr_node_jobs = count( $node_jobs );
+		$myhost = $node->getHostname();
+
+		foreach( $node_jobs as $myjob ) {
+
+			// Determine the weight of this job on the node it is running
+			// - what percentage of the node is in use by this job
+			//
+			$job_weight[$myjob] = ( 100 / count( $node_jobs ) ) / 100;
+			$qname = $jobs[$myjob][queue];
+
+			if( isset($piefilter) ) {
+				$countjob = 1;
+				if( $piefilter == 'id' ) {
+					if( $myjob != $filter[$piefilter] )
+						$countjob = 0;
+				} else if( $piefilter == 'user' ) {
+					if( $jobs[$myjob][owner] != $filter[$piefilter] )
+						$countjob = 0;
+				} else {
+					if( $jobs[$myjob][$piefilter] != $filter[$piefilter] )
+						$countjob = 0;
+				}
+
+				if( $countjob ) {
+
+					if( !isset( $filterpie[$filter[$piefilter]] ) )
+						$filterpie[$filter[$piefilter]] = $job_weight[$myjob];
+					else
+						$filterpie[$filter[$piefilter]] = $filterpie[$filter[$piefilter]] + $job_weight[$myjob];
+				} else {
+					if( !isset( $filterpie["other"] ) )
+						$filterpie["other"] = $job_weight[$myjob];
+					else
+						$filterpie["other"] = $filterpie["other"] + $job_weight[$myjob];
+
+				}
+				
+			} else {
+
+				if( !isset( $queues[$qname] ) )
+					$queues[$qname] = $job_weight[$myjob];
+				else
+					$queues[$qname] = $queues[$qname] + $job_weight[$myjob];
+			}
+		}
+	}
+
+	//$qcolors = array();
+	if( isset( $piefilter ) )
+		$graphvals = $filterpie;
+	else
+		$graphvals = $queues;
+
+	foreach( $graphvals as $name => $totalweight) {
+
+		$percentage = ( $totalweight / $used_nodes ) * $job_percentage;
+		
+		$color = randomColor( $qcolors );
+		$qcolors[] = $color;
+		$pie_args .= "&$name=$percentage,$color";
+	}
+	$pie = "../../pie.php?$pie_args";
+
+	return $pie;
+}
+
+
+function sortJobs( $jobs, $sortby, $sortorder ) {
+
+	$sorted = array();
+
+	$cmp = create_function( '$a, $b', 
+		"global \$sortby, \$sortorder;".
+
+		"if( \$a == \$b ) return 0;".
+
+		"if (\$sortorder==\"desc\")".
+			"return ( \$a < \$b ) ? 1 : -1;".
+		"else if (\$sortorder==\"asc\")".
+			"return ( \$a > \$b ) ? 1 : -1;" );
+
+        foreach( $jobs as $jobid => $jobattrs ) {
+
+                        $state = $jobattrs[status];
+                        $user = $jobattrs[owner];
+                        $queue = $jobattrs[queue];
+                        $name = $jobattrs[name];
+                        $req_cpu = $jobattrs[requested_time];
+                        $req_memory = $jobattrs[requested_memory];
+
+			if( $state == 'R' )
+				$nodes = count( $jobattrs[nodes] );
+			else
+				$nodes = $jobattrs[nodes];
+
+                        $ppn = (int) $jobattrs[ppn] ? $jobattrs[ppn] : 1;
+                        $cpus = $nodes * $ppn;
+                        $start_time = (int) $jobattrs[start_timestamp];
+			$runningtime = $report_time - $start_time;
+
+			switch( $sortby ) {
+				case "id":
+					$sorted[$jobid] = $jobid;
+					break;
+
+				case "state":
+					$sorted[$jobid] = $state;
+					break;
+
+				case "user":
+					$sorted[$jobid] = $user;
+					break;
+
+				case "queue":
+					$sorted[$jobid] = $queue;
+					break;
+
+				case "name":
+					$sorted[$jobid] = $name;
+					break;
+
+				case "req_cpu":
+					$sorted[$jobid] = timeToEpoch( $req_cpu );
+					break;
+
+				case "req_mem":
+					$sorted[$jobid] = $req_memory;
+					break;
+
+				case "nodes":
+					$sorted[$jobid] = $nodes;
+					break;
+
+				case "cpus":
+					$sorted[$jobid] = $cpus;
+					break;
+
+				case "start":
+					$sorted[$jobid] = $start_time;
+					break;
+
+				case "runningtime":
+					$sorted[$jobid] = $runningtime;
+					break;
+
+				default:
+					break;
+
+			}
+        }
+
+	//uasort( $sorted, $cmp );
+	if( $sortorder == "asc" )
+		arsort( $sorted );
+	else if( $sortorder == "desc" )
+		asort( $sorted );
+
+	return $sorted;
+}
+
+function makeOverview() {
+
+	global $jobs, $nodes, $heartbeat, $clustername, $tpl;
+	global $sortorder, $sortby, $filter, $sh, $hc, $m;
+	global $cluster_url, $get_metric_string, $host_url, $metrics;
+	global $start, $end, $reports, $gnodes, $default_showhosts;
+
+	$metricname = $m;
+
+	$tpl->assign("sortorder", $sortorder );
+	$tpl->assign("sortby", $sortby );
+
+	$sorted_jobs = sortJobs( $jobs, $sortby, $sortorder );
+
+	$even = 1;
+
+	$used_jobs = 0;
+	$used_cpus = 0;
+	$used_nodes = 0;
+
+	$all_used_nodes = array();
+
+	$avail_nodes = count( $gnodes );
+	$avail_cpus = cluster_sum("cpu_num", $metrics);
+
+	$view_cpus = 0;
+	$view_jobs = 0;
+	$view_nodes = 0;
+
+	$view_used_nodes = array();
+
+	foreach( $sorted_jobs as $jobid => $sortdec ) {
+
+		$report_time = $jobs[$jobid][reported];
+
+		$nodes = count( $jobs[$jobid][nodes] );
+		$ppn = (int) $jobs[$jobid][ppn] ? $jobs[$jobid][ppn] : 1;
+		$cpus = $nodes * $ppn;
+
+		foreach( $jobs[$jobid][nodes] as $tempnode )
+			$all_used_nodes[] = $tempnode;
+
+		if( $jobs[$jobid][status] == 'R' ) {
+			$used_cpus += $cpus;
+			$used_jobs++;
+		}
+
+		if( $report_time == $heartbeat ) {
+
+			$display_job = 1;
+
+			foreach( $filter as $filtername=>$filtervalue ) {
+
+				if( $filtername == 'id' && $jobid != $filtervalue )
+					$display_job = 0;
+				else if( $filtername == 'state' && $jobs[$jobid][status] != $filtervalue )
+					$display_job = 0;
+				else if( $filtername == 'queue' && $jobs[$jobid][queue] != $filtervalue )
+					$display_job = 0;
+				else if( $filtername == 'user' && $jobs[$jobid][owner] != $filtervalue )
+					$display_job = 0;
+			}
+
+			if( $display_job ) {
+
+				$tpl->newBlock("node");
+				$tpl->assign( "clustername", $clustername );
+				$tpl->assign("id", $jobid );
+				$tpl->assign("state", $jobs[$jobid][status] );
+				$tpl->assign("user", $jobs[$jobid][owner] );
+				$tpl->assign("queue", $jobs[$jobid][queue] );
+				$tpl->assign("name", $jobs[$jobid][name] );
+				$domain = $jobs[$jobid][domain];
+				$tpl->assign("req_cpu", makeTime( timeToEpoch( $jobs[$jobid][requested_time] ) ) );
+				$tpl->assign("req_memory", $jobs[$jobid][requested_memory] );
+
+				if( $jobs[$jobid][status] == 'R' )
+					$nodes = count( $jobs[$jobid][nodes] );
+				else if( $jobs[$jobid][status] == 'Q' )
+					$nodes = $jobs[$jobid][nodes];
+
+				$ppn = (int) $jobs[$jobid][ppn] ? $jobs[$jobid][ppn] : 1;
+				$cpus = $nodes * $ppn;
+				$tpl->assign("nodes", $nodes );
+				$tpl->assign("cpus", $cpus );
+				$start_time = (int) $jobs[$jobid][start_timestamp];
+				$job_start = $start_time;
+
+				$view_cpus += $cpus;
+				$view_jobs++;
+
+				if( $jobs[$jobid][status] == 'R' )
+					foreach( $jobs[$jobid][nodes] as $tempnode )
+						$view_used_nodes[] = $tempnode;
+				else if( $jobs[$jobid][status] == 'Q' )
+					$view_nodes += $jobs[$jobid][nodes];
+
+				if( $even ) {
+
+					$tpl->assign("nodeclass", "even");
+					$even = 0;
+				} else {
+
+					$tpl->assign("nodeclass", "odd");
+					$even = 1;
+				}
+
+				if( $start_time ) {
+
+					$runningtime = makeTime( $report_time - $start_time );
+					$job_runningtime = $report_time - $start_time;
+					$tpl->assign("started", makeDate( $start_time ) );
+					$tpl->assign("runningtime", $runningtime );
+				}
+			}
+		}
+	}
+	array_unique( $all_used_nodes );
+	array_unique( $view_used_nodes );
+	$used_nodes = count( $all_used_nodes );
+	$view_nodes += count( $view_used_nodes );
+
+	//$tpl->assignGlobal("cpus_nr", $overview_cpus );
+	//$tpl->assignGlobal("jobs_nr", $overview_jobs );
+
+	$tpl->assignGlobal("avail_nodes", $avail_nodes );
+	$tpl->assignGlobal("avail_cpus", $avail_cpus );
+
+	$tpl->assignGlobal("used_nodes", $used_nodes );
+	$tpl->assignGlobal("used_jobs", $used_jobs );
+	$tpl->assignGlobal("used_cpus", $used_cpus );
+
+	$tpl->assignGlobal("view_nodes", $view_nodes );
+	$tpl->assignGlobal("view_jobs", $view_jobs );
+	$tpl->assignGlobal("view_cpus", $view_cpus );
+
+	$tpl->assignGlobal("report_time", makeDate( $heartbeat));
+	
+	//$tpl->assignGlobal("f_cpus_nr", $f_cpus );
+	//$tpl->assignGlobal("f_jobs_nr", $f_jobs );
+
+	if( intval($view_jobs) == 1 and $start_time ) {
+		$tpl->newBlock( "showhosts" );
+
+		# Present a width list
+		$cols_menu = "<SELECT NAME=\"hc\" OnChange=\"toga_form.submit();\">\n";
+
+		$hostcols = ($hc) ? $hc : 4;
+
+		foreach(range(1,25) as $cols) {
+			$cols_menu .= "<OPTION VALUE=$cols ";
+			if ($cols == $hostcols)
+				$cols_menu .= "SELECTED";
+			$cols_menu .= ">$cols\n";
+		}
+		$cols_menu .= "</SELECT>\n";
+
+		//$tpl->assign("cluster", $clustername);
+		$tpl->assign("metric","$metricname $units");
+		$tpl->assign("id", $filter[id]);
+		# Host columns menu defined in header.php
+		$tpl->assign("cols_menu", $cols_menu);
+
+		$showhosts = isset($sh) ? $sh : $default_showhosts;
+		//if( !$showhosts) $showhosts = $default_showhosts;
+		$tpl->assign("checked$showhosts", "checked");
+
+		if( $showhosts ) {
+			//-----
+
+			if( !isset($start) ) $start="jobstart";
+			if( !isset($stop) ) $stop="now";
+			//$tpl->assign("start", $start);
+			//$tpl->assign("stop", $stop);
+
+			$sorted_hosts = array();
+			$hosts_up = $jobs[$filter[id]][nodes];
+
+			$r = intval($job_runningtime * 1.25);
+
+			$jobrange = ($job_runningtime < 3600) ? -3600 : -$r ;
+			$jobstart = $report_time - $job_runningtime;
+
+			if ($reports[$metricname])
+				$metricval = "g";
+			else
+				$metricval = "m";
+						
+			foreach ($hosts_up as $host ) {
+
+				$domain_len = 0 - strlen( $domain );
+				if( substr( $host, $domain_len ) != $domain ) {
+					$host = $host. '.'.$domain;
+				}
+				$cpus = $metrics[$host]["cpu_num"][VAL];
+				if (!$cpus) $cpus=1;
+				$load_one  = $metrics[$host]["load_one"][VAL];
+				$load = ((float) $load_one)/$cpus;
+				$host_load[$host] = $load;
+				$percent_hosts[load_color($load)] += 1;
+				if ($metricname=="load_one")
+					$sorted_hosts[$host] = $load;
+				else
+					$sorted_hosts[$host] = $metrics[$host][$metricname][VAL];
+			}
+			switch ($sort) {
+				case "descending":
+					arsort($sorted_hosts);
+					break;
+				case "by hostname":
+					ksort($sorted_hosts);
+					break;
+				default:
+				case "ascending":
+					asort($sorted_hosts);
+					break;
+			}
+
+			//$sorted_hosts = array_merge($down_hosts, $sorted_hosts);
+
+			# First pass to find the max value in all graphs for this
+			# metric. The $start,$end variables comes from get_context.php,
+			# included in index.php.
+			list($min, $max) = find_limits($sorted_hosts, $metricname);
+
+			# Second pass to output the graphs or metrics.
+			$i = 1;
+			foreach ( $sorted_hosts as $host=>$value  ) {
+				$tpl->newBlock ("sorted_list");
+				//$host = $host. '.'.$domain;
+				$host_url = rawurlencode($host);
+				$cluster_url = rawurlencode($clustername);
+
+				$textval = "";
+				//printf("host = %s, value = %s", $host, $value);
+				//echo "$host: $value, ";
+				$val = $metrics[$host][$metricname];
+				$class = "metric";
+				$host_link="\"../../?c=$cluster_url&h=$host_url&r=job&jr=$jobrange&js=$jobstart\"";
+
+				if ($val[TYPE]=="timestamp" or $always_timestamp[$metricname]) {
+					$textval = date("r", $val[VAL]);
+				} elseif ($val[TYPE]=="string" or $val[SLOPE]=="zero" or $always_constant[$metricname] or ($max_graphs > 0 and $i > $max_graphs )) {
+					$textval = "$val[VAL] $val[UNITS]";
+				} else {
+					$load_color = load_color($host_load[$host]);
+					$graphargs = ($reports[$metricname]) ? "g=$metricname&" : "m=$metricname&";
+					$graphargs .= "z=small&c=$cluster_url&h=$host_url&l=$load_color" ."&v=$val[VAL]&r=job&jr=$jobrange&js=$jobstart";
+					if( $max > 0 ) {
+
+						$graphargs .= "&x=$max&n=$min";
+					}
+				}
+				if ($textval) {
+					$cell="<td class=$class>".  "<b><a href=$host_link>$host</a></b><br>".  "<i>$metricname:</i> <b>$textval</b></td>";
+				} else {
+					$cell="<td><a href=$host_link>".  "<img src=\"../../graph.php?$graphargs\" ".  "alt=\"$host\" height=112 width=225 border=0></a></td>";
+				}
+
+				$tpl->assign("metric_image", $cell);
+				if (! ($i++ % $hostcols) )
+					 $tpl->assign ("br", "</tr><tr>");
+			}
+		}
+//---
+	}
+}
+?>
Index: trunk/web/addons/job_monarch/search.php
===================================================================
--- trunk/web/addons/job_monarch/search.php	(revision 203)
+++ trunk/web/addons/job_monarch/search.php	(revision 203)
@@ -0,0 +1,530 @@
+<?php
+
+global $clustername, $tpl;
+
+function validateFormInput() {
+	global $clustername, $tpl, $id, $user, $name, $start_from_time, $start_to_time, $queue;
+	global $end_from_time, $end_to_time, $period_start, $period_stop;
+
+	$error = 0;
+	$error_msg = "<FONT COLOR=\"red\"><B>";
+	$show_msg = 0;
+
+	$none_set = 0;
+
+	if( $id == '' and $user == '' and $name == '' and $start_from_time == '' and $start_to_time == '' and $queue == '' and $end_from_time == '' and $end_to_time == '') {
+		$error = 1;
+		$show_msg = 1;
+		$error_msg .= "No search criteria set!";
+	}
+
+	if( !is_numeric($id) and !$error and $id != '') {
+
+		$error = 1;
+		$show_msg = 1;
+		$error_msg .= "Id must be a number";
+	}
+
+	//printf( "period_start = %s period_stop = %s\n", $period_start, $period_stop );
+
+	if( !$error and $period_start != '' ) {
+		//printf( "period_start = %s period_stop = %s\n", $period_start, $period_stop );
+		$pstart_epoch = datetimeToEpoch( $period_start );
+		//printf( "period_start = %s period_stop = %s\n", $period_start, $period_stop );
+		if( $period_stop != '' ) {
+
+			$pstop_epoch = datetimeToEpoch( $period_stop );
+			//printf( "pstop_epoch = %s pstart_epoch = %s\n", $pstop_epoch, $pstart_epoch );
+
+			if( $pstart_epoch > $pstop_epoch ) {
+
+				$show_msg = 1;
+				$error_msg .= "Graph timeperiod reset: start date/time can't be later than end";
+				$period_stop = '';
+				$period_start = '';
+			} else if( $pstop_epoch == $pstart_epoch ) {
+
+				$show_msg = 1;
+				$error_msg .= "Graph timeperiod reset: start and end date/time can't be the same";
+				$period_stop = '';
+				$period_start = '';
+			}
+		}
+	}
+
+	$error_msg .= "</B></FONT>";
+	// doe checks en set error en error_msg in case shit
+
+	if( $show_msg )
+		$tpl->assign( "form_error_msg", $error_msg );
+
+	return ($error ? 0 : 1 );
+}
+
+function makeTime( $time ) {
+
+        $days = intval( $time / 86400 );
+        $time = ($days>0) ? $time % ($days * 86400) : $time;
+
+        //printf( "time = %s, days = %s\n", $time, $days );
+
+        $date_str = '';
+        $day_str = '';
+
+        if( $days > 0 ) {
+                if( $days > 1 )
+                        $day_str .= $days . ' days';
+                else
+                        $day_str .= $days . ' day';
+        }
+
+        $hours = intval( $time / 3600 );
+        $time = $hours ? $time % ($hours * 3600) : $time;
+
+        //printf( "time = %s, days = %s, hours = %s\n", $time, $days, $hours );
+
+        if( $hours > 0 ) {
+                $date_str .= $hours . ':';
+                $date_unit = 'hours';
+        }
+
+        $minutes = intval( $time / 60 );
+        $seconds = $minutes ? $time % ($minutes * 60) : $time;
+
+        if( $minutes > 0 ) {
+
+                if( $minutes >= 10 )
+                        $date_str .= $minutes . ':';
+                else
+                        $date_str .= '0' . $minutes . ':';
+
+                $date_unit = (!isset($date_unit)) ? 'minutes' : $date_unit;
+        } else {
+                if($hours > 0 ) {
+                        $date_str .= '00:';
+                        $date_unit = (!isset($date_unit)) ? 'minutes' : $date_unit;
+                }
+        }
+
+
+        $date_unit = (!isset($date_unit)) ? 'seconds' : $date_unit;
+
+        if( $seconds > 0 ) {
+
+                if( $seconds >= 10 )
+                        $date_str .= $seconds . ' ' . $date_unit;
+                else
+                        $date_str .= '0' . $seconds . ' ' . $date_unit;
+
+        } else if ( $hours > 0 or $minutes > 0 )
+
+                $date_str .= '00 ' . $date_unit;
+
+        if( $days > 0) {
+
+                if( $hours > 0 or $minutes > 0 or $seconds > 0 )
+                        $date_str = $day_str . ' - ' . $date_str;
+                else
+                        $date_str = $day_str;
+        }
+
+        return $date_str;
+}
+
+function makeDate( $time ) {
+        return strftime( "%a %d %b %Y %H:%M:%S", $time );
+}
+
+function datetimeToEpoch( $datetime ) {
+
+	//printf("datetime = %s\n", $datetime );
+	$datetime_fields = explode( ' ', $datetime );
+
+	$date = $datetime_fields[0];
+	$time = $datetime_fields[1];
+
+	$date_fields = explode( '-', $date );
+
+	$days = $date_fields[0];
+	$months = $date_fields[1];
+	$years = $date_fields[2];
+
+	//printf( "days = %s months = %s years = %s\n", $days, $months, $years );
+
+	$time_fields = explode( ':', $time );
+
+	$hours = $time_fields[0];
+	$minutes = $time_fields[1];
+	$seconds = $time_fields[2];
+
+	//printf( "hours = %s minutes = %s seconds = %s\n", $hours, $minutes, $seconds );
+
+	$timestamp = mktime( $hours, $minutes, $seconds, $months, $days, $years );
+
+	//printf( "timestamp = %s\n", $timestamp );
+
+	return $timestamp;
+}
+
+function timeToEpoch( $time ) {
+
+        $time_fields = explode( ':', $time );
+
+        if( count($time_fields) == 3 ) {
+
+                $hours = $time_fields[0];
+                $minutes = $time_fields[1];
+                $seconds = $time_fields[2];
+
+        } else if( count($time_fields) == 2 ) {
+
+                $hours = 0;
+                $minutes = $time_fields[0];
+                $seconds = $time_fields[1];
+
+        } else if( count($time_fields) == 1 ) {
+
+                $hours = 0;
+                $minutes = 0;
+                $seconds = $time_fields[0];
+        }
+
+        $myepoch = intval( $seconds + (intval( $minutes * 60 )) + (intval( $hours * 3600 )) );
+
+        return $myepoch;
+}
+
+function sortJobs( $jobs, $nodes, $sortby, $sortorder ) {
+
+	//printf("sortby = %s sortorder = %s\n", $sortby, $sortorder );
+
+        $sorted = array();
+
+        $cmp = create_function( '$a, $b',
+                "global \$sortby, \$sortorder;".
+
+                "if( \$a == \$b ) return 0;".
+
+                "if (\$sortorder==\"desc\")".
+                        "return ( \$a < \$b ) ? 1 : -1;".
+                "else if (\$sortorder==\"asc\")".
+                        "return ( \$a > \$b ) ? 1 : -1;" );
+
+	//print_r( $jobs );
+
+        foreach( $jobs as $jobid => $jobattrs ) {
+
+                        $state = $jobattrs[status];
+                        $user = $jobattrs[owner];
+                        $queue = $jobattrs[queue];
+                        $name = $jobattrs[name];
+                        $req_cpu = $jobattrs[requested_time];
+                        $req_memory = $jobattrs[requested_memory];
+
+                        //if( $state == 'R' )
+			$mynodes = count( $nodes[$jobid] );
+                        //else
+                        //        $nodes = $jobattrs[nodes];
+
+                        $ppn = (int) $jobattrs[ppn] ? $jobattrs[ppn] : 1;
+                        $cpus = $mynodes * $ppn;
+                        $start_time = (int) $jobattrs[start_timestamp];
+                        $stop_time = (int) $jobattrs[stop_timestamp];
+                        $runningtime = $stop_time - $start_time;
+
+                        switch( $sortby ) {
+                                case "id":
+                                        $sorted[$jobid] = $jobid;
+                                        break;
+
+                                case "state":
+                                        $sorted[$jobid] = $state;
+                                        break;
+
+                                case "user":
+                                        $sorted[$jobid] = $user;
+                                        break;
+
+                                case "queue":
+                                        $sorted[$jobid] = $queue;
+                                        break;
+
+                                case "name":
+                                        $sorted[$jobid] = $name;
+                                        break;
+
+                                case "req_cpu":
+                                        $sorted[$jobid] = timeToEpoch( $req_cpu );
+                                        break;
+
+                                case "req_mem":
+                                        $sorted[$jobid] = $req_memory;
+                                        break;
+
+                                case "nodes":
+                                        $sorted[$jobid] = $mynodes;
+                                        break;
+
+                                case "cpus":
+                                        $sorted[$jobid] = $cpus;
+                                        break;
+
+                                case "start":
+                                        $sorted[$jobid] = $start_time;
+                                        break;
+
+				case "finished":
+					$sorted[$jobid] = $stop_time;
+					break;
+
+                                case "runningtime":
+                                        $sorted[$jobid] = $runningtime;
+                                        break;
+
+                                default:
+                                        break;
+
+                        }
+        }
+
+        //uasort( $sorted, $cmp );
+        if( $sortorder == "asc" )
+                arsort( $sorted );
+        else if( $sortorder == "desc" )
+                asort( $sorted );
+
+	//print_r( $sorted );
+
+        return array_keys( $sorted );
+}
+
+function makeSearchPage() {
+	global $clustername, $tpl, $id, $user, $name, $start_from_time, $start_to_time, $queue;
+	global $end_from_time, $end_to_time, $filter, $default_showhosts, $m, $hosts_up;
+	global $period_start, $period_stop, $sortby, $sortorder;
+
+	$metricname = $m;
+	//printf("job_start = %s job_stop = %s\n", $job_start, $job_stop );
+	//printf("start = %s stop = %s\n", $start, $stop );
+
+	$tpl->assign( "cluster", $clustername );
+	$tpl->assign( "id_value", $id );
+	$tpl->assign( "user_value", $user );
+	$tpl->assign( "queue_value", $queue );
+	$tpl->assign( "name_value", $name );
+	$tpl->assign( "start_from_value", rawurldecode( $start_from_time ) );
+	$tpl->assign( "start_to_value", rawurldecode( $start_to_time ) );
+	$tpl->assign( "end_from_value", rawurldecode( $end_from_time ) );
+	$tpl->assign( "end_to_value", rawurldecode( $end_to_time ) );
+
+	if( validateFormInput() ) {
+
+		$tpl->newBlock( "search_results" );
+		$tpl->assign( "sortby", $sortby);
+		$tpl->assign( "sortorder", $sortorder);
+		$tdb = new TarchDbase();
+		if( $start_from_time ) $start_from_time = datetimeToEpoch( $start_from_time );
+		if( $start_to_time ) $start_to_time = datetimeToEpoch( $start_to_time );
+		if( $end_from_time ) $end_from_time = datetimeToEpoch( $end_from_time );
+		if( $end_to_time ) $end_to_time = datetimeToEpoch( $end_to_time );
+		$search_ids = $tdb->searchDbase( $id, $queue, $user, $name, $start_from_time, $start_to_time, $end_from_time, $end_to_time );
+
+		$jobs = array();
+		$nodes = array();
+
+		//print_r( $search_ids );
+
+		foreach( $search_ids as $myid ) {
+
+			//printf( "myid %s\n", $myid );
+			$jobs[$myid] = $tdb->getJobArray( $myid );
+			$nodes[$myid] = $tdb->getNodesForJob( $myid );
+		}
+
+		//print_r( $nodes );
+		$sorted_search = sortJobs( $jobs, $nodes, $sortby, $sortorder );
+
+		//print_r( $sorted_search );
+		foreach( $sorted_search as $sortid ) {
+
+			$job = $jobs[$sortid];
+			//print_r( $job );
+			$foundid = $job[id];
+			//printf( "foundid %s\n", $foundid );
+
+			//$job = $tdb->getJobArray( $foundid );
+			//$nodes = $tdb->getNodesForJob( $foundid );
+
+			$tpl->newBlock( "node" );
+			$tpl->assign( "id", $job[id] );
+			$tpl->assign( "state", $job[status] );
+			$tpl->assign( "user", $job[owner] );
+			$tpl->assign( "queue", $job[queue] );
+			$tpl->assign( "name", $job[name] );
+			$tpl->assign( "req_cpu", makeTime( TimeToEpoch( $job[requested_time] ) ) );
+			$tpl->assign( "req_memory", $job[requested_memory] );
+
+			$nodes_nr = count( $nodes[$foundid] );
+
+			// need to replace later with domain stored from dbase
+			//
+			//$job_domain = $job[domain];
+
+			//$myhost = $_SERVER[HTTP_HOST];
+			//$myhf = explode( '.', $myhost );
+			//$myhf = array_reverse( $myhf );
+			//array_pop( $myhf );
+			//$myhf = array_reverse( $myhf );
+			//$job_domain = implode( '.', $myhf );
+			
+			//print_r( $job );
+			//printf( "job domain = %s\n", $job_domain);
+			$ppn = (int) $job[ppn] ? $job[ppn] : 1;
+			$cpus = $nodes_nr * $ppn;
+
+			$tpl->assign( "nodes", $nodes_nr );
+			$tpl->assign( "cpus", $cpus );
+
+			$job_start = $job[start_timestamp];
+			$job_stop = $job[stop_timestamp];
+			$runningtime = intval( $job_stop - $job_start );
+			$tpl->assign( "started", makeDate( $job_start ) );
+			$tpl->assign( "finished", makeDate( $job_stop ) );
+			$tpl->assign( "runningtime", makeTime( $runningtime ) );
+			
+			//print_r( $job );
+			//print_r( $nodes );
+		}
+
+		if( count( $search_ids ) == 1 ) {
+
+			$tpl->newBlock( "showhosts" );
+
+			$showhosts = isset($sh) ? $sh : $default_showhosts;
+			//if( !$showhosts) $showhosts = $default_showhosts;
+			$tpl->assign("checked$showhosts", "checked");
+
+			# Present a width list
+			$cols_menu = "<SELECT NAME=\"hc\" OnChange=\"archive_search_form.submit();\">\n";
+
+			$hostcols = ($hc) ? $hc : 4;
+
+			foreach(range(1,25) as $cols) {
+				$cols_menu .= "<OPTION VALUE=$cols ";
+				if ($cols == $hostcols)
+					$cols_menu .= "SELECTED";
+				$cols_menu .= ">$cols\n";
+			}
+			$cols_menu .= "</SELECT>\n";
+
+			$tpl->assign("metric","$metricname $units");
+			$tpl->assign("id", $id);
+			# Host columns menu defined in header.php
+			$tpl->assign("cols_menu", $cols_menu);
+
+			if( $showhosts ) {
+				//bla
+
+				//printf("job_start = %s job_stop = %s\n", $job_start, $job_stop );
+				//printf("start = %s stop = %s\n", $start, $stop );
+
+				if( !$period_start ) // Add an extra 10% to graphstart
+					$period_start = intval( $job_start - (intval( $runningtime * 0.10 ) ) );
+				else
+					$period_start = datetimeToEpoch( $period_start );
+
+				if( !$period_stop ) // Add an extra 10% to graphend
+					$period_stop = intval( $job_stop + (intval( $runningtime * 0.10 ) ) );
+				else
+					$period_stop = datetimeToEpoch( $period_stop );
+
+				//printf("start = %s stop = %s\n", $start, $stop );
+
+		                $tpl->gotoBlock( "timeperiod" );
+
+				$tpl->assign("period_start", epochToDatetime( $period_start ) );
+				$tpl->assign("period_stop", epochToDatetime( $period_stop ) );
+
+		                $tpl->gotoBlock( "_ROOT" );
+
+				$hosts_up = array();
+
+				foreach( $nodes[$id] as $mynode )
+					$hosts_up[] = $mynode[hostname];
+
+				$sorted_hosts = array();
+				//$hosts_up = $jobs[$filter[id]][nodes];
+
+				foreach ($hosts_up as $host ) {
+					//$host = $host. '.'.$job_domain;
+					$cpus = $metrics[$host]["cpu_num"][VAL];
+					if (!$cpus) $cpus=1;
+					$load_one  = $metrics[$host]["load_one"][VAL];
+					$load = ((float) $load_one)/$cpus;
+					$host_load[$host] = $load;
+					$percent_hosts[load_color($load)] += 1;
+					if ($metricname=="load_one")
+						$sorted_hosts[$host] = $load;
+					else
+						$sorted_hosts[$host] = $metrics[$host][$metricname][VAL];
+				}
+				switch ($sort) {
+					case "descending":
+						arsort($sorted_hosts);
+						break;
+					case "by hostname":
+						ksort($sorted_hosts);
+						break;
+					default:
+					case "ascending":
+						asort($sorted_hosts);
+						break;
+				}
+
+				//$sorted_hosts = array_merge($down_hosts, $sorted_hosts);
+
+				# First pass to find the max value in all graphs for this
+				# metric. The $start,$end variables comes from get_context.php,
+				# included in index.php.
+				list($min, $max) = find_limits($sorted_hosts, $metricname);
+
+				# Second pass to output the graphs or metrics.
+				$i = 1;
+				foreach ( $sorted_hosts as $host=>$value  ) {
+					$tpl->newBlock ("sorted_list");
+					//$host = $host. '.'.$domain;
+					$host_url = rawurlencode($host);
+					$cluster_url = rawurlencode($clustername);
+
+					$textval = "";
+					//printf("host = %s, value = %s", $host, $value);
+					//echo "$host: $value, ";
+					$val = $metrics[$host][$metricname];
+					$class = "metric";
+					$host_link="\"?c=$cluster_url&h=$host_url&job_start=$job_start&job_stop=$job_stop&period_start=$period_start&period_stop=$period_stop\"";
+
+					if ($val[TYPE]=="timestamp" or $always_timestamp[$metricname]) {
+						$textval = date("r", $val[VAL]);
+					} elseif ($val[TYPE]=="string" or $val[SLOPE]=="zero" or $always_constant[$metricname] or ($max_graphs > 0 and $i > $max_graphs )) {
+						$textval = "$val[VAL] $val[UNITS]";
+					} else {
+						$graphargs = "z=small&c=$cluster_url&m=$metricname&h=$host_url&v=$val[VAL]&x=$max&n=$min&job_start=$job_start&job_stop=$job_stop&period_start=$period_start&period_stop=$period_stop&min=$min&max=$max";
+					}
+					if ($textval) {
+						$cell="<td class=$class>".  "<b><a href=$host_link>$host</a></b><br>".  "<i>$metricname:</i> <b>$textval</b></td>";
+					} else {
+						$cell="<td><a href=$host_link>".  "<img src=\"./graph.php?$graphargs\" ".  "alt=\"$host\" border=0></a></td>";
+					}
+
+					$tpl->assign("metric_image", $cell);
+					if (! ($i++ % $hostcols) )
+						 $tpl->assign ("br", "</tr><tr>");
+				}
+
+				//einde bla
+			}
+		}
+
+	}
+}
+?>
Index: trunk/web/addons/job_monarch/styles.css
===================================================================
--- trunk/web/addons/job_monarch/styles.css	(revision 203)
+++ trunk/web/addons/job_monarch/styles.css	(revision 203)
@@ -0,0 +1,211 @@
+/* The Ganglia Web-frontend Cascading Style Sheet. */
+
+A:link
+{
+   color: rgb(32,41,204);
+   text-decoration: none;
+}
+
+A:visited
+{
+   color: rgb(51,51,204);
+   text-decoration: none;
+}
+
+A:active
+{
+   color: rgb(204,205,226);
+   text-decoration: none;
+}
+
+h1 
+{
+   font: bold 18pt/22pt helvetica, sans-serif;
+   color: rgb(12,17,142);
+   margin-bottom: 2mm;
+}
+
+h2
+{
+   font: bold 14pt/16pt helvetica;
+   color: rgb(12,17,142); 
+   margin-left: 0.1em;
+   margin-right: 0.1em;
+}
+
+h3
+{
+   font: bold 12pt/15pt helvetica, sans-serif;
+   text-align: left;
+   margin-left: 3mm;
+   color: rgb(247,142,14);
+}
+
+h4
+{
+   font: bold 12pt/14pt helvetica;
+   color: rgb(12,17,142); 
+   margin-left: 0.1em;
+   margin-right: 0.1em;
+}
+
+small
+{
+   font: 10pt/12pt arial, helvetica, sans-serif;
+}
+
+td.title
+{
+   font-size: larger;
+   font-weight: normal;
+   background: rgb(238,238,238);
+   text-align: center;
+}
+
+td.metric
+{
+   background: rgb(217,218,224);
+   padding: 2mm;
+}
+
+td.cluster
+{
+   background: rgb(238,238,238);
+   /* padding: 1mm; */
+}
+
+td.grid
+{
+   vertical-align: top;
+   background: rgb(204,204,255);
+}
+
+td.self
+{
+   vertical-align: top;
+   text-align: center;
+   background: rgb(255,153,153);
+}
+
+td.even
+{
+   background: rgb(201,205,234);
+}
+
+td.odd
+{
+   background: rgb(217,218,224);
+}
+
+td.small
+{
+   font: 10pt/12pt times, serif;
+}
+
+td.L1
+{
+   background: rgb(184,249,119);
+}
+
+td.L2
+{
+   background: rgb(213,249,119);
+}
+
+td.L3
+{
+   background: rgb(228,249,119);
+}
+
+td.L4
+{
+   background: rgb(245,249,119);
+}
+
+td.L5
+{
+   background: rgb(249,239,119);
+}
+
+td.L6
+{
+   background: rgb(249,219,119);
+}
+
+td.L7
+{
+   background: rgb(249,202,119);
+}
+
+td.L8
+{
+   background: rgb(249,182,119);
+}
+
+td.L9
+{
+   background: rgb(249,152,119);
+}
+
+td.L10
+{
+   background: rgb(249,124,119);
+}
+
+td.down
+{
+   background: rgb(255,153,153);
+}
+
+th 
+{
+   font: bold 12pt/14pt helvetica, sans-serif;
+   color: rgb(238,238,238);
+   background: rgb(80,80,80);
+   border: thin solid rgb(47,47,47);
+}
+
+tr.even
+{
+   background: rgb(255,255,255);
+}
+
+tr.odd
+{
+   background: rgb(240,240,240);
+}
+
+tr.inactive
+{
+   color: rgb(210,210,210);
+}
+
+tr.toga th
+{
+   font: bold 12pt/14pt helvetica, sans-serif;
+   color: rgb(10,10,10);
+   background: rgb(240,240,240);
+   border: thin solid rgb(47,47,47);
+   padding: 2mm;
+   margin: 1mm;
+}
+
+td em
+{
+   font: 8pt/10pt helvetica, sans-serif;
+   color: rgb(31,31,112);
+   font-style: normal;
+}
+
+td strong
+{
+   color: rgb(31,31,112);
+   font-style: normal;
+}
+
+.footer
+{
+      font: 10pt/12pt helvetica, sans-serif;
+      color: rgb(100,100,100);
+}
+
Index: trunk/web/addons/job_monarch/templates/footer.tpl
===================================================================
--- trunk/web/addons/job_monarch/templates/footer.tpl	(revision 203)
+++ trunk/web/addons/job_monarch/templates/footer.tpl	(revision 203)
@@ -0,0 +1,17 @@
+<HR>
+<CENTER>
+<FONT SIZE="-1" class=footer>
+Job Monarch version {monarch-version}<BR>
+
+Ganglia version {webfrontend-version}
+<A HREF="http://ganglia.sourceforge.net/downloads.php?component=ganglia-webfrontend&amp;
+version={webfrontend-version}">Check for Updates.</A><BR>
+
+Downloading and parsing ganglia's XML tree took {parsetime}.<BR>
+Images created with <A HREF="http://www.rrdtool.com/">RRDTool</A>.<BR>
+</FONT>
+</CENTER>
+
+</FORM>
+</BODY>
+</HTML>
Index: trunk/web/addons/job_monarch/templates/header.tpl
===================================================================
--- trunk/web/addons/job_monarch/templates/header.tpl	(revision 203)
+++ trunk/web/addons/job_monarch/templates/header.tpl	(revision 203)
@@ -0,0 +1,97 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<HTML>
+<HEAD>
+<TITLE>Ganglia:: {page_title}</TITLE>
+<META http-equiv="Content-type" content="text/html; charset=utf-8">
+<META http-equiv="refresh" content="{refresh}{redirect}" >
+<LINK rel="stylesheet" href="./styles.css" type="text/css">
+<SCRIPT LANGUAGE="javascript" SRC="ts_picker.js"></SCRIPT>
+<SCRIPT LANGUAGE="javascript">
+
+        function setPeriodTimestamps() {
+
+                document.{form_name}.period_start.value = document.{form_name}.period_start_pick.value;
+                document.{form_name}.period_stop.value = document.{form_name}.period_stop_pick.value;
+        }
+
+</SCRIPT>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+
+<FORM ACTION="./" METHOD="GET" NAME="{form_name}">
+<INPUT TYPE="HIDDEN" NAME="c" VALUE="{cluster}">
+<INPUT TYPE="HIDDEN" NAME="view" VALUE="{view}">
+<TABLE WIDTH="100%">
+<TR>
+  <TD ROWSPAN="2" WIDTH="150">
+  <A HREF="http://monitor2.irc.sara.nl/ganglia/">
+  <IMG SRC="./logo_ned.gif" 
+      ALT="Ganglia" BORDER="0"></A>
+  </TD>
+  <TD VALIGN="TOP">
+
+  <TABLE WIDTH="100%" CELLPADDING="8" CELLSPACING="0" BORDER=0>
+  <TR BGCOLOR="#DDDDDD">
+     <TD BGCOLOR="#DDDDDD">
+     <FONT SIZE="+1">
+     <B>{page_title} for {date}</B>
+     </FONT>
+     </TD>
+     <TD BGCOLOR="#DDDDDD" ALIGN="RIGHT">
+     <INPUT TYPE="SUBMIT" VALUE="Get Fresh Data">
+     </TD>
+     <TD></TD>
+  </TR>
+  <TR>
+     <TD COLSPAN=1>
+     {metric_menu} &nbsp;&nbsp;
+     {range_menu}&nbsp;&nbsp;
+     {sort_menu}&nbsp;&nbsp;
+<!-- START BLOCK : timeperiod -->
+    <INPUT TYPE="HIDDEN" NAME="period_start" VALUE="{period_start}">
+    <INPUT TYPE="HIDDEN" NAME="period_stop" VALUE="{period_stop}">
+    <INPUT TYPE="HIDDEN" NAME="h" VALUE="{hostname}">
+    <BR><BR><B>Graph/ from
+    <INPUT TYPE="text" NAME="period_start_pick" VALUE="{period_start}" ALT="Start time" DISABLED="TRUE">
+    <a href="javascript:show_calendar('document.{form_name}.period_start_pick', document.{form_name}.period_start_pick.value);" alt="Click to select a date/time" title="Click to select a date/time">
+    <img src="cal.gif" width="16" height="16" border="0"></a>
+    <a href="#" onClick="javascript: document.{form_name}.period_start_pick.value=''" alt="Click here to clear field" title="Click here to clear field">
+    <IMG SRC="redcross.jpg" BORDER=0></A>
+    to <INPUT TYPE="text" NAME="period_stop_pick" VALUE="{period_stop}" ALT="Stop time" DISABLED="TRUE">
+    <a href="javascript:show_calendar('document.{form_name}.period_stop_pick', document.{form_name}.period_stop_pick.value);" alt="Click to select a date/time" title="Click to select a date/time">
+    <img src="cal.gif" width="16" height="16" border="0"></a>
+    <a href="#" onClick="javascript: document.{form_name}.period_stop_pick.value=''" alt="Click here to clear field" title="Click here to clear field">
+    </B>
+    <IMG SRC="redcross.jpg" BORDER=0></A>
+
+<!-- START BLOCK : hostview -->
+    <INPUT TYPE="HIDDEN" NAME="job_start" VALUE="{job_start}">
+    <INPUT TYPE="HIDDEN" NAME="job_stop" VALUE="{job_stop}">
+<!-- END BLOCK : hostview -->
+    <INPUT TYPE="submit" onClick="setPeriodTimestamps();" VALUE="Refresh graphs">
+<!-- END BLOCK : timeperiod -->
+     </TD>
+     <TD>
+      <B>{alt_view}</B>
+     </TD>
+
+  </TR>
+  </TABLE>
+
+<!-- START BLOCK : search -->
+     <TD align="right"><CENTER>
+       <A HREF="./?c={cluster_url}&view=search">
+       <B><I>Jobarchive</I></B><BR>
+       <IMG SRC="./document_archive.jpg" HEIGHT=100 ALT="Search the archive for {cluster}" TITLE="Search the archive for {cluster}" BORDER=0></A></CENTER>
+     </TD>
+<!-- END BLOCK : search -->
+
+  </TD>
+</TR>
+</TABLE> 
+
+<FONT SIZE="+1">
+{node_menu}
+</FONT>
+
+<HR SIZE="1" NOSHADE>
Index: trunk/web/addons/job_monarch/templates/host_view.tpl
===================================================================
--- trunk/web/addons/job_monarch/templates/host_view.tpl	(revision 203)
+++ trunk/web/addons/job_monarch/templates/host_view.tpl	(revision 203)
@@ -0,0 +1,91 @@
+<TABLE BORDER="0" WIDTH="100%">
+<TR>
+  <TD COLSPAN="2" BGCOLOR="#EEEEEE" ALIGN="CENTER">
+  <FONT SIZE="+2">{host} Overview</FONT>
+  </TD>
+</TR>
+
+<TR>
+ <TD ALIGN="LEFT" VALIGN="TOP">
+
+<IMG SRC="{node_image}" HEIGHT="60" WIDTH="30" ALT="{host}" BORDER="0">
+{node_msg}
+<P>
+
+<TABLE BORDER="0" WIDTH="100%">
+<TR>
+  <TD COLSPAN="2" CLASS=title>Time and String Metrics</TD>
+</TR>
+
+<!-- START BLOCK : string_metric_info -->
+<TR>
+ <TD CLASS=footer WIDTH=30%>{name}</TD><TD>{value}</TD>
+</TR>
+<!-- END BLOCK : string_metric_info -->
+
+<TR><TD>&nbsp;</TD></TR>
+
+<TR>
+  <TD COLSPAN=2 CLASS=title>Constant Metrics</TD>
+</TR>
+
+<!-- START BLOCK : const_metric_info -->
+<TR>
+ <TD CLASS=footer WIDTH=30%>{name}</TD><TD>{value}</TD>
+</TR>
+<!-- END BLOCK : const_metric_info -->
+
+<TR><TD>&nbsp;</TD></TR>
+
+<TR>
+ <TD COLSPAN=2 CLASS=title>
+ <a href="../../host_gmetrics.php?c={cluster_url}&h={host}">Gmetrics</a>
+ </TD>
+</TR>
+</TABLE>
+
+ <HR>
+<!-- INCLUDE BLOCK : extra -->
+
+</TD>
+
+<TD ALIGN="CENTER" VALIGN="TOP" WIDTH="395">
+<IMG HEIGHT="147" WIDTH="395" ALT="{cluster_url} LOAD"
+   SRC="./graph.php?g=load_report&z=medium&c={cluster_url}&{graphargs}">
+<IMG HEIGHT="160" WIDTH="395" ALT="{cluster_url} MEM"
+   SRC="./graph.php?g=mem_report&z=medium&c={cluster_url}&{graphargs}">
+<IMG HEIGHT="147" WIDTH="395" ALT="{cluster_url} CPU"
+   SRC="./graph.php?g=cpu_report&z=medium&c={cluster_url}&{graphargs}">
+<IMG HEIGHT="147" WIDTH="395" ALT="{cluster_url} NETWORK"
+   SRC="./graph.php?g=network_report&z=medium&c={cluster_url}&{graphargs}">
+<IMG HEIGHT="147" WIDTH="395" ALT="{cluster_url} PACKETS"
+   SRC="./graph.php?g=packet_report&z=medium&c={cluster_url}&{graphargs}">
+
+</TD>
+</TR>
+</TABLE>
+<BR>
+<BR>
+<TABLE BORDER="0" WIDTH="100%">
+<TR>
+  <TD CLASS=title>
+  {host} <strong>graphs</strong>
+  last <strong>{range}</strong>
+  sorted <strong>{sort}</strong>
+  </TD>
+</TR>
+</TABLE>
+
+<CENTER>
+<TABLE>
+<TR>
+ <TD>
+
+<!-- START BLOCK : vol_metric_info -->
+<IMG HEIGHT="147" WIDTH="395" ALT="{alt}" SRC="./graph.php?{graphargs}">{br}
+<!-- END BLOCK : vol_metric_info -->
+
+ </TD>
+</TR>
+</TABLE>
+</CENTER>
Index: trunk/web/addons/job_monarch/templates/index.tpl
===================================================================
--- trunk/web/addons/job_monarch/templates/index.tpl	(revision 203)
+++ trunk/web/addons/job_monarch/templates/index.tpl	(revision 203)
@@ -0,0 +1,9 @@
+<!-- TOGA SOB: <header> -->
+<!-- INCLUDE BLOCK : header -->
+<!-- TOGA EOB: </header> -->
+<!-- TOGA SOB: <main> -->
+<!-- INCLUDE BLOCK : main -->
+<!-- TOGA EOB: </main> -->
+<!-- TOGA SOB: <footer> -->
+<!-- INCLUDE BLOCK : footer -->
+<!-- TOGA EOB: </footer> -->
Index: trunk/web/addons/job_monarch/templates/overview.tpl
===================================================================
--- trunk/web/addons/job_monarch/templates/overview.tpl	(revision 203)
+++ trunk/web/addons/job_monarch/templates/overview.tpl	(revision 203)
@@ -0,0 +1,107 @@
+<BR><BR>
+
+<CENTER>
+<TABLE>
+<TR>
+  <TD ALIGN="CENTER">
+    <IMG SRC="{clusterimage}"><BR>
+
+<TABLE ALIGN=CENTER>
+<TR>
+<TD><FONT SIZE="-1" class=footer>Last updated:</FONT></TD><TD><FONT SIZE="-1" class=footer>{report_time}</TD>
+</TR><TR>
+<TD><FONT SIZE="-1" class=footer>Available:</FONT></TD><TD><FONT SIZE="-1" class=footer>{avail_nodes} nodes / {avail_cpus} cpu's</FONT></TD>
+</TR><TR>
+<TD><FONT SIZE="-1" class=footer>Usage:</FONT></TD><TD><FONT SIZE="-1" class=footer>{used_jobs} jobs - {used_nodes} nodes / {used_cpus} cpu's</FONT></TD>
+</TR><TR>
+<TD><FONT SIZE="-1" class=footer>View:</FONT></TD><TD><FONT SIZE="-1" class=footer>{view_jobs} jobs - {view_nodes} nodes / {view_cpus} cpu's</FONT></TD>
+</TR>
+</TABLE>
+</FONT>
+
+  </TD>
+  <TD ALIGN="CENTER">
+    <IMG SRC="{pie}">
+  </TD>
+</TR>
+</TABLE>
+
+<BR>
+
+<SCRIPT TYPE="text/javascript" SRC="libtoga.js"></SCRIPT>
+
+<INPUT TYPE="HIDDEN" NAME="sortby" VALUE="{sortby}">
+<INPUT TYPE="HIDDEN" NAME="sortorder" VALUE="{sortorder}">
+<INPUT TYPE="HIDDEN" NAME="c" VALUE="{clustername}">
+<INPUT TYPE="HIDDEN" NAME="queue" VALUE="{f_queue}">
+<INPUT TYPE="HIDDEN" NAME="state" VALUE="{f_state}">
+<INPUT TYPE="HIDDEN" NAME="user" VALUE="{f_user}">
+<INPUT TYPE="HIDDEN" NAME="id" VALUE="{f_id}">
+<INPUT TYPE="HIDDEN" NAME="filterorder" VALUE="{f_order}">
+
+<TABLE WIDTH="90%" CELLPADDING="8" CELLSPACING="3" BORDER=0>
+<TR CLASS="toga">
+<TH><B><A HREF="#" onClick="setSort( 'id' )">Id</A></B></TH>
+<TH><B><A HREF="#" onClick="setSort( 'state' )">State</A></B></TH>
+<TH><B><A HREF="#" onClick="setSort( 'user' )">User</A></B></TH>
+<TH><B><A HREF="#" onClick="setSort( 'queue' )">Queue</A></B></TH>
+<TH><B><A HREF="#" onClick="setSort( 'name' )">Name</A></B></TH>
+<TH><B><A HREF="#" onClick="setSort( 'req_cpu' )">Req. CPU time</A></B></TH>
+<TH><B><A HREF="#" onClick="setSort( 'req_mem' )">Req. Memory</A></B></TH>
+<TH><B><A HREF="#" onClick="setSort( 'nodes' )">Nodes</A>/<A HREF="#" onClick="setSort( 'cpus' )">Cpus</A></B></TH>
+<TH><B><A HREF="#" onClick="setSort( 'start' )">Started</A></B></TH>
+<TH><B><A HREF="#" onClick="setSort( 'runningtime' )">Runningtime</A></B></TH>
+</TR>
+
+<!-- START BLOCK : node -->
+  <TR CLASS="{nodeclass}">
+    <TD><A HREF="#" onClick="setFilter( 'id', '{id}' )">{id}</A></TD>
+    <TD><A HREF="#" onClick="setFilter( 'state', '{state}' )">{state}</A></TD>
+    <TD><A HREF="#" onClick="setFilter( 'user', '{user}' )">{user}</A></TD>
+    <TD><A HREF="#" onClick="setFilter( 'queue', '{queue}' )">{queue}</A></TD>
+    <TD>{name}</TD>
+    <TD>{req_cpu}</TD>
+    <TD>{req_memory}</TD>
+    <TD>{nodes}/{cpus}</TD>
+    <TD>{started}</TD>
+    <TD>{runningtime}</TD>
+  </TR>
+<!-- END BLOCK : node -->
+</TABLE>
+</CENTER>
+
+<!-- START BLOCK : showhosts -->
+<TABLE BORDER="0" WIDTH="100%">
+<TR>
+  <TD CLASS=title COLSPAN="2">
+  <FONT SIZE="-1">
+  Show Hosts:
+  yes<INPUT type=radio name="sh" value="1" OnClick="toga_form.submit();" {checked1}>
+  no<INPUT type=radio name="sh" value="0" OnClick="toga_form.submit();" {checked0}>
+  </FONT>
+  |
+  job <strong>{id}</strong> metric <strong>{metric}</strong>
+  |
+   <FONT SIZE="-1">
+   Columns&nbsp;&nbsp;{cols_menu}
+   </FONT>
+  </TD>
+</TR>
+   
+</TABLE>
+
+<CENTER>
+<TABLE>
+<TR>
+<!-- START BLOCK : sorted_list -->
+{metric_image}{br}
+<!-- END BLOCK : sorted_list -->
+</TR>
+</TABLE>
+
+<p>
+(Nodes colored by 1-minute load) | <A HREF="../../node_legend.html" ALT="Node Image egend">Legend</A>
+
+</CENTER>
+
+<!-- END BLOCK : showhosts -->
Index: trunk/web/addons/job_monarch/templates/search.tpl
===================================================================
--- trunk/web/addons/job_monarch/templates/search.tpl	(revision 203)
+++ trunk/web/addons/job_monarch/templates/search.tpl	(revision 203)
@@ -0,0 +1,271 @@
+<CENTER>
+
+<SCRIPT LANGUAGE="javascript">
+function setSort( sortbyval ) {
+
+        if( sortbyval != document.archive_search_form.sortby.value ) {
+
+                document.archive_search_form.sortby.value = sortbyval;
+                document.archive_search_form.sortorder.value = "asc";
+
+        } else {
+
+                if( document.archive_search_form.sortorder.value == "desc" )
+                        document.archive_search_form.sortorder.value = "asc";
+                else if( document.archive_search_form.sortorder.value == "asc" )
+                        document.archive_search_form.sortorder.value = "desc";
+        }
+
+        document.forms['archive_search_form'].submit();
+}
+
+function setFilter( filtername, filterval ) {
+
+        var myfilterorder = document.archive_search_form.elements['filterorder'].value;
+
+        if( document.archive_search_form.elements[filtername] ) {
+                document.archive_search_form.elements[filtername].value = filterval;
+                if( myfilterorder != '')
+                        myfilterorder = myfilterorder + "," + filtername;
+                else
+                        myfilterorder = filtername;
+
+        }
+        document.archive_search_form.elements['filterorder'].value = myfilterorder;
+
+        //setTimeout( "document.forms['archive_search_form'].submit();", 1000 );
+
+        document.forms['archive_search_form'].submit();
+}
+</SCRIPT>
+<SCRIPT LANGUAGE="javascript">
+
+	function setSearchTimestamps() {
+
+		document.archive_search_form.start_from_time.value = document.archive_search_form.start_from_pick.value; 
+		document.archive_search_form.start_to_time.value = document.archive_search_form.start_to_pick.value;
+		document.archive_search_form.end_from_time.value = document.archive_search_form.end_from_pick.value; 
+		document.archive_search_form.end_to_time.value = document.archive_search_form.end_to_pick.value;
+	}
+
+</SCRIPT>
+
+<!-- <FORM NAME="archive_search_form" ACTION="./"> -->
+
+<!-- <INPUT TYPE="hidden" NAME="view" VALUE="search"> -->
+
+<BR><BR>
+
+<TABLE WIDTH="90%">
+
+<TR>
+  <TD CLASS=title COLSPAN="2">
+  <B>Search job archive</B>
+  </TD>
+</TR>
+
+</TABLE>
+
+<BR><BR>
+
+<TABLE WIDTH="90%">
+
+<TR>
+  <TD></TD>
+  <TD></TD>
+  <TD></TD>
+  <TD></TD>
+  <TD></TD>
+  <TD></TD>
+</TR>
+
+<TR>
+
+  <TD>
+  Id:
+  </TD>
+  <TD>
+  <INPUT TYPE="TEXT" NAME="id" VALUE="{id_value}">
+  </TD>
+
+</TR>
+
+<TR>
+
+  <TD>
+  User:
+  </TD>
+  <TD>
+  <INPUT TYPE="TEXT" NAME="user" VALUE="{user_value}">
+  </TD>
+
+  <TD>
+  Queue:
+  </TD>
+  <TD>
+  <INPUT TYPE="TEXT" NAME="queue" VALUE="{queue_value}">
+  </TD>
+
+  <TD>
+  Name:
+  </TD>
+  <TD>
+  <INPUT TYPE="TEXT" NAME="name" VALUE="{name_value}">
+  </TD>
+
+</TR>
+
+<TR>
+
+  <TD></TD>
+  <TD>
+  Job <B>start</B>
+  </TD>
+
+  <TD>
+  From:
+  </TD>
+  <TD>
+  <INPUT TYPE="HIDDEN" NAME="start_from_time" VALUE="{start_from_value}">
+  <INPUT TYPE="TEXT" NAME="start_from_pick" VALUE="{start_from_value}" DISABLED="TRUE"> 
+  <A HREF="javascript:show_calendar('document.archive_search_form.start_from_pick', document.archive_search_form.start_from_pick.value );">
+  <IMG SRC="cal.gif" width="16" height="16" border="0" title="Click to select a date/time" alt="Click to select a date/time"></a> 
+  <a href="#" onClick="document.archive_search_form.start_from_pick.value=''" alt="Click here to clear field" title="Click here to clear field"><IMG SRC="redcross.jpg" BORDER=0></A>
+  </TD>
+  
+  <TD>
+  To:
+  </TD>
+  <TD>
+  <INPUT TYPE="HIDDEN" NAME="start_to_time" VALUE="{start_to_value}">
+  <INPUT TYPE="TEXT" NAME="start_to_pick" VALUE="{start_to_value}" DISABLED="TRUE">
+  <a href="javascript:show_calendar('document.archive_search_form.start_to_pick', document.archive_search_form.start_to_pick.value );"> 
+  <img src="cal.gif" width="16" height="16" border="0" title="Click to select a date/time" alt="Click to select a date/time"></a> 
+  <a href="#" onClick="document.archive_search_form.start_to_pick.value=''" alt="Click here to clear field" title="Click here to clear field">
+  <IMG SRC="redcross.jpg" BORDER=0></A>
+  </TD>
+  
+</TR>
+
+<TR>
+
+  <TD></TD>
+  <TD>
+  Job <B>finish</B>
+  </TD>
+
+  <TD>
+  From:
+  </TD>
+  <TD>
+  <INPUT TYPE="HIDDEN" NAME="end_from_time" VALUE="{end_from_value}">
+  <INPUT TYPE="TEXT" NAME="end_from_pick" VALUE="{end_from_value}" DISABLED="TRUE"> 
+  <A HREF="javascript:show_calendar('document.archive_search_form.end_from_pick', document.archive_search_form.end_from_pick.value );">
+  <IMG SRC="cal.gif" width="16" height="16" border="0" title="Click to select a date/time" alt="Click to select a date/time"></a> 
+  <a href="#" onClick="document.archive_search_form.end_from_pick.value=''" alt="Click here to clear field" title="Click here to clear field">
+  <IMG SRC="redcross.jpg" BORDER=0></A>
+  </TD>
+  
+  <TD>
+  To:
+  </TD>
+  <TD>
+  <INPUT TYPE="HIDDEN" NAME="end_to_time" VALUE="{end_to_value}">
+  <INPUT TYPE="TEXT" NAME="end_to_pick" VALUE="{end_to_value}" DISABLED="TRUE">
+  <a href="javascript:show_calendar('document.archive_search_form.end_to_pick', document.archive_search_form.end_to_pick.value );"> 
+  <img src="cal.gif" width="16" height="16" border="0" title="Click to select a date/time" alt="Click to select a date/time"></a> 
+  <a href="#" onClick="document.archive_search_form.end_to_pick.value=''" alt="Click here to clear field" title="Click here to clear field">
+  <IMG SRC="redcross.jpg" BORDER=0></A>
+  </TD>
+  
+</TR>
+
+<TR>
+
+  <TD></TD>
+  <TD></TD>
+  <TD></TD>
+  <TD></TD>
+  <TD></TD>
+  <TD>
+  <INPUT TYPE="submit" VALUE="Search archive" onClick="setSearchTimestamps();">
+  </TD>
+
+</TR>
+
+</TABLE>
+{form_error_msg}<BR><BR>
+<!-- START BLOCK : search_results -->
+
+<INPUT TYPE="HIDDEN" NAME="sortby" VALUE="{sortby}">
+<INPUT TYPE="HIDDEN" NAME="sortorder" VALUE="{sortorder}">
+<INPUT TYPE="HIDDEN" NAME="filterorder" VALUE="{f_order}">
+
+<TABLE WIDTH="90%" CELLPADDING="8" CELLSPACING="3" BORDER=0>
+<TR CLASS="toga">
+<TH><B><A HREF="#" onClick="setSort( 'id' )">Id</A></B></TH>
+<TH><B><A HREF="#" onClick="setSort( 'state' )">State</A></B></TH>
+<TH><B><A HREF="#" onClick="setSort( 'user' )">User</A></B></TH>
+<TH><B><A HREF="#" onClick="setSort( 'queue' )">Queue</A></B></TH>
+<TH><B><A HREF="#" onClick="setSort( 'name' )">Name</A></B></TH>
+<TH><B><A HREF="#" onClick="setSort( 'req_cpu' )">Req. CPU time</A></B></TH>
+<TH><B><A HREF="#" onClick="setSort( 'req_mem' )">Req. Memory</A></B></TH>
+<TH><B><A HREF="#" onClick="setSort( 'nodes' )">Nodes</A>/<A HREF="#" onClick="setSort( 'cpus' )">Cpus</A></
+B></TH>
+<TH><B><A HREF="#" onClick="setSort( 'start' )">Started</A></B></TH>
+<TH><B><A HREF="#" onClick="setSort( 'finished' )">Finished</A></B></TH>
+<TH><B><A HREF="#" onClick="setSort( 'runningtime' )">Runningtime</A></B></TH>
+</TR>
+
+<!-- START BLOCK : node -->
+  <TR CLASS="{nodeclass}">
+    <TD><A HREF="#" onClick="setFilter( 'id', '{id}' )">{id}</A></TD>
+    <TD><A HREF="#" onClick="setFilter( 'state', '{state}' )">{state}</A></TD>
+    <TD><A HREF="#" onClick="setFilter( 'user', '{user}' )">{user}</A></TD>
+    <TD><A HREF="#" onClick="setFilter( 'queue', '{queue}' )">{queue}</A></TD>
+    <TD>{name}</TD>
+    <TD>{req_cpu}</TD>
+    <TD>{req_memory}</TD>
+    <TD>{nodes}/{cpus}</TD>
+    <TD>{started}</TD>
+    <TD>{finished}</TD>
+    <TD>{runningtime}</TD>
+  </TR>
+<!-- END BLOCK : node -->
+</TABLE>
+</CENTER>
+
+<!-- START BLOCK : showhosts -->
+<TABLE BORDER="0" WIDTH="100%">
+<TR>
+  <TD CLASS=title COLSPAN="2">
+  <FONT SIZE="-1">
+  Show Hosts:
+  yes<INPUT type=radio name="sh" value="1" OnClick="archive_search_form.submit();" {checked1}>
+  no<INPUT type=radio name="sh" value="0" OnClick="archive_search_form.submit();" {checked0}>
+  </FONT>
+  |
+  job <strong>{id}</strong> metric <strong>{metric}</strong>
+  |
+   <FONT SIZE="-1">
+   Columns&nbsp;&nbsp;{cols_menu}
+   </FONT><BR>
+  </TD>
+</TR>
+
+</TABLE>
+
+<CENTER>
+<TABLE>
+<TR>
+<!-- START BLOCK : sorted_list -->
+{metric_image}{br}
+<!-- END BLOCK : sorted_list -->
+</TR>
+</TABLE>
+
+</CENTER>
+
+<!-- END BLOCK : showhosts -->
+<!-- END BLOCK : search_results -->
+</CENTER>
Index: trunk/web/addons/job_monarch/ts_picker.js
===================================================================
--- trunk/web/addons/job_monarch/ts_picker.js	(revision 203)
+++ trunk/web/addons/job_monarch/ts_picker.js	(revision 203)
@@ -0,0 +1,149 @@
+// Title: Timestamp picker
+// Description: See the demo at url
+// URL: http://us.geocities.com/tspicker/
+// Script featured on: http://javascriptkit.com/script/script2/timestamp.shtml
+// Version: 1.0
+// Date: 12-05-2001 (mm-dd-yyyy)
+// Author: Denis Gritcyuk <denis@softcomplex.com>; <tspicker@yahoo.com>
+// Notes: Permission given to use this script in any kind of applications if
+//    header lines are left unchanged. Feel free to contact the author
+//    for feature requests and/or donations
+//
+// Additional changes for Toga by Ramon Bastiaans:
+// - Time validation
+// - Setup of str_target on load of calendar (if it's empty)
+// - Commit new time when changed (not just when date is clicked)
+
+function show_calendar(str_target, str_datetime) {
+	var arr_months = ["January", "February", "March", "April", "May", "June",
+		"July", "August", "September", "October", "November", "December"];
+	var week_days = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
+	var n_weekstart = 1; // day week starts from (normally 0 or 1)
+
+	var dt_datetime = (str_datetime == null || str_datetime =="" ?  new Date() : str2dt(str_datetime));
+	var dt_prev_month = new Date(dt_datetime);
+	dt_prev_month.setMonth(dt_datetime.getMonth()-1);
+	var dt_next_month = new Date(dt_datetime);
+	dt_next_month.setMonth(dt_datetime.getMonth()+1);
+	var dt_firstday = new Date(dt_datetime);
+	dt_firstday.setDate(1);
+	dt_firstday.setDate(1-(7+dt_firstday.getDay()-n_weekstart)%7);
+	var dt_lastday = new Date(dt_next_month);
+	dt_lastday.setDate(0);
+	
+	// html generation (feel free to tune it for your particular application)
+	// print calendar header
+	var str_buffer = new String (
+		"<html>\n"+
+		"<head>\n"+
+		"	<title>Calendar</title>\n"+
+		"</head>\n"+
+		"<SCRIPT LANGUAGE=\"javascript\" SRC=\"ts_validatetime.js\"></SCRIPT>\n"+
+		"<body bgcolor=\"White\" onLoad=\"validateTime( '"+str_target+ "', '"+str_datetime+"' ); if( window.opener."+str_target+ ".value == '' ) window.opener."+str_target+ ".value='"+dt2dtstr( dt_datetime )+" '+document.cal.time.value;\" onUnload=\"validateTime( '"+str_target+ "', '"+str_datetime+"' ); if( window.opener."+str_target+ ".value == '' ) window.opener."+str_target+ ".value='"+dt2dtstr( dt_datetime )+"'+document.cal.time.value;\">\n"+
+		"<table class=\"clsOTable\" cellspacing=\"0\" border=\"0\" width=\"100%\">\n"+
+		"<tr><td bgcolor=\"#4682B4\">\n"+
+		"<table cellspacing=\"1\" cellpadding=\"3\" border=\"0\" width=\"100%\">\n"+
+		"<tr>\n	<td bgcolor=\"#4682B4\"><a href=\"javascript:window.opener.show_calendar('"+
+		str_target+"', '"+ dt2dtstr(dt_prev_month)+"'+document.cal.time.value);\">"+
+		"<img src=\"prev.gif\" width=\"16\" height=\"16\" border=\"0\""+
+		" alt=\"previous month\"></a></td>\n"+
+		"	<td bgcolor=\"#4682B4\" colspan=\"5\">"+
+		"<font color=\"white\" face=\"tahoma, verdana\" size=\"2\">"
+		+arr_months[dt_datetime.getMonth()]+" "+dt_datetime.getFullYear()+"</font></td>\n"+
+		"	<td bgcolor=\"#4682B4\" align=\"right\"><a href=\"javascript:window.opener.show_calendar('"
+		+str_target+"', '"+dt2dtstr(dt_next_month)+"'+document.cal.time.value);\">"+
+		"<img src=\"next.gif\" width=\"16\" height=\"16\" border=\"0\""+
+		" alt=\"next month\"></a></td>\n</tr>\n"
+	);
+
+	var dt_current_day = new Date(dt_firstday);
+	// print weekdays titles
+	str_buffer += "<tr>\n";
+	for (var n=0; n<7; n++)
+		str_buffer += "	<td bgcolor=\"#87CEFA\">"+
+		"<font color=\"white\" face=\"tahoma, verdana\" size=\"2\">"+
+		week_days[(n_weekstart+n)%7]+"</font></td>\n";
+	// print calendar table
+	str_buffer += "</tr>\n";
+	while (dt_current_day.getMonth() == dt_datetime.getMonth() ||
+		dt_current_day.getMonth() == dt_firstday.getMonth()) {
+		// print row heder
+		str_buffer += "<tr>\n";
+		for (var n_current_wday=0; n_current_wday<7; n_current_wday++) {
+				if (dt_current_day.getDate() == dt_datetime.getDate() &&
+					dt_current_day.getMonth() == dt_datetime.getMonth())
+					// print current date
+					str_buffer += "	<td bgcolor=\"#FFB6C1\" align=\"right\">";
+				else if (dt_current_day.getDay() == 0 || dt_current_day.getDay() == 6)
+					// weekend days
+					str_buffer += "	<td bgcolor=\"#DBEAF5\" align=\"right\">";
+				else
+					// print working days of current month
+					str_buffer += "	<td bgcolor=\"white\" align=\"right\">";
+
+				if (dt_current_day.getMonth() == dt_datetime.getMonth())
+					// print days of current month
+					str_buffer += "<a href=\"javascript:window.opener."+str_target+
+					".value='"+dt2dtstr(dt_current_day)+"'+document.cal.time.value; window.close();\">"+
+					"<font color=\"black\" face=\"tahoma, verdana\" size=\"2\">";
+				else 
+					// print days of other months
+					str_buffer += "<a href=\"javascript:window.opener."+str_target+
+					".value='"+dt2dtstr(dt_current_day)+"'+document.cal.time.value; window.close();\">"+
+					"<font color=\"gray\" face=\"tahoma, verdana\" size=\"2\">";
+				str_buffer += dt_current_day.getDate()+"</font></a></td>\n";
+				dt_current_day.setDate(dt_current_day.getDate()+1);
+		}
+		// print row footer
+		str_buffer += "</tr>\n";
+	}
+	// print calendar footer
+	str_buffer +=
+		"<form name=\"cal\" onsubmit=\"var mf = window.opener."+str_target+".value.split( ' ' );window.opener."+str_target+".value=mf[0]+' '+document.cal.time.value; window.close();\">\n<tr><td colspan=\"7\" bgcolor=\"#87CEFA\">"+
+		"<font color=\"White\" face=\"tahoma, verdana\" size=\"2\">"+
+		"Time: <input type=\"text\" name=\"time\" value=\""+dt2tmstr(dt_datetime)+
+		"\" size=\"8\" maxlength=\"8\" onChange=\"validateTime('"+str_target+"', '"+str_datetime+"');\"></font></td></tr>\n</form>\n" +
+		"</table>\n" +
+		"</tr>\n</td>\n</table>\n" +
+		"</body>\n" +
+		"</html>\n";
+
+	var vWinCal = window.open("", "Calendar", 
+		"width=200,height=250,status=no,resizable=yes,top=200,left=200");
+	vWinCal.opener = self;
+	var calc_doc = vWinCal.document;
+	calc_doc.write (str_buffer);
+	calc_doc.close();
+}
+// datetime parsing and formatting routimes. modify them if you wish other datetime format
+function str2dt (str_datetime) {
+	var re_date = /^(\d+)\-(\d+)\-(\d+)\s+(\d+)\:(\d+)\:(\d+)$/;
+	if (!re_date.exec(str_datetime))
+		return alert("Invalid Datetime format: "+ str_datetime);
+	return (new Date (RegExp.$3, RegExp.$2-1, RegExp.$1, RegExp.$4, RegExp.$5, RegExp.$6));
+}
+function dt2dtstr (dt_datetime) {
+	return (new String (
+			dt_datetime.getDate()+"-"+(dt_datetime.getMonth()+1)+"-"+dt_datetime.getFullYear()+" "));
+}
+function dt2tmstr (dt_datetime) {
+
+	if( dt_datetime.getHours() < 10 )
+		var hours = '0' + dt_datetime.getHours();
+	else
+		var hours = dt_datetime.getHours();
+
+	if( dt_datetime.getMinutes() < 10 )
+		var minutes = '0' + dt_datetime.getMinutes();
+	else
+		var minutes = dt_datetime.getMinutes();
+
+	if( dt_datetime.getSeconds() < 10 )
+		var seconds = '0' + dt_datetime.getSeconds();
+	else
+		var seconds = dt_datetime.getSeconds();
+		
+	return (new String (
+			hours+":"+minutes+":"+seconds));
+}
+
Index: trunk/web/addons/job_monarch/ts_validatetime.js
===================================================================
--- trunk/web/addons/job_monarch/ts_validatetime.js	(revision 203)
+++ trunk/web/addons/job_monarch/ts_validatetime.js	(revision 203)
@@ -0,0 +1,116 @@
+function validateTime( str_target, str_datetime ) {
+
+        var time = document.cal.time.value.split( ':' );
+        var invalid = 0;
+	var dt_datetime = (str_datetime == null || str_datetime =="" ?  new Date() : str2dt(str_datetime));
+
+        if( time.length <= 1 && invalid == 0 ) {
+
+                document.cal.time.value = dt2tmstr( dt_datetime );
+                alert( 'Invalid time specified (needs to be HH:MM:SS), reset to current time.' );
+                invalid = 1;
+
+        } else if( time.length == 2 ) {
+
+                if( time[1] != '' ) {
+
+                        document.cal.time.value = document.cal.time.value + ':00';
+
+                } else if( invalid == 0 ) {
+
+                        document.cal.time.value = dt2tmstr( dt_datetime );
+                        alert( 'Invalid time specified (needs to be HH:MM:SS), reset to current time.' );
+                        invalid = 1;
+                }
+
+        } else if( time.length == 3 ) {
+
+                newtime = '';
+
+                for( var i=0; i<time.length; i++) {
+
+                        time_field = time[i];
+			if( i == 0 )
+				var sep = '';
+			else
+				var sep = ':';
+				
+
+                        if( time_field.length == 0 && invalid == 0 ) {
+
+                                document.cal.time.value = dt2tmstr( dt_datetime );
+                                alert( 'Invalid time specified (needs to be HH:MM:SS), reset to current time.' );
+                                invalid = 1;
+
+                        } else if( time_field.length == 1 ) {
+
+                                newtime = newtime + sep + '0' + time_field;
+                        } else {
+                                newtime = newtime + sep + time_field;
+                        }
+
+                        for( var l=0; l<time_field.length; l++ ) {
+                                var mydigit = time_field.charAt(l)
+
+                                if(( mydigit < "0" || mydigit > "9" ) && invalid == 0 ) {
+
+                                        document.cal.time.value = dt2tmstr( dt_datetime );
+                                        alert( 'Invalid time specified (needs to be HH:MM:SS), reset to current time.' );
+                                        invalid = 1;
+
+                                }
+                        }
+                }
+
+                if( invalid == 0 ) {
+
+                        document.cal.time.value = newtime;
+                }
+
+        }
+
+        if( invalid == 0 ) {
+
+		target = str_target.split('.');
+		frm = target[1];
+		elm = target[2];
+                var mf = window.opener.document.forms[frm].elements[elm].value.split( ' ' );
+
+		if( mf[0] != '' )
+			window.opener.document.forms[frm].elements[elm].value=mf[0]+' '+document.cal.time.value;
+		else
+			window.opener.document.forms[frm].elements[elm].value=dt2dtstr( new Date() ) +document.cal.time.value;
+        }
+}
+
+// datetime parsing and formatting routimes. modify them if you wish other datetime format
+function str2dt (str_datetime) {
+        var re_date = /^(\d+)\-(\d+)\-(\d+)\s+(\d+)\:(\d+)\:(\d+)$/;
+        if (!re_date.exec(str_datetime))
+                return alert("Invalid Datetime format: "+ str_datetime);
+        return (new Date (RegExp.$3, RegExp.$2-1, RegExp.$1, RegExp.$4, RegExp.$5, RegExp.$6));
+}
+function dt2dtstr (dt_datetime) {
+        return (new String (
+                        dt_datetime.getDate()+"-"+(dt_datetime.getMonth()+1)+"-"+dt_datetime.getFullYear()+" "));
+}
+function dt2tmstr (dt_datetime) {
+
+        if( dt_datetime.getHours() < 10 )
+                var hours = '0' + dt_datetime.getHours();
+        else
+                var hours = dt_datetime.getHours();
+
+        if( dt_datetime.getMinutes() < 10 )
+                var minutes = '0' + dt_datetime.getMinutes();
+        else
+                var minutes = dt_datetime.getMinutes();
+
+        if( dt_datetime.getSeconds() < 10 )
+                var seconds = '0' + dt_datetime.getSeconds();
+        else
+                var seconds = dt_datetime.getSeconds();
+
+        return (new String (
+                        hours+":"+minutes+":"+seconds));
+}
Index: trunk/web/addons/job_monarch/version.php
===================================================================
--- trunk/web/addons/job_monarch/version.php	(revision 203)
+++ trunk/web/addons/job_monarch/version.php	(revision 203)
@@ -0,0 +1,3 @@
+<?php
+$monarchversion = "0.1";
+?>
Index: trunk/web/templates/job_monarch/cluster_extra.tpl
===================================================================
--- trunk/web/templates/job_monarch/cluster_extra.tpl	(revision 202)
+++ trunk/web/templates/job_monarch/cluster_extra.tpl	(revision 203)
@@ -3,11 +3,11 @@
 <tr>
  <td valign=center>
-  <a href="./addons/toga/?c={cluster}"><b>Joblist</b></a>
+  <a href="./addons/job_monarch/?c={cluster}"><b>Joblist</b></a>
  </td>
 </tr>
 <tr>
  <td>
-  <a href="./addons/toga/?c={cluster}">
-  <IMG SRC="./addons/toga/image.php?c={cluster}&view=small-clusterimage" BORDER=0>
+  <a href="./addons/job_monarch/?c={cluster}">
+  <IMG SRC="./addons/job_monarch/image.php?c={cluster}&view=small-clusterimage" BORDER=0>
   </a>
   </a>
