replace missing org.eclipse.test.performance.ui
diff --git a/bundles/org.eclipse.test.performance.ui/.classpath b/bundles/org.eclipse.test.performance.ui/.classpath
new file mode 100644
index 0000000..fad5b7e
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="output" path="src"/>
+</classpath>
diff --git a/bundles/org.eclipse.test.performance.ui/.project b/bundles/org.eclipse.test.performance.ui/.project
new file mode 100644
index 0000000..47525f5
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.eclipse.test.performance.ui</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/bundles/org.eclipse.test.performance.ui/META-INF/MANIFEST.MF b/bundles/org.eclipse.test.performance.ui/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..f7ee1b1
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/META-INF/MANIFEST.MF
@@ -0,0 +1,18 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %Bundle-Name
+Bundle-SymbolicName: org.eclipse.test.performance.ui; singleton:=true
+Bundle-Version: 1.0.100.qualifier
+Bundle-ClassPath: performanceui.jar
+Bundle-Activator: org.eclipse.test.performance.ui.UiPlugin
+Bundle-Vendor: %Bundle-Vendor
+Bundle-Localization: plugin
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.test.performance,
+ org.eclipse.swt,
+ org.apache.derby;resolution:=optional,
+ Cloudscape;resolution:=optional,
+ org.junit
+Eclipse-LazyStart: true
+Bundle-RequiredExecutionEnvironment: J2SE-1.4
+Export-Package: org.eclipse.test.performance.ui
diff --git a/bundles/org.eclipse.test.performance.ui/about.html b/bundles/org.eclipse.test.performance.ui/about.html
new file mode 100644
index 0000000..e336131
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/about.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
+<html>
+<head>
+<meta name="copyright" content="Copyright (c) IBM Corporation and others 2000, 2005. This page is made available under license. For full details see the LEGAL in the documentation book that contains this page." >
+<title>About</title>
+<meta http-equiv=Content-Type content="text/html; charset=ISO-8859-1">
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+ 
+<p>February 24, 2005</p>	
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;).  Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;).  A copy of the EPL is available at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content.  Check the Redistributor's license that was provided with the Content.  If no such license exists, contact the Redistributor.  Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content.</p>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/bundles/org.eclipse.test.performance.ui/build.properties b/bundles/org.eclipse.test.performance.ui/build.properties
new file mode 100644
index 0000000..2030d36
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/build.properties
@@ -0,0 +1,20 @@
+###############################################################################
+# Copyright (c) 2003, 2006 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#     IBM Corporation - initial API and implementation
+###############################################################################
+
+bin.includes = about.html,\
+               META-INF/,\
+               performanceui.jar,\
+               images/,\
+               plugin.xml,\
+               readme.html,\
+               scripts/
+source.performanceui.jar = src/
+jars.compile.order = performanceui.jar
diff --git a/bundles/org.eclipse.test.performance.ui/images/FAIL.gif b/bundles/org.eclipse.test.performance.ui/images/FAIL.gif
new file mode 100644
index 0000000..c65be5a
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/images/FAIL.gif
Binary files differ
diff --git a/bundles/org.eclipse.test.performance.ui/images/FAIL_caution.gif b/bundles/org.eclipse.test.performance.ui/images/FAIL_caution.gif
new file mode 100644
index 0000000..d2680d7
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/images/FAIL_caution.gif
Binary files differ
diff --git a/bundles/org.eclipse.test.performance.ui/images/FAIL_greyed.gif b/bundles/org.eclipse.test.performance.ui/images/FAIL_greyed.gif
new file mode 100644
index 0000000..1d80a8d
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/images/FAIL_greyed.gif
Binary files differ
diff --git a/bundles/org.eclipse.test.performance.ui/images/OK.gif b/bundles/org.eclipse.test.performance.ui/images/OK.gif
new file mode 100644
index 0000000..be6df8d
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/images/OK.gif
Binary files differ
diff --git a/bundles/org.eclipse.test.performance.ui/images/OK_caution.gif b/bundles/org.eclipse.test.performance.ui/images/OK_caution.gif
new file mode 100644
index 0000000..b5af61f
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/images/OK_caution.gif
Binary files differ
diff --git a/bundles/org.eclipse.test.performance.ui/images/Unknown.gif b/bundles/org.eclipse.test.performance.ui/images/Unknown.gif
new file mode 100644
index 0000000..1f69b55
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/images/Unknown.gif
Binary files differ
diff --git a/bundles/org.eclipse.test.performance.ui/images/descriptions.html b/bundles/org.eclipse.test.performance.ui/images/descriptions.html
new file mode 100644
index 0000000..dc9db05
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/images/descriptions.html
@@ -0,0 +1,18 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+	<head>
+		<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+		<title>Descriptions</title>
+	</head>
+
+<body bgcolor="#FFFFFF" text="#000000">
+<p><a name="fp"></a><font size="+2"><b>Fingerprint Example</b></font></p>
+<p><img src="fp.bmp"> </p>
+<p>&nbsp;</p><hr>
+<p><a name="sst"></a><font size="+2"><b>Scenario Status Table Example</b></font></p>
+<p><img src="sst.bmp"></p>
+<p>&nbsp;</p><hr>
+<p><a name="sr"></a><b><font size="+2">Scenario Results Example</font></b></p>
+<p><img src="sr.bmp"></p>
+</body>
+</html>
diff --git a/bundles/org.eclipse.test.performance.ui/images/fp.bmp b/bundles/org.eclipse.test.performance.ui/images/fp.bmp
new file mode 100644
index 0000000..1d7863e
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/images/fp.bmp
Binary files differ
diff --git a/bundles/org.eclipse.test.performance.ui/images/sr.bmp b/bundles/org.eclipse.test.performance.ui/images/sr.bmp
new file mode 100644
index 0000000..2c063f0
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/images/sr.bmp
Binary files differ
diff --git a/bundles/org.eclipse.test.performance.ui/images/sst.bmp b/bundles/org.eclipse.test.performance.ui/images/sst.bmp
new file mode 100644
index 0000000..8f36cf6
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/images/sst.bmp
Binary files differ
diff --git a/bundles/org.eclipse.test.performance.ui/performanceui.jar b/bundles/org.eclipse.test.performance.ui/performanceui.jar
new file mode 100644
index 0000000..7760695
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/performanceui.jar
Binary files differ
diff --git a/bundles/org.eclipse.test.performance.ui/plugin.properties b/bundles/org.eclipse.test.performance.ui/plugin.properties
new file mode 100644
index 0000000..0b19a7b
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/plugin.properties
@@ -0,0 +1,12 @@
+###############################################################################
+# Copyright (c) 2007 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#     IBM Corporation - initial API and implementation
+###############################################################################
+Bundle-Name= Ui Performance Test Framework Plug-in
+Bundle-Vendor= Eclipse.org
diff --git a/bundles/org.eclipse.test.performance.ui/plugin.xml b/bundles/org.eclipse.test.performance.ui/plugin.xml
new file mode 100644
index 0000000..d3e20a7
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/plugin.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.0"?>
+<plugin>
+
+<!-- Applications -->
+   <extension
+         id="resultGenerator"
+         point="org.eclipse.core.runtime.applications">
+      <application>
+         <run
+               class="org.eclipse.test.performance.ui.Main">
+         </run>
+      </application>
+   </extension>
+</plugin>
\ No newline at end of file
diff --git a/bundles/org.eclipse.test.performance.ui/readme.html b/bundles/org.eclipse.test.performance.ui/readme.html
new file mode 100644
index 0000000..e72c2ac
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/readme.html
@@ -0,0 +1,77 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+	<head>
+		<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+		<title>org.eclipse.test.performance.ui readme</title>
+	</head>
+
+<p><b><font size="+2">README</font></b><br> </p><p>last updated: October 26, 2005<br> 
+</p><p><b>Introduction</b><br> <br> This readme describes how to create performance 
+charts and tables similar to those available on the eclipse platform download 
+pages using the stand-alone java program <b>org.eclipse.test.performance.ui.Main</b> 
+stored in this project. Although the program is currently geared to generating 
+results for the Eclipse Platform builds, the program may work for you given the 
+following conditions:</p><ul> <li>The &quot;eclipse.perf.config&quot; system property 
+used to run tests used three keys config, build and jvm <ul> <li>for example, 
+"eclipse.perf.config=config=relengbuildwin2;build=I20050219-1500;jvm=sun1.4.2_06". 
+<br> <br> </li></ul></li><li>Values for the "build" key begin with either an 'I' 
+or 'N' with the exception of the reference builds (for example, 3.0). <ul> <li>The 
+line graphs plot the reference build, all builds starting with 'I' and the seven 
+'N' builds preceding the current build.</li><li>This can be overriden with the use of the &quot;-current.prefix&quot; parameter where you can specify a comma-separated list of prefixes for build ids to include in the main line graph.<br> <br> </li></ul></li><li>Scenario names 
+all contain a prefix &quot;&lt;component&gt;.test&quot; <ul> <li>For example, 
+it is assumed that the scenario &quot;org.eclipse.help.tests.performance.appserver.TestAppserver#testAppserverCycle()&quot; 
+belongs to the &quot;org.eclipse.help&quot; component. </li><li>Unique scenario 
+prefixes are derived from all the scenarios in the database and are used to group 
+results.</li></ul></li></ul><p><br> For purposes of this document, the term &quot;<a href="images/descriptions.html#fp">fingerprint</a>&quot; 
+will be used to refer to a bar graph which represents the performance summary 
+at a global or component level for each test configuration.<br> <br> The term 
+&quot;<a href="images/descriptions.html#sst">scenario status table</a>&quot; will 
+be used to refer to a table of scenarios with green checks and red x indicators 
+below a component fingerprint. This table gives an overall view of the status 
+for all scenarios for a component for all configurations.<br> </p><p>The term 
+&quot;<a href="images/descriptions.html#sr">scenario results</a>&quot; will be 
+used to refer to a web page comparing current performance measurements to the 
+baseline measurements for one scenario on one configuration. The web page displays 
+the raw data for the current and baseline measurements and also displays line 
+graphs showing the measured values over the course of builds between the current 
+and baseline.</p><p><br> <b>Requirements</b> </p><ul> <li>Windows or Linux (x86) 
+operating system</li><li>Cloudscape or Derby plug-in</li><li>org.eclipse.releng.basebuilder</li><li>1.4 
+level jvm installed and on path</li></ul><p><b>Setup</b><br> </p><ul> <li>Checkout 
+org.eclipse.releng.basebuilder from cvs repository dev.eclipse.org:/home/eclipse 
+(HEAD should be fine).</li><li>Create a Cloudscape or derby plug-in as described 
+<A HREF="http://dev.eclipse.org/viewcvs/index.cgi/*checkout*/org.eclipse.test.performance/doc/Performance%20Tests%20HowTo.html?rev=HEAD&content-type=text/html#cloudscape">here</A>.</li><li>Set 
+the environment variable &quot;dbloc&quot; to the location of the database containing 
+the performance data<br> For example:<br> <ul> <li> export dbloc=net://trelenggtk.ottawa.ibm.com 
+(Linux)</li><li>set dbloc==net://trelenggtk.ottawa.ibm.com (Windows)<br> </li></ul></li></ul><p><b>Running 
+the program</b></p><p>From a terminal or dos prompt,<br> </p><OL><LI>Set the environment 
+variable &quot;dbloc&quot; to the location of the database containing the performance 
+data<BR> For example:<UL><LI>export dbloc=net://trelenggtk.ottawa.ibm.com (Linux)</LI><LI>set 
+dbloc==net://trelenggtk.ottawa.ibm.com (Windows)<BR><BR></LI></UL></LI><LI>cd 
+to org.eclipse.releng.basebuilder\plugins\org.eclipse.test.performance.ui\scripts<BR></LI><LI>If 
+running on Linux, execute &quot;chmod 755 genresults&quot;</LI><LI>Execute the 
+following command:<b><br> <br> genresults -baseline &lt;baseline build id&gt; 
+-current &lt;current build id&gt; -config &lt;comma-separated list of configs&gt; 
+-jvm &lt;jvm name&gt; -output &lt;output dir&gt; [-config.properties &lt;properties&gt;] 
+[highlight &lt;buildid patterns&gt;] [scenario.pattern &lt;scenario prefix 
+patterns&gt;] [-fingerprints][-scenarioresults][-current.prefix &lt;comma-separated list of build id prefixes&gt;][-baseline.prefix &lt;comma-separated list of build id prefixes&gt;]</b></LI></OL><br> Parameter descriptions: 
+<blockquote> <p>-baseline &lt;baseline build id. A previous value used in the 
+&quot;build&quot; key in the eclipse.perf.config system property or the eclipse.perf.assertAgainst 
+property. &gt; <br> -current &lt;current build id. The value used in the &quot;build&quot; 
+key in the eclipse.perf.config system property.&gt;<br> -config &lt;a comma-separated 
+list of names of configurations for which to produce results. The values used 
+should be the same as values specified for the &quot;config&quot; key in the eclipse.perf.config 
+system property.&gt;<br> -jvm &lt;jvm description. The value used in the &quot;jvm&quot; 
+key in the eclipse.perf.config system property.&gt;<br> -output &lt;path to an 
+output directory for fingerprints and scenarios for each configuration specified 
+in -config parameter. Fingerprint gifs and html files are generated in the directory 
+specified, configuration specific subdirectories are created to store scenario 
+results and line graphs.&gt;</p></blockquote><p><br> Optional arguments:</p><blockquote> 
+<p>-config.properties &lt;semi-colon separated list of: config, alternate config 
+description.  The value should be quoted if there are spaces in the value.&gt;<BR>of builds which match any prefix in this list.  When omitted, a magenta line is draw on the graph which represents the baseline value specified in the -baseline parameter.&gt;<br> -highlight &lt;Comma-separated 
+list of build Id prefixes(excluding 'I' and 'N'), which are used to add and highlight 
+the most recent matching buildId on line graphs.&quot;&gt;<br> -scenario.pattern 
+&lt;Scenario prefix pattern used to query performance results database. Can be 
+used to generate results for a single component or subset of scenarios.&gt;<br> 
+-fingerprints or -scenarioresults &lt;use one or the other to generate fingerprints 
+or scenario results only. Not specifying either will execute both.&gt;<BR>-baseline.prefix &lt;semi-colon separated list of: build id prefixes used in eclipse.perf.assertAgainst property or eclipse.perf.config system property.  Values used to generate a second line graph representing changes in repeated baseline test runs&gt;.<BR>-current.prefix &lt;semi-colon separated list of: build id prefixes used in eclipse.perf.config system property.  Values here used to override default of &quot;N,I&quot;.  Used to select build id's to include in main line graph.&gt;</p></blockquote>
+</html>
\ No newline at end of file
diff --git a/bundles/org.eclipse.test.performance.ui/scripts/ToolTip.css b/bundles/org.eclipse.test.performance.ui/scripts/ToolTip.css
new file mode 100644
index 0000000..d9114d2
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/scripts/ToolTip.css
@@ -0,0 +1,34 @@
+
+.hidden_tooltip {
+	display:none;
+}
+
+span.visible_tooltip {
+	display:block;
+	position:absolute;
+	top:10px;
+	left:21px;
+	width:300px;
+	font-size:9px;;
+	padding-left:5px;
+	padding-right:5px;
+	border:1px solid black;
+	background-color:#FFFFCC;
+	text-decoration:none;
+	color:#000000;
+	z-index:10;
+} 
+
+a{  
+	text-decoration:none;
+}
+span {
+z-index=100;
+}
+img, table{
+z-index:1;
+}
+
+.tooltipSource {
+	position:relative;
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.test.performance.ui/scripts/ToolTip.js b/bundles/org.eclipse.test.performance.ui/scripts/ToolTip.js
new file mode 100644
index 0000000..98008cc
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/scripts/ToolTip.js
@@ -0,0 +1,23 @@
+// General purpose functions. 
+
+function hide_element(elementId) {
+	element = document.getElementById(elementId);
+	if(element != null) {
+		currentClass = element.className;
+		if(currentClass =='visible_tooltip') {
+			element.className = 'hidden_tooltip';
+		}
+	}
+}
+
+function show_element(elementId) {
+	element = document.getElementById(elementId);
+	if(element != null) {
+		currentClass = element.className;
+		if(currentClass == 'hidden_tooltip') {
+			element.className = 'visible_tooltip';
+		}
+	}
+}
+
+
diff --git a/bundles/org.eclipse.test.performance.ui/scripts/genresults b/bundles/org.eclipse.test.performance.ui/scripts/genresults
new file mode 100644
index 0000000..abe595d
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/scripts/genresults
@@ -0,0 +1,7 @@
+# !/bin/sh
+
+#export dbloc=net://trelenggtk.ottawa.ibm.com
+#required when running on Linux Motif
+export LD_LIBRARY_PATH=./../../..
+
+java -Declipse.perf.dbloc=$dbloc -jar ./../../../plugins/org.eclipse.equinox.launcher.jar -application org.eclipse.test.performance.ui.resultGenerator $*
diff --git a/bundles/org.eclipse.test.performance.ui/scripts/genresults.bat b/bundles/org.eclipse.test.performance.ui/scripts/genresults.bat
new file mode 100644
index 0000000..a4dc454
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/scripts/genresults.bat
@@ -0,0 +1,6 @@
+@echo off
+
+REM set dbloc=net://trelenggtk.ottawa.ibm.com
+
+java -Declipse.perf.dbloc=%dbloc% -jar .\..\..\..\plugins\org.eclipse.equinox.launcher.jar -application org.eclipse.test.performance.ui.resultGenerator %*
+
diff --git a/bundles/org.eclipse.test.performance.ui/scripts/plugin.xml.template b/bundles/org.eclipse.test.performance.ui/scripts/plugin.xml.template
new file mode 100644
index 0000000..cf91a73
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/scripts/plugin.xml.template
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.0"?>
+<plugin
+   id="Cloudscape"
+   name="Cloudscape"
+   version="1.0.0">
+   
+   <runtime>
+      <library name="db2jcc.jar">
+         <export name="*"/>
+      </library>
+      <library name="db2jcc_license_c.jar">
+         <export name="*"/>
+      </library>
+      <library name="cstools.jar">
+         <export name="*"/>
+      </library>
+      <library name="csnet.jar">
+         <export name="*"/>
+      </library>
+      <library name="cs.jar">
+         <export name="*"/>
+      </library>
+   </runtime>
+   <requires>
+      <import plugin="org.eclipse.osgi"/>
+   </requires>
+</plugin>
diff --git a/bundles/org.eclipse.test.performance.ui/scripts/results.properties b/bundles/org.eclipse.test.performance.ui/scripts/results.properties
new file mode 100644
index 0000000..979c6bf
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/scripts/results.properties
@@ -0,0 +1,20 @@
+###############################################################################
+# Copyright (c) 2005, 2006 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#     IBM Corporation - initial API and implementation
+###############################################################################
+args=\
+-baseline 3.0_200406251208_200505301645 \
+-baseline.prefix 3.0_ \
+-highlight 3.0.2_,2.1.3_,3.1M6_,3.1M7_ ,3.1RC1 \
+-current 3.1RC1_200505271300_200505301912 \
+-jvm sun1.4.2_08 \
+-output d:/m7perf \
+-config eclipseperfwin2 \
+-config.properties "eclipseperfwin1,Win XP Sun 1.4.2_08 (2 GHz 512 MB),win,d:/m7perf/win;eclipseperflnx1,RHEL 3.0 Sun 1.4.2_08 (2 GHz 512 MB),linux,d:/m7perf/linux;eclipseperfwin2,Win XP Sun 1.4.2_08 (3 GHz 2 GB),win2,d:/m7perf/win2;eclipseperflnx2,RHEL 3.0 Sun 1.4.2_08 (3 GHz 2 GB),linux2,d:/m7perf/linux2" \
+-scenario.pattern org.eclipse.ant
diff --git a/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/BarGraph.java b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/BarGraph.java
new file mode 100644
index 0000000..2dc79d0
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/BarGraph.java
@@ -0,0 +1,291 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.test.performance.ui;
+
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Display;
+
+public class BarGraph {
+
+	private static final int MARGIN= 5; // margin on all four sides
+	private static final int BARHEIGHT= 8; // height of bar
+	private static final int GAP= 10; // gap between bars
+	private static final int TGAP= 5; // gap between lines and labels
+
+	private static final boolean NO_SCALE= true; // 
+
+	// if NO_SCALE is true the following values are used:
+	private static final double RATIO= 0.6; // fraction of width reserved for bar graph; needs tweaking
+	private static final int FROM_END= 20; // a break (//) is shown this far from end of bar
+	private static final int SLANT= 8; // slant of break
+	private static final int GAP2= 5; // width of break
+
+	private StringBuffer fAreaBuffer;
+
+	private static class BarItem {
+
+		String title;
+		double value, error;
+		String url;
+		String slowdownExpected;
+		boolean significant;
+
+		BarItem(String t, double[] stats, String u, String slow, boolean sig) {
+			title= t;
+			value= stats[0]==0 ? 0 : -stats[0] * 100;
+			error = stats[1] * 100;
+			url= u;
+			slowdownExpected= slow;
+			significant= sig;
+		}
+	}
+
+	private String fTitle;
+	private List fItems;
+
+	BarGraph(String title) {
+		fTitle= title;
+		fItems= new ArrayList();
+	}
+
+	public void addItem(String name, double[] stats, String url, String slow, boolean significant) {
+		fItems.add(new BarItem(name, stats, url, slow, significant));
+	}
+
+	public int getHeight() {
+		int n= fItems.size();
+		int textHeight= 16;
+		int titleHeight= 0;
+		if (fTitle != null)
+			titleHeight= textHeight + GAP;
+		return MARGIN + titleHeight + n * (GAP + BARHEIGHT) + GAP + textHeight + MARGIN;
+	}
+
+	public void paint(Display display, int width, int height, GC gc) {
+
+		NumberFormat nf= NumberFormat.getInstance();
+
+		BarItem[] bars= (BarItem[]) fItems.toArray(new BarItem[fItems.size()]);
+
+		// draw white background
+		Color bg= display.getSystemColor(SWT.COLOR_WHITE);
+		gc.setBackground(bg);
+		gc.fillRectangle(0, 0, width, height);
+
+		// determine the widths of the bar and the label areas
+		int w;
+		if (NO_SCALE) {
+			// we use a fixed width
+			w= (int) (RATIO * width);
+		} else {
+			// we calculate the max width
+			int maxNameLength= 0;
+			for (int i= 0; i < bars.length; i++) {
+				Point es= gc.stringExtent(bars[i].title);
+				maxNameLength= Math.max(maxNameLength, es.x);
+			}
+			w= width - maxNameLength - TGAP - 2 * MARGIN;
+		}
+
+		Color fg= display.getSystemColor(SWT.COLOR_BLACK);
+
+		int vstart= 0; // start rows here
+		if (fTitle != null) {
+			vstart= gc.stringExtent(fTitle).y + GAP;
+			gc.drawString(fTitle, MARGIN, MARGIN, true); // draw title left aligned
+		}
+
+		int center= MARGIN + w / 2;
+		int w2= w / 2 - gc.stringExtent("-999.9").x - TGAP; // reserve space //$NON-NLS-1$
+
+		// determine maximum of values
+		double max= 0.0;
+		for (int i= 0; i < bars.length; i++)
+			max= Math.max(max, Math.abs(bars[i].value));
+
+		double d;
+		if (NO_SCALE) {
+			d= 25;
+			max= 125;
+		} else {
+			if (max > 400.0) {
+				d= 200;
+			} else if (max > 200.0) {
+				d= 100;
+			} else if (max > 100.0) {
+				d= 50;
+			} else if (max > 50) {
+				d= 25;
+			} else if (max > 25) {
+				d= 10;
+			} else if (max > 10) {
+				d= 5;
+			} else if (max > 5) {
+				d= 2.5;
+			} else {
+				d= 1.0;
+			}
+		}
+
+		// draw striped background
+		int y= MARGIN + vstart;
+		Color lightblue= new Color(display, 237, 243, 254);
+		gc.setBackground(lightblue);
+		for (int i= 0; i < bars.length; i++)
+			if (i % 2 == 0)
+				gc.fillRectangle(0, y + i * (BARHEIGHT + GAP), width, BARHEIGHT + GAP);
+
+		// draw grid
+		int yy= y + bars.length * (BARHEIGHT + GAP);
+		gc.drawLine(center, y, center, yy + TGAP);
+		Color grey= display.getSystemColor(SWT.COLOR_GRAY);
+		for (int i= 1; d * i < max; i++) {
+
+			double xx= d * i;
+			int x= (int) ((xx / max) * w2);
+
+			gc.setForeground(grey);
+			gc.drawLine(center - x, y, center - x, yy + TGAP);
+			gc.drawLine(center + x, y, center + x, yy + TGAP);
+
+			gc.setForeground(fg);
+
+			String s3= nf.format(-xx) + "%"; //$NON-NLS-1$
+			Point es3= gc.stringExtent(s3);
+			gc.drawString(s3, center - x - es3.x / 2, yy + TGAP, true);
+
+			String s4= nf.format(xx) + "%"; //$NON-NLS-1$
+			Point es4= gc.stringExtent(s4);
+			gc.drawString(s4, center + x - es4.x / 2, yy + TGAP, true);
+		}
+		gc.drawLine(0, yy, w, yy);
+
+		nf.setMaximumFractionDigits(1);
+
+		// link color
+		Color blue= display.getSystemColor(SWT.COLOR_BLUE);
+		// draw bars
+		Color green= display.getSystemColor(SWT.COLOR_GREEN);
+		Color red= display.getSystemColor(SWT.COLOR_RED);
+		Color gray= display.getSystemColor(SWT.COLOR_GRAY);
+		Color yellow= display.getSystemColor(SWT.COLOR_YELLOW);
+		Color white= display.getSystemColor(SWT.COLOR_WHITE);
+		for (int i= 0; i < bars.length; i++) {
+
+			BarItem bar= bars[i];
+			double delta = bar.value;
+			double orgDelta= delta;
+			
+			boolean clamped= false;
+			if (NO_SCALE) {
+				if (delta > max) {
+					delta= max;
+					clamped= true;
+				} else if (delta < -max) {
+					delta= -max;
+					clamped= true;
+				}
+			}
+
+			int barLength= (int) (delta / max * w2);
+
+			if (delta < 0) {
+				if (bar.slowdownExpected != null) {
+					gc.setBackground(gray);
+				} else if (!bar.significant) {
+					gc.setBackground(yellow);
+				} else  {
+					gc.setBackground(red);
+				}
+			} else if (!bar.significant) {
+				gc.setBackground(yellow);
+			} else {
+				gc.setBackground(green);
+			}
+
+			if (barLength > 0) {
+				gc.fillRectangle(center, y + (GAP / 2), barLength, BARHEIGHT);
+				gc.drawRectangle(center, y + (GAP / 2), barLength, BARHEIGHT);
+			} else if (barLength < 0) {
+				gc.fillRectangle(center+barLength, y + (GAP / 2), -barLength, BARHEIGHT);
+				gc.drawRectangle(center+barLength, y + (GAP / 2), -barLength, BARHEIGHT);
+			}
+
+			if (clamped) {
+
+				int h2= (BARHEIGHT + GAP);
+				int x= center + barLength;
+				if (barLength > 0)
+					x-= FROM_END;
+				else
+					x+= FROM_END - GAP2 - SLANT;
+				int[] pts= new int[] { x, y + h2 - 1, x + SLANT, y + 1, x + SLANT + GAP2, y + 1, x + GAP2, y + h2 - 1};
+				if (i % 2 == 0)
+					gc.setBackground(lightblue);
+				else
+					gc.setBackground(white);
+				gc.fillPolygon(pts);
+				gc.drawLine(pts[0], pts[1], pts[2], pts[3]);
+				gc.drawLine(pts[4], pts[5], pts[6], pts[7]);
+			}
+
+			String label= nf.format(orgDelta);
+			Point labelExtent= gc.stringExtent(label);
+			int labelxpos= center + barLength;
+			int labelvpos= y + (BARHEIGHT + GAP - labelExtent.y) / 2;
+			if (orgDelta > 0.0) {
+				gc.drawString(label, labelxpos + TGAP, labelvpos, true);
+			} else {
+				gc.drawString(label, labelxpos - TGAP - labelExtent.x, labelvpos, true);
+			}
+
+			int x= MARGIN + w + TGAP;
+			String title= bar.title;
+			boolean hasURL= bar.url != null;
+			Color oldfg= gc.getForeground();
+			if (hasURL) {
+				gc.setForeground(blue);
+				Point e= gc.stringExtent(title);
+				gc.drawLine(x, labelvpos + e.y - 1, x + e.x, labelvpos + e.y - 1);
+			}
+			gc.drawString(title, x, labelvpos, true);
+			if (hasURL)
+				gc.setForeground(oldfg);
+
+			int y0= y;
+			y+= BARHEIGHT + GAP;
+
+			if (hasURL) {
+				if (fAreaBuffer == null)
+					fAreaBuffer= new StringBuffer();
+				fAreaBuffer.append("<area shape=\"RECT\" coords=\"0," + y0 + ',' + width + ',' + y + "\" href=\"" + bar.url + "\">\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+			}
+		}
+
+		lightblue.dispose();
+	}
+
+	public String getAreas() {
+		if (fAreaBuffer != null) {
+			String s= fAreaBuffer.toString();
+			fAreaBuffer= null;
+			return s;
+		}
+		return null;
+	}
+}
diff --git a/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/FingerPrint.java b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/FingerPrint.java
new file mode 100644
index 0000000..054f65a
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/FingerPrint.java
@@ -0,0 +1,184 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.test.performance.ui;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.ImageLoader;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.test.internal.performance.results.AbstractResults;
+import org.eclipse.test.internal.performance.results.ConfigResults;
+import org.eclipse.test.internal.performance.results.PerformanceResults;
+import org.eclipse.test.internal.performance.results.ScenarioResults;
+
+/**
+ * Class used to create scenario fingerprint.
+ */
+public class FingerPrint {
+
+private static final int GRAPH_WIDTH = 1000;
+
+	String component;
+	PrintStream stream;
+	File outputDir;
+
+public FingerPrint(String name, PrintStream ps, File outputDir) {
+	if (!name.equals("global")) this.component = name;
+	this.stream = ps;
+	this.outputDir = outputDir;
+}
+
+/**
+ * Create and save fingerprints as image and print their reference in the current stream.
+ * 
+ * @param performanceResults The performance results used to print the fingerprints
+ */
+public void print(PerformanceResults performanceResults) {
+	String baselineBuildName = performanceResults.getBaselineName();
+	String buildName = performanceResults.getName();
+	
+	// Compute fingerprint output file name prefix
+	int referenceUnderscoreIndex = baselineBuildName.indexOf('_');
+	String baselinePrefix = baselineBuildName;
+	if (referenceUnderscoreIndex != -1) {
+		baselinePrefix = baselineBuildName.substring(0, referenceUnderscoreIndex);
+	}
+	int currentUnderscoreIndex = buildName.indexOf('_');
+	if  (currentUnderscoreIndex != -1){
+		buildName = buildName.substring(0, currentUnderscoreIndex);
+	}
+	StringBuffer buffer = new StringBuffer("FP_");
+	if (this.component != null) {
+		buffer.append(this.component);
+		buffer.append('_');
+	}
+	buffer.append(baselinePrefix);
+	buffer.append('_');
+	buffer.append(buildName);
+	buffer.append('.');
+	String filePrefix = buffer.toString();
+
+	// Create each fingerprint and save it
+	String[] configNames = performanceResults.getConfigNames(false/* not sorted*/);
+	String[] configBoxes = performanceResults.getConfigBoxes(false/* not sorted*/);
+	int length = configNames.length;
+	for (int c=0; c<length; c++) {
+		String configName  = configNames[c];
+		List scenarios = performanceResults.getComponentSummaryScenarios(this.component, configName);
+		if (scenarios == null) continue;
+
+		// Create BarGraph
+//		BarGraph barGraph = new BarGraph(null);
+		BarGraph barGraph = null;
+		for (int i=0, size=scenarios.size(); i<size; i++) {
+			ScenarioResults scenarioResults = (ScenarioResults) scenarios.get(i);
+			ConfigResults configResults = scenarioResults.getConfigResults(configName);
+			if (configResults == null || !configResults.isValid()) continue;
+			double[] results = configResults.getCurrentBuildDeviation();
+			double percent = -results[0] * 100.0;
+			if (results != null && Math.abs(percent) < 200) {
+				String defaultDimensionName = AbstractResults.SUPPORTED_DIMS[0].getName();
+				String name = scenarioResults.getLabel() + " (" + defaultDimensionName + ")";
+				if (!configResults.getCurrentBuildName().equals(buildName)) {
+					continue; // the test didn't run on last build, skip it
+				}
+				if (!configResults.isBaselined()) {
+					name = "*" + name + " (" + configResults.getBaselineBuildName() + ")";
+				}
+				if (barGraph == null) {
+					barGraph = new BarGraph(null);
+				}
+				barGraph.addItem(name,
+				    results,
+				    configName + "/" + scenarioResults.getFileName() + ".html#" + defaultDimensionName,
+				    configResults.getCurrentBuildResults().getComment(),
+				    (Utils.confidenceLevel(results) & Utils.ERR) == 0);
+			}
+		}
+		 if (barGraph == null) continue;
+
+		// Save image file
+		String fileName = filePrefix + configName ;
+		File outputFile = new File(this.outputDir, fileName+".gif");
+		save(barGraph, outputFile);
+
+		// Print image file reference in stream
+		String boxName = configBoxes[c];
+		if (outputFile.exists()) {
+			String areas = barGraph.getAreas();
+			if (areas == null) areas = "";
+			this.stream.print("<h4>");
+			this.stream.print(boxName);
+			this.stream.print("</h4>");
+			this.stream.print("<img src=\"");
+			this.stream.print(fileName);
+			this.stream.print(".gif\" usemap=\"#");
+			this.stream.print(fileName);
+			this.stream.print("\"><map name=\"");
+			this.stream.print(fileName);
+			this.stream.print("\">");
+			this.stream.print(areas);
+			this.stream.print("</map>\n");
+		} else {
+			this.stream.print("<br><br>There is no fingerprint for ");
+			this.stream.print(boxName);
+			this.stream.print("<br><br>\n");
+		}
+	}
+}
+
+/*
+ * Save the computed bar graph.
+ */
+private void save(BarGraph barGraph, File outputFile) {
+
+	// Create and paint image
+	Display display = Display.getDefault();
+	int height = barGraph.getHeight();
+	Image image = new Image(display, GRAPH_WIDTH, height);
+	GC gc = new GC(image);
+	barGraph.paint(display, GRAPH_WIDTH, height, gc);
+	gc.dispose();
+
+	// Save image
+	ImageData data = Utils.downSample(image);
+	ImageLoader imageLoader = new ImageLoader();
+	imageLoader.data = new ImageData[] { data };
+
+	OutputStream out = null;
+	try {
+		out = new BufferedOutputStream(new FileOutputStream(outputFile));
+		imageLoader.save(out, SWT.IMAGE_GIF);
+	} catch (FileNotFoundException e) {
+		e.printStackTrace();
+	} finally {
+		image.dispose();
+		if (out != null) {
+			try {
+				out.close();
+			} catch (IOException e1) {
+				// silently ignored
+			}
+		}
+	}
+}
+}
diff --git a/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/LineGraph.java b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/LineGraph.java
new file mode 100644
index 0000000..1a15884
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/LineGraph.java
@@ -0,0 +1,200 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.test.performance.ui;
+
+import java.util.*;
+
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.test.internal.performance.data.Dim;
+
+public class LineGraph {
+    
+    StringBuffer fAreaBuffer;
+    
+    private static class GraphItem {
+
+        String title;
+        String description=null;
+        double value;
+        Color color;
+        boolean displayDescription=false;
+
+        GraphItem(String title, String description,double value, Color color,boolean display) {
+        	this(title, description, value, color);
+        	this.displayDescription=display;
+        }
+
+        GraphItem(String title, String description, double value, Color color) {
+            this.title= title;
+            this.value= value;
+            this.color= color;
+            this.description= description;
+        }
+        
+        Point getSize(GC g) {
+            Point e1= g.stringExtent(description);
+            Point e2= g.stringExtent(title);
+            return new Point(Math.max(e1.x, e2.x), e1.y+e2.y);
+        }
+    }
+    
+    static final int PADDING= 15;
+    
+
+    String fTitle;
+    List fItems;
+    Dim fDimension;
+
+    
+    public LineGraph(String title, Dim dim) {
+        fTitle= title;
+        fItems= new ArrayList();
+        fDimension= dim;
+    }
+
+    public void paint(Image im) {
+        
+        Rectangle bounds= im.getBounds();
+        
+        GC g= new GC(im);
+
+        Point ee= g.stringExtent(fTitle);
+        int titleHeight= ee.y;
+
+        double maxItem= getMaxItem();
+        double minItem= getMinItem();
+        
+        int max= (int) (Math.ceil(maxItem * (maxItem < 0 ? 0.9 : 1.2)));
+        int min= (int) (Math.floor(minItem * (minItem < 0 ? 1.2 : 0.9)));
+
+        String smin= fDimension.getDisplayValue(min);
+        Point emin= g.stringExtent(smin);
+        
+        String smax= fDimension.getDisplayValue(max);
+        Point emax= g.stringExtent(smax);
+        
+        int labelWidth= Math.max(emin.x, emax.x) + 2;
+                
+        int top= PADDING;
+        int bottom= bounds.height - titleHeight - PADDING;
+        int left= PADDING + labelWidth;
+
+        GraphItem lastItem= (GraphItem) fItems.get(fItems.size()-1);
+        int right= bounds.width - lastItem.getSize(g).x - PADDING/2;
+
+        // draw the title
+        //g.drawString(fTitle, (bounds.width - titleWidth) / 2, titleHeight, true);
+        
+        // draw the max and min values
+        g.drawString(smin, PADDING/2+labelWidth-emin.x, bottom-titleHeight, true);
+        g.drawString(smax, PADDING/2+labelWidth-emax.x, top, true);
+        
+        // draw the vertical and horizontal lines
+        g.drawLine(left, top, left, bottom);
+        g.drawLine(left, bottom, right, bottom);
+
+        Color oldbg= g.getBackground();
+        Color oldfg= g.getForeground();
+
+        int n= fItems.size();
+        int xincrement= n > 1 ? (right-left) / (n-1) : 0;
+         
+        int graduations= max - min;
+        if (graduations == 0)
+            graduations= 1;
+       
+        int lastx= 0;
+        int lasty= 0;
+
+        int xposition= left;
+
+        for (int i= 0; i < n; i++) {
+            GraphItem thisItem= (GraphItem) fItems.get(i);
+            
+            int yposition= (int) (bottom - (((thisItem.value-min) * (bottom-top)) / graduations));
+
+            if (i > 0)	// don't draw for first segment
+                g.drawLine(lastx, lasty, xposition, yposition);
+            
+            g.setBackground(thisItem.color);
+            g.setForeground(thisItem.color);
+            g.fillOval(xposition-2, yposition-2, 5, 5);
+            
+            if (fAreaBuffer == null)
+                fAreaBuffer= new StringBuffer();
+            
+            fAreaBuffer.append("\r<area shape=\"CIRCLE\" coords=\""+(xposition-2)+','+(yposition-2)+','+5+" alt=\""+ thisItem.title+": "+thisItem.description+"\""+ " title=\""+ thisItem.title+": "+thisItem.description+"\">");
+            
+            
+            int shift;
+            if (i > 0 && yposition < lasty)
+                shift= 3;	 // below dot
+            else     
+                shift= -(2*titleHeight+3);	// above dot
+            if (thisItem.displayDescription){
+            	g.drawString(thisItem.title, xposition+2, yposition+shift, true);
+            	g.drawString(thisItem.description, xposition+2, yposition+shift+titleHeight, true);
+            }
+            g.setBackground(oldbg);
+            g.setForeground(oldfg);
+            
+            lastx= xposition;
+            lasty= yposition;
+            xposition+= xincrement;
+        }
+        
+        g.dispose();
+    }
+
+    public void addItem(String name, String description, double value, Color col) {
+    	addItem(name, description, value, col,false);
+    }
+
+    public void addItem(String name, String description, double value, Color col, boolean display) {
+        fItems.add(new GraphItem(name, description, value, col,display));
+    }
+
+    public double getMaxItem() {
+        double maxItem= 0;
+        for (int i= 0; i < fItems.size(); i++) {
+            GraphItem graphItem= (GraphItem) fItems.get(i);
+            if (graphItem.value > maxItem)
+                maxItem= graphItem.value;
+        }
+        if (maxItem == 0)
+            return 1;
+        return maxItem;
+    }
+
+    public double getMinItem() {
+        double minItem= getMaxItem();
+        for (int i= 0; i < fItems.size(); i++) {
+            GraphItem graphItem= (GraphItem) fItems.get(i);
+            if (graphItem.value < minItem)
+                minItem= graphItem.value;
+        }
+        if (minItem == 0)
+            return -1;
+        return minItem;
+    }
+    public String getAreas() {
+        if (fAreaBuffer != null) {
+            String s= fAreaBuffer.toString();
+            fAreaBuffer= null;
+            return s;
+        }
+        return null;
+    }
+}
diff --git a/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/Main.java b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/Main.java
new file mode 100644
index 0000000..c9992d8
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/Main.java
@@ -0,0 +1,780 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.test.performance.ui;
+
+import java.io.*;
+import java.net.URL;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.equinox.app.IApplication;
+import org.eclipse.equinox.app.IApplicationContext;
+import org.eclipse.test.internal.performance.PerformanceTestPlugin;
+import org.eclipse.test.internal.performance.results.AbstractResults;
+import org.eclipse.test.internal.performance.results.ConfigResults;
+import org.eclipse.test.internal.performance.results.DB_Results;
+import org.eclipse.test.internal.performance.results.PerformanceResults;
+import org.eclipse.test.internal.performance.results.ScenarioResults;
+import org.osgi.framework.Bundle;
+
+/**
+ * Main class to generate performance results of all scenarios matching a given pattern
+ * in one HTML page per component.
+ * 
+ * @see #printUsage() method to see a detailed parameters usage
+ */
+public class Main implements IApplication {
+
+/**
+ * Prefix of baseline builds displayed in data graphs.
+ * This field is set using <b>-baselinePrefix</b> argument.
+ * <p>
+ * Example:
+ *		<pre>-baseline.prefix 3.2_200606291905</pre>
+ *
+ * @see #currentBuildPrefixes
+ */
+private String baselinePrefix = null;
+
+/**
+ * Root directory where all files are generated.
+ * This field is set using <b>-output</b> argument.
+ * <p>
+ * Example:
+ * 	<pre>-output /releng/results/I20070615-1200/performance</pre>
+ */
+private File outputDir;
+
+/**
+ * Root directory where all data are locally stored to speed-up generation.
+ * This field is set using <b>-dataDir</b> argument.
+ * <p>
+ * Example:
+ * 	<pre>-dataDir /tmp</pre>
+ */
+private File dataDir;
+
+/**
+ * Arrays of 2 strings which contains config information: name and description.
+ * This field is set using <b>-config</b> and/or <b>-config.properties</b> arguments.
+ * <p>
+ * Example:
+ * <pre>
+ * 	-config eclipseperflnx3_R3.3,eclipseperfwin2_R3.3,eclipseperflnx2_R3.3,eclipseperfwin1_R3.3,eclipseperflnx1_R3.3
+ * 	-config.properties
+ * 		"eclipseperfwin1_R3.3,Win XP Sun 1.4.2_08 (2 GHz 512 MB);
+ * 		eclipseperflnx1_R3.3,RHEL 3.0 Sun 1.4.2_08 (2 GHz 512 MB);
+ * 		eclipseperfwin2_R3.3,Win XP Sun 1.4.2_08 (3 GHz 2 GB);
+ * 		eclipseperflnx2_R3.3,RHEL 3.0 Sun 1.4.2_08 (3 GHz 2 GB);
+ * 		eclipseperflnx3_R3.3,RHEL 4.0 Sun 1.4.2_08 (3 GHz 2.5 GB)"
+ * </pre>
+ * Note that:
+ * <ul>
+ * <li>if only <b>-config</b> is set, then configuration name is used for description </li>
+ * <li>if only <b>-config.properties</b> is set, then all configurations defined with this argument are generated
+ * <li>if both arguments are defined, then only configurations defined by <b>-config</b> argument are generated,
+ * 		<b>-config.properties</b> argument is only used to set the configuration description.</li>
+ * </ul>
+ */
+private String[][] configDescriptors;
+
+/**
+ * Scenario pattern used to generate performance results.
+ * This field is set using <b>-scenarioPattern</b> argument.
+ * <p>
+ * Note that this pattern uses SQL conventions, not RegEx ones,
+ * which means that '%' is used to match several consecutive characters
+ * and '_' to match a single character.
+ * <p>
+ * Example:
+ * 	<pre>-scenario.pattern org.eclipse.%.test</pre>
+ */
+private String scenarioPattern;
+
+/**
+ * A list of prefixes for builds displayed in data graphs.
+ * This field is set using <b>-currentPrefix</b> argument.
+ * <p>
+ * Example:
+ * 	<pre>-current.prefix N, I</pre>
+ * 
+ * @see #baselinePrefix
+ */
+private List currentBuildPrefixes;
+
+/**
+ * A list of prefixes of builds to highlight in displayed data graphs.
+ * This field is set using <b>-highlight</b> and/or <b>-highlight.latest</b> arguments.
+ * <p>
+ * Example:
+ * 	<pre>-higlight 3_2</pre>
+ */
+private List pointsOfInterest;
+
+/**
+ * Tells whether only fingerprints has to be generated.
+ * This field is set to <code>true</code> if <b>-fingerprints</b> argument is specified.
+ * <p>
+ * Default is <code>false</code> which means that scenario data
+ * will also be generated.
+ * 
+ * @see #genData
+ * @see #genAll
+ */
+private boolean genFingerPrints = false;
+
+/**
+ * Tells whether only fingerprints has to be generated.
+ * This field is set to <code>true</code> if <b>-data</b> argument is specified.
+ * <p>
+ * Default is <code>false</code> which means that fingerprints
+ * will also be generated.
+ * 
+ * @see #genFingerPrints
+ * @see #genAll
+ */
+private boolean genData = false;
+
+/**
+ * Tells whether only fingerprints has to be generated.
+ * This field is set to <code>false</code>
+ * if <b>-fingerprints</b> or <b>-data</b> argument is specified.
+ * <p>
+ * Default is <code>true</code> which means that scenario data
+ * will also be generated.
+ * 
+ * @see #genData
+ * @see #genFingerPrints
+ */
+private boolean genAll = true;
+
+/**
+ * Tells whether information should be displayed in the console while generating.
+ * This field is set to <code>true</code> if <b>-print</b> argument is specified.
+ * <p>
+ * Default is <code>false</code> which means that nothing is print during the generation.
+ */
+private boolean print = false;
+
+/*
+ * Parse the command arguments and create corresponding performance
+ * results object.
+ */
+private PerformanceResults parse(Object argsObject) {
+	StringBuffer buffer = new StringBuffer("Parameters used to generate performance results (");
+	buffer.append(new SimpleDateFormat().format(new Date(System.currentTimeMillis())));
+	buffer.append("):\n");
+	String[] args = (String[]) argsObject;
+	int i = 0;
+	if (args.length == 0) {
+		printUsage();
+	}
+
+	String currentBuildId = null;
+	String baseline = null;
+	String jvm = null;
+	this.configDescriptors = null;
+
+	while (i < args.length) {
+		String arg = args[i];
+		if (!arg.startsWith("-")) {
+			i++;
+			continue;
+		}
+		if (args.length == i + 1 && i != args.length - 1) {
+			System.out.println("Missing value for last parameter");
+			printUsage();
+		}
+		if (arg.equals("-baseline")) {
+			baseline = args[i + 1];
+			if (baseline.startsWith("-")) {
+				System.out.println("Missing value for -baseline parameter");
+				printUsage();
+			}
+			buffer.append("	-baseline = "+baseline+'\n');
+			i++;
+			continue;
+		}
+		if (arg.equals("-baseline.prefix")) {
+			this.baselinePrefix = args[i + 1];
+			if (this.baselinePrefix.startsWith("-")) {
+				System.out.println("Missing value for -baseline.prefix parameter");
+				printUsage();
+			}
+			buffer.append("	-baselinePrefix = "+this.baselinePrefix+'\n');
+			i++;
+			continue;
+		}
+		if (arg.equals("-current.prefix")) {
+			String idPrefixList = args[i + 1];
+			if (idPrefixList.startsWith("-")) {
+				System.out.println("Missing value for -current.prefix parameter");
+				printUsage();
+			}
+			buffer.append("	-current.prefix = ");
+			String[] ids = idPrefixList.split(",");
+			this.currentBuildPrefixes = new ArrayList();
+			for (int j = 0; j < ids.length; j++) {
+				this.currentBuildPrefixes.add(ids[j]);
+				buffer.append(ids[j]);
+			}
+			buffer.append('\n');
+			i++;
+			continue;
+		}
+		if (arg.equals("-highlight") || arg.equals("-highlight.latest")) {
+			if (args[i + 1].startsWith("-")) {
+				System.out.println("Missing value for -highlight parameter");
+				printUsage();
+			}
+			buffer.append("	"+arg+" = ");
+			String[] ids = args[i + 1].split(",");
+			this.pointsOfInterest = new ArrayList();
+			for (int j = 0; j < ids.length; j++) {
+				this.pointsOfInterest.add(ids[j]);
+				buffer.append(ids[j]);
+			}
+			buffer.append('\n');
+			i++;
+			continue;
+		}
+		if (arg.equals("-current")) {
+			currentBuildId  = args[i + 1];
+			if (currentBuildId.startsWith("-")) {
+				System.out.println("Missing value for -current parameter");
+				printUsage();
+			}
+			buffer.append("	-current = "+currentBuildId+'\n');
+			i++;
+			continue;
+		}
+		if (arg.equals("-jvm")) {
+			jvm = args[i + 1];
+			if (jvm.startsWith("-")) {
+				System.out.println("Missing value for -jvm parameter");
+				printUsage();
+			}
+			buffer.append("	-jvm = "+jvm+'\n');
+			i++;
+			continue;
+		}
+		if (arg.equals("-output")) {
+			String dir = args[++i];
+			if (dir.startsWith("-")) {
+				System.out.println("Missing value for -output parameter");
+				printUsage();
+			}
+			this.outputDir = new File(dir);
+			if (!this.outputDir.exists() && !this.outputDir.mkdirs()) {
+				System.err.println("Cannot create directory "+dir+" to write results in!");
+				System.exit(2);
+			}
+			buffer.append("	-output = "+dir+'\n');
+			continue;
+		}
+		if (arg.equals("-dataDir")) {
+			String dir = args[++i];
+			if (dir.startsWith("-")) {
+				System.out.println("Missing value for -output parameter");
+				printUsage();
+			}
+			this.dataDir = new File(dir);
+			if (!this.dataDir.exists() && !this.dataDir.mkdirs()) {
+				System.err.println("Cannot create directory "+dir+" to save data locally!");
+				System.exit(2);
+			}
+			buffer.append("	-dataDir = "+dir+'\n');
+			continue;
+		}
+		if (arg.equals("-config")) {
+			String configs = args[i + 1];
+			if (configs.startsWith("-")) {
+				System.out.println("Missing value for -config parameter");
+				printUsage();
+			}
+			String[] names = configs.split(",");
+			int length = names.length;
+			buffer.append("	-config = ");
+			for (int j=0; j<length; j++) {
+				if (j>0) buffer.append(',');
+				buffer.append(names[j]);
+			}
+			if (this.configDescriptors == null) {
+				this.configDescriptors = new String[length][2];
+				for (int j=0; j<length; j++) {
+					this.configDescriptors[j][0] = names[j];
+					this.configDescriptors[j][1] = names[j];
+				}
+			} else {
+				int confLength = this.configDescriptors[0].length;
+				int newLength = confLength;
+				mainLoop: for (int j=0; j<confLength; j++) {
+					for (int k=0; k<length; k++) {
+						if (this.configDescriptors[j][0].equals(names[k])) {
+							continue mainLoop;
+						}
+					}
+					this.configDescriptors[j][0] = null;
+					this.configDescriptors[j][1] = null;
+					newLength--;
+				}
+				if (newLength < confLength) {
+					String[][] newDescriptors = new String[newLength][2];
+					for (int j=0, c=0; j<newLength; j++) {
+						if (this.configDescriptors[c] != null) {
+							newDescriptors[j][0] = this.configDescriptors[c][0];
+							newDescriptors[j][1] = this.configDescriptors[c][1];
+						} else {
+							c++;
+						}
+					}
+					this.configDescriptors = newDescriptors;
+				}
+			}
+			buffer.append('\n');
+			i++;
+			continue;
+		}
+		if (arg.equals("-config.properties")) {
+			String configProperties = args[i + 1];
+			if (configProperties.startsWith("-")) {
+				System.out.println("Missing value for -config.properties parameter");
+				printUsage();
+			}
+			if (this.configDescriptors == null) {
+				System.out.println("Missing -config parameter");
+				printUsage();
+			}
+			int length = this.configDescriptors.length;
+			StringTokenizer tokenizer = new StringTokenizer(configProperties, ";");
+			buffer.append("	-config.properties = ");
+			while (tokenizer.hasMoreTokens()) {
+				String labelDescriptor = tokenizer.nextToken();
+				String[] elements = labelDescriptor.trim().split(",");
+				for (int j=0; j<length; j++) {
+					if (elements[0].equals(this.configDescriptors[j][0])) {
+						this.configDescriptors[j][1] = elements[1];
+						buffer.append("\n\t\t+ ");
+						buffer.append(elements[0]);
+						buffer.append(" -> ");
+						buffer.append(elements[1]);
+					}
+				}
+			}
+			buffer.append('\n');
+			i++;
+			continue;
+		}
+		if (arg.equals("-scenario.filter") || arg.equals("-scenario.pattern")) {
+			this.scenarioPattern= args[i + 1];
+			if (this.scenarioPattern.startsWith("-")) {
+				System.out.println("Missing value for -baseline parameter");
+				printUsage();
+			}
+			buffer.append("	"+arg+" = "+this.scenarioPattern+'\n');
+			i++;
+			continue;
+		}
+		if (arg.equals("-fingerprints")) {
+			this.genFingerPrints = true;
+			this.genAll = false;
+			buffer.append("	-fingerprints\n");
+			i++;
+			continue;
+		}
+		if (arg.equals("-data")) {
+			this.genData = true;
+			this.genAll = false;
+			buffer.append("	-data\n");
+			i++;
+			continue;
+		}
+		if (arg.equals("-print")) {
+			this.print = true;
+			buffer.append("	-print\n");
+			i++;
+			continue;
+		}
+		i++;
+	}
+	if (this.print) System.out.println(buffer.toString());
+	if (baseline == null || this.outputDir == null || this.configDescriptors == null || jvm == null || currentBuildId == null) {
+		printUsage();
+	}
+	if (this.baselinePrefix == null) {
+		// Assume that baseline name format is *always* x.y_yyyyMMddhhmm_yyyyMMddhhmm
+		this.baselinePrefix = baseline.substring(0, baseline.lastIndexOf('_'));
+	}
+
+	if (this.currentBuildPrefixes == null) {
+		this.currentBuildPrefixes = new ArrayList();
+		this.currentBuildPrefixes.add("N");
+		this.currentBuildPrefixes.add("I");
+	}
+	return new PerformanceResults(currentBuildId, baseline, this.print);
+}
+
+/*
+ * Print component PHP file
+ */
+private void printComponent(PerformanceResults performanceResults, String component) throws FileNotFoundException {
+	if (this.print) System.out.print(".");
+	File outputFile = new File(this.outputDir, component + ".php");
+	PrintStream stream = new PrintStream(new BufferedOutputStream(new FileOutputStream(outputFile)));
+	stream.println(Utils.HTML_OPEN);
+	stream.println("<link href=\"ToolTip.css\" rel=\"stylesheet\" type=\"text/css\"><script src=\"ToolTip.js\"></script>");
+	stream.println(Utils.HTML_DEFAULT_CSS);
+	stream.println("<body>");
+
+	String baselineName = performanceResults.getBaselineName();
+	String currentName = performanceResults.getName();
+	boolean isGlobal = component.equals("global");
+	StringBuffer title = new StringBuffer("<h3>Performance of ");
+	if (!isGlobal) {
+		title.append(component);
+		title.append(": ");
+	}
+	title.append(currentName);
+	title.append(" relative to ");
+	int index = baselineName.indexOf('_');
+	title.append(baselineName.substring(0, index));
+	title.append(" (");
+	index = baselineName.lastIndexOf('_');
+	title.append(baselineName.substring(index+1, baselineName.length()));
+	title.append(")</h3>");
+	stream.println(title.toString());
+
+	// print the html representation of fingerprint for each config
+	if (genFingerPrints || genAll) {
+		FingerPrint fingerprint = new FingerPrint(component, stream, this.outputDir);
+		try {
+			fingerprint.print(performanceResults);
+		} catch (Exception ex) {
+			ex.printStackTrace();
+		}
+	}
+
+	// print scenario status table
+	if (isGlobal) {
+		if (!PerformanceTestPlugin.getDBLocation().startsWith("net://")) {
+			stream.println("<table border=0 cellpadding=2 cellspacing=5 width=\"100%\">");
+			stream.println("<tbody><tr> <td colspan=3 align=\"left\" bgcolor=\"#0080c0\" valign=\"top\"><b><font color=\"#ffffff\" face=\"Arial,Helvetica\">");
+			stream.println("Detailed performance data grouped by scenario prefix</font></b></td></tr></tbody></table>");
+			stream.println("<a href=\"org.eclipse.ant.php?\">org.eclipse.ant*</a><br>");
+			stream.println("<a href=\"org.eclipse.compare.php?\">org.eclipse.compare*</a><br>");
+			stream.println("<a href=\"org.eclipse.core.php?\">org.eclipse.core*</a><br>");
+			stream.println("<a href=\"org.eclipse.jdt.core.php?\">org.eclipse.jdt.core*</a><br>");
+			stream.println("<a href=\"org.eclipse.jdt.debug.php?\">org.eclipse.jdt.debug*</a><br>");
+			stream.println("<a href=\"org.eclipse.jdt.text.php?\">org.eclipse.jdt.text*</a><br>");
+			stream.println("<a href=\"org.eclipse.jdt.ui.php?\">org.eclipse.jdt.ui*</a><br>");
+			stream.println("<a href=\"org.eclipse.jface.php?\">org.eclipse.jface*</a><br>");
+			stream.println("<a href=\"org.eclipse.osgi.php?\">org.eclipse.osgi*</a><br>");
+			stream.println("<a href=\"org.eclipse.pde.ui.php?\">org.eclipse.pde.ui*</a><br>");
+			stream.println("<a href=\"org.eclipse.swt.php?\">org.eclipse.swt*</a><br>");
+			stream.println("<a href=\"org.eclipse.team.php?\">org.eclipse.team*</a><br>");
+			stream.println("<a href=\"org.eclipse.ua.php?\">org.eclipse.ua*</a><br>");
+			stream.println("<a href=\"org.eclipse.ui.php?\">org.eclipse.ui*</a><br><p><br><br>");
+		}
+	} else if (component.length() > 0) {
+		// print the component scenario status table beneath the fingerprint
+		ScenarioStatusTable sst = new ScenarioStatusTable(component, stream);
+		try {
+			sst.print(performanceResults);
+		} catch (Exception ex) {
+			ex.printStackTrace();
+		}
+	}
+
+	stream.println(Utils.HTML_CLOSE);
+	stream.close();
+}
+
+/*
+ * Print summary of coefficient of variation for each scenario of the given pattern
+ * both for baseline and current builds.
+ */
+private void printSummary(PerformanceResults performanceResults) {
+	long start = System.currentTimeMillis();
+	if (this.print) System.out.print("Print scenarios variations summary...");
+	File outputFile = new File(this.outputDir, "cvsummary.html");
+	PrintStream stream = null;
+	try {
+		stream = new PrintStream(new BufferedOutputStream(new FileOutputStream(outputFile)));
+		printSummaryPresentation(stream);
+		List scenarioNames = DB_Results.getScenariosNames();
+		int size = scenarioNames.size();
+		printSummaryColumnsTitle(stream, performanceResults);
+		String[] configs = performanceResults.getConfigNames(true/*sorted*/);
+		int configsLength = configs.length;
+		for (int i=0; i<size; i++) {
+			String scenarioName = (String) scenarioNames.get(i);
+			if (scenarioName == null) continue;
+			ScenarioResults scenarioResults = performanceResults.getScenarioResults(scenarioName);
+			if (scenarioResults != null) {
+				stream.println("<tr>");
+				for (int j=0; j<2; j++) {
+					for (int c=0; c<configsLength; c++) {
+						printSummaryScenarioLine(j, configs[c], scenarioResults, stream);
+					}
+				}
+				stream.print("<td>");
+				stream.print(scenarioName);
+				stream.println("</td></tr>");
+			}
+		}
+	} catch (Exception e) {
+		e.printStackTrace();
+	} finally {
+		stream.println("</table></body></html>");
+		stream.flush();
+		stream.close();
+	}
+	if (this.print) System.out.println("done in "+(System.currentTimeMillis()-start)+"ms");
+}
+
+/*
+ * Print summary presentation (eg. file start and text presenting the purpose of this file contents)..
+ */
+private void printSummaryPresentation(PrintStream stream) {
+	stream.println(Utils.HTML_OPEN);
+	stream.print(Utils.HTML_DEFAULT_CSS);
+	stream.println("<title>Summary of Elapsed Process Variation Coefficients</title></head>");
+	stream.println("<body><h3>Summary of Elapsed Process Variation Coefficients</h3>\n");
+	stream.println("<p> This table provides a bird's eye view of variability in elapsed process times\n");
+	stream.print("for baseline and current build stream performance scenarios.");
+	stream.print(" This summary is provided to facilitate the identification of scenarios that should be examined due to high variability.");
+	stream.println("The variability for each scenario is expressed as a <a href=\"http://en.wikipedia.org/wiki/Coefficient_of_variation\">coefficient\n");
+	stream.println("of variation</a> (CV). The CV is calculated by dividing the <b>standard deviation\n");
+	stream.println("of the elapse process time over builds</b> by the <b>average elapsed process\n");
+	stream.println("time over builds</b> and multiplying by 100.\n");
+	stream.println("</p><p>High CV values may be indicative of any of the following:<br></p>\n");
+	stream.println("<ol><li> an unstable performance test. </li>\n");
+	stream.println("<ul><li>may be evidenced by an erratic elapsed process line graph.<br><br></li></ul>\n");
+	stream.println("<li>performance regressions or improvements at some time in the course of builds.</li>\n");
+	stream.println("<ul><li>may be evidenced by plateaus in elapsed process line graphs.<br><br></li></ul>\n");
+	stream.println("<li>unstable testing hardware.\n");
+	stream.print("<ul><li>consistent higher CV values for one test configuration as compared to others across");
+	stream.println(" scenarios may be related to hardward problems.</li></ul></li></ol>\n");
+	stream.println("<p> Scenarios are listed in alphabetical order in the far right column. A scenario's\n");
+	stream.println("variation coefficients (CVs) are in columns to the left for baseline and current\n");
+	stream.println("build streams for each test configuration. Scenarios with CVs > 10% are highlighted\n");
+	stream.println("in yellow (10%<CV>&lt;CV<20%) and orange(CV>20%). </p>\n");
+	stream.println("<p> Each CV value links to the scenario's detailed results to allow viewers to\n");
+	stream.println("investigate the variability.</p>\n");
+}
+
+/*
+ * Print columns titles of the summary table.
+ */
+private void printSummaryColumnsTitle(PrintStream stream, PerformanceResults performanceResults) {
+	String[] configBoxes = performanceResults.getConfigBoxes(true/*sorted*/);
+	int length = configBoxes.length;
+	stream.print("<table border=\"1\"><tr><td colspan=\"");
+	stream.print(length);
+	stream.print("\"><b>Baseline CVs</b></td><td colspan=\"");
+	stream.print(length);
+	stream.println("\"><b>Current Build Stream CVs</b></td><td rowspan=\"2\"><b>Scenario Name</b></td></tr>");
+	stream.print("<tr>");
+	for (int n=0; n<2; n++) {
+		for (int c=0; c<length; c++) {
+			stream.print("<td>");
+			stream.print(configBoxes[c]);
+			stream.print("</td>");
+		}
+	}
+	stream.println("</tr>\n");
+}
+
+/*
+ * Print a scenario line in the summary table.
+ */
+private void printSummaryScenarioLine(int i, String config, ScenarioResults scenarioResults, PrintStream stream) {
+	ConfigResults configResults = scenarioResults.getConfigResults(config);
+	if (configResults == null || !configResults.isValid()) {
+		stream.print("<td>n/a</td>");
+		return;
+	}
+	String url = config + "/" + scenarioResults.getFileName()+".html";
+	double[] stats = null;
+	int dim_id = AbstractResults.SUPPORTED_DIMS[0].getId();
+	if (i==0) { // baseline results
+		List baselinePrefixes = new ArrayList();
+		baselinePrefixes.add(this.baselinePrefix);
+		stats = configResults.getStatistics(baselinePrefixes, dim_id);
+	} else {
+		stats = configResults.getStatistics(this.currentBuildPrefixes, dim_id);
+	}
+	double variation = stats[3];
+	if (variation > 10 && variation < 20) {
+		stream.print("<td bgcolor=\"yellow\">");
+	} else if (variation >= 20) {
+		stream.print("<td bgcolor=\"FF9900\">");
+	} else {
+		stream.print("<td>");
+	}
+	stream.print("<a href=\"");
+	stream.print(url);
+	stream.print("\"/>");
+	stream.print(variation);
+	stream.print("%</a></td>");
+}
+
+/*
+ * Print usage in case one of the argument of the line was incorrect.
+ * Note that calling this method ends the program run due to final System.exit()
+ */
+private void printUsage() {
+	System.out.println(
+		"Usage:\n\n" +
+		"-baseline\n" +
+		"	Build id against which to compare results.\n" +
+		"	Same as value specified for the \"build\" key in the eclipse.perf.config system property.\n\n" +
+
+		"[-baseline.prefix]\n" +
+		"	Optional.  Build id prefix used in baseline test builds and reruns.  Used to plot baseline historical data.\n" +
+		"	A common prefix used for the value of the \"build\" key in the eclipse.perf.config system property when rerunning baseline tests.\n\n" +
+
+		"-current\n" +
+		"	build id for which to generate results.  Compared to build id specified in -baseline parameter above.\n" +
+		"	Same as value specified for the \"build\" key in the eclipse.perf.config system property. \n\n" +
+
+		"[-current.prefix]\n" +
+		"	Optional.  Comma separated list of build id prefixes used in current build stream.\n" +
+		"	Used to plot current build stream historical data.  Defaults to \"N,I\".\n" +
+		"	Prefixes for values specified for the \"build\" key in the eclipse.perf.config system property. \n\n" +
+
+		"-jvm\n" +
+		"	Value specified in \"jvm\" key in eclipse.perf.config system property for current build.\n\n" +
+
+		"-config\n" +
+		"	Comma separated list of config names for which to generate results.\n" +
+		"	Same as values specified in \"config\" key in eclipse.perf.config system property.\n\n" +
+
+		"-output\n" +
+		"	Path to default output directory.\n\n" +
+
+		"[-config.properties]\n" +
+		"	Optional.  Used by scenario status table to provide the following:\n" +
+		"		alternate descriptions of config values to use in columns.\n" +
+		"	The value should be specified in the following format:\n" +
+		"	name1,description1;name2,description2;etc..\n\n" +
+
+		"[-highlight]\n" +
+		"	Optional.  Comma-separated list of build Id prefixes used to find most recent matching for each entry.\n" +
+		"	Result used to highlight points in line graphs.\n\n" +
+
+		"[-scenario.pattern]\n" +
+		"	Optional.  Scenario prefix pattern to query database.  If not specified,\n" +
+		"	default of % used in query.\n\n" +
+
+		"[-fingerprints]\n" +
+		"	Optional.  Use to generate fingerprints only.\n\n" +
+
+		"[-data]\n" +
+		"	Optional.  Generates table of scenario reference and current data with line graphs.\n\n" +
+
+		"[-print]\n" +
+		"	Optional.  Display output in the console while generating.\n"
+	);
+
+	System.exit(1);
+}
+
+/**
+ * Generate the performance results for a specified build regarding to a specific reference.
+ * This action generates following HTML files:
+ * <ul>
+ * <li>A summary table to see the variations for all the concerned scenarios</li>
+ * <li>A global php file including global scenario fingerprints and links for all concerned components results php files</li>
+ * <li>A php file for each component including scenario fingerprints and status table with links to a scenario data file</li>
+ * <li>A data HTML file for each config of each scenario included in status table</li>
+ * </ul>
+ * @see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.IApplicationContext)
+ */
+public Object start(IApplicationContext context) throws Exception {
+
+	long begin = System.currentTimeMillis();
+
+	// Parse arguments and read DB info
+	PerformanceResults performanceResults = parse(context.getArguments().get("application.args"));
+	performanceResults.read(this.configDescriptors, this.scenarioPattern, this.dataDir);
+
+	// Print whole scenarios summary
+	printSummary(performanceResults);
+
+	// Copy images and scripts to output dir
+	Bundle bundle = UiPlugin.getDefault().getBundle();
+	URL images = bundle.getEntry("images");
+	URL scripts = bundle.getEntry("scripts");
+	if (images != null) {
+		images = FileLocator.resolve(images);
+		Utils.copyImages(new File(images.getPath()), this.outputDir);
+	}
+	if (scripts != null) {
+		scripts = FileLocator.resolve(scripts);
+		Utils.copyScripts(new File(scripts.getPath()), this.outputDir);
+	}
+
+	// Print HTML pages and all linked files
+	if (this.print) {
+		System.out.println("Print performance results HTML pages:");
+		System.out.print("	- all components");
+	}
+	long start = System.currentTimeMillis();
+	printComponent(performanceResults, "global");
+	Iterator components = performanceResults.getComponents().iterator();
+	while (components.hasNext()) {
+		printComponent(performanceResults, (String) components.next());
+	}
+	if (this.print) System.out.println("done in "+(System.currentTimeMillis()-start)+"ms");
+
+	// Print the scenarios data
+	if (genData || genAll) {
+		start = System.currentTimeMillis();
+		if (this.print) System.out.print("	- all scenarios data...");
+		ScenarioData data = new ScenarioData(this.baselinePrefix, this.pointsOfInterest, this.currentBuildPrefixes, this.outputDir);
+		try {
+			data.print(performanceResults);
+		} catch (Exception ex) {
+			ex.printStackTrace();
+		}
+		if (this.print) System.out.println("done in "+(System.currentTimeMillis()-start)+"ms");
+	}
+	if (this.print) {
+		long time = System.currentTimeMillis();
+		System.out.println("End of generation: "+new SimpleDateFormat("H:mm:ss").format(new Date(time)));
+		long ms = System.currentTimeMillis() - begin;
+		int sec = (int) (ms / 1000L);
+		if ((ms - (sec*1000)) >= 500) sec++;
+		if (sec < 60) {
+			System.out.println("=> done in "+sec+" second"+(sec==1?"":"s"));
+		} else if (sec < 3600) {
+			int m = sec / 60;
+			int s = sec % 60;
+			System.out.println("=> done in "+m+" minute"+(m==1?"":"s")+" and "+s+" second"+(s==1?"":"s"));
+		} else {
+			int h = sec / 3600;
+			int m = (sec-h*3600) / 60;
+			int s = (sec-h*3600)  % 60;
+			System.out.println("=> done in "+h+" hour"+(h==1?"":"s")+", "+m+" minute"+(m==1?"":"s")+" and "+s+" second"+(s==1?"":"s"));
+		}
+	}
+	return null;
+}
+
+/* (non-Javadoc)
+ * @see org.eclipse.equinox.app.IApplication#stop()
+ */
+public void stop() {
+	// Do nothing
+}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/Messages.java b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/Messages.java
new file mode 100644
index 0000000..615d686
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/Messages.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.test.performance.ui;
+
+import java.text.MessageFormat;
+
+import org.eclipse.osgi.util.NLS;
+
+public class Messages extends NLS {
+
+	private static final String BUNDLE_NAME = "org.eclipse.test.performance.ui.messages";//$NON-NLS-1$
+
+	private Messages() {
+		// Do not instantiate
+	}
+
+	public static String standardError;
+
+	static {
+		NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+	}
+	
+	/**
+	 * Bind the given message's substitution locations with the given string values.
+	 * 
+	 * @param message the message to be manipulated
+	 * @return the manipulated String
+	 */
+	public static String bind(String message) {
+		return bind(message, null);
+	}
+	
+	/**
+	 * Bind the given message's substitution locations with the given string values.
+	 * 
+	 * @param message the message to be manipulated
+	 * @param binding the object to be inserted into the message
+	 * @return the manipulated String
+	 */
+	public static String bind(String message, Object binding) {
+		return bind(message, new Object[] {binding});
+	}
+
+	/**
+	 * Bind the given message's substitution locations with the given string values.
+	 * 
+	 * @param message the message to be manipulated
+	 * @param binding1 An object to be inserted into the message
+	 * @param binding2 A second object to be inserted into the message
+	 * @return the manipulated String
+	 */
+	public static String bind(String message, Object binding1, Object binding2) {
+		return bind(message, new Object[] {binding1, binding2});
+	}
+
+	/**
+	 * Bind the given message's substitution locations with the given string values.
+	 * 
+	 * @param message the message to be manipulated
+	 * @param bindings An array of objects to be inserted into the message
+	 * @return the manipulated String
+	 */
+	public static String bind(String message, Object[] bindings) {
+		return MessageFormat.format(message, bindings);
+	}
+
+}
diff --git a/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/RawDataTable.java b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/RawDataTable.java
new file mode 100644
index 0000000..c18861e
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/RawDataTable.java
@@ -0,0 +1,183 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.test.performance.ui;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.test.internal.performance.data.Dim;
+import org.eclipse.test.internal.performance.results.AbstractResults;
+import org.eclipse.test.internal.performance.results.BuildResults;
+import org.eclipse.test.internal.performance.results.ConfigResults;
+
+/**
+ * Class used to fill details file of scenario builds data.
+ * @see ScenarioData
+ */
+public class RawDataTable {
+
+	private ConfigResults configResults;
+	private List buildPrefixes;
+	private PrintStream stream;
+	private Dim[] dimensions = AbstractResults.SUPPORTED_DIMS;
+	private boolean debug = false;
+
+private RawDataTable(ConfigResults results, PrintStream ps) {
+	this.configResults = results;
+	this.stream = ps;
+}
+
+public RawDataTable(ConfigResults results, List prefixes, PrintStream ps) {
+	this(results, ps);
+	this.buildPrefixes = prefixes;
+}
+public RawDataTable(ConfigResults results, String baselinePrefix, PrintStream ps) {
+	this(results, ps);
+	this.buildPrefixes = new ArrayList();
+	this.buildPrefixes.add(baselinePrefix);
+}
+
+/**
+ * Print all build data to the current stream.
+ */
+public void print(){
+	stream.print("<table border=\"1\">");
+	printSummary();
+	printDetails();
+	stream.println("</table>");
+}
+
+/*
+ * Print table columns headers.
+ */
+private void printColumnHeaders() {
+	StringBuffer buffer = new StringBuffer();
+	int length = this.dimensions.length;
+	for (int i=0; i<length; i++) {
+		buffer.append("<td><b>");
+		buffer.append(this.dimensions[i].getName());
+		buffer.append("</b></td>");
+	}
+	stream.print(buffer.toString());
+}
+
+/*
+ * Print all build results in the table.
+ */
+private void printDetails() {
+	stream.print("<tr><td><b>Build ID</b></td>");
+	printColumnHeaders();
+	stream.println("</tr>");
+
+	List builds = this.configResults.getBuildsMatchingPrefixes(this.buildPrefixes);
+	Collections.reverse(builds);
+	int size = builds.size();
+	for (int i=0; i<size; i++) {
+		BuildResults buildResults = (BuildResults) builds.get(i);
+		stream.print("<tr><td>");
+		stream.print(buildResults.getName());
+		stream.print("</td>");
+		int dimLength = this.dimensions.length;
+		for (int d=0; d<dimLength; d++) {
+			int dim_id = this.dimensions[d].getId();
+			double value = buildResults.getValue(dim_id);
+			printDimTitle(this.dimensions[d].getName());
+			String displayValue = this.dimensions[d].getDisplayValue(value);
+			stream.print(displayValue);
+			if (debug) System.out.print("\t"+displayValue);
+			stream.print("</td>");
+		}
+		if (debug) System.out.println();
+		stream.println("</tr>");
+	}
+	if (debug) System.out.println("\n");
+}
+
+/*
+ * Print summary on top of the table.
+ */
+private void printSummary() {
+	stream.print("<tr><td><b>Stats</b></td>");
+	printColumnHeaders();
+	stream.println("</tr>");
+
+	int length = this.dimensions.length;
+	double[][] dimStats = new double[2][];
+	for (int i=0; i<this.dimensions.length; i++) {
+		dimStats[i] = this.configResults.getStatistics(this.buildPrefixes, this.dimensions[i].getId());
+	}
+
+	stream.print("<tr><td>#BUILDS SAMPLED</td>");
+	for (int i=0; i<length; i++) {
+		String dimName = this.dimensions[i].getName();
+		printDimTitle(dimName);
+		stream.print((int)dimStats[i][0]);
+		stream.print("</td>");
+	}
+	stream.println("</tr>");
+	stream.print("<tr><td>MEAN</td>");
+	printRowDoubles(dimStats, 1);
+	stream.println("</tr>");
+	stream.print("<tr><td>STD DEV</td>");
+	printRowDoubles(dimStats, 2);
+	stream.println("</tr>");
+	stream.print("<tr><td>COEF. VAR</td>");
+	printRowDoubles(dimStats, 3);
+	stream.println("</tr>");
+
+	// Blank line
+	stream.print("<tr>");
+	for (int i=0; i<length+1;	i++){
+		stream.print("<td>&nbsp;</td>");
+	}
+	stream.println("</tr>");
+}
+
+/*
+ * Print values in table row.
+ */
+private void printRowDoubles(double[][] stats, int idx) {
+	int length = this.dimensions.length;
+	for (int i=0; i<length; i++) {
+		double value = stats[i][idx];
+		String dimName = this.dimensions[i].getName();
+		if (idx == 3) {
+			if (value>10 && value<20) {
+				stream.print("<td bgcolor=\"yellow\" title=\"");
+			} else if (value>=20) {
+				stream.print("<td bgcolor=\"FF9900\" title=\"");
+			} else {
+				stream.print("<td title=\"");
+			}
+			stream.print(dimName);
+			stream.print("\">");
+			stream.print(value);
+			stream.print("%</td>");
+		} else {
+			printDimTitle(dimName);
+			stream.print(this.dimensions[i].getDisplayValue(value));
+			stream.print("</td>");
+		}
+	}
+}
+
+/*
+ * Print dim title inside value reference.
+ * TODO (frederic) See if this title is really necessary
+ */
+private void printDimTitle(String dimName) {
+    stream.print("<td title=\"");
+    stream.print(dimName);
+    stream.print("\">");
+}
+}
diff --git a/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/ScenarioData.java b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/ScenarioData.java
new file mode 100644
index 0000000..d41a12a
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/ScenarioData.java
@@ -0,0 +1,409 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.test.performance.ui;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.AssertionFailedError;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.ImageLoader;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.test.internal.performance.data.Dim;
+import org.eclipse.test.internal.performance.data.DimensionMessages;
+import org.eclipse.test.internal.performance.results.AbstractResults;
+import org.eclipse.test.internal.performance.results.BuildResults;
+import org.eclipse.test.internal.performance.results.ComponentResults;
+import org.eclipse.test.internal.performance.results.ConfigResults;
+import org.eclipse.test.internal.performance.results.PerformanceResults;
+import org.eclipse.test.internal.performance.results.ScenarioResults;
+
+/**
+ * Class used to print scenario all builds data.
+ */
+public class ScenarioData {
+	private String baselinePrefix = null;
+	private List pointsOfInterest;
+	private List buildIDStreamPatterns;
+	private File rootDir;
+	private static final int GRAPH_WIDTH = 600;
+	private static final int GRAPH_HEIGHT = 200;
+
+/**
+ * Summary of results for a scenario for a given build compared to a
+ * reference.
+ *
+ * @param baselinePrefix The prefix of the baseline build names
+ * @param pointsOfInterest A list of buildId's to highlight on line graphs
+ * @param buildIDPatterns
+ * @param outputDir The directory root where the files are generated
+ *
+*/
+public ScenarioData(String baselinePrefix, List pointsOfInterest, List buildIDPatterns, File outputDir) {
+	this.baselinePrefix = baselinePrefix;
+	this.pointsOfInterest = pointsOfInterest;
+	this.buildIDStreamPatterns = buildIDPatterns;
+	this.rootDir = outputDir;
+}
+
+/**
+ * Print the scenario all builds data from the given performance results.
+ * 
+ * @param performanceResults The needed information to generate scenario data
+ */
+public void print(PerformanceResults performanceResults) {
+	String[] configNames = performanceResults.getConfigNames(false/*not sorted*/);
+	String[] configBoxes = performanceResults.getConfigBoxes(false/*not sorted*/);
+	int length = configNames.length;
+	for (int i=0; i<length; i++) {
+		File outputDir = new File(this.rootDir, configNames[i]);
+		outputDir.mkdir();
+		Iterator components = performanceResults.getResults();
+		while (components.hasNext()) {
+			ComponentResults componentResults = (ComponentResults) components.next();
+			printSummary(configNames[i], configBoxes[i], componentResults, outputDir);
+			printDetails(configNames[i], configBoxes[i], componentResults, outputDir);
+		}
+	}
+}
+
+/*
+ * Print the summary file of the builds data.
+ */
+private void printSummary(String configName, String configBox, ComponentResults componentResults, File outputDir) {
+	Iterator scenarios = componentResults.getResults();
+	while (scenarios.hasNext()) {
+		List highlightedPoints = new ArrayList();
+		ScenarioResults scenarioResults = (ScenarioResults) scenarios.next();
+		ConfigResults configResults = scenarioResults.getConfigResults(configName);
+		if (configResults == null || !configResults.isValid()) continue;
+
+		// get latest points of interest matching
+		if (this.pointsOfInterest != null) {
+			Iterator buildPrefixes = this.pointsOfInterest.iterator();
+			while (buildPrefixes.hasNext()) {
+				String buildPrefix = (String) buildPrefixes.next();
+				List builds = configResults.getBuilds(buildPrefix);
+				if (buildPrefix.indexOf('*') <0 && buildPrefix.indexOf('?') < 0) {
+					if (builds.size() > 0) {
+						highlightedPoints.add(builds.get(builds.size()-1));
+					}
+				} else {
+					highlightedPoints.addAll(builds);
+				}
+			}
+		}
+
+		String scenarioFileName = scenarioResults.getFileName();
+		File outFile = new File(outputDir, scenarioFileName + ".html");
+		PrintStream stream = null;
+		try {
+			stream = new PrintStream(new BufferedOutputStream(new FileOutputStream(outFile)));
+		} catch (FileNotFoundException e) {
+			System.err.println("can't create output file" + outFile); //$NON-NLS-1$
+		}
+		if (stream == null) {
+			stream = System.out;
+		}
+		stream.println(Utils.HTML_OPEN);
+		stream.println(Utils.HTML_DEFAULT_CSS);
+
+		stream.println("<title>" + scenarioResults.getName() + "(" + configBox + ")" + "</title></head>"); //$NON-NLS-1$
+		stream.println("<h4>Scenario: " + scenarioResults.getName() + " (" + configBox + ")</h4><br>"); //$NON-NLS-1$ //$NON-NLS-2$
+
+		String failureMessage = Utils.failureMessage(configResults.getCurrentBuildDeviation(), true);
+ 		if (failureMessage != null){
+   			stream.println("<table><tr><td><b>"+failureMessage+"</td></tr></table>\n");
+ 		}
+
+ 		BuildResults currentBuildResults = configResults.getCurrentBuildResults();
+ 		String comment = currentBuildResults.getComment();
+		if (comment != null) {
+			stream.println("<p><b>Note:</b><br>\n");
+			stream.println(comment + "</p>");
+		}
+
+		// Print link to raw data.
+		String rawDataFile = scenarioFileName+"_raw.html";
+		stream.println("<br><br><b><a href=\""+rawDataFile+"\">Raw data and Stats</a></b><br><br>\n");
+		stream.println("<b>Click measurement name to view line graph of measured values over builds.</b><br><br>\n");
+
+		try {
+			// Print build result table
+			stream.println("<table border=\"1\">"); //$NON-NLS-1$
+			stream.print("<tr><td><b>Build Id</b></td>"); //$NON-NLS-1$
+			Dim[] dimensions = AbstractResults.SUPPORTED_DIMS;
+			int dimLength = dimensions.length;
+			for (int d=0; d<dimLength; d++) {
+				String dimName = dimensions[d].getName();
+				stream.print("<td><a href=\"#" + configName + "_" + scenarioFileName + "_" + dimName + "\"><b>" + dimName + "</b></a></td>");
+			}
+			stream.println("</tr>\n");
+
+			// Write build lines
+			printTableLine(stream, currentBuildResults);
+			printTableLine(stream, configResults.getBaselineBuildResults());
+
+			// Write difference line
+			printDifferenceLine(stream, configResults);
+
+			// End of table
+			stream.println("</table>");
+			stream.println("*Delta values in red and green indicate degradation > 10% and improvement > 10%,respectively.<br><br>");
+			stream.println("<br><hr>\n\n");
+
+			// print text legend.
+			stream.println("Black and yellow points plot values measured in integration and last seven nightly builds.<br>\n" + "Magenta points plot the repeated baseline measurement over time.<br>\n"
+					+ "Boxed points represent previous releases, milestone builds, current reference and current build.<br><br>\n"
+					+ "Hover over any point for build id and value.\n");
+
+			// print image maps of historical
+			for (int d=0; d<dimLength; d++) {
+				String dimName = dimensions[d].getName();
+				int dim_id = dimensions[d].getId();
+				TimeLineGraph lineGraph = getLineGraph(scenarioResults, configResults, dimensions[d], highlightedPoints, this.buildIDStreamPatterns);
+
+				File graphsDir = new File(outputDir, "graphs");
+				graphsDir.mkdir();
+				File imgFile = new File(graphsDir, scenarioFileName + "_" + dimName + ".gif");
+				saveGraph(lineGraph, imgFile);
+				stream.println("<br><a name=\"" + configName + "_" + scenarioFileName + "_" + dimName + "\"></a>");
+				stream.println("<br><b>" + dimName + "</b><br>");
+				stream.println(DimensionMessages.getDescription(dim_id) + "<br><br>\n");
+				stream.print("<img src=\"graphs/");
+				stream.print(imgFile.getName());
+				stream.print("\" usemap=\"#" + lineGraph.fTitle + "\">");
+				stream.print("<map name=\"" + lineGraph.fTitle + "\">");
+				stream.print(lineGraph.getAreas());
+				stream.println("</map>");
+			}
+			stream.println("<br><br></body>");
+			stream.println(Utils.HTML_CLOSE);
+			if (stream != System.out)
+				stream.close();
+
+		} catch (AssertionFailedError e) {
+			e.printStackTrace();
+			continue;
+		}
+	}
+}
+
+/*
+ * Print the data for a build results.
+ */
+private void printTableLine(PrintStream stream, BuildResults buildResults) {
+	stream.print("<tr><td>");
+	stream.print(buildResults.getName());
+	if (buildResults.isBaseline()) stream.print(" (reference)");
+	stream.print("</td>");
+	Dim[] dimensions = AbstractResults.SUPPORTED_DIMS;
+	int dimLength = dimensions.length;
+	for (int d=0; d<dimLength; d++) {
+		int dim_id = dimensions[d].getId();
+		double stddev = buildResults.getDeviation(dim_id);
+		String displayValue = dimensions[d].getDisplayValue(buildResults.getValue(dim_id));
+		stream.print("<td>");
+		stream.print(displayValue);
+		if (stddev < 0) {
+			stream.println(" [n/a]");
+		} else if (stddev > 0) {
+			stream.print(" [");
+			stream.print(dimensions[d].getDisplayValue(stddev));
+			stream.print("]");
+		}
+		stream.print( "</td>");
+	}
+	stream.println("</tr>");
+}
+
+/*
+ * Print the line showing the difference between current and baseline builds.
+ */
+private void printDifferenceLine(PrintStream stream, ConfigResults configResults) {
+	stream.print("<tr><td>*Delta</td>");
+	Dim[] dimensions = AbstractResults.SUPPORTED_DIMS;
+	int dimLength = dimensions.length;
+	for (int d=0; d<dimLength; d++) {
+		Dim currentDim = dimensions[d];
+		int dim_id = currentDim.getId();
+		BuildResults currentBuild = configResults.getCurrentBuildResults();
+		BuildResults baselineBuild = configResults.getBaselineBuildResults();
+
+		double baselineValue = baselineBuild.getValue(dim_id);
+		double diffValue = currentBuild.getValue(dim_id) - baselineValue;
+		double diffPercentage =  baselineValue == 0 ? 0 : Math.round(diffValue / baselineValue * 1000) / 10.0;
+		String diffDisplayValue = currentDim.getDisplayValue(diffValue);
+		// green
+		String fontColor = "";
+		if ((diffPercentage < -10 && !currentDim.largerIsBetter()) || (diffPercentage > 10 && currentDim.largerIsBetter()))
+			fontColor = "#006600";
+		if ((diffPercentage < -10 && currentDim.largerIsBetter()) || (diffPercentage > 10 && !currentDim.largerIsBetter()))
+			fontColor = "#FF0000";
+
+		diffPercentage = Math.abs(diffPercentage);
+		String percentage = (diffPercentage == 0) ? "" : "<br>" + diffPercentage + " %";
+
+		if (diffPercentage > 10 || diffPercentage < -10) {
+			stream.print("<td><FONT COLOR=\"" + fontColor + "\"><b>" + diffDisplayValue + percentage + "</b></FONT></td>");
+		} else {
+			stream.print("<td>" + diffDisplayValue + percentage + "</td>");
+		}
+	}
+	stream.print("</tr></font>");
+}
+
+/*
+ * Returns a LineGraph object representing measurements for a scenario over builds.
+ */
+private TimeLineGraph getLineGraph(ScenarioResults scenarioResults, ConfigResults configResults, Dim dim, List highlightedPoints, List currentBuildIdPrefixes) {
+	Display display = Display.getDefault();
+
+	Color black = display.getSystemColor(SWT.COLOR_BLACK);
+	Color yellow = display.getSystemColor(SWT.COLOR_DARK_YELLOW);
+	Color magenta = display.getSystemColor(SWT.COLOR_MAGENTA);
+
+	String scenarioName = scenarioResults.getName();
+	TimeLineGraph graph = new TimeLineGraph(scenarioName + ": " + dim.getName(), dim);
+	String baseline = configResults.getBaselineBuildName();
+	String current = configResults.getCurrentBuildName();
+
+	Iterator builds = configResults.getResults();
+	List lastSevenNightlyBuilds = configResults.lastNightlyBuildNames(7);
+	buildLoop: while (builds.hasNext()) {
+		BuildResults buildResults = (BuildResults) builds.next();
+		String buildID = buildResults.getName();
+		int underscoreIndex = buildID.indexOf('_');
+		String label = (underscoreIndex != -1 && (buildID.equals(baseline) || buildID.equals(current))) ? buildID.substring(0, underscoreIndex) : buildID;
+
+		double value = buildResults.getValue(dim.getId());
+
+		if (buildID.equals(current)) {
+			Color color = black;
+			if (buildID.startsWith("N"))
+				color = yellow;
+
+			graph.addItem("main", label, dim.getDisplayValue(value), value, color, true, Utils.getDateFromBuildID(buildID), true);
+			continue;
+		}
+		if (highlightedPoints.contains(buildID)) {
+			graph.addItem("main", label, dim.getDisplayValue(value), value, black, false, Utils.getDateFromBuildID(buildID, false), true);
+			continue;
+		}
+		if (buildID.charAt(0) == 'N') {
+			if (lastSevenNightlyBuilds.contains(buildID)) {
+				graph.addItem("main", buildID, dim.getDisplayValue(value), value, yellow, false, Utils.getDateFromBuildID(buildID), false);
+			}
+			continue;
+		}
+		for (int i=0;i<currentBuildIdPrefixes.size();i++){
+			if (buildID.startsWith(currentBuildIdPrefixes.get(i).toString())) {
+				graph.addItem("main", buildID, dim.getDisplayValue(value), value, black, false, Utils.getDateFromBuildID(buildID), false);
+				continue buildLoop;
+			}
+		}
+		if (buildID.equals(baseline)) {
+			boolean drawBaseline = (baselinePrefix != null) ? false : true;
+			graph.addItem("reference", label, dim.getDisplayValue(value), value, magenta, true, Utils.getDateFromBuildID(buildID, true), true, drawBaseline);
+			continue;
+		}
+		if (baselinePrefix != null) {
+			if (buildID.startsWith(baselinePrefix) && !buildID.equals(baseline) && Utils.getDateFromBuildID(buildID, true) <= Utils.getDateFromBuildID(baseline, true)) {
+				graph.addItem("reference", label, dim.getDisplayValue(value), value, magenta, false, Utils.getDateFromBuildID(buildID, true), false);
+				continue;
+			}
+		}
+	}
+	return graph;
+}
+
+/*
+ * Print details file of the scenario builds data.
+ */
+private void printDetails(String configName, String configBox, ComponentResults componentResults, File outputDir) {
+	Iterator scenarios = componentResults.getResults();
+	while (scenarios.hasNext()) {
+		ScenarioResults scenarioResults = (ScenarioResults) scenarios.next();
+		ConfigResults configResults = scenarioResults.getConfigResults(configName);
+		if (configResults == null || !configResults.isValid()) continue;
+		String scenarioName= scenarioResults.getName();
+		String scenarioFileName = scenarioResults.getFileName();
+		File outFile = new File(outputDir, scenarioFileName + "_raw.html");
+		PrintStream stream = null;
+		try {
+			stream = new PrintStream(new BufferedOutputStream(new FileOutputStream(outFile)));
+		} catch (FileNotFoundException e) {
+			System.err.println("can't create output file" + outFile); //$NON-NLS-1$
+		}
+		if (stream == null) stream = System.out;
+		RawDataTable currentResultsTable = new RawDataTable(configResults, this.buildIDStreamPatterns, stream);
+		RawDataTable baselineResultsTable = new RawDataTable(configResults, this.baselinePrefix, stream);
+		stream.println(Utils.HTML_OPEN);
+		stream.println(Utils.HTML_DEFAULT_CSS);
+		stream.println("<title>" + scenarioName + "(" + configBox + ")" + " - Details</title></head>"); //$NON-NLS-1$
+		stream.println("<h4>Scenario: " + scenarioName + " (" + configBox + ")</h4>"); //$NON-NLS-1$
+		stream.println("<a href=\""+scenarioFileName+".html\">VIEW GRAPH</a><br><br>"); //$NON-NLS-1$
+		stream.println("<table><td><b>Current Stream Test Runs</b></td><td><b>Baseline Test Runs</b></td></tr>\n");
+		stream.println("<tr valign=\"top\">");
+		stream.print("<td>");
+		currentResultsTable.print();
+		stream.println("</td>");
+		stream.print("<td>");
+		baselineResultsTable.print();
+		stream.println("</td>");
+		stream.println("</tr>");
+		stream.println("</table>");
+		stream.close();
+	}
+}
+
+/*
+ * Prints a LineGraph object as a gif file.
+ */
+private void saveGraph(LineGraph p, File outputFile) {
+	Image image = new Image(Display.getDefault(), GRAPH_WIDTH, GRAPH_HEIGHT);
+	p.paint(image);
+
+	/* Downscale to 8 bit depth palette to save to gif */
+	ImageData data = Utils.downSample(image);
+	ImageLoader il = new ImageLoader();
+	il.data = new ImageData[] { data };
+	OutputStream out = null;
+	try {
+		out = new BufferedOutputStream(new FileOutputStream(outputFile));
+		il.save(out, SWT.IMAGE_GIF);
+
+	} catch (FileNotFoundException e) {
+		e.printStackTrace();
+	} finally {
+		image.dispose();
+		if (out != null) {
+			try {
+				out.close();
+			} catch (IOException e1) {
+				// silently ignored
+			}
+		}
+	}
+}
+}
diff --git a/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/ScenarioStatusTable.java b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/ScenarioStatusTable.java
new file mode 100644
index 0000000..3ddf979
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/ScenarioStatusTable.java
@@ -0,0 +1,216 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.test.performance.ui;
+
+import java.io.PrintStream;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.eclipse.test.internal.performance.results.BuildResults;
+import org.eclipse.test.internal.performance.results.ConfigResults;
+import org.eclipse.test.internal.performance.results.PerformanceResults;
+import org.eclipse.test.internal.performance.results.ScenarioResults;
+
+/**
+ * Class used to print a scenario status table.
+ */
+public class ScenarioStatusTable {
+
+	private String component;
+	private PrintStream stream;
+	private int jsIdCount;
+
+/**
+ * Creates an HTML table of red x/green check for a scenario for each
+ * configuration.
+ */
+public ScenarioStatusTable(String  name, PrintStream stream) {
+    this.component = name;
+    this.stream = stream;
+}
+
+/**
+ * Prints the HTML representation of scenario status table into the given stream.
+ */
+public void print(PerformanceResults performanceResults) {
+	printTitle();
+	List scenarios = performanceResults.getComponentScenarios(this.component);
+	String baselineName = performanceResults.getBaselineName();
+	int size = scenarios.size();
+	printColumnsTitle(size, performanceResults);
+	this.jsIdCount = 0;
+	for (int i=0; i<size; i++) {
+		ScenarioResults scenarioResults = (ScenarioResults) scenarios.get(i);
+		this.stream.println("<tr>");
+		this.stream.print("<td>");
+		boolean hasSummary = scenarioResults.hasSummary();
+		if (hasSummary) this.stream.print("<b>");
+		String scenarioBaseline = scenarioResults.getBaselineBuildName();
+		boolean hasBaseline = baselineName.equals(scenarioBaseline);
+		if (!hasBaseline) {
+			this.stream.print("*");
+			this.stream.print(scenarioResults.getShortName());
+			this.stream.print(" <small>(vs.&nbsp;");
+			this.stream.print(scenarioBaseline);
+			this.stream.print(")</small>");
+		} else {
+			this.stream.print(scenarioResults.getShortName());
+		}
+		if (hasSummary) this.stream.print("</b>");
+		this.stream.println();
+		String[] configs = performanceResults.getConfigNames(true/*sort*/);
+		int length = configs.length;
+		for (int j=0; j<length; j++) {
+			printConfigStats(scenarioResults, configs[j]);
+		}
+	}
+	this.stream.println("</table>");
+}
+
+/*
+ * Print the table columns title.
+ */
+private void printColumnsTitle(int size, PerformanceResults performanceResults) {
+	this.stream.println("<table border=\"1\">");
+	this.stream.println("<tr>");
+	this.stream.print("<td><h4>All ");
+	this.stream.print(size);
+	this.stream.println(" scenarios</h4></td>");
+	String[] configNames = performanceResults.getConfigNames(true/*sort*/);
+	String[] configBoxes = performanceResults.getConfigBoxes(true/*sort*/);
+	int length = configNames.length;
+	for (int i=0; i<length; i++) {
+		String columnTitle = configNames[i];
+		String boxName = configBoxes[i];
+		int idx = boxName.indexOf('(');
+		if (idx < 0) {
+			columnTitle = boxName;
+		} else {
+			// first line
+			StringTokenizer tokenizer = new StringTokenizer(boxName.substring(0, idx).trim(), " ");
+			StringBuffer buffer = new StringBuffer(tokenizer.nextToken());
+			while (tokenizer.hasMoreTokens()) {
+				buffer.append("&nbsp;");
+				buffer.append(tokenizer.nextToken());
+			}
+			buffer.append(' ');
+			// second line
+			tokenizer = new StringTokenizer(boxName.substring(idx).trim(), " ");
+			buffer.append(tokenizer.nextToken());
+			while (tokenizer.hasMoreTokens()) {
+				buffer.append("&nbsp;");
+				buffer.append(tokenizer.nextToken());
+			}
+			columnTitle = buffer.toString();
+		}
+		this.stream.print("<td><h5>");
+		this.stream.print(columnTitle);
+		this.stream.println("</h5>");
+	}
+}
+
+/*
+ * Print the scenario statistics value for the given configuration.
+ */
+private void printConfigStats(ScenarioResults scenarioResults, String config) {
+	ConfigResults configResults = scenarioResults.getConfigResults(config);
+	if (configResults == null || !configResults.isValid()) {
+		this.stream.print("<td>n/a</td>");
+		return;
+	}
+	BuildResults currentBuildResults = configResults.getCurrentBuildResults();
+	String failure = currentBuildResults.getFailure();
+	double[] deviation = configResults.getCurrentBuildDeviation();
+	int confidence = Utils.confidenceLevel(deviation);
+	boolean hasFailure = failure != null;
+	String comment = currentBuildResults.getComment();
+	String image = Utils.getImage(confidence, hasFailure, comment != null);
+	this.stream.print("<td><a ");
+	if (!hasFailure|| (confidence & Utils.NAN) != 0 || failure.length() == 0){
+		// write deviation with error in table when test pass
+		this.stream.print("href=\"");
+		this.stream.print(configResults.getName());
+		this.stream.print('/');
+		this.stream.print(scenarioResults.getFileName());
+		this.stream.println(".html\">");
+		this.stream.print("<img hspace=\"10\" border=\"0\" src=\"");
+		this.stream.print(image);
+		this.stream.println("\"/></a>");
+	} else {
+		// create message with tooltip text including deviation with error plus failure message
+		this.jsIdCount+=1;
+		this.stream.print("class=\"tooltipSource\" onMouseover=\"show_element('toolTip");
+		this.stream.print(jsIdCount);
+		this.stream.print("')\" onMouseout=\"hide_element('toolTip");
+		this.stream.print(jsIdCount);
+		this.stream.print("')\" \nhref=\"");
+		this.stream.print(configResults.getName());
+		this.stream.print('/');
+		this.stream.print(scenarioResults.getFileName());
+		this.stream.println(".html\">");
+		this.stream.print("<img hspace=\"10\" border=\"0\" src=\"");
+		this.stream.print(image);
+		this.stream.println("\"/>");
+		this.stream.print("<span class=\"hidden_tooltip\" id=\"toolTip");
+		this.stream.print(jsIdCount);
+		this.stream.print("\">");
+		this.stream.print(failure);
+		this.stream.println("</span></a>");
+	}
+	String result = Utils.failureMessage(deviation, false);
+	this.stream.println(result);
+}
+
+/*
+ * Print the status table explanationtitle.
+ */
+private void printTitle() {
+	this.stream.println("<br><h4>Scenario Status</h4>");
+	this.stream.println("The following table gives a complete but compact view of performance results for the component.<br>");
+	this.stream.println("Each line of the table shows the results for one scenario on all machines.<br><br>");
+	this.stream.println("The name of the scenario is in <b>bold</b> when its results are also displayed in the fingerprints<br>");
+	this.stream.println("and starts with an '*' when the scenario has no results in the last baseline run.<br><br>");
+	this.stream.println("Here are information displayed for each test (ie. in each cell):");
+	this.stream.println("<ul>");
+	this.stream.println("<li>an icon showing whether the test fails or passes and whether it's reliable or not.<br>");
+	this.stream.println("The legend for this icon is:");
+	this.stream.println("<ul>");
+	this.stream.print("<li>Green (<img src=\"");
+	this.stream.print(Utils.OK_IMAGE);
+	this.stream.print("\">): mark a <b>successful result</b>, which means this test has neither significant performance regression nor significant standard error</li>");
+	this.stream.print("<li>Red (<img src=\"");
+	this.stream.print(Utils.FAIL_IMAGE);
+	this.stream.println("\">): mark a <b>failing result</b>, which means this test shows a significant performance regression (more than 10%)</li>");
+	this.stream.print("<li>Gray (<img src=\"");
+	this.stream.print(Utils.FAIL_IMAGE_EXPLAINED);
+	this.stream.println("\">): mark a <b>failing result</b> (see above) with a comment explaining this degradation.</li>");
+	this.stream.print("<li>Yellow (<img src=\"");
+	this.stream.print(Utils.FAIL_IMAGE_WARN);
+	this.stream.print("\"> or <img src=\"");
+	this.stream.print(Utils.OK_IMAGE_WARN);
+	this.stream.print("\">): mark a <b>failing or successful result</b> with a significant standard error (more than ");
+	this.stream.print(Utils.STANDARD_ERROR_THRESHOLD_STRING);
+	this.stream.println(")</li>");
+	this.stream.print("<li>Black (<img src=\"");
+	this.stream.print(Utils.UNKNOWN_IMAGE);
+	this.stream.print("\">): mark an <b>undefined result</b>, which means that deviation on this test is not a number (<code>NaN</code>) or is infinite (happens when the reference value is equals to 0!)</li>");
+	this.stream.println("<li>\"n/a\": mark a test for with <b>no</b> performance results</li>");
+	this.stream.println("</ul></li>");
+	this.stream.println("<li>the value of the deviation from the baseline as a percentage (ie. formula is: <code>(build_test_time - baseline_test_time) / baseline_test_time</code>)</li>");
+	this.stream.println("<li>the value of the standard error of this deviation as a percentage (ie. formula is: <code>sqrt(build_test_stddev^2 / N + baseline_test_stddev^2 / N) / baseline_test_time</code>)<br>");
+	this.stream.println("When test only has one measure, the standard error cannot be computed and is replaced with a '<font color=\"#CCCC00\">[n/a]</font>'.</li>");
+	this.stream.println("</ul>");
+	this.stream.println("<u>Hints</u>:<ul>");
+	this.stream.println("<li>fly over image of failing tests to see the complete error message</li>");
+	this.stream.println("<li>to look at the complete and detailed test results, click on its image</li>");
+	this.stream.println("</ul>");
+}
+}
diff --git a/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/TimeLineGraph.java b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/TimeLineGraph.java
new file mode 100644
index 0000000..514eec1
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/TimeLineGraph.java
@@ -0,0 +1,299 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.test.performance.ui;
+
+import java.util.*;
+
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.test.internal.performance.data.Dim;
+
+public class TimeLineGraph extends LineGraph{
+    
+    Hashtable fItemGroups;
+     
+    public TimeLineGraph (String title, Dim dim) {
+        super(title, dim);
+        fItemGroups=new Hashtable();
+    }
+
+    public void paint(Image im) {
+        
+        Rectangle bounds= im.getBounds();
+        
+        GC g= new GC(im);
+
+        Point ee= g.stringExtent(fTitle);
+        int titleHeight= ee.y;
+
+        double maxItem= getMaxItem();
+        double minItem= getMinItem();
+        
+        int max= (int) (Math.ceil(maxItem * (maxItem < 0 ? 0.8 : 1.2)));
+        int min= (int) (Math.floor(minItem * (minItem < 0 ? 1.2 : 0.8)));
+
+        String smin= fDimension.getDisplayValue(min);
+        Point emin= g.stringExtent(smin);
+        
+        String smax= fDimension.getDisplayValue(max);
+        Point emax= g.stringExtent(smax);
+        
+        int labelWidth= Math.max(emin.x, emax.x) + 2;
+                
+        int top= PADDING;
+        int bottom= bounds.height - titleHeight - PADDING;
+        int left= PADDING + labelWidth;
+
+        //getMostRecent
+        TimeLineGraphItem lastItem= getMostRecent(fItemGroups);
+        int right=bounds.width - PADDING/2;
+        if (lastItem!=null)
+        	right= bounds.width - lastItem.getSize(g).x - PADDING/2;
+             
+        // draw the max and min values
+        g.drawString(smin, PADDING/2+labelWidth-emin.x, bottom-titleHeight, true);
+        g.drawString(smax, PADDING/2+labelWidth-emax.x, top, true);
+        g.drawString("TIME (not drawn to scale)", (right-left)/3+PADDING+titleHeight,bottom-PADDING+(titleHeight*2), true);
+    
+        // draw the vertical and horizontal lines
+        g.drawLine(left, top, left, bottom);
+        g.drawLine(left, bottom, right, bottom);
+
+        Color oldbg= g.getBackground();
+        Color oldfg= g.getForeground();
+
+        setCoordinates(right-left,left,bottom-top,bottom,max-min);
+        
+        Enumeration _enum=fItemGroups.elements();
+        Comparator comparator=new TimeLineGraphItem.GraphItemComparator();
+ 
+        while (_enum.hasMoreElements()) {
+ 			List items = (List) _enum.nextElement();
+			Object[] fItemsArray=items.toArray();
+			Arrays.sort(fItemsArray,comparator);
+			int lastx = 0;
+			int lasty = 0;
+
+			int n = fItemsArray.length;
+
+			for (int i = 0; i < n; i++) {
+				TimeLineGraphItem thisItem = (TimeLineGraphItem) fItemsArray[i];
+
+				int yposition = thisItem.y;
+				int xposition = thisItem.x;
+				g.setLineWidth(1);
+				
+				g.setBackground(thisItem.color);
+				g.setForeground(thisItem.color);
+
+				if (thisItem.drawAsBaseline){
+					g.setLineWidth(0);					
+					g.drawLine(xposition, yposition,right,yposition);
+					g.drawLine(left,yposition,xposition, yposition);
+    		    }
+    		    
+				if (i > 0) // don't draw for first segment
+					g.drawLine(lastx, lasty, xposition, yposition);
+
+				g.setBackground(thisItem.color);
+				g.setForeground(thisItem.color);
+			//	g.fillOval(xposition - 2, yposition - 2, 6, 6);
+				g.fillRectangle(xposition - 2, yposition - 2, 5, 5);
+
+				if (thisItem.isSpecial)
+					g.drawRectangle(xposition -4, yposition - 4, 8, 8);
+		
+				if (fAreaBuffer == null)
+					fAreaBuffer = new StringBuffer();
+
+				fAreaBuffer.append("\r<area shape=\"circle\" coords=\""
+						+ (xposition - 2) + ',' + (yposition - 2) + ',' + 5
+						+ " alt=\"" + thisItem.title + ": "
+						+ thisItem.description + "\"" + " title=\""
+						+ thisItem.title + ": " + thisItem.description + "\">");
+
+				int shift;
+				if (i > 0 && yposition < lasty)
+					shift = 3; // below dot
+				else
+					shift = -(2 * titleHeight + 3); // above dot
+				if (thisItem.displayDescription) {
+					g.drawString(thisItem.title, xposition + 2, yposition
+							+ shift, true);
+					g.drawString(thisItem.description, xposition + 2, yposition
+							+ shift + titleHeight, true);
+				}
+				g.setBackground(oldbg);
+				g.setForeground(oldfg);
+
+				lastx = xposition;
+				lasty = yposition;
+			}
+		}
+        
+        g.dispose();
+    }
+    
+    public void addItem(String groupName,String name, String description, double value, Color col, boolean display, long timestamp) {
+    	addItem(groupName, name, description, value, col, display,	timestamp,false);
+    }
+
+    public void addItem(String groupName,String name, String description, double value, Color col, boolean display, long timestamp,boolean isSpecial) {
+ 		addItem(groupName, name,description, value, col, display,
+ 				timestamp,isSpecial,false);
+	}
+
+    public void addItem(String groupName,String name, String description, double value, Color col, boolean display, long timestamp,boolean isSpecial,boolean drawBaseline) {
+      	List items = (List) fItemGroups.get(groupName);
+  		if (fItemGroups.get(groupName) == null) {
+  			items=new ArrayList();
+  			fItemGroups.put(groupName, items);
+  		}
+  		items.add(new TimeLineGraphItem(name, description, value, col, display,
+  				timestamp,isSpecial,drawBaseline));
+    }
+     
+    public double getMaxItem() {
+    	Enumeration _enum=fItemGroups.elements();
+        double maxItem= 0;
+    	while (_enum.hasMoreElements()) {
+			List items = (List) _enum.nextElement();
+			for (int i = 0; i < items.size(); i++) {
+				TimeLineGraphItem graphItem = (TimeLineGraphItem) items.get(i);
+				if (graphItem.value > maxItem)
+					maxItem = graphItem.value;
+			}
+		}
+        if (maxItem == 0)
+            return 1;
+        return maxItem;
+    }
+
+    public double getMinItem() {
+       	Enumeration _enum = fItemGroups.elements();
+		double minItem = getMaxItem();
+
+		while (_enum.hasMoreElements()) {
+			List items = (List) _enum.nextElement();
+			for (int i = 0; i < items.size(); i++) {
+				TimeLineGraphItem graphItem = (TimeLineGraphItem) items.get(i);
+				if (graphItem.value < minItem)
+					minItem = graphItem.value;
+			}
+		}
+        if (minItem == 0)
+            return -1;
+        return minItem;
+    }
+    
+    private TimeLineGraphItem getMostRecent(Hashtable lineGraphGroups) {
+		Enumeration _enum = lineGraphGroups.elements();
+		long mostRecentTimestamp = 0;
+		TimeLineGraphItem mostRecentItem = null;
+
+		while (_enum.hasMoreElements()) {
+			List items = (List) _enum.nextElement();
+			for (int i = 0; i < items.size(); i++) {
+				if (items.size() == 1)
+					return (TimeLineGraphItem) items.get(i);
+				else {
+					TimeLineGraphItem graphItem = (TimeLineGraphItem) items.get(i);
+					if (graphItem.timestamp > mostRecentTimestamp) {
+						mostRecentTimestamp = graphItem.timestamp;
+						mostRecentItem = (TimeLineGraphItem) items.get(i);
+					}
+				}
+			}
+		}
+		return mostRecentItem;
+	}
+      
+    private void setCoordinates(int width, int xOffset, int height, int yOffset, int yValueRange){
+ 
+        List mainGroup=(ArrayList)fItemGroups.get("main");
+        List referenceGroup=(ArrayList)fItemGroups.get("reference");
+        
+        Comparator comparator=new TimeLineGraphItem.GraphItemComparator();
+ 
+ 		Object[] fItemsArray=mainGroup.toArray();
+		Arrays.sort(fItemsArray,comparator);
+
+		int n = mainGroup.size();
+		int xIncrement=width/n;
+		double max=getMaxItem()*1.2;
+//		double min=getMinItem()*0.8;
+
+		for (int i = 0; i < n; i++) {
+			TimeLineGraphItem thisItem = (TimeLineGraphItem) fItemsArray[i];
+			thisItem.setX(xOffset + (i * xIncrement));
+			thisItem.setY((int)(PADDING+((max-thisItem.value) * (height)/(yValueRange))));
+			
+			}
+		
+		if (referenceGroup==null)
+			return;
+		
+		n = referenceGroup.size();
+		for (int i = 0; i < n; i++) {
+			 TimeLineGraphItem thisItem = (TimeLineGraphItem) referenceGroup.get(i);
+			 if (thisItem.timestamp==-1)
+				 thisItem.setX(xOffset + (i * (width/n)));
+			 else
+				 setRelativeXPosition(thisItem,mainGroup);
+
+			 thisItem.setY((int)(PADDING+((max-thisItem.value) * (height)/(yValueRange))));
+
+		}
+    }
+	
+
+	private void setRelativeXPosition (TimeLineGraphItem thisItem, List items){
+			Comparator comparator=new TimeLineGraphItem.GraphItemComparator();
+			Object[] fItemsArray=items.toArray();
+			Arrays.sort(fItemsArray,comparator);
+			
+			TimeLineGraphItem closestPrecedingItem=null;
+			long minimumTimeDiffPreceding=thisItem.timestamp;
+			
+			TimeLineGraphItem closestFollowingItem=null;
+			long minimumTimeDiffFollowing=thisItem.timestamp;
+		
+			for (int i=0;i<fItemsArray.length;i++){
+				TimeLineGraphItem anItem=(TimeLineGraphItem)fItemsArray[i];
+				long timeDiff=thisItem.timestamp-anItem.timestamp;
+
+				 if (timeDiff>0&&timeDiff<minimumTimeDiffPreceding){
+					 closestPrecedingItem=anItem;
+				 	minimumTimeDiffPreceding=thisItem.timestamp-anItem.timestamp;
+				 } 
+				 if (timeDiff<=0&&Math.abs(timeDiff)<=minimumTimeDiffFollowing){
+					 closestFollowingItem=anItem;
+					 minimumTimeDiffFollowing=thisItem.timestamp-anItem.timestamp;
+				 }
+			}
+			if (closestFollowingItem==null && closestPrecedingItem!=null)
+				thisItem.setX(closestPrecedingItem.x);
+
+			else if (closestFollowingItem!=null && closestPrecedingItem==null)
+				thisItem.setX(closestFollowingItem.x);
+			else{	
+				long timeRange=closestFollowingItem.timestamp-closestPrecedingItem.timestamp;
+			
+				int xRange=closestFollowingItem.x-closestPrecedingItem.x;
+				double increments=(xRange*1.0)/timeRange;
+			
+				thisItem.setX((int)(Math.round((thisItem.timestamp-closestPrecedingItem.timestamp)*increments)+closestPrecedingItem.x));
+			}
+	}
+}
diff --git a/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/TimeLineGraphItem.java b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/TimeLineGraphItem.java
new file mode 100644
index 0000000..cd24861
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/TimeLineGraphItem.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.test.performance.ui;
+
+import java.util.Comparator;
+
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+
+public class TimeLineGraphItem {
+
+
+    String title;
+    String description=null;
+    double value;
+    Color color;
+    boolean displayDescription=false;
+    long timestamp;
+    boolean isSpecial=false;
+    boolean drawAsBaseline=false;
+    int x;
+    int y;
+       
+    TimeLineGraphItem(String title, String description,double value,Color color,boolean display, long timestamp, boolean isSpecial,boolean isBaseline) {
+    	this(title, description, value, color,display, timestamp,isSpecial);
+    	this.drawAsBaseline=isBaseline;
+    }
+    
+    TimeLineGraphItem(String title, String description,double value,Color color,boolean display, long timestamp, boolean isSpecial) {
+    	this(title, description, value, color,display, timestamp);
+    	this.isSpecial=isSpecial;
+    }
+    
+    TimeLineGraphItem(String title, String description,double value,Color color,boolean display, long timestamp) {
+    	this(title, description, value, color,timestamp);
+    	this.displayDescription=display;
+    }
+
+    TimeLineGraphItem(String title, String description, double value, Color color,long timestamp) {
+        this.title= title;
+        this.value= value;
+        this.color= color;
+        this.description= description;
+        this.timestamp=timestamp;
+    }
+    
+    Point getSize(GC g) {
+        Point e1= g.stringExtent(description);
+        Point e2= g.stringExtent(title);
+        return new Point(Math.max(e1.x, e2.x), e1.y+e2.y);
+    }
+
+    public static class GraphItemComparator implements Comparator{
+		public int compare(Object o1, Object o2) {
+			long ts1=((TimeLineGraphItem)o1).timestamp;
+			long ts2=((TimeLineGraphItem)o2).timestamp;
+				
+			if (ts1>ts2)
+				return 1;
+			if (ts1<ts2)
+				return -1;
+
+			return 0;
+		}
+    }
+
+	public int getX() {
+		return x;
+	}
+
+	public void setX(int x) {
+		this.x = x;
+	}
+
+	public int getY() {
+		return y;
+	}
+
+	public void setY(int y) {
+		this.y = y;
+	}
+
+
+}
diff --git a/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/UiPlugin.java b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/UiPlugin.java
new file mode 100644
index 0000000..29f52be
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/UiPlugin.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.test.performance.ui;
+
+import org.eclipse.core.runtime.Plugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The main plugin class to be used in the desktop.
+ */
+public class UiPlugin extends Plugin {
+	//The shared instance.
+	private static UiPlugin plugin;
+	
+	/**
+	 * The constructor.
+	 */
+	public UiPlugin() {
+		super();
+		plugin = this;
+	}
+
+	/**
+	 * This method is called upon plug-in activation
+	 */
+	public void start(BundleContext context) throws Exception {
+		super.start(context);
+	}
+
+	/**
+	 * This method is called when the plug-in is stopped
+	 */
+	public void stop(BundleContext context) throws Exception {
+		super.stop(context);
+		plugin = null;
+	}
+
+	/**
+	 * Returns the shared instance.
+	 */
+	public static UiPlugin getDefault() {
+		return plugin;
+	}
+
+}
diff --git a/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/Utils.java b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/Utils.java
new file mode 100644
index 0000000..795b63e
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/Utils.java
@@ -0,0 +1,387 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.test.performance.ui;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.HashMap;
+
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.PaletteData;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.test.internal.performance.PerformanceTestPlugin;
+import org.eclipse.test.internal.performance.db.Variations;
+
+
+public class Utils {
+
+	public final static double STANDARD_ERROR_THRESHOLD = 0.03; // 3%
+	static final NumberFormat PERCENT_FORMAT = NumberFormat.getPercentInstance();
+	static {
+		PERCENT_FORMAT.setMaximumFractionDigits(1);
+	}
+	static final DecimalFormat DEVIATION_FORMAT = (DecimalFormat) NumberFormat.getPercentInstance();
+	static {
+		DEVIATION_FORMAT.setMaximumFractionDigits(1);
+		DEVIATION_FORMAT.setMinimumFractionDigits(1);
+		DEVIATION_FORMAT.setPositivePrefix("+");
+		DEVIATION_FORMAT.setNegativePrefix("- ");
+	}
+	static final DecimalFormat STDERR_FORMAT = (DecimalFormat) NumberFormat.getNumberInstance();
+	static {
+		STDERR_FORMAT.setMaximumFractionDigits(1);
+		STDERR_FORMAT.setMinimumFractionDigits(1);
+		STDERR_FORMAT.setMultiplier(100);
+	}
+	public final static String STANDARD_ERROR_THRESHOLD_STRING = PERCENT_FORMAT.format(STANDARD_ERROR_THRESHOLD);
+	public final static String UNKNOWN_IMAGE="Unknown.gif";
+	public final static String OK_IMAGE="OK.gif";
+	public final static String OK_IMAGE_WARN="OK_caution.gif";
+	public final static String FAIL_IMAGE="FAIL.gif";
+	public final static String FAIL_IMAGE_WARN="FAIL_caution.gif";
+	public final static String FAIL_IMAGE_EXPLAINED="FAIL_greyed.gif";
+	public final static int OK = 0;
+	public final static int NAN = 0x1;
+	public final static int ERR = 0x2;
+
+	/**
+	 * Return &lt;html&gt;&lt;head&gt;&lt;meta http-equiv="Content-Type"
+	 *         content="text/html; charset=iso-8859-1"&gt;
+	 */
+	public static String HTML_OPEN = "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">";
+
+	/**
+	 * Return "&lt;/html&gt;".
+	 */
+	public static String HTML_CLOSE = "</html>";
+
+	/**
+	 * Default style-sheet used on eclipse.org
+	 */
+	public static String HTML_DEFAULT_CSS = "<style type=\"text/css\">" + "p, table, td, th {  font-family: arial, helvetica, geneva; font-size: 10pt}\n"
+			+ "pre {  font-family: \"Courier New\", Courier, mono; font-size: 10pt}\n" + "h2 { font-family: arial, helvetica, geneva; font-size: 18pt; font-weight: bold ; line-height: 14px}\n"
+			+ "code {  font-family: \"Courier New\", Courier, mono; font-size: 10pt}\n" + "sup {  font-family: arial,helvetica,geneva; font-size: 10px}\n"
+			+ "h3 {  font-family: arial, helvetica, geneva; font-size: 14pt; font-weight: bold}\n" + "li {  font-family: arial, helvetica, geneva; font-size: 10pt}\n"
+			+ "h1 {  font-family: arial, helvetica, geneva; font-size: 28px; font-weight: bold}\n"
+			+ "body {  font-family: arial, helvetica, geneva; font-size: 10pt; clip:   rect(   ); margin-top: 5mm; margin-left: 3mm}\n"
+			+ ".indextop { font-size: x-large;; font-family: Verdana, Arial, Helvetica, sans-serif; font-weight: bold}\n"
+			+ ".indexsub { font-size: xx-small;; font-family: Arial, Helvetica, sans-serif; color: #8080FF}\n" + "</style>";
+
+	/**
+	 * Creates a Variations object using build id pattern, config and jvm.
+	 *
+	 * @param buildIdPattern
+	 * @param config
+	 * @param jvm
+	 */
+	public static Variations getVariations(String buildIdPattern, String config, String jvm) {
+		String buildIdPatterns = buildIdPattern.replace(',', '%');
+		Variations variations = new Variations();
+		variations.put(PerformanceTestPlugin.CONFIG, config);
+		variations.put(PerformanceTestPlugin.BUILD, buildIdPatterns);
+		variations.put("jvm", jvm);
+		return variations;
+	}
+
+	/**
+	 * Utility method to copy a file.
+	 *
+	 * @param src the source file.
+	 * @param dest the destination.
+	 */
+	private static void copyFile(File src, File dest) {
+
+		try {
+			InputStream in = new FileInputStream(src);
+			OutputStream out = new FileOutputStream(dest);
+			byte[] buf = new byte[1024];
+			int len;
+			while ((len = in.read(buf)) > 0) {
+				out.write(buf, 0, len);
+			}
+			in.close();
+			out.close();
+
+		} catch (FileNotFoundException e) {
+			e.printStackTrace();
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+	public static void copyImages(File images, File output) {
+		copyFile(new File(images, FAIL_IMAGE), new File(output, FAIL_IMAGE));
+		copyFile(new File(images, FAIL_IMAGE_EXPLAINED), new File(output, FAIL_IMAGE_EXPLAINED));
+		copyFile(new File(images, FAIL_IMAGE_WARN), new File(output, FAIL_IMAGE_WARN));
+		copyFile(new File(images, OK_IMAGE), new File(output, OK_IMAGE));
+		copyFile(new File(images, OK_IMAGE_WARN), new File(output, OK_IMAGE_WARN));
+		copyFile(new File(images, UNKNOWN_IMAGE), new File(output, UNKNOWN_IMAGE));
+	}
+	public static void copyScripts(File scripts, File output) {
+		copyFile(new File(scripts, "ToolTip.css"), new File(output, "ToolTip.css"));
+		copyFile(new File(scripts, "ToolTip.js"), new File(output, "ToolTip.js"));
+	}
+
+	/**
+	 * Downsample Image to 8 bit depth format so that the resulting image data
+	 * can be saved to GIF. Note. If the source image contains photo quality
+	 * content with more than 256 colours, resulting data will look very poor.
+	 */
+	static int closest(RGB[] rgbs, int n, RGB rgb) {
+		int minDist = 256 * 256 * 3;
+		int minIndex = 0;
+		for (int i = 0; i < n; ++i) {
+			RGB rgb2 = rgbs[i];
+			int da = rgb2.red - rgb.red;
+			int dg = rgb2.green - rgb.green;
+			int db = rgb2.blue - rgb.blue;
+			int dist = da * da + dg * dg + db * db;
+			if (dist < minDist) {
+				minDist = dist;
+				minIndex = i;
+			}
+		}
+		return minIndex;
+	}
+
+	static class ColorCounter implements Comparable {
+		RGB rgb;
+
+		int count;
+
+		public int compareTo(Object o) {
+			return ((ColorCounter) o).count - count;
+		}
+	}
+
+	public static ImageData downSample(Image image) {
+		ImageData data = image.getImageData();
+		if (!data.palette.isDirect && data.depth <= 8)
+			return data;
+
+		// compute a histogram of color frequencies
+		HashMap freq = new HashMap();
+		int width = data.width;
+		int[] pixels = new int[width];
+		int[] maskPixels = new int[width];
+		for (int y = 0, height = data.height; y < height; ++y) {
+			data.getPixels(0, y, width, pixels, 0);
+			for (int x = 0; x < width; ++x) {
+				RGB rgb = data.palette.getRGB(pixels[x]);
+				ColorCounter counter = (ColorCounter) freq.get(rgb);
+				if (counter == null) {
+					counter = new ColorCounter();
+					counter.rgb = rgb;
+					freq.put(rgb, counter);
+				}
+				counter.count++;
+			}
+		}
+
+		// sort colors by most frequently used
+		ColorCounter[] counters = new ColorCounter[freq.size()];
+		freq.values().toArray(counters);
+		Arrays.sort(counters);
+
+		// pick the most frequently used 256 (or fewer), and make a palette
+		ImageData mask = null;
+		if (data.transparentPixel != -1 || data.maskData != null) {
+			mask = data.getTransparencyMask();
+		}
+		int n = Math.min(256, freq.size());
+		RGB[] rgbs = new RGB[n + (mask != null ? 1 : 0)];
+		for (int i = 0; i < n; ++i)
+			rgbs[i] = counters[i].rgb;
+		if (mask != null) {
+			rgbs[rgbs.length - 1] = data.transparentPixel != -1 ? data.palette.getRGB(data.transparentPixel) : new RGB(255, 255, 255);
+		}
+		PaletteData palette = new PaletteData(rgbs);
+
+		// create a new image using the new palette:
+		// for each pixel in the old image, look up the best matching
+		// index in the new palette
+		ImageData newData = new ImageData(width, data.height, 8, palette);
+		if (mask != null)
+			newData.transparentPixel = rgbs.length - 1;
+		for (int y = 0, height = data.height; y < height; ++y) {
+			data.getPixels(0, y, width, pixels, 0);
+			if (mask != null)
+				mask.getPixels(0, y, width, maskPixels, 0);
+			for (int x = 0; x < width; ++x) {
+				if (mask != null && maskPixels[x] == 0) {
+					pixels[x] = rgbs.length - 1;
+				} else {
+					RGB rgb = data.palette.getRGB(pixels[x]);
+					pixels[x] = closest(rgbs, n, rgb);
+				}
+			}
+			newData.setPixels(0, y, width, pixels, 0);
+		}
+		return newData;
+	}
+
+	/**
+	 * Returns the date/time from the build id in format yyyymmddhm
+	 *
+	 * @param buildId
+	 * @return date/time in format YYYYMMDDHHMM, ie. 200504060010
+	 */
+	public static long getDateFromBuildID(String buildId) {
+		return getDateFromBuildID(buildId, false);
+	}
+
+	public static long getDateFromBuildID(String buildId, boolean matchLast) {
+		Calendar calendar = Calendar.getInstance();
+
+		if (buildId.indexOf('_') != -1) {
+			String[] buildIdParts = buildId.split("_");
+
+			int buildIdSegment = 1;
+			if (matchLast)
+				buildIdSegment = buildIdParts.length - 1;
+			// if release build, expect <release>_<release date and
+			// timestamp>_<date and timestamp test ran>
+			// use test date and time for plotting
+			int year = Integer.parseInt(buildIdParts[buildIdSegment].substring(0, 4));
+			int month = Integer.parseInt(buildIdParts[buildIdSegment].substring(4, 6)) - 1;
+			int date = Integer.parseInt(buildIdParts[buildIdSegment].substring(6, 8));
+			int hours = Integer.parseInt(buildIdParts[buildIdSegment].substring(8, 10));
+			int min = Integer.parseInt(buildIdParts[buildIdSegment].substring(10, 12));
+
+			calendar.set(year, month, date, hours, min);
+			return calendar.getTimeInMillis();
+
+		} else if (buildId.indexOf('-') != -1) {
+			// if regular build, expect <buildType><date>-<time> format
+			String[] buildIdParts = buildId.split("-");
+			int year = Integer.parseInt(buildIdParts[0].substring(1, 5));
+			int month = Integer.parseInt(buildIdParts[0].substring(5, 7)) - 1;
+			int date = Integer.parseInt(buildIdParts[0].substring(7, 9));
+			int hours = Integer.parseInt(buildIdParts[1].substring(0, 2));
+			int min = Integer.parseInt(buildIdParts[1].substring(2, 4));
+			calendar.set(year, month, date, hours, min);
+
+			return calendar.getTimeInMillis();
+		}
+
+		return -1;
+	}
+	
+	/**
+	 * Returns a message corresponding to given statistics.
+	 * 
+	 * @param resultStats The value with its standard error
+	 * @param full
+	 * @return The failure message. May be empty if stats are good...
+	 */
+	public static String failureMessage(double[] resultStats, boolean full) {
+		StringBuffer buffer = new StringBuffer();
+		int level = confidenceLevel(resultStats);
+//		boolean isWarn = (level & WARN) != 0;
+		boolean isErr = (level & ERR) != 0;
+		if (full) {
+			if (isErr) {
+				buffer.append("*** WARNING ***  ");
+	 			buffer.append(Messages.bind(Messages.standardError, PERCENT_FORMAT.format(resultStats[1]), STANDARD_ERROR_THRESHOLD_STRING));
+			}
+			return buffer.toString();
+		}
+		if (resultStats != null) {
+			double deviation = resultStats[0];
+			buffer.append("<font color=\"#0000FF\" size=\"1\">");
+			if (Double.isNaN(deviation) || Double.isInfinite(deviation)) {
+	 			buffer.append(" [n/a]");
+ 			} else {
+				double stderr = resultStats[1];
+				deviation = Math.abs(deviation)<0.001 ? 0 : -deviation;
+	 			if (Double.isNaN(stderr) || Double.isInfinite(stderr)) {
+		 			buffer.append(DEVIATION_FORMAT.format(deviation));
+					buffer.append("</font><font color=\"#DDDD00\" size=\"1\"> ");
+		 			buffer.append(" [n/a]");
+	 			} else {
+		 			buffer.append(DEVIATION_FORMAT.format(deviation));
+	 				buffer.append(" [&#177;");
+	 				buffer.append(STDERR_FORMAT.format(Math.abs(stderr)));
+	 				buffer.append(']');
+	 			}
+ 			}
+			buffer.append("</font>");
+		}
+		return buffer.toString();
+	}
+	
+	/**
+	 * Returns the confidence level for given statistics:
+	 * <ul>
+	 * <li>{@link #NAN}: if the value is infinite or not a number</li>
+	 * <li>{@link #ERR}: if the standard error is over the expected threshold ({@link #STANDARD_ERROR_THRESHOLD})</li>
+	 * <li>{@link #OK}: in all other cases</li>
+	 * </ul>
+	 * 
+	 * @param resultStats array of 2 doubles, the former is the average value and
+	 * 	the latter is the standard error made while computing the average.
+	 * @return a value telling caller the level of confidence of the provided value
+	 */
+	public static int confidenceLevel(double[] resultStats) {
+		int level = OK;
+ 		if (resultStats != null){
+			if (Double.isNaN(resultStats[0]) || Double.isInfinite(resultStats[0])) {
+				level = NAN;
+ 			} else {
+//	 			if (resultStats[1] >= (STANDARD_ERROR_THRESHOLD/2)) { // warns standard error higher than the half of authorized threshold
+//	 				level |= WARN;
+//	 			}
+	 			if (resultStats[1] >= STANDARD_ERROR_THRESHOLD) { // standard error higher than the authorized threshold
+	 				level = ERR;
+	 			}
+ 			}
+ 		}
+		return level;
+	}
+
+	/**
+	 * Get an icon image corresponding to a given level of confidence and explanation.
+	 * 
+	 * @param confidence the confiden level
+	 * @param hasExplanation flags indicates whether the confidence may be tempered by an explanation
+	 * @return Corresponding image
+	 */
+	public static String getImage(int confidence, boolean scenarioFailed, boolean hasExplanation) {
+	    String image = null;
+
+	    if (scenarioFailed) {
+	    	if (hasExplanation) {
+		    	image = FAIL_IMAGE_EXPLAINED;
+		    } else if ((confidence & ERR) != 0) {
+    			image = FAIL_IMAGE_WARN;
+		    } else {
+    			image = FAIL_IMAGE;
+		    }
+	    } else if ((confidence & NAN) != 0) {
+			image = UNKNOWN_IMAGE;
+	    } else if ((confidence & ERR) != 0) {
+	   		image = OK_IMAGE_WARN;
+	    } else {
+   			image = OK_IMAGE;
+	    }
+	    return image;
+    }
+
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/messages.properties b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/messages.properties
new file mode 100644
index 0000000..a486ba1
--- /dev/null
+++ b/bundles/org.eclipse.test.performance.ui/src/org/eclipse/test/performance/ui/messages.properties
@@ -0,0 +1,14 @@
+###############################################################################
+# Copyright (c) 2000, 2007 IBM Corporation and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#     IBM Corporation - initial API and implementation
+###############################################################################
+
+### Performance Tests Messages.
+
+standardError = Standard error on this test is {0} (should be less than {1} to become reliable!)