Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/App_Code/AdminHelper.cshtml
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/App_Code/AdminHelper.cshtml	(revision 11020)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/App_Code/AdminHelper.cshtml	(revision 11020)
@@ -0,0 +1,60 @@
+﻿@* HeuristicLab
+ * Copyright (C) 2002-2013 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ *@
+
+@helper UserList(string destinationTag, string url, bool multiline) {
+  <script>
+    $.ajax({
+      url: "@(new HtmlString(url))", datatype: "json", success: function (result) {
+        $("#" + "@destinationTag").html("");
+        @if(multiline) {
+          @:$("#" + "@destinationTag").attr("size", result.length);
+        }
+        else {
+          @:$("#" + "@destinationTag").append("<option></option>");
+        }
+        for (var i = 0; i < result.length; i++) {
+          $("#" + "@destinationTag").append("<option>" + result[i] + "</option>");
+        }
+      }
+    });
+  </script>
+}
+
+@helper UserTaskStats(string destinationTag, string overallUrl, string userUrl, string userName, string start, string end)
+{
+  if(userName!="") {
+    <text>
+      $.ajax({
+        url: "@(new HtmlString(overallUrl))?start=" + @start + "&end=" + @end, datatype: "json", success: function (overallResult) {
+          $.ajax({
+            url: "@(new HtmlString(userUrl))?userName=" + @userName + "&start=" + @start + "&end=" + @end, datatype: "json", success: function (userResult) {
+              $("#" + "@destinationTag").html("");
+              for (var i = 0; i < userResult.length; i++) {
+                $("#" + "@destinationTag").append('<label class="barLabel">' + userResult[i].Key + '</label>');
+                $("#" + "@destinationTag").append('<div class="outerBar"><div class="innerBar" id="InnerBar' + i + '"><p class="innerBarText">' + +userResult[i].Value.toFixed(4) + '</p></div><p class="outerBarText" id="OuterText' + i + '">' + +overallResult[i].toFixed(4) + '</p></div>');
+                $("#InnerBar" + i).css('width',((userResult[i].Value/overallResult[i])*100).toFixed(2) + '%');
+                $("#OuterText" + i).css('width',(98 - ((userResult[i].Value/overallResult[i])*100)).toFixed(2) + '%');
+              }
+            }
+          });
+        }
+      });
+    </text>
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/App_Code/ChartHelper.cshtml
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/App_Code/ChartHelper.cshtml	(revision 9662)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/App_Code/ChartHelper.cshtml	(revision 11020)
@@ -18,5 +18,6 @@
  *@
 
-@helper AjaxDataRenderer() {
+@helper AjaxDataRenderer()
+{
     <script>
         var ajaxDataRenderer = function (url, plot, options) {
@@ -35,5 +36,6 @@
 }
 
-@helper LineChartTime(string destinationTag, string url, string title = "", double? minY = null, double? maxY = null, string axisYFormat = null) {
+@helper LineChartTime(string destinationTag, string url, string title = "", double? minY = null, double? maxY = null, string axisYFormat = null)
+{
     <script>
         var @(destinationTag)Plot = $.jqplot("@destinationTag", "@url", {
@@ -53,5 +55,6 @@
                 },
                 yaxis: {
-                    @if (axisYFormat != null) {<text>
+                    @if (axisYFormat != null)
+                    {<text>
                     tickOptions: {
                         formatString: "@axisYFormat",
@@ -60,8 +63,10 @@
                     autoscale: true,
                     pad: 0,
-                    @if (minY != null) {
+                    @if (minY != null)
+                    {
                         @:min: @minY,
                     }
-                    @if (maxY != null) {
+                    @if (maxY != null)
+                    {
                         @:max: @maxY,
                     }
@@ -93,12 +98,298 @@
 }
 
-@helper RefreshChart(string destinationTag, string url, string startDateVar, string endDateVar) {
-    <text>
-    $.ajax({url: "@(new HtmlString(url))?start=" + @startDateVar + "&end=" + @endDateVar, datatype: "json", success: function(result) {
-        for (var i = 0; i < result.length; i++) {
-            @(destinationTag)Plot.series[i].data = result[i];
+@helper RefreshChart(string destinationTag, string url, string startDateVar, string endDateVar)
+{
+  <text>
+  $.ajax({url: "@(new HtmlString(url))?start=" + @startDateVar + "&end=" + @endDateVar, datatype: "json", success: function(result) {
+    for (var i = 0; i < result.length; i++) {
+      @(destinationTag)Plot.series[i].data = result[i];
+    }
+    @(destinationTag)Plot.replot({ resetAxes: true })
+  }});
+  </text>
+}
+
+@helper TasksForUser(string container, string destinationTag, string url, string userName, string startDate = null, string endDate = null)
+{
+  <text>
+    $.ajax({url: "@(new HtmlString(url))?userName=" + @(userName) + "&start=" + @startDate + "&end=" + @endDate, datatype: "json", success: function(result) {
+      $("#@container").html("");
+      if(result[0].length==0) {
+        $("#@container").append(
+          '<section class="chartContainer"><h1 class="title">' + @userName + ' has no tasks for the given time period!</h1></section>'
+        )
+      }
+      var waitTime;
+      var transferTime;
+      var runTime;
+      var seriesDescriptions = ["Time waiting","Time transferring","Time calculating"];
+
+      //Globally accesible, for use when resizing, eliminates extra DB request
+      window["numberTasks"] = result[0].length;
+
+      //For each result create a seperate collapsable section with a chart and info label
+      for(var i = 0; i < result[0].length; i++){
+        $("#" + "@container").append(
+          '<section class="chartContainer"><h1 class="title">Task ' + (i + 1) + 
+          '</h1><button class="collapse" onclick="collapseSection(this)">-</button><div id="@(destinationTag)' + i + 
+          '"></div><label id="@(destinationTag)' + i + 'Info"></label></section>'
+        )
+        waitTime = [result[0][i]];
+        transferTime = [result[1][i]];
+        runTime = [result[2][i]];
+        window["@(destinationTag)Plot" + i] = $.jqplot("@destinationTag" + i, [waitTime,transferTime,runTime], {
+          //stackSeries: true,
+          seriesDefaults:{
+            renderer:$.jqplot.BarRenderer,
+            shadowAngle: 135,
+            //rendererOptions: {
+            //  barDirection: 'horizontal'
+            //},
+            pointLabels: {show: true, formatString: '%.3f'}
+          },
+          series:[
+            {label:'Waiting'},
+            {label:'Transferring'},
+            {label:'Calculating'}
+          ],
+          legend: {
+            show: true,
+            location: 'e',
+            placement: 'outside'
+          },
+          axes: {
+            xaxis: {
+              renderer: $.jqplot.CategoryAxisRenderer,
+              showLabel: false,
+              pad: 0
+            },
+            yaxis: {
+              pad: 0
+            }
+          },
+          cursor: {
+            showTooltip: false
+          }
+        });
+        /* Bind a datalistener to each chart and display details of clicked
+          upon data in the label below the chart */
+        $("#" + "@(destinationTag)" + i).bind('jqplotDataClick', function (ev, seriesIndex, pointIndex, data) {
+          $("#" + $(this).attr('id') + "Info").html(seriesDescriptions[seriesIndex] + ': ' + data[1]);
+        }); 
+      }
+    }});
+  </text>
+}
+
+@helper ResizeTasks(string destinationTag)
+{
+  <text>
+  $(window).resize(function() {
+    for(var i = 0; i < numberTasks; i++) {
+      window[ "@(destinationTag)Plot" + i].replot({ resetAxes: true });
+    }
+  });
+  </text>
+}
+
+@* OLD SMOOTHIE CHART FUNCTIONS *@
+@*@helper CreateSmoothieChart(string destinationTag, string stroke, string fill, string label)
+{
+  <text>
+    var @(destinationTag)Smoothie = new SmoothieChart({
+      grid: {
+        strokeStyle: '@stroke', fillStyle: '@fill',
+        lineWidth: 1, millisPerLine: 450, verticalSections: 4,
+      },
+      labels: {
+        fillStyle: '@label'
+      }
+    });
+
+    var @(destinationTag)TimeSeries = new Array()
+  </text>
+}
+
+@helper SetSmoothieCanvas(string destinationTag, string delay)
+{
+  <text>
+  @(destinationTag)Smoothie.streamTo(document.getElementById("@destinationTag"), @delay);
+  </text>
+}
+
+@helper AssignTimeSeries(string seriesName, string destinationTag, string stroke, string fill)
+{
+  <text>
+  var @(seriesName)TS = new TimeSeries();
+  @(destinationTag)Smoothie.addTimeSeries(@(seriesName)TS, { strokeStyle: '@stroke', fillStyle: '@fill', lineWidth: 3 });
+  @(destinationTag)TimeSeries.push(@(seriesName)TS);
+  </text>
+}
+
+@helper UpdateChartData(string destinationTag, string url)
+{
+  <text>
+  $.ajax({
+    url: '@(url)', datatype: "json", success: function (result) {
+      var i
+      for (i = 0; i < @(destinationTag)TimeSeries.length; i++) {
+        @(destinationTag)TimeSeries[i].append(new Date().getTime(), result[i]);
+      }
+    }
+  });
+  </text>
+}*@
+
+@helper SetStreamingProperties(int refresh, int chartLength, int upperY) {
+  <text>
+  //Refresh time (in millisec)
+  var refreshRate = @(refresh);
+  //Number of data points on chart
+  var chartSize = @(chartLength);
+  //Amount to add to max Y value
+  var upperYBuffer = @(upperY);
+
+  //Used to return a string containing the names of the series
+  //to be used in plot creation
+  function getSeries(numberData,dataName){ 
+    var result = "[";
+    for(i=0; i < numberData; i++) {
+      if(i < numberData -1) {
+        result += dataName + i + ",";
+      }
+      else {
+        result += dataName + i + "]";
+      }
+    }
+    return result;
+  }
+  </text>
+}
+
+@helper CreateStreamChart(string dataName, string destinationTag, string url, string title, string format = null, double? maxY = null) {
+  <text>
+  //Get current time, used to create initial values
+  var @(dataName)CurrentDate = (new Date()).getTime();
+
+  var @(dataName)Data = [];
+  var @(dataName)CurrentValue = [];
+
+  //Get the most recent value(s) from the given URL
+  $.ajax({ 
+    async: false, url: '@(url)', datatype: "json", success: function (result) {
+      for(i = 0; i < result.length; i++) {
+        @(dataName)CurrentValue[i] = result[i];
+      }
+    }
+  });
+  
+  //Create a chartSize worth of data using CurrentDate and CurrentValue
+  //for each CurrentValue
+  for(i = 0; i < @(dataName)CurrentValue.length; i++) {
+    window["@(dataName)Data" + i] = [];
+    for (j = 0; j < chartSize; j++) {
+      window[ "@(dataName)Data" + i].push([@(dataName)CurrentDate - (chartSize - 1 - j) * refreshRate, @(dataName)CurrentValue[i]]);
+    }
+  }
+
+  //Options for the chart to be created
+  var @(destinationTag)PlotOptions = {
+    title: "@title",
+    axes: {
+      xaxis: {
+        numberTicks: 4,
+        renderer: $.jqplot.DateAxisRenderer,
+        tickOptions: { formatString: '%H:%M:%S' },
+        min: window["@(dataName)Data" + 0][0][0],
+        max: window["@(dataName)Data" + 0][window["@(dataName)Data" + 0].length - 1][0]
+      },
+      yaxis: {
+        @if (format != null)
+        {<text>
+        tickOptions: {
+            formatString: "@format",
+        },
+        </text>}
+        min: 0, 
+        @if (maxY != null) {
+          @:max: @maxY,
         }
-        @(destinationTag)Plot.replot({ resetAxes: true })
-    }});
-    </text>
-}
+        else{
+          @:max: window["@(dataName)Data" + 0][window["@(dataName)Data" + 0].length - 1][1] + upperYBuffer,
+        }
+        numberTicks: 6
+      }
+    },
+    seriesDefaults: {
+      rendererOptions: { smooth: true },
+      markerOptions: {
+        show: false
+      }
+    }
+  };
+
+  //Declares the jqPlot variable, evals the string of series returned
+  //from getSeries which allows for any number of series
+  window[ "@(destinationTag)Plot"] = $.jqplot('@destinationTag', eval(getSeries(@(dataName)CurrentValue.length,"@(dataName)Data")), @(destinationTag)PlotOptions);
+  </text>
+}
+
+@helper UpdateStreamChart(string dataName, string destinationTag, string url, string fixedY = null)
+{
+  <text>
+  //If the data is beyond chartSize use shift to trim one off the end
+  for(i = 0; i < @(dataName)CurrentValue.length; i++) {
+    if (window["@(dataName)Data" + i].length > chartSize - 1) {
+      window["@(dataName)Data" + i].shift();
+    }
+  }
+
+  //Get the up-to-date data, each result assigned to it's own array
+  $.ajax({
+    async: false, url: '@(url)', datatype: "json", success: function (result) {
+      for(i = 0; i < result.length; i++) {
+        window[ "@(dataName)Data" + i].push([(new Date()).getTime(), result[i]]);
+      }
+    }
+  });
+
+  //If the plot exists currently destroy it
+  if ( @(destinationTag)Plot) {
+    @(destinationTag)Plot.destroy();
+  }
+
+  //Assign series
+  for(i = 0; i < @(dataName)CurrentValue.length; i++) {
+    @(destinationTag)Plot.series[i].data = window["@(dataName)Data" + i];
+  }
+
+  //Recalculate x and possibly y axis max and mins
+  @(destinationTag)PlotOptions.axes.xaxis.min = window["@(dataName)Data" + 0][0][0];
+  @(destinationTag)PlotOptions.axes.xaxis.max = window["@(dataName)Data" + 0][window["@(dataName)Data" + 0].length - 1][0];
+  @if (fixedY == null) {
+    @:@(destinationTag)PlotOptions.axes.yaxis.max = window["@(dataName)Data" + 0][window["@(dataName)Data" + 0].length - 1][1] + upperYBuffer;
+  }
+
+  //Re-assigns the jqPlot variable, evals the string of series returned
+  //from getSeries which allows for any number of series
+  @(destinationTag)Plot = $.jqplot('@destinationTag', eval(getSeries(@(dataName)CurrentValue.length,"@(dataName)Data")), @(destinationTag)PlotOptions);
+  </text>
+}
+
+@helper MakeCollapsable()
+{
+  <text>
+  $(document).ready(function() {
+    $(".collapse").click(function () {
+      if ($(this).html() == "-") {
+        $(this).parent().children("canvas, div, fieldset, label").fadeOut();
+        $(this).html("+");
+      }
+      else {
+        $(this).parent().children("canvas, div, fieldset, label").fadeIn();
+        $(this).html("-");
+      }
+    });
+  });
+  </text>
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Content/Site.css
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Content/Site.css	(revision 9662)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Content/Site.css	(revision 11020)
@@ -61,4 +61,56 @@
 }
 
+/* Progress bar styles */
+.barLabel {
+  margin: 2% 0% 0% 10%;
+  font-size: 1.1em;
+  font-family: inherit;
+  color: #6B6B6B;
+  display: block;
+}
+
+.outerBar {
+  height: 25px;
+  width: 80%;
+  margin-left: 10%;
+  border: 2px outset grey;
+}
+
+.outerBar:last-of-type {
+  margin-bottom: 2%;
+}
+
+.innerBar {
+  height: 100%;
+  vertical-align: middle;
+  background: rgb(32,122,2); /* Old browsers */
+  /* IE9 SVG, needs conditional override of 'filter' to 'none' */
+  background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzIwN2EwMiIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjUwJSIgc3RvcC1jb2xvcj0iIzQwZDgwNCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiMwMDZkMDciIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+);
+  background: -moz-linear-gradient(top,  rgba(32,122,2,1) 0%, rgba(64,216,4,1) 50%, rgba(0,109,7,1) 100%); /* FF3.6+ */
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(32,122,2,1)), color-stop(50%,rgba(64,216,4,1)), color-stop(100%,rgba(0,109,7,1))); /* Chrome,Safari4+ */
+  background: -webkit-linear-gradient(top,  rgba(32,122,2,1) 0%,rgba(64,216,4,1) 50%,rgba(0,109,7,1) 100%); /* Chrome10+,Safari5.1+ */
+  background: -o-linear-gradient(top,  rgba(32,122,2,1) 0%,rgba(64,216,4,1) 50%,rgba(0,109,7,1) 100%); /* Opera 11.10+ */
+  background: -ms-linear-gradient(top,  rgba(32,122,2,1) 0%,rgba(64,216,4,1) 50%,rgba(0,109,7,1) 100%); /* IE10+ */
+  background: linear-gradient(to bottom,  rgba(32,122,2,1) 0%,rgba(64,216,4,1) 50%,rgba(0,109,7,1) 100%); /* W3C */
+  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#207a02', endColorstr='#006d07',GradientType=0 ); /* IE6-8 */
+  display: inline-block;
+}
+
+.innerBarText, .outerBarText {
+  height: auto;
+  margin: 0%;
+  margin-left: 1%;
+  font-family: inherit;
+  font-size: 1.4em;
+  text-shadow: 0px 0px 6px #D9FCE4;
+  color: #000000;
+  display: inline-block;
+}
+
+.outerBarText {
+  text-align: right;
+}
+
+/* Login Page Styles*/
 #login {
   display: block;
@@ -89,7 +141,10 @@
 }
 
-
 #login form {
   display: inline;
+}
+
+#loginForm ol {
+  list-style: none;
 }
 
@@ -160,18 +215,18 @@
 }
 
+input[type="text"], input[type="password"] {
+  border: 1px solid #CCC;
+}
+
+/*Index Page Styles*/
 fieldset {
   margin: 1em 0;
+  margin-bottom: 2em;
   padding: 1em;
   padding-top: 0;
-  border: 1px solid #CCC;
-}
-
-fieldset ol {
-  padding: 0;
-}
-
-fieldset li {
-  list-style: none;
-  margin: 0.5em 0;
+  -webkit-border-radius: 3px;
+  -moz-border-radius: 3px;
+  border-radius: 3px;
+  border: 1px solid #8297F5;
 }
 
@@ -180,19 +235,175 @@
   font-weight: 600;
   padding: 2px 4px 8px 4px;
-}
-
-input[type="text"], input[type="password"] {
-  border: 1px solid #CCC;
-}
-
-.charts {
+  color: #6B6B6B;
+}
+
+fieldset > label, fieldset > input {
+  font-size: 1.1em;
+  font-weight: 600;
+  color: #6B6B6B;
+  display: block;
+}
+
+fieldset > input {
+  margin-bottom: 2%;
+}
+
+.charts, .chartContainer, .collapse {
   font-size: 1.5em;
 }
 
-.charts > div {
-  height: 300px;
-  margin-top: 15px;
-  margin-bottom: 5px;
-  margin-left: 10px;
-  margin-right: 20px;
-}
+.chartContainer {
+  width: 90%;
+  padding: 3%;
+  margin: 3% 0% 3% 2%;
+  -webkit-border-radius: 15px;
+  -moz-border-radius: 15px;
+  border-radius: 15px;
+  -webkit-box-shadow: 5px 5px 3px #A3A3A2;
+  box-shadow: 5px 5px 3px #A3A3A2;
+  border: 3px solid #8297F5;
+}
+
+.chartContainer > .title {
+  width: 95%;
+  border-bottom: none;
+  display:inline-block;
+}
+
+.chartContainer canvas {
+  margin: 0% 0% 2% 6%;
+}
+
+.chartContainer > div {
+  width: 90%;
+  height: 180px;
+  margin-left: 3%;
+}
+
+.chartContainer > .smoothieHolder {
+  width: auto;
+  height: auto;
+  margin: 0%;
+}
+
+.chartContainer .smoothieLabel {
+  width: 100%;
+  margin: 10px;
+  display: block;
+  text-align: center;
+  font-family: inherit;
+  font-size: 13pt;
+  color: #707070;
+}
+
+.collapse {
+  width: 3%;
+  min-width: 20px;
+  margin: 0px;
+  background: none;
+  color: #F7921D;
+  -webkit-border-radius: 3px;
+  -moz-border-radius: 3px;
+  border-radius: 3px;
+  border: 2px solid #F7921D;
+  text-align: center;
+  font-size: 1em;
+  display: inline-block;
+}
+
+.collapse:hover {
+  background-color: rgba(247,146,29,0.42);
+}
+/* User Page Styles*/
+#tasksContainer div[id^="Task"] {
+  margin: 2% 0%;
+}
+
+#tasksContainer .jqplot-xaxis {
+  display: none;
+}
+
+label[id$="Info"] {
+  font-family: inherit;
+  font-size: 13pt;
+  color: #707070;
+}
+
+#filters {
+  margin: 2% 2% 3% 2%;
+}
+
+#filters legend, #filters label, #filters input {
+  font-size: 1.6em;
+}
+
+/* Admin Page Styles */
+[id$="OverviewButton"] {
+  margin: 3% 0% 0% 0%;
+  background: none;
+  color: #707070;
+  font-size: 1.4em;
+  -webkit-border-radius: 0 3px 0 0;
+  border-radius: 0 5px 0 0;
+  border: 1px solid #8297F5;
+  text-align: center;
+  z-index: 3;
+}
+
+#UserOverviewButton {
+  border-bottom: 1px solid #E0E6FF;
+  background-color: #E0E6FF;
+  margin-left: 3%;
+}
+
+[id$="OverviewButton"]:hover {
+  background-color: #D1D9FF;
+}
+
+[id$="OverviewButton"]:focus {
+  -webkit-border-radius: 0 3px 0 0;
+  border-radius: 0 5px 0 0;
+  border-bottom: 1px solid #FAFAFA;
+}
+
+[id$="OverviewTab"] {
+  width: 90%;
+  padding: 1%;
+  margin: 0% 0% 3% 3%;
+  -webkit-border-radius: 0 15px 15px 15px;
+  border-radius: 0 15px 15px 15px;
+  -webkit-box-shadow: 5px 5px 3px #A3A3A2;
+  box-shadow: 5px 5px 3px #A3A3A2;
+  border: 1px solid #8297F5;
+  display: none;
+}
+
+#UserOverviewTab {
+  display: block;
+}
+
+.usersField {
+  width: 20%;
+  padding: 1% 2% 2% 2%;
+  margin: 1% 0% 2% 2%;
+  font-size: 1.4em;
+  vertical-align: top;
+  display: inline-block;
+}
+
+.usersList {
+  width: 100%;
+  font-family: inherit;
+  font-size: 10pt;
+  color: #707070;
+}
+
+.usersField label {
+  margin-top: 1em;
+}
+
+.adminDataContainer {
+  width: 70%;
+  padding-left: 1%;
+  display: inline-block;
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Controllers/AdminDataController.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Controllers/AdminDataController.cs	(revision 11020)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Controllers/AdminDataController.cs	(revision 11020)
@@ -0,0 +1,88 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+using System.Web.Mvc;
+using HeuristicLab.Services.Hive.DataAccess;
+
+namespace HeuristicLab.Services.Hive.Statistics.Controllers {
+  public class AdminDataController : Controller {
+
+    public JsonResult UserList()
+    {
+      using (var db = new HiveDataContext(Settings.Default.HeuristicLab_Hive_LinqConnectionString))
+      {
+        var allUsers = (from users in db.DimUsers
+                            select new { users.Name })
+                            .ToList();
+
+        List<string> UserNames = new List<string>();
+        allUsers.ForEach(u => UserNames.Add(u.Name));
+
+        return Json(UserNames, JsonRequestBehavior.AllowGet);
+      }
+    }
+
+    public JsonResult UserTaskStats(string userName, DateTime start, DateTime end)
+    {
+      using (var db = new HiveDataContext(Settings.Default.HeuristicLab_Hive_LinqConnectionString))
+      {
+        var taskStats = (from tasks in db.FactTasks
+                        join jobs in db.DimJobs
+                          on tasks.JobId equals jobs.JobId
+                        where jobs.UserName == userName &&
+                        tasks.StartTime >= start &&
+                        tasks.EndTime < end
+                        select new { tasks.TotalWaitingTime, tasks.TotalTransferTime, tasks.TotalRuntime, tasks.NumCalculationRuns, 
+                          tasks.CoresRequired, tasks.MemoryRequired, tasks.TaskSize, tasks.ResultSize})
+                          .ToList();
+
+        List<KeyValuePair<string, double>> FullStats = new List<KeyValuePair<string, double>>();
+        FullStats.Add(new KeyValuePair<string, double>("Total Waiting Time",taskStats.Sum(w => w.TotalWaitingTime)));
+        FullStats.Add(new KeyValuePair<string, double>("Total Transfer Time", taskStats.Sum(t => t.TotalTransferTime)));
+        FullStats.Add(new KeyValuePair<string, double>("Total Runtime", taskStats.Sum(r => r.TotalRuntime)));
+        FullStats.Add(new KeyValuePair<string, double>("Number Calculation Runs", taskStats.Sum(n => n.NumCalculationRuns)));
+        FullStats.Add(new KeyValuePair<string, double>("Cores Required", taskStats.Sum(c => c.CoresRequired)));
+        FullStats.Add(new KeyValuePair<string, double>("Memory Required", taskStats.Sum(m => m.MemoryRequired)));
+        FullStats.Add(new KeyValuePair<string, double>("Task Size", taskStats.Sum(ts => ts.TaskSize)));
+        FullStats.Add(new KeyValuePair<string, double>("Result Size", taskStats.Sum(rs => Convert.ToDouble(rs.ResultSize))));
+
+        return Json(FullStats, JsonRequestBehavior.AllowGet);
+      }
+    }
+
+    public JsonResult AllTaskStats(DateTime start, DateTime end)
+    {
+      using (var db = new HiveDataContext(Settings.Default.HeuristicLab_Hive_LinqConnectionString))
+      {
+        var taskStats = (from tasks in db.FactTasks
+                         where tasks.StartTime >= start &&
+                         tasks.EndTime < end
+                         select new
+                         {
+                           tasks.TotalWaitingTime,
+                           tasks.TotalTransferTime,
+                           tasks.TotalRuntime,
+                           tasks.NumCalculationRuns,
+                           tasks.CoresRequired,
+                           tasks.MemoryRequired,
+                           tasks.TaskSize,
+                           tasks.ResultSize
+                         })
+                          .ToList();
+
+        List<double> FullStats = new List<double>();
+        FullStats.Add(taskStats.Sum(w => w.TotalWaitingTime));
+        FullStats.Add(taskStats.Sum(t => t.TotalTransferTime));
+        FullStats.Add(taskStats.Sum(r => r.TotalRuntime));
+        FullStats.Add(taskStats.Sum(n => n.NumCalculationRuns));
+        FullStats.Add(taskStats.Sum(c => c.CoresRequired));
+        FullStats.Add(taskStats.Sum(m => m.MemoryRequired));
+        FullStats.Add(taskStats.Sum(ts => ts.TaskSize));
+        FullStats.Add(taskStats.Sum(rs => Convert.ToDouble(rs.ResultSize)));
+
+        return Json(FullStats, JsonRequestBehavior.AllowGet);
+      }
+    }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Controllers/ChartDataController.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Controllers/ChartDataController.cs	(revision 9662)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Controllers/ChartDataController.cs	(revision 11020)
@@ -24,4 +24,5 @@
 using System.Linq;
 using System.Web.Mvc;
+using System.Web.Script.Serialization;
 using HeuristicLab.Services.Hive.DataAccess;
 
@@ -33,4 +34,8 @@
     public JsonResult AverageCpuUtilization(DateTime? start = null, DateTime? end = null) {
       using (var db = new HiveDataContext(Settings.Default.HeuristicLab_Hive_LinqConnectionString)) {
+        //If no given start date, get date of most recent record
+        if (start == null) {
+          start = GetRecentDate(db);
+        }
         var data =
           from facts in GetClientFacts(db, start, end)
@@ -48,4 +53,8 @@
     public JsonResult UsedCores(DateTime? start = null, DateTime? end = null) {
       using (var db = new HiveDataContext(Settings.Default.HeuristicLab_Hive_LinqConnectionString)) {
+        //If no given start date, get date of most recent record
+        if (start == null) {
+          start = GetRecentDate(db);
+        }
         var data =
           from facts in GetClientFacts(db, start, end)
@@ -64,4 +73,8 @@
     public JsonResult UsedMemory(DateTime? start = null, DateTime? end = null) {
       using (var db = new HiveDataContext(Settings.Default.HeuristicLab_Hive_LinqConnectionString)) {
+        //If no given start date, get date of most recent record
+        if (start == null) {
+          start = GetRecentDate(db);
+        }
         var data =
           from facts in GetClientFacts(db, start, end)
@@ -76,4 +89,86 @@
           CreateSeriesData(data.ToList(), x => x.Time, x => x.UsedMemory / 1000, x => x.TotalMemory / 1000),
           JsonRequestBehavior.AllowGet);
+      }
+    }
+
+    public JsonResult CurrentCores()
+    {
+      using (var db = new HiveDataContext(Settings.Default.HeuristicLab_Hive_LinqConnectionString))
+      {
+        var currentCores = (from client in db.FactClientInfos
+                            select new { client.NumTotalCores, client.NumUsedCores })
+                            .ToList();
+
+        List<int> result = new List<int>();
+        result.Add(currentCores.Sum(c => c.NumTotalCores));
+        result.Add(currentCores.Sum(s => s.NumUsedCores));
+
+        return Json(result, JsonRequestBehavior.AllowGet);
+      }
+    }
+
+    public JsonResult CurrentCpuUtilization()
+    {
+      using (var db = new HiveDataContext(Settings.Default.HeuristicLab_Hive_LinqConnectionString))
+      {
+        var currentCpuUtil = (from client in db.FactClientInfos
+                            select new { client.CpuUtilization })
+                            .ToList();
+
+        List<double> result = new List<double>();
+        result.Add(Math.Round(currentCpuUtil.Average(s => s.CpuUtilization), 2));
+
+        return Json(result, JsonRequestBehavior.AllowGet);
+      }
+    }
+
+    public JsonResult CurrentMemory()
+    {
+      using (var db = new HiveDataContext(Settings.Default.HeuristicLab_Hive_LinqConnectionString))
+      {
+        var currentMemory = (from client in db.FactClientInfos
+                            select new { client.TotalMemory, client.UsedMemory })
+                            .ToList();
+
+        List<int> result = new List<int>();
+        result.Add(currentMemory.Sum(c => c.TotalMemory)/1000);
+        result.Add(currentMemory.Sum(s => s.UsedMemory)/1000);
+
+        return Json(result, JsonRequestBehavior.AllowGet);
+      }
+    }
+
+    public JsonResult GetUserTask(string userName, DateTime? start = null, DateTime? end = null)
+    {
+      start = start ?? DateTime.Now - DefaultDuration;
+      end = end ?? DateTime.Now;
+      using (var db = new HiveDataContext(Settings.Default.HeuristicLab_Hive_LinqConnectionString))
+      {
+        var data =
+          (from tasks in db.FactTasks
+          join jobs in db.DimJobs
+            on tasks.JobId equals jobs.JobId
+          where jobs.UserName == userName &&
+          tasks.StartTime >= start &&
+          tasks.EndTime < end
+          select new
+          {
+            TotalWaiting = tasks.TotalWaitingTime,
+            TotalTransfer = tasks.TotalTransferTime,
+            TotalRuntime = tasks.TotalRuntime
+          }).ToList();
+
+        List<List<double>> overallResult = new List<List<double>>();
+        List<double> wait = new List<double>();
+        List<double> transfer = new List<double>();
+        List<double> run = new List<double>();
+        data.ForEach(w => wait.Add(w.TotalWaiting));
+        data.ForEach(t => transfer.Add(t.TotalTransfer));
+        data.ForEach(r => run.Add(r.TotalRuntime));
+        overallResult.Add(wait);
+        overallResult.Add(transfer);
+        overallResult.Add(run);
+
+        return Json(overallResult,JsonRequestBehavior.AllowGet);
       }
     }
@@ -98,4 +193,12 @@
       );
     }
+
+    private static DateTime GetRecentDate(HiveDataContext db)
+    {
+      var mostRecent = from dates in db.FactClientInfos
+        group dates by dates.Time into startDate
+        select startDate.OrderByDescending(t=>t.Time).FirstOrDefault();
+      return mostRecent.Max(t=>t.Time);
+    }
   }
 
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Controllers/LoginRequiredController.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Controllers/LoginRequiredController.cs	(revision 11020)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Controllers/LoginRequiredController.cs	(revision 11020)
@@ -0,0 +1,32 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+using System.Web.Mvc;
+using HeuristicLab.Services.Hive.Statistics.Models;
+
+namespace HeuristicLab.Services.Hive.Statistics.Controllers {
+  public class LoginRequiredController : Controller {
+      
+    [Authorize]
+    public ActionResult UserTask() {
+      var result = new UserModel {
+        UserName = User.Identity.Name
+      };
+      return View(result);
+    }
+
+    [Authorize]
+    public ActionResult Admin() {
+      var result = new AdminModel {
+        IsAdmin = false,
+        UserName = User.Identity.Name
+      };
+      if (User.IsInRole("Hive Administrator")) {
+        result.IsAdmin = true;
+      }
+
+      return View(result);
+    }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/HeuristicLab.Services.Hive.Statistics-3.3.csproj
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/HeuristicLab.Services.Hive.Statistics-3.3.csproj	(revision 9662)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/HeuristicLab.Services.Hive.Statistics-3.3.csproj	(revision 11020)
@@ -108,6 +108,9 @@
     <Compile Include="App_Start\RouteConfig.cs" />
     <Compile Include="Controllers\AccountController.cs" />
+    <Compile Include="Controllers\AdminDataController.cs" />
     <Compile Include="Controllers\ChartDataController.cs" />
     <Compile Include="Controllers\HomeController.cs" />
+    <Compile Include="Controllers\LoginRequiredController.cs" />
+    <Compile Include="Models\AdminModel.cs" />
     <Compile Include="Models\OverallStatistics.cs" />
     <Compile Include="Global.asax.cs">
@@ -116,7 +119,13 @@
     <Compile Include="Helper\HtmMenulHelper.cs" />
     <Compile Include="Models\AccountModels.cs" />
+    <Compile Include="Models\UserModel.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Content Include="App_Code\ChartHelper.cshtml" />
+    <Content Include="App_Code\AdminHelper.cshtml" />
     <None Include="Properties\AssemblyInfo.cs.frame" />
+    <Content Include="Scripts\CollapsingSection.js" />
+    <Content Include="Scripts\SmoothieChartResize.js" />
+    <Content Include="Views\LoginRequired\UserTask.cshtml" />
+    <Content Include="Views\LoginRequired\Admin.cshtml" />
   </ItemGroup>
   <ItemGroup>
@@ -177,4 +186,5 @@
     <Content Include="Content\hl-logo.png" />
     <Content Include="Global.asax" />
+    <None Include="Properties\PublishProfiles\HiveStatistics-3.3.pubxml" />
     <None Include="Scripts\jquery-1.8.2.intellisense.js" />
     <Content Include="HeuristicLab.ico" />
@@ -266,4 +276,5 @@
     <Content Include="Scripts\jquery.validate.unobtrusive.min.js" />
     <Content Include="Scripts\modernizr-2.6.2.js" />
+    <Content Include="Scripts\smoothie.js" />
     <Content Include="Web.config" />
     <Content Include="Web.Debug.config">
@@ -283,5 +294,7 @@
     <Content Include="Views\Shared\_LoginPartial.cshtml" />
     <Content Include="Views\Shared\_Layout.cshtml" />
-    <Content Include="Views\Web.config" />
+    <Content Include="Views\Web.config">
+      <SubType>Designer</SubType>
+    </Content>
   </ItemGroup>
   <ItemGroup>
@@ -316,9 +329,10 @@
       <FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
         <WebProjectProperties>
-          <UseIIS>True</UseIIS>
+          <UseIIS>False</UseIIS>
           <AutoAssignPort>True</AutoAssignPort>
-          <DevelopmentServerPort>0</DevelopmentServerPort>
+          <DevelopmentServerPort>4496</DevelopmentServerPort>
           <DevelopmentServerVPath>/</DevelopmentServerVPath>
-          <IISUrl>http://localhost:2088/</IISUrl>
+          <IISUrl>
+          </IISUrl>
           <NTLMAuthentication>False</NTLMAuthentication>
           <UseCustomServer>False</UseCustomServer>
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Models/AdminModel.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Models/AdminModel.cs	(revision 11020)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Models/AdminModel.cs	(revision 11020)
@@ -0,0 +1,6 @@
+﻿namespace HeuristicLab.Services.Hive.Statistics.Models {
+  public class AdminModel {
+    public bool IsAdmin { get; set; }
+    public string UserName { get; set; }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Models/UserModel.cs
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Models/UserModel.cs	(revision 11020)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Models/UserModel.cs	(revision 11020)
@@ -0,0 +1,5 @@
+﻿namespace HeuristicLab.Services.Hive.Statistics.Models {
+  public class UserModel {
+    public string UserName { get; set; }
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Properties/PublishProfiles/HiveStatistics-3.3.pubxml
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Properties/PublishProfiles/HiveStatistics-3.3.pubxml	(revision 11020)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Properties/PublishProfiles/HiveStatistics-3.3.pubxml	(revision 11020)
@@ -0,0 +1,51 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<!--
+This file is used by the publish/package process of your Web project. You can customize the behavior of this process
+by editing this MSBuild file. In order to learn more about this please visit http://go.microsoft.com/fwlink/?LinkID=208121. 
+-->
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <WebPublishMethod>MSDeploy</WebPublishMethod>
+    <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
+    <LastUsedPlatform>Any CPU</LastUsedPlatform>
+    <SiteUrlToLaunchAfterPublish />
+    <LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
+    <ExcludeApp_Data>False</ExcludeApp_Data>
+    <MSDeployServiceURL>localhost</MSDeployServiceURL>
+    <DeployIisAppPath>Default Web Site/HiveStatistics-3.3</DeployIisAppPath>
+    <RemoteSitePhysicalPath />
+    <SkipExtraFilesOnServer>True</SkipExtraFilesOnServer>
+    <MSDeployPublishMethod>InProc</MSDeployPublishMethod>
+    <EnableMSDeployBackup>False</EnableMSDeployBackup>
+    <UserName />
+    <_SavePWD>False</_SavePWD>
+    <PublishDatabaseSettings>
+      <Objects xmlns="">
+        <ObjectGroup Name="HeuristicLab.Services.Hive.DataAccess.Settings.HeuristicLab_Hive_LinqConnectionString" Order="1" Enabled="False">
+          <Destination Path="" />
+          <Object Type="DbDacFx">
+            <PreSource Path="Data Source=.\SQLEXPRESS;Initial Catalog=HeuristicLab.Hive-3.3;Integrated Security=True" includeData="False" />
+            <Source Path="$(IntermediateOutputPath)AutoScripts\HeuristicLab.Services.Hive.DataAccess.Settings.HeuristicLab_Hive_LinqConnectionString_IncrementalSchemaOnly.dacpac" dacpacAction="Deploy" />
+          </Object>
+          <UpdateFrom Type="Web.Config">
+            <Source MatchValue="Data Source=.\SQLEXPRESS;Initial Catalog=HeuristicLab.Hive-3.3;Integrated Security=True;" MatchAttributes="$(UpdateFromConnectionStringAttributes)" />
+          </UpdateFrom>
+        </ObjectGroup>
+        <ObjectGroup Name="HeuristicLab.Authentication" Order="2" Enabled="False">
+          <Destination Path="" />
+          <Object Type="DbDacFx">
+            <PreSource Path="data source=.\SQLEXPRESS;Integrated Security=SSPI;Initial Catalog=HeuristicLab.Authentication" includeData="False" />
+            <Source Path="$(IntermediateOutputPath)AutoScripts\HeuristicLab.Authentication_IncrementalSchemaOnly.dacpac" dacpacAction="Deploy" />
+          </Object>
+          <UpdateFrom Type="Web.Config">
+            <Source MatchValue="data source=.\SQLEXPRESS;Integrated Security=SSPI;Initial Catalog=HeuristicLab.Authentication" MatchAttributes="$(UpdateFromConnectionStringAttributes)" />
+          </UpdateFrom>
+        </ObjectGroup>
+      </Objects>
+    </PublishDatabaseSettings>
+  </PropertyGroup>
+  <ItemGroup>
+    <MSDeployParameterValue Include="$(DeployParameterPrefix)HeuristicLab.Authentication-Web.config Connection String" />
+    <MSDeployParameterValue Include="$(DeployParameterPrefix)HeuristicLab.Services.Hive.DataAccess.Settings.HeuristicLab_Hive_LinqConnectionString-Web.config Connection String" />
+  </ItemGroup>
+</Project>
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Scripts/CollapsingSection.js
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Scripts/CollapsingSection.js	(revision 11020)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Scripts/CollapsingSection.js	(revision 11020)
@@ -0,0 +1,27 @@
+﻿/* This file contains the method for shrinking and expanding the collapsable sections */
+
+$(".collapse").click(function () {
+  if ($(this).html() == "-") {
+    $(this).parent().children("canvas, div, fieldset, label").fadeOut();
+    $(this).html("+");
+  }
+  else {
+    $(this).parent().children("canvas, div, fieldset, label").fadeIn();
+    $(this).html("-");
+  }
+});
+
+/* Because Task chart sections are created on the fly adding an event listener
+  was impossible. Therefore this function is hardcoded as an HTML onclick event
+  for the dynamically created buttons of these sections */
+function collapseSection(caller) {
+  var jqCaller = $(caller);
+  if (jqCaller.html() == "-") {
+    jqCaller.parent().children("canvas, div, fieldset, label").fadeOut();
+    jqCaller.html("+");
+  }
+  else {
+    jqCaller.parent().children("canvas, div, fieldset, label").fadeIn();
+    jqCaller.html("-");
+  }
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Scripts/SmoothieChartResize.js
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Scripts/SmoothieChartResize.js	(revision 11020)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Scripts/SmoothieChartResize.js	(revision 11020)
@@ -0,0 +1,11 @@
+﻿/* Contains function to resize the Smoothie Charts on the page */
+
+/* Resizes each smoothieChart on the page to 90 percent of the width
+of the parent container and height is set here*/
+function resizeSmoothie() {
+  $(".smoothieChart").each(function () {
+    var chartParent = $(this).parent().parent();
+    var chartWidth = (chartParent.width() * .88);
+    $(this).parent().html('<canvas id="' + $(this).attr('id') + '" class="smoothieChart" height="110" width="' + chartWidth + '"></canvas>')
+  });
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Scripts/smoothie.js
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Scripts/smoothie.js	(revision 11020)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Scripts/smoothie.js	(revision 11020)
@@ -0,0 +1,736 @@
+// MIT License:
+//
+// Copyright (c) 2010-2013, Joe Walnes
+//               2013-2014, Drew Noakes
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/**
+ * Smoothie Charts - http://smoothiecharts.org/
+ * (c) 2010-2013, Joe Walnes
+ *     2013-2014, Drew Noakes
+ *
+ * v1.0: Main charting library, by Joe Walnes
+ * v1.1: Auto scaling of axis, by Neil Dunn
+ * v1.2: fps (frames per second) option, by Mathias Petterson
+ * v1.3: Fix for divide by zero, by Paul Nikitochkin
+ * v1.4: Set minimum, top-scale padding, remove timeseries, add optional timer to reset bounds, by Kelley Reynolds
+ * v1.5: Set default frames per second to 50... smoother.
+ *       .start(), .stop() methods for conserving CPU, by Dmitry Vyal
+ *       options.interpolation = 'bezier' or 'line', by Dmitry Vyal
+ *       options.maxValue to fix scale, by Dmitry Vyal
+ * v1.6: minValue/maxValue will always get converted to floats, by Przemek Matylla
+ * v1.7: options.grid.fillStyle may be a transparent color, by Dmitry A. Shashkin
+ *       Smooth rescaling, by Kostas Michalopoulos
+ * v1.8: Set max length to customize number of live points in the dataset with options.maxDataSetLength, by Krishna Narni
+ * v1.9: Display timestamps along the bottom, by Nick and Stev-io
+ *       (https://groups.google.com/forum/?fromgroups#!topic/smoothie-charts/-Ywse8FCpKI%5B1-25%5D)
+ *       Refactored by Krishna Narni, to support timestamp formatting function
+ * v1.10: Switch to requestAnimationFrame, removed the now obsoleted options.fps, by Gergely Imreh
+ * v1.11: options.grid.sharpLines option added, by @drewnoakes
+ *        Addressed warning seen in Firefox when seriesOption.fillStyle undefined, by @drewnoakes
+ * v1.12: Support for horizontalLines added, by @drewnoakes
+ *        Support for yRangeFunction callback added, by @drewnoakes
+ * v1.13: Fixed typo (#32), by @alnikitich
+ * v1.14: Timer cleared when last TimeSeries removed (#23), by @davidgaleano
+ *        Fixed diagonal line on chart at start/end of data stream, by @drewnoakes
+ * v1.15: Support for npm package (#18), by @dominictarr
+ *        Fixed broken removeTimeSeries function (#24) by @davidgaleano
+ *        Minor performance and tidying, by @drewnoakes
+ * v1.16: Bug fix introduced in v1.14 relating to timer creation/clearance (#23), by @drewnoakes
+ *        TimeSeries.append now deals with out-of-order timestamps, and can merge duplicates, by @zacwitte (#12)
+ *        Documentation and some local variable renaming for clarity, by @drewnoakes
+ * v1.17: Allow control over font size (#10), by @drewnoakes
+ *        Timestamp text won't overlap, by @drewnoakes
+ * v1.18: Allow control of max/min label precision, by @drewnoakes
+ *        Added 'borderVisible' chart option, by @drewnoakes
+ *        Allow drawing series with fill but no stroke (line), by @drewnoakes
+ * v1.19: Avoid unnecessary repaints, and fixed flicker in old browsers having multiple charts in document (#40), by @asbai
+ * v1.20: Add SmoothieChart.getTimeSeriesOptions and SmoothieChart.bringToFront functions, by @drewnoakes
+ * v1.21: Add 'step' interpolation mode, by @drewnoakes
+ * v1.22: Add support for different pixel ratios. Also add optional y limit formatters, by @copacetic
+ * v1.23: Fix bug introduced in v1.22 (#44), by @drewnoakes
+ */
+
+;(function(exports) {
+
+  var Util = {
+    extend: function() {
+      arguments[0] = arguments[0] || {};
+      for (var i = 1; i < arguments.length; i++)
+      {
+        for (var key in arguments[i])
+        {
+          if (arguments[i].hasOwnProperty(key))
+          {
+            if (typeof(arguments[i][key]) === 'object') {
+              if (arguments[i][key] instanceof Array) {
+                arguments[0][key] = arguments[i][key];
+              } else {
+                arguments[0][key] = Util.extend(arguments[0][key], arguments[i][key]);
+              }
+            } else {
+              arguments[0][key] = arguments[i][key];
+            }
+          }
+        }
+      }
+      return arguments[0];
+    }
+  };
+
+  /**
+   * Initialises a new <code>TimeSeries</code> with optional data options.
+   *
+   * Options are of the form (defaults shown):
+   *
+   * <pre>
+   * {
+   *   resetBounds: true,        // enables/disables automatic scaling of the y-axis
+   *   resetBoundsInterval: 3000 // the period between scaling calculations, in millis
+   * }
+   * </pre>
+   *
+   * Presentation options for TimeSeries are specified as an argument to <code>SmoothieChart.addTimeSeries</code>.
+   *
+   * @constructor
+   */
+  function TimeSeries(options) {
+    this.options = Util.extend({}, TimeSeries.defaultOptions, options);
+    this.data = [];
+    this.maxValue = Number.NaN; // The maximum value ever seen in this TimeSeries.
+    this.minValue = Number.NaN; // The minimum value ever seen in this TimeSeries.
+  }
+
+  TimeSeries.defaultOptions = {
+    resetBoundsInterval: 3000,
+    resetBounds: true
+  };
+
+  /**
+   * Recalculate the min/max values for this <code>TimeSeries</code> object.
+   *
+   * This causes the graph to scale itself in the y-axis.
+   */
+  TimeSeries.prototype.resetBounds = function() {
+    if (this.data.length) {
+      // Walk through all data points, finding the min/max value
+      this.maxValue = this.data[0][1];
+      this.minValue = this.data[0][1];
+      for (var i = 1; i < this.data.length; i++) {
+        var value = this.data[i][1];
+        if (value > this.maxValue) {
+          this.maxValue = value;
+        }
+        if (value < this.minValue) {
+          this.minValue = value;
+        }
+      }
+    } else {
+      // No data exists, so set min/max to NaN
+      this.maxValue = Number.NaN;
+      this.minValue = Number.NaN;
+    }
+  };
+
+  /**
+   * Adds a new data point to the <code>TimeSeries</code>, preserving chronological order.
+   *
+   * @param timestamp the position, in time, of this data point
+   * @param value the value of this data point
+   * @param sumRepeatedTimeStampValues if <code>timestamp</code> has an exact match in the series, this flag controls
+   * whether it is replaced, or the values summed (defaults to false.)
+   */
+  TimeSeries.prototype.append = function(timestamp, value, sumRepeatedTimeStampValues) {
+    // Rewind until we hit an older timestamp
+    var i = this.data.length - 1;
+    while (i > 0 && this.data[i][0] > timestamp) {
+      i--;
+    }
+
+    if (this.data.length > 0 && this.data[i][0] === timestamp) {
+      // Update existing values in the array
+      if (sumRepeatedTimeStampValues) {
+        // Sum this value into the existing 'bucket'
+        this.data[i][1] += value;
+        value = this.data[i][1];
+      } else {
+        // Replace the previous value
+        this.data[i][1] = value;
+      }
+    } else if (i < this.data.length - 1) {
+      // Splice into the correct position to keep timestamps in order
+      this.data.splice(i + 1, 0, [timestamp, value]);
+    } else {
+      // Add to the end of the array
+      this.data.push([timestamp, value]);
+    }
+
+    this.maxValue = isNaN(this.maxValue) ? value : Math.max(this.maxValue, value);
+    this.minValue = isNaN(this.minValue) ? value : Math.min(this.minValue, value);
+  };
+
+  TimeSeries.prototype.dropOldData = function(oldestValidTime, maxDataSetLength) {
+    // We must always keep one expired data point as we need this to draw the
+    // line that comes into the chart from the left, but any points prior to that can be removed.
+    var removeCount = 0;
+    while (this.data.length - removeCount >= maxDataSetLength && this.data[removeCount + 1][0] < oldestValidTime) {
+      removeCount++;
+    }
+    if (removeCount !== 0) {
+      this.data.splice(0, removeCount);
+    }
+  };
+
+  /**
+   * Initialises a new <code>SmoothieChart</code>.
+   *
+   * Options are optional, and should be of the form below. Just specify the values you
+   * need and the rest will be given sensible defaults as shown:
+   *
+   * <pre>
+   * {
+   *   minValue: undefined,                      // specify to clamp the lower y-axis to a given value
+   *   maxValue: undefined,                      // specify to clamp the upper y-axis to a given value
+   *   maxValueScale: 1,                         // allows proportional padding to be added above the chart. for 10% padding, specify 1.1.
+   *   yRangeFunction: undefined,                // function({min: , max: }) { return {min: , max: }; }
+   *   scaleSmoothing: 0.125,                    // controls the rate at which y-value zoom animation occurs
+   *   millisPerPixel: 20,                       // sets the speed at which the chart pans by
+   *   enableDpiScaling: true,                   // support rendering at different DPI depending on the device
+   *   yMinFormatter: function(min, precision) { // callback function that formats the min y value label
+   *     return min.toFixed(precision);
+   *   },
+   *   yMaxFormatter: function(max, precision) { // callback function that formats the max y value label
+   *     return max.toFixed(precision);
+   *   },
+   *   maxDataSetLength: 2,
+   *   interpolation: 'bezier'                   // one of 'bezier', 'linear', or 'step'
+   *   timestampFormatter: null,                 // optional function to format time stamps for bottom of chart
+   *                                             // you may use SmoothieChart.timeFormatter, or your own: function(date) { return ''; }
+   *   horizontalLines: [],                      // [ { value: 0, color: '#ffffff', lineWidth: 1 } ]
+   *   grid:
+   *   {
+   *     fillStyle: '#000000',                   // the background colour of the chart
+   *     lineWidth: 1,                           // the pixel width of grid lines
+   *     strokeStyle: '#777777',                 // colour of grid lines
+   *     millisPerLine: 1000,                    // distance between vertical grid lines
+   *     sharpLines: false,                      // controls whether grid lines are 1px sharp, or softened
+   *     verticalSections: 2,                    // number of vertical sections marked out by horizontal grid lines
+   *     borderVisible: true                     // whether the grid lines trace the border of the chart or not
+   *   },
+   *   labels
+   *   {
+   *     disabled: false,                        // enables/disables labels showing the min/max values
+   *     fillStyle: '#ffffff',                   // colour for text of labels,
+   *     fontSize: 15,
+   *     fontFamily: 'sans-serif',
+   *     precision: 2
+   *   }
+   * }
+   * </pre>
+   *
+   * @constructor
+   */
+  function SmoothieChart(options) {
+    this.options = Util.extend({}, SmoothieChart.defaultChartOptions, options);
+    this.seriesSet = [];
+    this.currentValueRange = 1;
+    this.currentVisMinValue = 0;
+    this.lastRenderTimeMillis = 0;
+  }
+
+  SmoothieChart.defaultChartOptions = {
+    millisPerPixel: 20,
+    enableDpiScaling: true,
+    yMinFormatter: function(min, precision) { return min.toFixed(precision); },
+    yMaxFormatter: function(max, precision) { return max.toFixed(precision); },
+    maxValueScale: 1,
+    interpolation: 'bezier',
+    scaleSmoothing: 0.125,
+    maxDataSetLength: 2,
+    grid: {
+      fillStyle: '#000000',
+      strokeStyle: '#777777',
+      lineWidth: 1,
+      sharpLines: false,
+      millisPerLine: 1000,
+      verticalSections: 2,
+      borderVisible: true
+    },
+    labels: {
+      fillStyle: '#ffffff',
+      disabled: false,
+      fontSize: 10,
+      fontFamily: 'monospace',
+      precision: 2
+    },
+    horizontalLines: []
+  };
+
+  // Based on http://inspirit.github.com/jsfeat/js/compatibility.js
+  SmoothieChart.AnimateCompatibility = (function() {
+    var requestAnimationFrame = function(callback, element) {
+          var requestAnimationFrame =
+            window.requestAnimationFrame        ||
+            window.webkitRequestAnimationFrame  ||
+            window.mozRequestAnimationFrame     ||
+            window.oRequestAnimationFrame       ||
+            window.msRequestAnimationFrame      ||
+            function(callback) {
+              return window.setTimeout(function() {
+                callback(new Date().getTime());
+              }, 16);
+            };
+          return requestAnimationFrame.call(window, callback, element);
+        },
+        cancelAnimationFrame = function(id) {
+          var cancelAnimationFrame =
+            window.cancelAnimationFrame ||
+            function(id) {
+              clearTimeout(id);
+            };
+          return cancelAnimationFrame.call(window, id);
+        };
+
+    return {
+      requestAnimationFrame: requestAnimationFrame,
+      cancelAnimationFrame: cancelAnimationFrame
+    };
+  })();
+
+  SmoothieChart.defaultSeriesPresentationOptions = {
+    lineWidth: 1,
+    strokeStyle: '#ffffff'
+  };
+
+  /**
+   * Adds a <code>TimeSeries</code> to this chart, with optional presentation options.
+   *
+   * Presentation options should be of the form (defaults shown):
+   *
+   * <pre>
+   * {
+   *   lineWidth: 1,
+   *   strokeStyle: '#ffffff',
+   *   fillStyle: undefined
+   * }
+   * </pre>
+   */
+  SmoothieChart.prototype.addTimeSeries = function(timeSeries, options) {
+    this.seriesSet.push({timeSeries: timeSeries, options: Util.extend({}, SmoothieChart.defaultSeriesPresentationOptions, options)});
+    if (timeSeries.options.resetBounds && timeSeries.options.resetBoundsInterval > 0) {
+      timeSeries.resetBoundsTimerId = setInterval(
+        function() {
+          timeSeries.resetBounds();
+        },
+        timeSeries.options.resetBoundsInterval
+      );
+    }
+  };
+
+  /**
+   * Removes the specified <code>TimeSeries</code> from the chart.
+   */
+  SmoothieChart.prototype.removeTimeSeries = function(timeSeries) {
+    // Find the correct timeseries to remove, and remove it
+    var numSeries = this.seriesSet.length;
+    for (var i = 0; i < numSeries; i++) {
+      if (this.seriesSet[i].timeSeries === timeSeries) {
+        this.seriesSet.splice(i, 1);
+        break;
+      }
+    }
+    // If a timer was operating for that timeseries, remove it
+    if (timeSeries.resetBoundsTimerId) {
+      // Stop resetting the bounds, if we were
+      clearInterval(timeSeries.resetBoundsTimerId);
+    }
+  };
+
+  /**
+   * Gets render options for the specified <code>TimeSeries</code>.
+   *
+   * As you may use a single <code>TimeSeries</code> in multiple charts with different formatting in each usage,
+   * these settings are stored in the chart.
+   */
+  SmoothieChart.prototype.getTimeSeriesOptions = function(timeSeries) {
+    // Find the correct timeseries to remove, and remove it
+    var numSeries = this.seriesSet.length;
+    for (var i = 0; i < numSeries; i++) {
+      if (this.seriesSet[i].timeSeries === timeSeries) {
+        return this.seriesSet[i].options;
+      }
+    }
+  };
+
+  /**
+   * Brings the specified <code>TimeSeries</code> to the top of the chart. It will be rendered last.
+   */
+  SmoothieChart.prototype.bringToFront = function(timeSeries) {
+    // Find the correct timeseries to remove, and remove it
+    var numSeries = this.seriesSet.length;
+    for (var i = 0; i < numSeries; i++) {
+      if (this.seriesSet[i].timeSeries === timeSeries) {
+        var set = this.seriesSet.splice(i, 1);
+        this.seriesSet.push(set[0]);
+        break;
+      }
+    }
+  };
+
+  /**
+   * Instructs the <code>SmoothieChart</code> to start rendering to the provided canvas, with specified delay.
+   *
+   * @param canvas the target canvas element
+   * @param delayMillis an amount of time to wait before a data point is shown. This can prevent the end of the series
+   * from appearing on screen, with new values flashing into view, at the expense of some latency.
+   */
+  SmoothieChart.prototype.streamTo = function(canvas, delayMillis) {
+    this.canvas = canvas;
+    this.delay = delayMillis;
+    this.start();
+  };
+
+  /**
+   * Starts the animation of this chart.
+   */
+  SmoothieChart.prototype.start = function() {
+    if (this.frame) {
+      // We're already running, so just return
+      return;
+    }
+    // Make sure the canvas has the optimal resolution for the device's pixel ratio.
+    if (this.options.enableDpiScaling && window && window.devicePixelRatio !== 1) {
+      var canvasWidth = this.canvas.getAttribute('width');
+      var canvasHeight = this.canvas.getAttribute('height');
+
+      this.canvas.setAttribute('width', canvasWidth * window.devicePixelRatio);
+      this.canvas.setAttribute('height', canvasHeight * window.devicePixelRatio);
+      this.canvas.style.width = canvasWidth + 'px';
+      this.canvas.style.height = canvasHeight + 'px';
+      this.canvas.getContext('2d').scale(window.devicePixelRatio, window.devicePixelRatio);
+    }
+
+    // Renders a frame, and queues the next frame for later rendering
+    var animate = function() {
+      this.frame = SmoothieChart.AnimateCompatibility.requestAnimationFrame(function() {
+        this.render();
+        animate();
+      }.bind(this));
+    }.bind(this);
+
+    animate();
+  };
+
+  /**
+   * Stops the animation of this chart.
+   */
+  SmoothieChart.prototype.stop = function() {
+    if (this.frame) {
+      SmoothieChart.AnimateCompatibility.cancelAnimationFrame(this.frame);
+      delete this.frame;
+    }
+  };
+
+  SmoothieChart.prototype.updateValueRange = function() {
+    // Calculate the current scale of the chart, from all time series.
+    var chartOptions = this.options,
+        chartMaxValue = Number.NaN,
+        chartMinValue = Number.NaN;
+
+    for (var d = 0; d < this.seriesSet.length; d++) {
+      // TODO(ndunn): We could calculate / track these values as they stream in.
+      var timeSeries = this.seriesSet[d].timeSeries;
+      if (!isNaN(timeSeries.maxValue)) {
+        chartMaxValue = !isNaN(chartMaxValue) ? Math.max(chartMaxValue, timeSeries.maxValue) : timeSeries.maxValue;
+      }
+
+      if (!isNaN(timeSeries.minValue)) {
+        chartMinValue = !isNaN(chartMinValue) ? Math.min(chartMinValue, timeSeries.minValue) : timeSeries.minValue;
+      }
+    }
+
+    // Scale the chartMaxValue to add padding at the top if required
+    if (chartOptions.maxValue != null) {
+      chartMaxValue = chartOptions.maxValue;
+    } else {
+      chartMaxValue *= chartOptions.maxValueScale;
+    }
+
+    // Set the minimum if we've specified one
+    if (chartOptions.minValue != null) {
+      chartMinValue = chartOptions.minValue;
+    }
+
+    // If a custom range function is set, call it
+    if (this.options.yRangeFunction) {
+      var range = this.options.yRangeFunction({min: chartMinValue, max: chartMaxValue});
+      chartMinValue = range.min;
+      chartMaxValue = range.max;
+    }
+
+    if (!isNaN(chartMaxValue) && !isNaN(chartMinValue)) {
+      var targetValueRange = chartMaxValue - chartMinValue;
+      var valueRangeDiff = (targetValueRange - this.currentValueRange);
+      var minValueDiff = (chartMinValue - this.currentVisMinValue);
+      this.isAnimatingScale = Math.abs(valueRangeDiff) > 0.1 || Math.abs(minValueDiff) > 0.1;
+      this.currentValueRange += chartOptions.scaleSmoothing * valueRangeDiff;
+      this.currentVisMinValue += chartOptions.scaleSmoothing * minValueDiff;
+    }
+
+    this.valueRange = { min: chartMinValue, max: chartMaxValue };
+  };
+
+  SmoothieChart.prototype.render = function(canvas, time) {
+    var nowMillis = new Date().getTime();
+
+    if (!this.isAnimatingScale) {
+      // We're not animating. We can use the last render time and the scroll speed to work out whether
+      // we actually need to paint anything yet. If not, we can return immediately.
+
+      // Render at least every 1/6th of a second. The canvas may be resized, which there is
+      // no reliable way to detect.
+      var maxIdleMillis = Math.min(1000/6, this.options.millisPerPixel);
+
+      if (nowMillis - this.lastRenderTimeMillis < maxIdleMillis) {
+        return;
+      }
+    }
+    this.lastRenderTimeMillis = nowMillis;
+
+    canvas = canvas || this.canvas;
+    time = time || nowMillis - (this.delay || 0);
+
+    // Round time down to pixel granularity, so motion appears smoother.
+    time -= time % this.options.millisPerPixel;
+
+    var context = canvas.getContext('2d'),
+        chartOptions = this.options,
+        dimensions = { top: 0, left: 0, width: canvas.clientWidth, height: canvas.clientHeight },
+        // Calculate the threshold time for the oldest data points.
+        oldestValidTime = time - (dimensions.width * chartOptions.millisPerPixel),
+        valueToYPixel = function(value) {
+          var offset = value - this.currentVisMinValue;
+          return this.currentValueRange === 0
+            ? dimensions.height
+            : dimensions.height - (Math.round((offset / this.currentValueRange) * dimensions.height));
+        }.bind(this),
+        timeToXPixel = function(t) {
+          return Math.round(dimensions.width - ((time - t) / chartOptions.millisPerPixel));
+        };
+
+    this.updateValueRange();
+
+    context.font = chartOptions.labels.fontSize + 'px ' + chartOptions.labels.fontFamily;
+
+    // Save the state of the canvas context, any transformations applied in this method
+    // will get removed from the stack at the end of this method when .restore() is called.
+    context.save();
+
+    // Move the origin.
+    context.translate(dimensions.left, dimensions.top);
+
+    // Create a clipped rectangle - anything we draw will be constrained to this rectangle.
+    // This prevents the occasional pixels from curves near the edges overrunning and creating
+    // screen cheese (that phrase should need no explanation).
+    context.beginPath();
+    context.rect(0, 0, dimensions.width, dimensions.height);
+    context.clip();
+
+    // Clear the working area.
+    context.save();
+    context.fillStyle = chartOptions.grid.fillStyle;
+    context.clearRect(0, 0, dimensions.width, dimensions.height);
+    context.fillRect(0, 0, dimensions.width, dimensions.height);
+    context.restore();
+
+    // Grid lines...
+    context.save();
+    context.lineWidth = chartOptions.grid.lineWidth;
+    context.strokeStyle = chartOptions.grid.strokeStyle;
+    // Vertical (time) dividers.
+    if (chartOptions.grid.millisPerLine > 0) {
+      var textUntilX = dimensions.width - context.measureText(minValueString).width + 4;
+      for (var t = time - (time % chartOptions.grid.millisPerLine);
+           t >= oldestValidTime;
+           t -= chartOptions.grid.millisPerLine) {
+        var gx = timeToXPixel(t);
+        if (chartOptions.grid.sharpLines) {
+          gx -= 0.5;
+        }
+        context.beginPath();
+        context.moveTo(gx, 0);
+        context.lineTo(gx, dimensions.height);
+        context.stroke();
+        context.closePath();
+
+        // Display timestamp at bottom of this line if requested, and it won't overlap
+        if (chartOptions.timestampFormatter && gx < textUntilX) {
+          // Formats the timestamp based on user specified formatting function
+          // SmoothieChart.timeFormatter function above is one such formatting option
+          var tx = new Date(t),
+            ts = chartOptions.timestampFormatter(tx),
+            tsWidth = context.measureText(ts).width;
+          textUntilX = gx - tsWidth - 2;
+          context.fillStyle = chartOptions.labels.fillStyle;
+          context.fillText(ts, gx - tsWidth, dimensions.height - 2);
+        }
+      }
+    }
+
+    // Horizontal (value) dividers.
+    for (var v = 1; v < chartOptions.grid.verticalSections; v++) {
+      var gy = Math.round(v * dimensions.height / chartOptions.grid.verticalSections);
+      if (chartOptions.grid.sharpLines) {
+        gy -= 0.5;
+      }
+      context.beginPath();
+      context.moveTo(0, gy);
+      context.lineTo(dimensions.width, gy);
+      context.stroke();
+      context.closePath();
+    }
+    // Bounding rectangle.
+    if (chartOptions.grid.borderVisible) {
+      context.beginPath();
+      context.strokeRect(0, 0, dimensions.width, dimensions.height);
+      context.closePath();
+    }
+    context.restore();
+
+    // Draw any horizontal lines...
+    if (chartOptions.horizontalLines && chartOptions.horizontalLines.length) {
+      for (var hl = 0; hl < chartOptions.horizontalLines.length; hl++) {
+        var line = chartOptions.horizontalLines[hl],
+            hly = Math.round(valueToYPixel(line.value)) - 0.5;
+        context.strokeStyle = line.color || '#ffffff';
+        context.lineWidth = line.lineWidth || 1;
+        context.beginPath();
+        context.moveTo(0, hly);
+        context.lineTo(dimensions.width, hly);
+        context.stroke();
+        context.closePath();
+      }
+    }
+
+    // For each data set...
+    for (var d = 0; d < this.seriesSet.length; d++) {
+      context.save();
+      var timeSeries = this.seriesSet[d].timeSeries,
+          dataSet = timeSeries.data,
+          seriesOptions = this.seriesSet[d].options;
+
+      // Delete old data that's moved off the left of the chart.
+      timeSeries.dropOldData(oldestValidTime, chartOptions.maxDataSetLength);
+
+      // Set style for this dataSet.
+      context.lineWidth = seriesOptions.lineWidth;
+      context.strokeStyle = seriesOptions.strokeStyle;
+      // Draw the line...
+      context.beginPath();
+      // Retain lastX, lastY for calculating the control points of bezier curves.
+      var firstX = 0, lastX = 0, lastY = 0;
+      for (var i = 0; i < dataSet.length && dataSet.length !== 1; i++) {
+        var x = timeToXPixel(dataSet[i][0]),
+            y = valueToYPixel(dataSet[i][1]);
+
+        if (i === 0) {
+          firstX = x;
+          context.moveTo(x, y);
+        } else {
+          switch (chartOptions.interpolation) {
+            case "linear":
+            case "line": {
+              context.lineTo(x,y);
+              break;
+            }
+            case "bezier":
+            default: {
+              // Great explanation of Bezier curves: http://en.wikipedia.org/wiki/Bezier_curve#Quadratic_curves
+              //
+              // Assuming A was the last point in the line plotted and B is the new point,
+              // we draw a curve with control points P and Q as below.
+              //
+              // A---P
+              //     |
+              //     |
+              //     |
+              //     Q---B
+              //
+              // Importantly, A and P are at the same y coordinate, as are B and Q. This is
+              // so adjacent curves appear to flow as one.
+              //
+              context.bezierCurveTo( // startPoint (A) is implicit from last iteration of loop
+                Math.round((lastX + x) / 2), lastY, // controlPoint1 (P)
+                Math.round((lastX + x)) / 2, y, // controlPoint2 (Q)
+                x, y); // endPoint (B)
+              break;
+            }
+            case "step": {
+              context.lineTo(x,lastY);
+              context.lineTo(x,y);
+              break;
+            }
+          }
+        }
+
+        lastX = x; lastY = y;
+      }
+
+      if (dataSet.length > 1) {
+        if (seriesOptions.fillStyle) {
+          // Close up the fill region.
+          context.lineTo(dimensions.width + seriesOptions.lineWidth + 1, lastY);
+          context.lineTo(dimensions.width + seriesOptions.lineWidth + 1, dimensions.height + seriesOptions.lineWidth + 1);
+          context.lineTo(firstX, dimensions.height + seriesOptions.lineWidth);
+          context.fillStyle = seriesOptions.fillStyle;
+          context.fill();
+        }
+
+        if (seriesOptions.strokeStyle && seriesOptions.strokeStyle !== 'none') {
+          context.stroke();
+        }
+        context.closePath();
+      }
+      context.restore();
+    }
+
+    // Draw the axis values on the chart.
+    if (!chartOptions.labels.disabled && !isNaN(this.valueRange.min) && !isNaN(this.valueRange.max)) {
+      var maxValueString = chartOptions.yMaxFormatter(this.valueRange.max, chartOptions.labels.precision),
+          minValueString = chartOptions.yMinFormatter(this.valueRange.min, chartOptions.labels.precision);
+      context.fillStyle = chartOptions.labels.fillStyle;
+      context.fillText(maxValueString, dimensions.width - context.measureText(maxValueString).width - 2, chartOptions.labels.fontSize);
+      context.fillText(minValueString, dimensions.width - context.measureText(minValueString).width - 2, dimensions.height - 2);
+    }
+
+    context.restore(); // See .save() above.
+  };
+
+  // Sample timestamp formatting function
+  SmoothieChart.timeFormatter = function(date) {
+    function pad2(number) { return (number < 10 ? '0' : '') + number }
+    return pad2(date.getHours()) + ':' + pad2(date.getMinutes()) + ':' + pad2(date.getSeconds());
+  };
+
+  exports.TimeSeries = TimeSeries;
+  exports.SmoothieChart = SmoothieChart;
+
+})(typeof exports === 'undefined' ? this : exports);
+
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Views/Home/Index.cshtml
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Views/Home/Index.cshtml	(revision 9662)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Views/Home/Index.cshtml	(revision 11020)
@@ -2,78 +2,98 @@
 
 @{
-    ViewBag.Title = "Status Monitor";
+  ViewBag.Title = "Status Monitor";
 }
 
 <h1>Current Status</h1>
 
+@*
+Original code
 <section>
-    <table>
-        <tr>
-            <td>Overall Available Cores</td>
-            <td>@Model.OverallCurrentlyAvailableCores</td>
-        </tr>
-        <tr>
-            <td>Availabe Cores (real)</td>
-            <td>@Model.CurrentlyAvailableCores</td>
-        </tr>
-        <tr>
-            <td>Used Cores</td>
-            <td>@Model.CurrentlyUsedCores</td>
-        </tr>
-        <tr>
-            <td>System-Wide Waiting Tasks</td>
-            <td>@Model.CurrentlyJobsWaiting</td>
-        </tr>
-        <tr>
-            <td>Overall Avg. CPU Utilization</td>
-            <td>@Model.OverallCpuUtilization</td>
-        </tr>
-        <tr>
-            <td>Available Avg. CPU Utilization</td>
-            <td>@Model.AvailableCpuUtilization</td>
-        </tr>
-    </table>
+  <table>
+    <tr>
+      <td>Overall Available Cores</td>
+      <td>@Model.OverallCurrentlyAvailableCores</td>
+    </tr>
+    <tr>
+      <td>Availabe Cores (real)</td>
+      <td>@Model.CurrentlyAvailableCores</td>
+    </tr>
+    <tr>
+      <td>Used Cores</td>
+      <td>@Model.CurrentlyUsedCores</td>
+    </tr>
+    <tr>
+      <td>System-Wide Waiting Tasks</td>
+      <td>@Model.CurrentlyJobsWaiting</td>
+    </tr>
+    <tr>
+      <td>Overall Avg. CPU Utilization</td>
+      <td>@Model.OverallCpuUtilization</td>
+    </tr>
+    <tr>
+      <td>Available Avg. CPU Utilization</td>
+      <td>@Model.AvailableCpuUtilization</td>
+    </tr>
+  </table>
+</section>*@
+
+<section class="chartContainer">
+  <h1 class="title">Current Hive Status</h1>
+  <button class="collapse">-</button>
+@*  <label id="lblCurrentCPUUtilization" class="smoothieLabel">Current CPU Utilization</label>
+  <div class="smoothieHolder">
+    <canvas id="CurrentCPUUtilization" class="smoothieChart"></canvas>
+  </div>
+  <label id="lblCurrentTotalUsedCores" class="smoothieLabel">Current Total and Used Cores</label>
+  <div class="smoothieHolder">
+    <canvas id="CurrentTotalUsedCores" class="smoothieChart"></canvas>
+  </div>
+  <label id="lblCurrentTotalUsedMemory" class="smoothieLabel">Current Total and Used Memory</label>
+  <div class="smoothieHolder">
+    <canvas id="CurrentTotalUsedMemory" class="smoothieChart"></canvas>
+  </div>*@
+  <div id="CurrentCPUUtilization"></div>
+  <div id="CurrentTotalUsedCores"></div>
+  <div id="CurrentTotalUsedMemory"></div>
 </section>
 
-<fieldset>
-        <legend>Range</legend>
-        <ol>
-            <li>Start</li>
-            <li>
-                @Html.TextBox("Start", (DateTime.Now - new TimeSpan(1, 0, 0, 0)).ToString("yyyy-MM-dd"), new { @class = "date" })
-            </li>
-            <li>End</li>
-            <li>
-                @Html.TextBox("End", (DateTime.Now + new TimeSpan(1, 0, 0, 0)).ToString("yyyy-MM-dd"), new { @class = "date" })
-            </li>
-        </ol>
-        <button id="refresh">Refresh</button>
-    </fieldset>
-
-<section class="charts">
-    <div id="AverageCpuUtilization"></div>
-    <div id="UsedCores"></div>
-    <div id="UsedMemory"></div>
+<section class="chartContainer">
+  <h1 class="title">Historic Hive Status</h1>
+  <button class="collapse">-</button>
+  <fieldset>
+    <legend>Range</legend>
+    <label>Start</label>
+    @Html.TextBox("Start", (DateTime.Now - new TimeSpan(1, 0, 0, 0)).ToString("yyyy-MM-dd"), new { @class = "date" })
+    <label>End</label>
+    @Html.TextBox("End", (DateTime.Now + new TimeSpan(1, 0, 0, 0)).ToString("yyyy-MM-dd"), new { @class = "date" })
+    <button id="Refresh">Refresh</button>
+  </fieldset>
+  <div id="AverageCpuUtilization"></div>
+  <div id="UsedCores"></div>
+  <div id="UsedMemory"></div>
 </section>
 
 @section Styles {
-    @Styles.Render("~/Styles/jqPlot/jquery.jqplot")
-    @Styles.Render("~/Content/themes/base/css")
+  @Styles.Render("~/Styles/jqPlot/jquery.jqplot")
+  @Styles.Render("~/Content/themes/base/css")
 }
 
 @section Scripts {
-    @Scripts.Render("~/bundles/jqueryui")
-    <script>
-    $("#refresh").button({
-        icons: {
-            primary: "ui-icon-refresh"
-        }
+  @Scripts.Render("~/bundles/jqueryui")
+  @Scripts.Render("~/Scripts/smoothie.js")
+  @Scripts.Render("~/Scripts/SmoothieChartResize.js")
+  @Scripts.Render("~/Scripts/CollapsingSection.js")
+  <script>
+    $("#Refresh").button({
+      icons: {
+        primary: "ui-icon-refresh"
+      }
     });
-    </script>
+  </script>
 
-    @Scripts.Render("~/Scripts/jqPlot/jquery.jqplot")
-    @ChartHelper.AjaxDataRenderer()
+  @Scripts.Render("~/Scripts/jqPlot/jquery.jqplot")
+  @ChartHelper.AjaxDataRenderer()
 
-    @ChartHelper.LineChartTime(
+  @ChartHelper.LineChartTime(
         "AverageCpuUtilization",
         Url.Action("AverageCpuUtilization", "ChartData"),
@@ -82,5 +102,5 @@
         minY: 0, maxY: 100)
 
-    @ChartHelper.LineChartTime(
+  @ChartHelper.LineChartTime(
         "UsedCores",
         Url.Action("UsedCores", "ChartData"),
@@ -88,5 +108,5 @@
         minY: 0)
 
-    @ChartHelper.LineChartTime(
+  @ChartHelper.LineChartTime(
         "UsedMemory",
         Url.Action("UsedMemory", "ChartData"),
@@ -94,26 +114,74 @@
         minY: 0)
 
-    <script>
-        $(document).ready(function () {
-            $(".date").datepicker({
-                dateFormat: "yy-mm-dd",
-                onSelect: function () { refreshCharts(); }
-            });
+  <script>
+    $(document).ready(function () {
+      $(".date").datepicker({
+        dateFormat: "yy-mm-dd",
+        onSelect: function () { refreshCharts(); }
+      });
 
-            $("#refresh").click(function() {
-                refreshCharts();
-            });
+      $("#Refresh").click(function () {
+        refreshCharts();
+      });
 
-            
-        });
-        
-        function refreshCharts() {
-            var startDate = $('#Start').val();
-            var endDate = $('#End').val();
+      //resizeSmoothie();
+      //createSmoothie();
+    });
 
-            @ChartHelper.RefreshChart("AverageCpuUtilization", Url.Action("AverageCpuUtilization", "ChartData"), "startDate", "endDate")
-            @ChartHelper.RefreshChart("UsedCores", Url.Action("UsedCores", "ChartData"), "startDate", "endDate")
-            @ChartHelper.RefreshChart("UsedMemory", Url.Action("UsedMemory", "ChartData"), "startDate", "endDate")
-        }
-    </script>
+    function refreshCharts() {
+      var startDate = $('#Start').val();
+      var endDate = $('#End').val();
+
+      @ChartHelper.RefreshChart("AverageCpuUtilization", Url.Action("AverageCpuUtilization", "ChartData"), "startDate", "endDate")
+      @ChartHelper.RefreshChart("UsedCores", Url.Action("UsedCores", "ChartData"), "startDate", "endDate")
+      @ChartHelper.RefreshChart("UsedMemory", Url.Action("UsedMemory", "ChartData"), "startDate", "endDate")
+    }
+
+@*    function createSmoothie() {
+      //Create new SmoothieChart(s)
+      @ChartHelper.CreateSmoothieChart("CurrentCPUUtilization","rgb(179, 179, 179)","rgb(242, 242, 242)","rgb(0, 22, 84)")
+      @ChartHelper.CreateSmoothieChart("CurrentTotalUsedCores","rgb(179, 179, 179)","rgb(242, 242, 242)","rgb(0, 22, 84)")
+      @ChartHelper.CreateSmoothieChart("CurrentTotalUsedMemory","rgb(179, 179, 179)","rgb(242, 242, 242)","rgb(0, 22, 84)")
+
+      //Second argument is delay in chart display, used to make drawing smooth,
+      //Should be matched to interval time below
+      @ChartHelper.SetSmoothieCanvas("CurrentCPUUtilization","5000")
+      @ChartHelper.SetSmoothieCanvas("CurrentTotalUsedCores","5000")
+      @ChartHelper.SetSmoothieCanvas("CurrentTotalUsedMemory","5000")
+
+      //Set interval to run ajax and get new values
+      @ChartHelper.AssignTimeSeries("averageUsage", "CurrentCPUUtilization", "rgb(0, 255, 0)", "rgba(0, 255, 0, 0.4)")
+      @ChartHelper.AssignTimeSeries("overallCore", "CurrentTotalUsedCores", "rgb(0, 255, 0)", "rgba(0, 255, 0, 0.4)")
+      @ChartHelper.AssignTimeSeries("usedCore", "CurrentTotalUsedCores", "rgb(242, 182, 70)", "rgba(255, 199, 94, 0.4)")
+      @ChartHelper.AssignTimeSeries("overallMemory", "CurrentTotalUsedMemory", "rgb(0, 255, 0)", "rgba(0, 255, 0, 0.4)")
+      @ChartHelper.AssignTimeSeries("usedMemory", "CurrentTotalUsedMemory", "rgb(242, 182, 70)", "rgba(255, 199, 94, 0.4)")
+
+      setInterval(function () { getChartUpdate() }, 5000);
+
+      //Hit by interval, jQuery ajax request to get new data from db
+      function getChartUpdate() {
+        @ChartHelper.UpdateChartData("CurrentCPUUtilization", Url.Action("CurrentCpuUtilization","ChartData"))
+        @ChartHelper.UpdateChartData("CurrentTotalUsedCores", Url.Action("CurrentCores","ChartData"))
+        @ChartHelper.UpdateChartData("CurrentTotalUsedMemory", Url.Action("CurrentMemory","ChartData"))
+      }
+    }*@
+
+    $(document).ready(function () {
+      @ChartHelper.SetStreamingProperties(1000,20,10)
+
+      @ChartHelper.CreateStreamChart("CurrentCPU", "CurrentCPUUtilization",Url.Action("CurrentCpuUtilization","ChartData"),"Current CPU Utilization","%.2f%%",100.00)
+      @ChartHelper.CreateStreamChart("CurrentCores", "CurrentTotalUsedCores",Url.Action("CurrentCores","ChartData"),"Current Total vs. Used Cores")
+      @ChartHelper.CreateStreamChart("CurrentMemory", "CurrentTotalUsedMemory",Url.Action("CurrentMemory","ChartData"),"Current Total vs. Used Memory")
+
+      function doUpdate() {
+        @ChartHelper.UpdateStreamChart("CurrentCPU","CurrentCPUUtilization", Url.Action("CurrentCpuUtilization","ChartData"),"FixedY")
+        @ChartHelper.UpdateStreamChart("CurrentCores","CurrentTotalUsedCores", Url.Action("CurrentCores","ChartData"))
+        @ChartHelper.UpdateStreamChart("CurrentMemory","CurrentTotalUsedMemory", Url.Action("CurrentMemory","ChartData"))
+        setTimeout(doUpdate, refreshRate);
+      }
+
+      doUpdate();
+
+    });
+  </script>
 }
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Views/LoginRequired/Admin.cshtml
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Views/LoginRequired/Admin.cshtml	(revision 11020)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Views/LoginRequired/Admin.cshtml	(revision 11020)
@@ -0,0 +1,115 @@
+﻿@model HeuristicLab.Services.Hive.Statistics.Models.AdminModel
+
+@{
+    ViewBag.Title = "Admin";
+}
+
+@if(!Model.IsAdmin) {
+  <h1>The user you are logged in as: @Model.UserName, is not an administrator.</h1>
+}
+else {
+    <!--[if gte IE 9]>
+    <style type="text/css">
+      .innerBar {
+          filter: none;
+      }
+    </style>
+  <![endif]-->
+  <h1>Welcome to the administrator page @Model.UserName!</h1>
+  <button id="UserOverviewButton" class="tabButton">User Overview</button>
+  <button id="TaskOverviewButton" class="tabButton">Task Overview</button>
+  //User overview
+  <section id="UserOverviewTab" class="tabSection">
+    <fieldset id="Users" class="usersField">
+      <legend>Users</legend>
+      <select id="UserList" class="usersList">
+      </select>
+      <label>Start</label>
+      @Html.TextBox("UserStart", (DateTime.Now - new TimeSpan(8, 0, 0, 0)).ToString("yyyy-MM-dd"), new { @class = "date" })
+      <label>End</label>
+      @Html.TextBox("UserEnd", (DateTime.Now + new TimeSpan(1, 0, 0, 0)).ToString("yyyy-MM-dd"), new { @class = "date" })
+    </fieldset>
+    <section id="TasksContainer" class="adminDataContainer"></section>
+  </section>
+  //Task overview
+  <section id="TaskOverviewTab" class="tabSection">
+    <fieldset id="TaskUsers" class="usersField">
+      <legend>Users</legend>
+      <select id="TaskUserList" class="usersList">
+      </select>
+      <label>Start</label>
+      @Html.TextBox("TaskStart", (DateTime.Now - new TimeSpan(8, 0, 0, 0)).ToString("yyyy-MM-dd"), new { @class = "date" })
+      <label>End</label>
+      @Html.TextBox("TaskEnd", (DateTime.Now + new TimeSpan(1, 0, 0, 0)).ToString("yyyy-MM-dd"), new { @class = "date" })
+    </fieldset>
+    <section id="TaskStatsContainer" class="adminDataContainer"></section>
+  </section>
+}
+
+@section Styles {
+  @Styles.Render("~/Styles/jqPlot/jquery.jqplot")
+  @Styles.Render("~/Content/themes/base/css")
+}
+
+@section Scripts {
+  @Scripts.Render("~/bundles/jqueryui")
+  @Scripts.Render("~/Scripts/CollapsingSection.js")
+  @Scripts.Render("~/Scripts/jqPlot/jquery.jqplot")
+  @Scripts.Render("~/Scripts/jqPlot/plugins/jqplot.barRenderer.min.js")
+  @Scripts.Render("~/Scripts/jqPlot/plugins/jqplot.categoryAxisRenderer.min.js")
+  @Scripts.Render("~/Scripts/jqPlot/plugins/jqplot.pointLabels.min.js")
+
+  @AdminHelper.UserList("UserList", Url.Action("UserList", "AdminData"),true)
+  @AdminHelper.UserList("TaskUserList", Url.Action("UserList", "AdminData"),false)
+
+  <script>
+    var startDate;
+    var endDate;
+    var selectedUser;
+
+    $(document).ready(function () {
+      $("#UserStart, #UserEnd").datepicker({
+        dateFormat: "yy-mm-dd",
+        onSelect: function () { RefreshUser(); }
+      });
+    });
+
+    $("#UserList").change(function () {
+      RefreshUser();
+    });
+
+    function RefreshUser () {
+      selectedUser = $("#UserList").val();
+      startDate = $('#UserStart').val();
+      endDate = $('#UserEnd').val();
+      @ChartHelper.TasksForUser("TasksContainer", "Task", Url.Action("GetUserTask", "ChartData"),"selectedUser","startDate","endDate")
+      @ChartHelper.ResizeTasks("Task")
+    }
+
+    $(document).ready(function () {
+      $("#TaskStart, #TaskEnd").datepicker({
+        dateFormat: "yy-mm-dd",
+        onSelect: function () { RefreshTask(); }
+      });
+    });
+
+    $("#TaskUserList").change(function () {
+      RefreshTask();
+    });
+
+    function RefreshTask() {
+      selectedUser = $("#TaskUserList").val();
+      startDate = $('#TaskStart').val();
+      endDate = $('#TaskEnd').val();
+      @AdminHelper.UserTaskStats("TaskStatsContainer",Url.Action("AllTaskStats", "AdminData"),Url.Action("UserTaskStats", "AdminData"),"selectedUser","startDate","endDate")
+    }
+
+    $(".tabButton").click(function () {
+      var sender = $(this).attr('id');
+      $(".tabButton").css({'border-bottom' : '1px solid #8297F5', 'background' : 'none' });
+      $(this).css({ 'border-bottom': '1px solid #E0E6FF', 'background-color': '#E0E6FF' });
+      $(".tabSection").css('display', 'none');
+      $("#" + sender.slice(0, -6) + "Tab").css('display', 'block');
+    })
+  </script>
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Views/LoginRequired/UserTask.cshtml
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Views/LoginRequired/UserTask.cshtml	(revision 11020)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Views/LoginRequired/UserTask.cshtml	(revision 11020)
@@ -0,0 +1,68 @@
+﻿@model HeuristicLab.Services.Hive.Statistics.Models.UserModel
+
+@{
+    ViewBag.Title = "Task Information";
+}
+
+<h1>Task Information for User: @Model.UserName</h1>
+<section>
+  <fieldset id="filters">
+    <legend>Filters</legend>
+    <label>Start</label>
+    @Html.TextBox("Start", (DateTime.Now - new TimeSpan(1, 0, 0, 0)).ToString("yyyy-MM-dd"), new { @class = "date" })
+    <label>End</label>
+    @Html.TextBox("End", (DateTime.Now + new TimeSpan(1, 0, 0, 0)).ToString("yyyy-MM-dd"), new { @class = "date" })
+    <button id="Apply">Apply</button>
+  </fieldset>
+</section>
+<section id="TasksContainer">
+</section>
+
+@section Styles {
+  @Styles.Render("~/Styles/jqPlot/jquery.jqplot")
+  @Styles.Render("~/Content/themes/base/css")
+}
+
+@section Scripts {
+  @Scripts.Render("~/bundles/jqueryui")
+  @Scripts.Render("~/Scripts/CollapsingSection.js")
+  @Scripts.Render("~/Scripts/jqPlot/jquery.jqplot")
+  @Scripts.Render("~/Scripts/jqPlot/plugins/jqplot.barRenderer.min.js")
+  @Scripts.Render("~/Scripts/jqPlot/plugins/jqplot.categoryAxisRenderer.min.js")
+  @Scripts.Render("~/Scripts/jqPlot/plugins/jqplot.pointLabels.min.js")
+
+  @ChartHelper.AjaxDataRenderer()
+  
+  <script>
+    $("#Apply").button({
+      icons: {
+        primary: "ui-icon-refresh"
+      }
+    });
+    $(document).ready(function () {
+      $(".date").datepicker({
+        dateFormat: "yy-mm-dd",
+        onSelect: function () { filterTasks(); }
+      });
+    });
+    $("#Apply").click(function () {
+      filterTasks();
+    });
+
+    function filterTasks() {
+      startDate = $('#Start').val();
+      endDate = $('#End').val();
+
+      @ChartHelper.TasksForUser("TasksContainer","Task",Url.Action("GetUserTask", "ChartData"),"userName","startDate","endDate")
+      @ChartHelper.ResizeTasks("Task")
+    }
+
+    var userName = "@Model.UserName";
+    var startDate = $('#Start').val();
+    var endDate = $('#End').val();
+
+    @ChartHelper.TasksForUser("TasksContainer","Task",Url.Action("GetUserTask", "ChartData"),"userName","startDate","endDate")
+    @ChartHelper.ResizeTasks("Task")
+  </script>
+
+}
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Views/Shared/_Layout.cshtml
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Views/Shared/_Layout.cshtml	(revision 9662)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Views/Shared/_Layout.cshtml	(revision 11020)
@@ -22,4 +22,6 @@
             <ul>
                 <li>@Html.MenuItem("Home", "Index", "Home")</li>
+                <li>@Html.MenuItem("User", "UserTask", "LoginRequired")</li>
+                <li>@Html.MenuItem("Admin", "Admin", "LoginRequired")</li>
                 <li>@Html.MenuItem("About", "About", "Home")</li>
                 <li>@Html.MenuItem("Contact", "Contact", "Home")</li>
Index: branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Web.config
===================================================================
--- branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Web.config	(revision 9662)
+++ branches/HiveStatistics/sources/HeuristicLab.Services.Hive.Statistics/3.3/Web.config	(revision 11020)
@@ -1,3 +1,3 @@
-﻿<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0"?>
 <!--
   For more information on how to configure your ASP.NET application, please visit
@@ -6,64 +6,64 @@
 <configuration>
   <connectionStrings>
-    <add name="HeuristicLab.Authentication" connectionString="data source=localhost;Integrated Security=SSPI;Initial Catalog=HeuristicLab.Authentication" />
-    <!--<add name="HeuristicLab.Services.Hive.DataAccess.Settings.HeuristicLab_Hive_LinqConnectionString" connectionString="Data Source=localhost;Initial Catalog=HeuristicLab.Hive-3.3;Integrated Security=True;" providerName="System.Data.SqlClient" />-->
+    <add name="HeuristicLab.Authentication" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;Initial Catalog=HeuristicLab.Authentication"/>
+    <add name="HeuristicLab.Services.Hive.DataAccess.Settings.HeuristicLab_Hive_LinqConnectionString" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=HeuristicLab.Hive-3.3;Integrated Security=True;" providerName="System.Data.SqlClient"/>
   </connectionStrings>
   <appSettings>
-    <add key="webpages:Version" value="2.0.0.0" />
-    <add key="webpages:Enabled" value="false" />
-    <add key="PreserveLoginUrl" value="true" />
-    <add key="ClientValidationEnabled" value="true" />
-    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
+    <add key="webpages:Version" value="2.0.0.0"/>
+    <add key="webpages:Enabled" value="false"/>
+    <add key="PreserveLoginUrl" value="true"/>
+    <add key="ClientValidationEnabled" value="true"/>
+    <add key="UnobtrusiveJavaScriptEnabled" value="true"/>
   </appSettings>
   <system.web>
-    <compilation debug="true" targetFramework="4.0" />
+    <compilation targetFramework="4.0" debug="true"/>
     <authentication mode="Forms">
-      <forms loginUrl="~/Account/Login" timeout="2880" />
+      <forms loginUrl="~/Account/Login" timeout="2880"/>
     </authentication>
     <membership>
       <providers>
-        <clear />
-        <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="HeuristicLab.Authentication" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="HeuristicLab.Authentication" />
+        <clear/>
+        <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="HeuristicLab.Authentication" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="HeuristicLab.Authentication"/>
       </providers>
     </membership>
     <roleManager enabled="true">
       <providers>
-        <clear />
-        <add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="HeuristicLab.Authentication" applicationName="HeuristicLab.Authentication" />
+        <clear/>
+        <add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="HeuristicLab.Authentication" applicationName="HeuristicLab.Authentication"/>
       </providers>
     </roleManager>
     <pages>
       <namespaces>
-        <add namespace="System.Web.Helpers" />
-        <add namespace="System.Web.Mvc" />
-        <add namespace="System.Web.Mvc.Ajax" />
-        <add namespace="System.Web.Mvc.Html" />
-        <add namespace="System.Web.Optimization" />
-        <add namespace="System.Web.Routing" />
-        <add namespace="System.Web.WebPages" />
+        <add namespace="System.Web.Helpers"/>
+        <add namespace="System.Web.Mvc"/>
+        <add namespace="System.Web.Mvc.Ajax"/>
+        <add namespace="System.Web.Mvc.Html"/>
+        <add namespace="System.Web.Optimization"/>
+        <add namespace="System.Web.Routing"/>
+        <add namespace="System.Web.WebPages"/>
       </namespaces>
     </pages>
   </system.web>
   <system.webServer>
-    <validation validateIntegratedModeConfiguration="false" />
-    <modules runAllManagedModulesForAllRequests="true" />
+    <validation validateIntegratedModeConfiguration="false"/>
+    <modules runAllManagedModulesForAllRequests="true"/>
   </system.webServer>
   <runtime>
     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
       <dependentAssembly>
-        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
-        <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
+        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35"/>
+        <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="2.0.0.0"/>
       </dependentAssembly>
       <dependentAssembly>
-        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
-        <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
+        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35"/>
+        <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0"/>
       </dependentAssembly>
       <dependentAssembly>
-        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
-        <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
+        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35"/>
+        <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="2.0.0.0"/>
       </dependentAssembly>
       <dependentAssembly>
-        <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
-        <bindingRedirect oldVersion="0.0.0.0-1.3.0.0" newVersion="1.3.0.0" />
+        <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35"/>
+        <bindingRedirect oldVersion="0.0.0.0-1.3.0.0" newVersion="1.3.0.0"/>
       </dependentAssembly>
     </assemblyBinding>
