Index: branches/2931_OR-Tools_LP_MIP/Build.cmd
===================================================================
--- branches/2931_OR-Tools_LP_MIP/Build.cmd	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/Build.cmd	(revision 16235)
@@ -1,100 +1,2 @@
 @ECHO OFF
-
-SET CLEANBEFOREBUILD=
-
-SET SELECTED=
-SET CONFIGURATION=
-SET PLATFORM=
-
-IF "%~1"=="" GOTO :prompt_solution
-
-SET SELECTED=%1
-IF NOT EXIST %SELECTED% (
-  ECHO Solution file %SELECTED% could not be found.
-  GOTO :end
-)
-ECHO Building solution %SELECTED% ...
-GOTO :config_selection
-
-:prompt_solution
-SET /A COUNT=0
-FOR /F "tokens=*" %%A IN ('dir /B *.sln') DO (
-  CALL :forloopbody "%%A"
-)
-
-IF "%COUNT%"=="1" (
-  SET SELECTED=%SOLUTIONS.1%
-  ECHO Building %SOLUTIONS.1% as it is the only solution that was found ...
-  GOTO :config_selection
-)
-
-ECHO Found the following solutions:
-FOR /F "tokens=2* delims=.=" %%A IN ('SET SOLUTIONS.') DO ECHO %%A = %%B
-ECHO.
-SET /P SOLUTIONINDEX=Which solution to build? Type the number: 
-
-SET SELECTED=""
-FOR /F "tokens=2* delims=.=" %%A IN ('SET SOLUTIONS.') DO (
-  IF "%%A"=="%SOLUTIONINDEX%" SET SELECTED=%%B
-)
-
-IF %SELECTED%=="" GOTO :eof
-
-:config_selection
-IF "%~2"==""  GOTO :prompt_config
-
-SET CONFIGURATION=%~2
-ECHO Building configuration %CONFIGURATION% ...
-GOTO :platform_selection
-
-:prompt_config
-SET /P CONFIGURATION=Which configuration to build [Release]: 
-IF "%CONFIGURATION%"=="" SET CONFIGURATION=Release
-
-:platform_selection
-IF "%~3"=="" GOTO :prompt_platform
-  
-SET PLATFORM=%~3
-ECHO Building platform %PLATFORM% ...
-GOTO :clean
-
-:prompt_platform
-SET /P PLATFORM=Which platform to build [Any CPU]: 
-IF "%PLATFORM%"=="" SET PLATFORM=Any CPU
-
-:clean
-IF "%~4"=="" GOTO :prompt_clean
-
-SET CLEANBEFOREBUILD=%~4
-GOTO :main
-
-:prompt_clean
-SET /P CLEANBEFOREBUILD=Would you like to clean before building [n]: 
-IF "%CLEANBEFOREBUILD%"=="" SET CLEANBEFOREBUILD=n
-
-:main
-REM Then execute msbuild to clean and build the solution
-REM Disable that msbuild creates a cache file of the solution
-SET MSBuildUseNoSolutionCache=1
-REM Run msbuild to clean and then build
-IF "%CLEANBEFOREBUILD%" NEQ "n" (
-  ECHO Cleaning ...
-  msbuild.exe %SELECTED% /target:Clean /p:Configuration="%CONFIGURATION%",Platform="%PLATFORM%" /m:2 /nologo /verbosity:q /clp:ErrorsOnly
-)
-ECHO Building ...
-msbuild.exe %SELECTED% /target:Build /p:Configuration="%CONFIGURATION%",Platform="%PLATFORM%" /m:2 /nologo /verbosity:q /clp:ErrorsOnly
-
-ECHO.
-ECHO DONE.
-
-:end
-
-PAUSE
-
-GOTO :eof
-
-REM This workaround is necessary so that COUNT gets reevaluated
-:forloopbody
-SET /A COUNT+=1
-SET SOLUTIONS.%COUNT%=%1
-GOTO :eof
+powershell.exe .\Build.ps1
Index: branches/2931_OR-Tools_LP_MIP/Build.ps1
===================================================================
--- branches/2931_OR-Tools_LP_MIP/Build.ps1	(revision 16235)
+++ branches/2931_OR-Tools_LP_MIP/Build.ps1	(revision 16235)
@@ -0,0 +1,114 @@
+﻿# find ms build
+$programFilesX86Dir = ($Env:ProgramFiles, ${Env:ProgramFiles(x86)})[[bool]${Env:ProgramFiles(x86)}]
+$locations = @(
+  [System.IO.Path]::Combine($programFilesX86Dir, "Microsoft Visual Studio", "2017", "Enterprise", "MSBuild", "15.0", "Bin", "amd64")
+  [System.IO.Path]::Combine($programFilesX86Dir, "Microsoft Visual Studio", "2017", "Enterprise", "MSBuild", "15.0", "Bin")
+  [System.IO.Path]::Combine($programFilesX86Dir, "Microsoft Visual Studio", "2017", "Community", "MSBuild", "15.0", "Bin", "amd64")
+  [System.IO.Path]::Combine($programFilesX86Dir, "Microsoft Visual Studio", "2017", "Community", "MSBuild", "15.0", "Bin")
+  [System.IO.Path]::Combine($programFilesX86Dir, "Microsoft Visual Studio", "2017", "BuildTools", "MSBuild", "15.0", "Bin", "amd64"),
+  [System.IO.Path]::Combine($programFilesX86Dir, "Microsoft Visual Studio", "2017", "BuildTools", "MSBuild", "15.0", "Bin")
+)
+
+$msBuildPath = $undefined
+Foreach ($loc in $locations) {
+  $loc = [System.IO.Path]::Combine($loc, "MSBuild.exe")
+  If ([System.IO.File]::Exists($loc)) {
+    $msBuildPath = $loc
+    Break;
+  }
+}
+
+if ($msBuildPath -eq $undefined) {
+  "Could not locate MSBuild, ABORTING ..."
+} else {
+  $curPath = $MyInvocation.MyCommand.Path
+  $curDir = Split-Path $curPath
+
+  $slnFiles = Get-ChildItem $curDir -Filter *.sln
+
+  "Found the following solutions:"
+
+  ""
+
+  $slnFiles | % { $i = 0 } { ("  {0}. `"{1}`"" -f ($i + 1), $_.Name); $i++ }
+
+  ""
+
+  $success = $false
+
+  # query solution to build
+  $slnIndex = -1
+  $slnIndices = @()
+  Do {
+      $input = Read-Host "Which solution(s) to build? {1..$($slnFiles.Count)}"
+      $inputParts = $input -Split " "
+
+      Foreach ($part in $inputParts) {
+        If ($part -eq "") { Continue }
+
+        $success = [int]::TryParse($part, [ref]$slnIndex) -and ($slnIndex -gt 0) -and ($slnIndex -le $slnFiles.Count)
+
+        If ($success) {
+          $slnIndices += $slnIndex - 1
+        } Else {
+          $slnIndices = @()
+          Break
+        }
+      }
+  } While (-Not $success)
+
+  $slnIndices = $slnIndices | Select-Object -Unique
+
+  # query configuration to build
+  $config = "Release"
+  $input = Read-Host "Which configuration to build? [$($config)]"
+  $config = ($config, $input)[[bool]$input]
+
+  # query platform to build
+  $platform = "Any CPU"
+  $input = Read-Host "Which platform to build? [$($platform)]"
+  $platform = ($platform, $input)[[bool]$input]
+
+  # query clean desire
+  $clean = $false
+  Do {
+      $input = Read-Host "Would you like to clean before building? [y/N]"
+      $input = ([string]("n", $input)[[bool]$input]).ToLowerInvariant()
+      $success = $input -eq "n" -or ($clean = $input -eq "y")
+  } While (-Not $success)
+
+  ""
+
+  if ($clean) {
+    Foreach ($slnIndex in $slnIndices) {
+      $solution = $slnFiles[$slnIndex]
+      "Cleaning `"$($solution.Name)`" ..."
+      $args = @(
+        $solution.FullName,
+        "/t:Clean",
+        "/p:Configuration=`"$config`",Platform=`"$platform`"",
+        "/m", "/nologo", "/verbosity:q", "/clp:ErrorsOnly"
+      )
+      & $msBuildPath $args
+      "===== CLEAN FINISHED ====="
+    }
+  }
+
+  Foreach ($slnIndex in $slnIndices) {
+    $solution = $slnFiles[$slnIndex]
+    "Building `"$($solution.Name)`" ($config|$platform) ..."
+    $args = @(
+      $solution.FullName,
+      "/t:Build",
+      "/p:Configuration=`"$config`",Platform=`"$platform`"",
+      "/m", "/nologo", "/verbosity:q", "/clp:ErrorsOnly"
+    )
+    & $msBuildPath $args
+    "===== BUILD FINISHED ====="
+  }
+}
+
+""
+
+Write-Host -NoNewline "Press any key to continue ... "
+[void][System.Console]::ReadKey($true)
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleModel.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleModel.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleModel.cs	(revision 16235)
@@ -36,15 +36,6 @@
   public sealed class NeuralNetworkEnsembleModel : ClassificationModel, INeuralNetworkEnsembleModel {
 
+    private object mlpEnsembleLocker = new object();
     private alglib.mlpensemble mlpEnsemble;
-    public alglib.mlpensemble MultiLayerPerceptronEnsemble {
-      get { return mlpEnsemble; }
-      set {
-        if (value != mlpEnsemble) {
-          if (value == null) throw new ArgumentNullException();
-          mlpEnsemble = value;
-          OnChanged(EventArgs.Empty);
-        }
-      }
-    }
 
     public override IEnumerable<string> VariablesUsedForPrediction {
@@ -103,5 +94,5 @@
         }
         // mlpeprocess writes data in mlpEnsemble and is therefore not thread-safe
-        lock (mlpEnsemble) {
+        lock (mlpEnsembleLocker) {
           alglib.mlpeprocess(mlpEnsemble, x, ref y);
         }
@@ -123,5 +114,5 @@
         }
         // mlpeprocess writes data in mlpEnsemble and is therefore not thread-safe
-        lock (mlpEnsemble) {
+        lock (mlpEnsembleLocker) {
           alglib.mlpeprocess(mlpEnsemble, x, ref y);
         }
@@ -145,14 +136,5 @@
       return new NeuralNetworkEnsembleClassificationSolution(this, new ClassificationEnsembleProblemData(problemData));
     }
-
-    #region events
-    public event EventHandler Changed;
-    private void OnChanged(EventArgs e) {
-      var handlers = Changed;
-      if (handlers != null)
-        handlers(this, e);
-    }
-    #endregion
-
+   
     #region persistence
     [Storable]
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkModel.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkModel.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkModel.cs	(revision 16235)
@@ -36,15 +36,6 @@
   public sealed class NeuralNetworkModel : ClassificationModel, INeuralNetworkModel {
 
+    private object mlpLocker = new object();
     private alglib.multilayerperceptron multiLayerPerceptron;
-    public alglib.multilayerperceptron MultiLayerPerceptron {
-      get { return multiLayerPerceptron; }
-      set {
-        if (value != multiLayerPerceptron) {
-          if (value == null) throw new ArgumentNullException();
-          multiLayerPerceptron = value;
-          OnChanged(EventArgs.Empty);
-        }
-      }
-    }
 
     public override IEnumerable<string> VariablesUsedForPrediction {
@@ -107,5 +98,5 @@
         }
         // NOTE: mlpprocess changes data in multiLayerPerceptron and is therefore not thread-save!
-        lock (multiLayerPerceptron) {
+        lock (mlpLocker) {
           alglib.mlpprocess(multiLayerPerceptron, x, ref y);
         }
@@ -127,5 +118,5 @@
         }
         // NOTE: mlpprocess changes data in multiLayerPerceptron and is therefore not thread-save!
-        lock (multiLayerPerceptron) {
+        lock (mlpLocker) {
           alglib.mlpprocess(multiLayerPerceptron, x, ref y);
         }
@@ -150,13 +141,4 @@
     }
 
-    #region events
-    public event EventHandler Changed;
-    private void OnChanged(EventArgs e) {
-      var handlers = Changed;
-      if (handlers != null)
-        handlers(this, e);
-    }
-    #endregion
-
     #region persistence
     [Storable]
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Analysis/3.3/DataVisualization/IndexedDataRow.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Analysis/3.3/DataVisualization/IndexedDataRow.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Analysis/3.3/DataVisualization/IndexedDataRow.cs	(revision 16235)
@@ -20,12 +20,12 @@
 #endregion
 
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
 using HeuristicLab.Collections;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Linq;
 
 namespace HeuristicLab.Analysis {
@@ -58,8 +58,23 @@
       set { visualProperties = value; }
     }
-    [Storable(Name = "values")]
+    // BackwardsCompatibility3.3
+    #region Backwards compatible code, remove with 3.4
+    // tuples are stored inefficiently
+    [Storable(Name = "values", AllowOneWay = true)]
     private IEnumerable<Tuple<T, double>> StorableValues {
-      get { return values; }
       set { values = new ObservableList<Tuple<T, double>>(value); }
+    }
+    #endregion
+    private T[] storableX;
+    [Storable(Name = "x")]
+    private T[] StorableX {
+      get { return Values.Select(x => x.Item1).ToArray(); }
+      set { storableX = value; }
+    }
+    private double[] storableY;
+    [Storable(Name = "y")]
+    private double[] StorableY {
+      get { return Values.Select(x => x.Item2).ToArray(); }
+      set { storableY = value; }
     }
     #endregion
@@ -109,4 +124,13 @@
       VisualProperties.DisplayName = Name;
     }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (storableX != null && storableY != null) {
+        values = new ObservableList<Tuple<T, double>>(storableX.Zip(storableY, (x, y) => Tuple.Create(x, y)));
+        storableX = null;
+        storableY = null;
+      } else if (values == null) throw new InvalidOperationException("Deserialization problem with IndexedDataRow.");
+    }
   }
 }
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Access.Views/3.3/UserViews/RefreshableLightweightUserInformationView.Designer.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Access.Views/3.3/UserViews/RefreshableLightweightUserInformationView.Designer.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Access.Views/3.3/UserViews/RefreshableLightweightUserInformationView.Designer.cs	(revision 16235)
@@ -20,5 +20,4 @@
 #endregion
 
-using System;
 namespace HeuristicLab.Clients.Access.Views {
   partial class RefreshableLightweightUserInformationView {
@@ -34,5 +33,4 @@
     protected override void Dispose(bool disposing) {
       if (disposing && (components != null)) {
-        lightweightUserInformationView.UserInformationChanged -= new EventHandler(lightweightUserInformationView_Changed);
         components.Dispose();
       }
@@ -47,12 +45,21 @@
     /// </summary>
     private void InitializeComponent() {
+      components = new System.ComponentModel.Container();
       System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(RefreshableLightweightUserInformationView));
       this.lightweightUserInformationView = new HeuristicLab.Clients.Access.Views.LightweightUserInformationView();
-      this.storeButton = new System.Windows.Forms.Button();
+      this.refreshButton = new System.Windows.Forms.Button();
+      this.toolTip = new System.Windows.Forms.ToolTip(this.components);
       this.SuspendLayout();
       // 
       // refreshButton
       // 
+      this.refreshButton.Image = HeuristicLab.Common.Resources.VSImageLibrary.Refresh;
       this.refreshButton.Location = new System.Drawing.Point(4, 3);
+      this.refreshButton.Name = "refreshButton";
+      this.refreshButton.Size = new System.Drawing.Size(24, 24);
+      this.refreshButton.TabIndex = 1;
+      this.toolTip.SetToolTip(this.refreshButton, "Refresh data");
+      this.refreshButton.UseVisualStyleBackColor = true;
+      this.refreshButton.Click += new System.EventHandler(this.refreshButton_Click);
       // 
       // lightweightUserInformationView
@@ -69,15 +76,4 @@
       this.lightweightUserInformationView.TabIndex = 2;
       // 
-      // storeButton
-      // 
-      this.storeButton.Enabled = false;
-      this.storeButton.Image = HeuristicLab.Common.Resources.VSImageLibrary.PublishToWeb;
-      this.storeButton.Location = new System.Drawing.Point(34, 3);
-      this.storeButton.Name = "storeButton";
-      this.storeButton.Size = new System.Drawing.Size(24, 24);
-      this.storeButton.TabIndex = 3;
-      this.storeButton.UseVisualStyleBackColor = true;
-      this.storeButton.Click += new System.EventHandler(this.storeButton_Click);
-      // 
       // RefreshableLightweightUserInformationView
       // 
@@ -85,10 +81,9 @@
       this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
       this.Controls.Add(this.lightweightUserInformationView);
-      this.Controls.Add(this.storeButton);
+      this.Controls.Add(this.refreshButton);
       this.Name = "RefreshableLightweightUserInformationView";
       this.Size = new System.Drawing.Size(384, 281);
-      this.Controls.SetChildIndex(this.storeButton, 0);
       this.Controls.SetChildIndex(this.lightweightUserInformationView, 0);
-      this.Controls.SetChildIndex(this.refreshButton, 0);
+      this.Controls.SetChildIndex(this.refreshButton, 1);
       this.ResumeLayout(false);
 
@@ -98,6 +93,6 @@
 
     private LightweightUserInformationView lightweightUserInformationView;
-    private System.Windows.Forms.Button storeButton;
-
+    private System.Windows.Forms.ToolTip toolTip;
+    private System.Windows.Forms.Button refreshButton;
   }
 }
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Access.Views/3.3/UserViews/RefreshableLightweightUserInformationView.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Access.Views/3.3/UserViews/RefreshableLightweightUserInformationView.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Access.Views/3.3/UserViews/RefreshableLightweightUserInformationView.cs	(revision 16235)
@@ -22,9 +22,74 @@
 using System;
 using System.Windows.Forms;
+using HeuristicLab.MainForm;
+using HeuristicLab.MainForm.WindowsForms;
 
 namespace HeuristicLab.Clients.Access.Views {
-  public partial class RefreshableLightweightUserInformationView : RefreshableView {
+  [View("RefreshableLightweightUserInformation View")]
+  [Content(typeof(LightweightUser), false)]
+  public partial class RefreshableLightweightUserInformationView : AsynchronousContentView {
+    public new LightweightUser Content {
+      get { return (LightweightUser)base.Content; }
+      set { base.Content = value; }
+    }
+
     public RefreshableLightweightUserInformationView() {
       InitializeComponent();
+    }
+
+    protected override void OnContentChanged() {
+      base.OnContentChanged();
+      lightweightUserInformationView.Content = Content;
+    }
+
+    protected override void SetEnabledStateOfControls() {
+      base.SetEnabledStateOfControls();
+      this.Locked = true;
+      refreshButton.Enabled = Content != null;
+    }
+
+    protected override void DeregisterContentEvents() {
+      Refreshing -= new EventHandler(Content_Refreshing);
+      Refreshed -= new EventHandler(Content_Refreshed);
+      base.DeregisterContentEvents();
+    }
+
+    protected override void RegisterContentEvents() {
+      base.RegisterContentEvents();
+      Refreshing += new EventHandler(Content_Refreshing);
+      Refreshed += new EventHandler(Content_Refreshed);
+    }
+
+    protected void Content_Refreshing(object sender, EventArgs e) {
+      if (InvokeRequired) {
+        Invoke(new EventHandler(Content_Refreshing), sender, e);
+      } else {
+        Cursor = Cursors.AppStarting;
+        refreshButton.Enabled = false;
+
+        lightweightUserInformationView.Enabled = false;
+      }
+    }
+
+    protected void Content_Refreshed(object sender, EventArgs e) {
+      if (InvokeRequired) {
+        Invoke(new EventHandler(Content_Refreshed), sender, e);
+      } else {
+        Cursor = Cursors.Default;
+        refreshButton.Enabled = true;
+
+        lightweightUserInformationView.Enabled = true;
+        if (!UserInformation.Instance.UserExists) {
+          MessageBox.Show("Couldn't fetch user information from the server." + Environment.NewLine +
+            "Please verify that you have an existing user and that your user name and password is correct. ", "HeuristicLab Access Service", MessageBoxButtons.OK, MessageBoxIcon.Error);
+          lightweightUserInformationView.Content = null;
+        } else {
+          lightweightUserInformationView.Content = Content;
+        }
+      }
+    }
+
+    void lightweightUserInformationView_Changed(object sender, EventArgs e) {
+      // nothing to do
     }
 
@@ -34,43 +99,46 @@
     }
 
-    void lightweightUserInformationView_Changed(object sender, EventArgs e) {
-      if (!storeButton.Enabled) storeButton.Enabled = true;
+    private void RefreshData() {
+      ExecuteActionAsync(RefreshUserData, PluginInfrastructure.ErrorHandling.ShowErrorDialog);
     }
 
-    protected override void RefreshData() {
-      Content.ExecuteActionAsync(RefreshUserData, PluginInfrastructure.ErrorHandling.ShowErrorDialog);
+    public void ManualRefresh() {
+      RefreshData();
     }
 
-    protected override void Content_Refreshing(object sender, EventArgs e) {
-      if (InvokeRequired) {
-        Invoke(new EventHandler(Content_Refreshing), sender, e);
-      } else {
-        base.Content_Refreshing(sender, e);
-        lightweightUserInformationView.Enabled = false;
-        storeButton.Enabled = false;
-      }
+    protected void refreshButton_Click(object sender, System.EventArgs e) {
+      RefreshData();
     }
 
-    protected override void Content_Refreshed(object sender, EventArgs e) {
-      if (InvokeRequired) {
-        Invoke(new EventHandler(Content_Refreshed), sender, e);
-      } else {
-        base.Content_Refreshed(sender, e);
-        lightweightUserInformationView.Enabled = true;
-        if (!UserInformation.Instance.UserExists) {
-          MessageBox.Show("Couldn't fetch user information from the server." + Environment.NewLine +
-            "Please verify that you have an existing user and that your user name and password is correct. ", "HeuristicLab Access Service", MessageBoxButtons.OK, MessageBoxIcon.Error);
-          lightweightUserInformationView.Content = null;
-        } else {
-          lightweightUserInformationView.Content = UserInformation.Instance.User;
+    public void ExecuteActionAsync(Action action, Action<Exception> exceptionCallback) {
+      var call = new Func<Exception>(delegate () {
+        try {
+          OnRefreshing();
+          action();
+        } catch (Exception ex) {
+          return ex;
+        } finally {
+          OnRefreshed();
         }
-      }
+        return null;
+      });
+      call.BeginInvoke(delegate (IAsyncResult result) {
+        Exception ex = call.EndInvoke(result);
+        if (ex != null) exceptionCallback(ex);
+      }, null);
     }
 
-    private void storeButton_Click(object sender, EventArgs e) {
-      AccessClient.Instance.ExecuteActionAsync(new Action(delegate {
-        AccessClient.CallAccessService(x => x.UpdateLightweightUser(UserInformation.Instance.User));
-      }), HeuristicLab.PluginInfrastructure.ErrorHandling.ShowErrorDialog);
+    #region Events
+    public event EventHandler Refreshing;
+    private void OnRefreshing() {
+      EventHandler handler = Refreshing;
+      if (handler != null) handler(this, EventArgs.Empty);
     }
+    public event EventHandler Refreshed;
+    private void OnRefreshed() {
+      EventHandler handler = Refreshed;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    #endregion
   }
 }
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/HiveAdministratorView.Designer.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/HiveAdministratorView.Designer.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/HiveAdministratorView.Designer.cs	(revision 16235)
@@ -29,12 +29,12 @@
       this.components = new System.ComponentModel.Container();
       this.tabAdmin = new System.Windows.Forms.TabControl();
-      this.tabSlaves = new System.Windows.Forms.TabPage();
+      this.tabResources = new System.Windows.Forms.TabPage();
       this.resourcesView = new HeuristicLab.Clients.Hive.Administrator.Views.ResourcesView();
-      this.tabPage1 = new System.Windows.Forms.TabPage();
+      this.tabProjects = new System.Windows.Forms.TabPage();
       this.imageListUsers = new System.Windows.Forms.ImageList(this.components);
       this.projectsView = new HeuristicLab.Clients.Hive.Administrator.Views.ProjectsView();
       this.tabAdmin.SuspendLayout();
-      this.tabSlaves.SuspendLayout();
-      this.tabPage1.SuspendLayout();
+      this.tabResources.SuspendLayout();
+      this.tabProjects.SuspendLayout();
       this.SuspendLayout();
       // 
@@ -44,6 +44,6 @@
             | System.Windows.Forms.AnchorStyles.Left) 
             | System.Windows.Forms.AnchorStyles.Right)));
-      this.tabAdmin.Controls.Add(this.tabSlaves);
-      this.tabAdmin.Controls.Add(this.tabPage1);
+      this.tabAdmin.Controls.Add(this.tabResources);
+      this.tabAdmin.Controls.Add(this.tabProjects);
       this.tabAdmin.Location = new System.Drawing.Point(3, 0);
       this.tabAdmin.Name = "tabAdmin";
@@ -52,14 +52,14 @@
       this.tabAdmin.TabIndex = 0;
       // 
-      // tabSlaves
+      // tabResources
       // 
-      this.tabSlaves.Controls.Add(this.resourcesView);
-      this.tabSlaves.Location = new System.Drawing.Point(4, 22);
-      this.tabSlaves.Name = "tabSlaves";
-      this.tabSlaves.Padding = new System.Windows.Forms.Padding(3);
-      this.tabSlaves.Size = new System.Drawing.Size(734, 520);
-      this.tabSlaves.TabIndex = 3;
-      this.tabSlaves.Text = "Slaves";
-      this.tabSlaves.UseVisualStyleBackColor = true;
+      this.tabResources.Controls.Add(this.resourcesView);
+      this.tabResources.Location = new System.Drawing.Point(4, 22);
+      this.tabResources.Name = "tabResources";
+      this.tabResources.Padding = new System.Windows.Forms.Padding(3);
+      this.tabResources.Size = new System.Drawing.Size(734, 520);
+      this.tabResources.TabIndex = 3;
+      this.tabResources.Text = "Resources";
+      this.tabResources.UseVisualStyleBackColor = true;
       // 
       // resourcesView
@@ -76,13 +76,13 @@
       this.resourcesView.TabIndex = 0;
       // 
-      // tabPage1
+      // tabProjects
       // 
-      this.tabPage1.Controls.Add(this.projectsView);
-      this.tabPage1.Location = new System.Drawing.Point(4, 22);
-      this.tabPage1.Name = "tabPage1";
-      this.tabPage1.Size = new System.Drawing.Size(734, 520);
-      this.tabPage1.TabIndex = 4;
-      this.tabPage1.Text = "Projects";
-      this.tabPage1.UseVisualStyleBackColor = true;
+      this.tabProjects.Controls.Add(this.projectsView);
+      this.tabProjects.Location = new System.Drawing.Point(4, 22);
+      this.tabProjects.Name = "tabProjects";
+      this.tabProjects.Size = new System.Drawing.Size(734, 520);
+      this.tabProjects.TabIndex = 4;
+      this.tabProjects.Text = "Projects";
+      this.tabProjects.UseVisualStyleBackColor = true;
       // 
       // imageListUsers
@@ -112,6 +112,6 @@
       this.Size = new System.Drawing.Size(745, 546);
       this.tabAdmin.ResumeLayout(false);
-      this.tabSlaves.ResumeLayout(false);
-      this.tabPage1.ResumeLayout(false);
+      this.tabResources.ResumeLayout(false);
+      this.tabProjects.ResumeLayout(false);
       this.ResumeLayout(false);
 
@@ -122,6 +122,6 @@
     private System.ComponentModel.IContainer components;
     private System.Windows.Forms.ImageList imageListUsers;
-    private System.Windows.Forms.TabPage tabSlaves;
-    private System.Windows.Forms.TabPage tabPage1;
+    private System.Windows.Forms.TabPage tabResources;
+    private System.Windows.Forms.TabPage tabProjects;
     private ProjectsView projectsView;
   }
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectJobsView.Designer.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectJobsView.Designer.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectJobsView.Designer.cs	(revision 16235)
@@ -20,4 +20,5 @@
 #endregion
 
+using System.Windows.Forms;
 using HeuristicLab.Data.Views;
 
@@ -50,4 +51,7 @@
       this.refreshButton = new System.Windows.Forms.Button();
       this.removeButton = new System.Windows.Forms.Button();
+      this.startButton = new System.Windows.Forms.Button();
+      this.stopButton = new System.Windows.Forms.Button();
+      this.pauseButton = new System.Windows.Forms.Button();
       this.matrixView = new HeuristicLab.Data.Views.StringConvertibleMatrixView();
       this.toolTip = new System.Windows.Forms.ToolTip(this.components);
@@ -72,7 +76,44 @@
       this.removeButton.Size = new System.Drawing.Size(24, 24);
       this.removeButton.TabIndex = 2;
-      this.toolTip.SetToolTip(this.removeButton, "Delete job(s)");
+      this.toolTip.SetToolTip(this.removeButton, "Remove job(s)");
       this.removeButton.UseVisualStyleBackColor = true;
       this.removeButton.Click += new System.EventHandler(this.removeButton_Click);
+      // 
+      // startButton
+      // 
+      this.startButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)));
+      this.startButton.Image = HeuristicLab.Common.Resources.VSImageLibrary.Play;
+      this.startButton.Location = new System.Drawing.Point(63, 3);
+      this.startButton.Name = "startButton";
+      this.startButton.Size = new System.Drawing.Size(24, 24);
+      this.startButton.TabIndex = 4;
+      this.toolTip.SetToolTip(this.startButton, "Resume job(s)");
+      this.startButton.UseVisualStyleBackColor = true;
+      this.startButton.Click += new System.EventHandler(this.startButton_Click);
+      // 
+      // pauseButton
+      // 
+      this.pauseButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)));
+      this.pauseButton.Enabled = false;
+      this.pauseButton.Image = HeuristicLab.Common.Resources.VSImageLibrary.Pause;
+      this.pauseButton.Location = new System.Drawing.Point(93, 3);
+      this.pauseButton.Name = "pauseButton";
+      this.pauseButton.Size = new System.Drawing.Size(24, 24);
+      this.pauseButton.TabIndex = 5;
+      this.toolTip.SetToolTip(this.pauseButton, "Pause job(s)");
+      this.pauseButton.UseVisualStyleBackColor = true;
+      this.pauseButton.Click += new System.EventHandler(this.pauseButton_Click);
+      // 
+      // stopButton
+      // 
+      this.stopButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)));
+      this.stopButton.Image = HeuristicLab.Common.Resources.VSImageLibrary.Stop;
+      this.stopButton.Location = new System.Drawing.Point(123, 3);
+      this.stopButton.Name = "stopButton";
+      this.stopButton.Size = new System.Drawing.Size(24, 24);
+      this.stopButton.TabIndex = 6;
+      this.toolTip.SetToolTip(this.stopButton, "Stop job(s)");
+      this.stopButton.UseVisualStyleBackColor = true;
+      this.stopButton.Click += new System.EventHandler(this.stopButton_Click);
       // 
       // matrixView
@@ -98,4 +139,7 @@
       this.Controls.Add(this.refreshButton);
       this.Controls.Add(this.removeButton);
+      this.Controls.Add(this.startButton);
+      this.Controls.Add(this.pauseButton);
+      this.Controls.Add(this.stopButton);
       this.Name = "ProjectJobsView";
       this.Size = new System.Drawing.Size(510, 385);
@@ -110,4 +154,7 @@
     private System.Windows.Forms.Button refreshButton;
     private System.Windows.Forms.Button removeButton;
+    private System.Windows.Forms.Button startButton;
+    private System.Windows.Forms.Button stopButton;
+    private System.Windows.Forms.Button pauseButton;
     private StringConvertibleMatrixView matrixView;
   }
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectJobsView.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectJobsView.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectJobsView.cs	(revision 16235)
@@ -24,4 +24,5 @@
 using System.Drawing;
 using System.Linq;
+using System.Threading.Tasks;
 using System.Windows.Forms;
 using HeuristicLab.MainForm;
@@ -30,4 +31,5 @@
 using HeuristicLab.Data;
 using HeuristicLab.Clients.Hive.Views;
+using HeuristicLab.Core;
 
 namespace HeuristicLab.Clients.Hive.Administrator.Views {
@@ -41,9 +43,11 @@
     private const string JOB_DATECREATED = "Date Created";
     private const string JOB_STATE = "State";
+    private const string JOB_EXECUTIONSTATE = "Execution State";
+    private const string JOB_EXECUTIONTIME = "Execution Time";
     private const string JOB_DESCRIPTION = "Description";
     private const string JOB_TASKCOUNT = "Tasks";
+    private const string JOB_WAITINGTASKCOUNT = "Waiting";
     private const string JOB_CALCULATINGTASKCOUNT = "Calculating";
     private const string JOB_FINISHEDTASKCOUNT = "Finished";
-
 
     private readonly Color onlineStatusColor = Color.FromArgb(255, 189, 249, 143); // #bdf98f
@@ -53,4 +57,13 @@
     private readonly Color deletionPendingStatusColor2 = Color.FromArgb(255, 249, 149, 143); // #f9958f
 
+    private IProgress progress;
+    public IProgress Progress {
+      get { return progress; }
+      set {
+        this.progress = value;
+        OnIsProgressingChanged();
+      }
+    }
+
     public new Project Content {
       get { return (Project)base.Content; }
@@ -60,18 +73,23 @@
     public ProjectJobsView() {
       InitializeComponent();
-
-      removeButton.Enabled = false;
+      progress = new Progress();
+
+      removeButton.Enabled = false;      
+    }
+
+    protected override void RegisterContentEvents() {
+      base.RegisterContentEvents();
       matrixView.DataGridView.SelectionChanged += DataGridView_SelectionChanged;
+      MainFormManager.GetMainForm<HeuristicLab.MainForm.WindowsForms.MainForm>().AddOperationProgressToView(this, progress);
+    }
+
+    protected override void DeregisterContentEvents() {
+      matrixView.DataGridView.SelectionChanged -= DataGridView_SelectionChanged;
+      MainFormManager.GetMainForm<HeuristicLab.MainForm.WindowsForms.MainForm>().RemoveOperationProgressFromView(this, false);
+      base.DeregisterContentEvents();
     }
 
     private void DataGridView_SelectionChanged(object sender, EventArgs e) {
-      if (matrixView.DataGridView.SelectedRows == null || matrixView.DataGridView.SelectedRows.Count == 0) return;
-
-      bool anyDeletable = false;
-      foreach (DataGridViewRow r in matrixView.DataGridView.SelectedRows) {
-        if (((string)r.Cells[0].Value) == JobState.Online.ToString()) anyDeletable = true;
-      }
-
-      removeButton.Enabled = anyDeletable;
+      SetEnabledStateOfControls();
     }
 
@@ -81,13 +99,36 @@
       removeButton.Enabled = false;
       UpdateJobs();
-    }
+      SetEnabledStateOfControls();
+    }
+
     protected override void SetEnabledStateOfControls() {
       base.SetEnabledStateOfControls();
       bool enabled = Content != null && !Locked && !ReadOnly;
 
-      refreshButton.Enabled = enabled;
-      removeButton.Enabled = false;
       matrixView.Enabled = enabled;
-    }
+
+      // Buttons (start/resume, pause, stop, remove)
+      refreshButton.Enabled = startButton.Enabled = pauseButton.Enabled = stopButton.Enabled = removeButton.Enabled = false;
+
+      if (enabled && progress.ProgressState != ProgressState.Started) {
+        var jobs = GetSelectedJobs().ToList();
+        if (jobs.Any()) {
+                    
+          startButton.Enabled = jobs.All(x =>
+            !x.IsProgressing && HiveAdminClient.Instance.Tasks.ContainsKey(x.Id) && HiveAdminClient.Instance.Tasks[x.Id].Count > 0
+            && x.Job.ProjectId != Guid.Empty //&& x.Job.ResourceIds != null && x.Job.ResourceIds.Any()
+            && (x.ExecutionState == ExecutionState.Prepared || x.ExecutionState == ExecutionState.Paused));
+          pauseButton.Enabled = jobs.All(x => !x.IsProgressing && x.ExecutionState == ExecutionState.Started);
+          stopButton.Enabled = jobs.All(x => !x.IsProgressing && (x.ExecutionState == ExecutionState.Started || x.ExecutionState == ExecutionState.Paused));
+          removeButton.Enabled = jobs.All(x => !x.IsProgressing && x.Job.State == JobState.Online);
+        }
+      }
+
+      // refresh Button
+      if (Content != null && !Locked && progress.ProgressState != ProgressState.Started) {
+        refreshButton.Enabled = true;
+      }
+    }
+
     #endregion Overrides
 
@@ -98,22 +139,20 @@
 
     private void refreshButton_Click(object sender, EventArgs e) {
-      RefreshJobs();
-    }
-
-    private async void removeButton_Click(object sender, EventArgs e) {
-      if (matrixView.DataGridView.SelectedRows == null || matrixView.DataGridView.SelectedRows.Count == 0) return;
-
-      var jobNamesToDelete = new List<string>();
-      var jobIdsToDelete = new List<Guid>();
-      foreach (DataGridViewRow r in matrixView.DataGridView.SelectedRows) {
-        if(((string)r.Cells[0].Value) == JobState.Online.ToString()) {
-          jobNamesToDelete.Add(" - " + ((string)r.Cells[3].Value));
-          jobIdsToDelete.Add(Guid.Parse((string)r.Cells[8].Value));
-        }
-      }
-
-      if(jobIdsToDelete.Any()) {
+      progress.Start("Refreshing jobs...");
+      SetEnabledStateOfControls();
+      var task = System.Threading.Tasks.Task.Factory.StartNew(RefreshJobsAsync);
+
+      task.ContinueWith((t) => {
+        progress.Finish();        
+        SetEnabledStateOfControls();
+      });
+    }
+
+    private void removeButton_Click(object sender, EventArgs e) {
+      var jobs = GetSelectedJobs();
+
+      if (jobs.Any()) {
         var result = MessageBox.Show("Do you really want to remove following job(s):\n\n"
-          + String.Join("\n", jobNamesToDelete),
+                                     + String.Join("\n", jobs.Select(x => x.Job.Name)),
           "HeuristicLab Hive Administrator",
           MessageBoxButtons.YesNo,
@@ -121,23 +160,144 @@
 
         if (result == DialogResult.Yes) {
-          await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
-            action: () => {
-              DeleteJobs(jobIdsToDelete);
-            },
-            finallyCallback: () => {
-              matrixView.DataGridView.ClearSelection();
-              removeButton.Enabled = false;
-              RefreshJobs();
-            });
-        }
-      } 
-    }
-
+          progress.Start("Removing job(s)...");
+          SetEnabledStateOfControls();
+          var task = System.Threading.Tasks.Task.Factory.StartNew(RemoveJobsAsync, jobs);
+
+          task.ContinueWith((t) => {
+            RefreshJobs();
+            progress.Finish();
+            SetEnabledStateOfControls();
+          }, TaskContinuationOptions.NotOnFaulted);
+
+          task.ContinueWith((t) => {
+            RefreshJobs();
+            progress.Finish();
+            SetEnabledStateOfControls();
+            MessageBox.Show("An error occured removing the job(s).", "HeuristicLab Hive Administrator", MessageBoxButtons.OK, MessageBoxIcon.Error);
+          }, TaskContinuationOptions.OnlyOnFaulted);
+        }
+      }
+    }
+
+    private void startButton_Click(object sender, EventArgs e) {
+      var jobs = GetSelectedJobs();
+
+      if (jobs.Any()) {
+        var result = MessageBox.Show("Do you really want to resume following job(s):\n\n"
+                                     + String.Join("\n", jobs.Select(x => x.Job.Name)),
+          "HeuristicLab Hive Administrator",
+          MessageBoxButtons.YesNo,
+          MessageBoxIcon.Question);
+
+        if (result == DialogResult.Yes) {
+          progress.Start("Resuming job(s)...");
+          SetEnabledStateOfControls();
+          var task = System.Threading.Tasks.Task.Factory.StartNew(ResumeJobsAsync, jobs);
+
+          task.ContinueWith((t) => {
+            RefreshJobs();            
+            progress.Finish();
+            SetEnabledStateOfControls();
+          }, TaskContinuationOptions.NotOnFaulted);
+
+          task.ContinueWith((t) => {
+            RefreshJobs();
+            progress.Finish();
+            SetEnabledStateOfControls();
+            MessageBox.Show("An error occured resuming the job(s).", "HeuristicLab Hive Administrator", MessageBoxButtons.OK, MessageBoxIcon.Error);
+          }, TaskContinuationOptions.OnlyOnFaulted);
+        }
+      }
+    }
+
+    private void pauseButton_Click(object sender, EventArgs e) {
+      var jobs = GetSelectedJobs();
+
+      if (jobs.Any()) {
+        var result = MessageBox.Show("Do you really want to pause following job(s):\n\n"
+                                     + String.Join("\n", jobs.Select(x => x.Job.Name)),
+          "HeuristicLab Hive Administrator",
+          MessageBoxButtons.YesNo,
+          MessageBoxIcon.Question);
+
+        if (result == DialogResult.Yes) {
+          progress.Start("Pausing job(s)...");
+          SetEnabledStateOfControls();
+          var task = System.Threading.Tasks.Task.Factory.StartNew(PauseJobsAsync, jobs);
+
+          task.ContinueWith((t) => {
+            RefreshJobs();            
+            progress.Finish();
+            SetEnabledStateOfControls();
+          }, TaskContinuationOptions.NotOnFaulted);
+
+          task.ContinueWith((t) => {
+            RefreshJobs();
+            progress.Finish();
+            SetEnabledStateOfControls();
+            MessageBox.Show("An error occured pausing the job(s).", "HeuristicLab Hive Administrator", MessageBoxButtons.OK, MessageBoxIcon.Error);
+          }, TaskContinuationOptions.OnlyOnFaulted);
+        }
+      }
+    }
+
+    private void stopButton_Click(object sender, EventArgs e) {
+      var jobs = GetSelectedJobs();
+
+      if (jobs.Any()) {
+        var result = MessageBox.Show("Do you really want to stop following job(s):\n\n"
+                                     + String.Join("\n", jobs.Select(x => x.Job.Name)),
+          "HeuristicLab Hive Administrator",
+          MessageBoxButtons.YesNo,
+          MessageBoxIcon.Question);
+
+        if (result == DialogResult.Yes) {
+          progress.Start("Stopping job(s)...");
+          SetEnabledStateOfControls();
+          var task = System.Threading.Tasks.Task.Factory.StartNew(StopJobsAsync, jobs);
+
+          task.ContinueWith((t) => {
+            RefreshJobs();
+            progress.Finish();
+            SetEnabledStateOfControls();
+          }, TaskContinuationOptions.NotOnFaulted);
+
+          task.ContinueWith((t) => {
+            RefreshJobs();
+            progress.Finish();
+            SetEnabledStateOfControls();
+            MessageBox.Show("An error occured stopping the job(s).", "HeuristicLab Hive Administrator", MessageBoxButtons.OK, MessageBoxIcon.Error);            
+          }, TaskContinuationOptions.OnlyOnFaulted);
+        }
+      }
+    }
+
+    public event EventHandler IsProgressingChanged;
+    private void OnIsProgressingChanged() {
+      var handler = IsProgressingChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
     #endregion Event Handlers
 
     #region Helpers
+
+    private IEnumerable<RefreshableJob> GetSelectedJobs() {
+      if (Content == null || matrixView.DataGridView.SelectedRows == null || matrixView.DataGridView.SelectedRows.Count == 0)
+        return Enumerable.Empty<RefreshableJob>() ;
+
+      var jobs = new List<RefreshableJob>();
+      foreach (DataGridViewRow r in matrixView.DataGridView.SelectedRows) {
+        if (((string)r.Cells[0].Value) == JobState.Online.ToString()) {
+          jobs.Add(HiveAdminClient.Instance.Jobs[Content.Id].FirstOrDefault(x => x.Id == Guid.Parse((string) r.Cells[11].Value)));
+        }
+      }
+
+      return jobs;
+    }
+
     private void RefreshJobs() {
       HiveAdminClient.Instance.RefreshJobs();
       UpdateJobs();
+      SetEnabledStateOfControls();
     }
 
@@ -148,23 +308,25 @@
       var jobs = HiveAdminClient.Instance.Jobs[Content.Id];
       var resources = HiveAdminClient.Instance.Resources;
-      string[,] values = new string[jobs.Count, 10];
+      string[,] values = new string[jobs.Count, 13];
 
       for(int i = 0; i < jobs.Count; i++) {
-        var job = jobs.ElementAt(i);
-        
-        values[i, 0] = job.State.ToString();
-        values[i, 1] = job.DateCreated.ToString();
-        values[i, 2] = job.OwnerUsername;
-        values[i, 3] = job.Name;
-        values[i, 4] = job.JobCount.ToString();
-        values[i, 5] = job.CalculatingCount.ToString();
-        values[i, 6] = job.FinishedCount.ToString();
-        values[i, 7] = job.Description;        
-        values[i, 8] = job.Id.ToString();
-        values[i, 9] = job.OwnerUserId.ToString();
+        var job = jobs.ElementAt(i);        
+        values[i, 0] = job.Job.State.ToString();
+        values[i, 1] = job.ExecutionState.ToString();
+        values[i, 2] = job.ExecutionTime.ToString();
+        values[i, 3] = job.Job.DateCreated.ToString();
+        values[i, 4] = job.Job.OwnerUsername;
+        values[i, 5] = job.Job.Name;
+        values[i, 6] = job.Job.JobCount.ToString();
+        values[i, 7] = (job.Job.JobCount - job.Job.CalculatingCount - job.Job.FinishedCount).ToString();
+        values[i, 8] = job.Job.CalculatingCount.ToString();
+        values[i, 9] = job.Job.FinishedCount.ToString();
+        values[i, 10] = job.Job.Description;        
+        values[i, 11] = job.Job.Id.ToString();
+        values[i, 12] = job.Job.OwnerUserId.ToString();
       }
       
       var matrix = new StringMatrix(values);
-      matrix.ColumnNames = new string[] { JOB_STATE, JOB_DATECREATED, JOB_OWNER, JOB_NAME, JOB_TASKCOUNT, JOB_CALCULATINGTASKCOUNT, JOB_FINISHEDTASKCOUNT, JOB_DESCRIPTION, JOB_ID, JOB_OWNERID };
+      matrix.ColumnNames = new string[] { JOB_STATE, JOB_EXECUTIONSTATE, JOB_EXECUTIONTIME, JOB_DATECREATED, JOB_OWNER, JOB_NAME, JOB_TASKCOUNT, JOB_WAITINGTASKCOUNT, JOB_CALCULATINGTASKCOUNT, JOB_FINISHEDTASKCOUNT, JOB_DESCRIPTION, JOB_ID, JOB_OWNERID };
       matrix.SortableView = true;
       return matrix;
@@ -193,18 +355,45 @@
             matrixView.DataGridView.Columns[1].MinimumWidth = 108;
           }
-        } else {
-          refreshButton.Enabled = false;
-          removeButton.Enabled = false;
-          matrixView.Content = null;
-        }
-      }
-    }
-
-    private void DeleteJobs(List<Guid> jobIds) {
-      try {
-        HiveAdminClient.DeleteJobs(jobIds);
-      } catch (AnonymousUserException) {
-        ShowHiveInformationDialog();
-      }
+        } 
+      }
+    }
+
+    private void RefreshJobsAsync() {
+      HiveAdminClient.Instance.RefreshJobs();
+      UpdateJobs();
+    }
+
+    private void ResumeJobsAsync(object jobs) {
+      var jobList = (IEnumerable<RefreshableJob>)jobs;
+      foreach (var job in jobList) {
+        progress.Status = "Resuming job \"" + job.Job.Name + "\"...";
+        HiveAdminClient.ResumeJob(job);
+      }
+    }
+
+    private void PauseJobsAsync(object jobs) {
+      var jobList = (IEnumerable<RefreshableJob>)jobs;
+      foreach (var job in jobList) {
+        progress.Status = "Pausing job \"" + job.Job.Name + "\"...";
+        HiveAdminClient.PauseJob(job);
+      }
+    }
+
+    private void StopJobsAsync(object jobs) {
+      var jobList = (IEnumerable<RefreshableJob>) jobs;
+      foreach (var job in jobList) {        
+        progress.Status = "Stopping job \"" + job.Job.Name + "\"...";
+        HiveAdminClient.StopJob(job);
+      }
+    }
+
+    private void RemoveJobsAsync(object jobs) {
+      var jobList = (IEnumerable<RefreshableJob>)jobs;
+      progress.Start();
+      foreach (var job in jobList) {
+        progress.Status = "Removing job \"" + job.Job.Name + "\"...";
+        HiveAdminClient.RemoveJob(job);
+      }
+      progress.Finish();
     }
 
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectPermissionsView.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectPermissionsView.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectPermissionsView.cs	(revision 16235)
@@ -78,7 +78,7 @@
         detailsViewHost.Content = null;
       } else {
-        UpdatePermissionList();
-        detailsViewHost.ActiveView.Locked = true;
-      }
+        UpdatePermissionList();        
+      }
+      SetEnabledStateOfControls();
     }
 
@@ -90,4 +90,9 @@
       saveButton.Enabled = enabled;
       treeView.Enabled = enabled;
+
+      if (detailsViewHost != null) {
+        detailsViewHost.Locked = true;
+      }
+
     }
     #endregion
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectResourcesView.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectResourcesView.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectResourcesView.cs	(revision 16235)
@@ -30,4 +30,5 @@
 using HeuristicLab.MainForm;
 using System.Collections;
+using HeuristicLab.Common;
 
 namespace HeuristicLab.Clients.Hive.Administrator.Views {
@@ -72,7 +73,16 @@
       treeView.ImageList.Images.Add(VSImageLibrary.MonitorLarge);
       treeView.ImageList.Images.Add(VSImageLibrary.NetworkCenterLarge);
+
+      HiveAdminClient.Instance.Refreshing += HiveAdminClient_Instance_Refreshing;
+      HiveAdminClient.Instance.Refreshed += HiveAdminClient_Instance_Refreshed;
     }
 
     #region Overrides
+    protected override void OnClosing(FormClosingEventArgs e) {
+      HiveAdminClient.Instance.Refreshed -= HiveAdminClient_Instance_Refreshed;
+      HiveAdminClient.Instance.Refreshing -= HiveAdminClient_Instance_Refreshing;
+      base.OnClosing(e);
+    }
+
     protected override void OnContentChanged() {
       base.OnContentChanged();
@@ -86,8 +96,7 @@
         UpdateAssignedResources();
         UpdateIncludedResources();
-        var top = BuildResourceTree();
-        detailsViewHost.Content = top;
-        detailsViewHost.Locked = true;
-      }
+        detailsViewHost.Content = BuildResourceTree();
+      }
+      SetEnabledStateOfControls();
     }
 
@@ -99,8 +108,26 @@
       saveButton.Enabled = enabled;
       treeView.Enabled = enabled;
+
+      if (detailsViewHost != null) {
+        detailsViewHost.Locked = true;
+      }
     }
     #endregion
 
     #region Event Handlers
+    private void HiveAdminClient_Instance_Refreshing(object sender, EventArgs e) {
+      if (InvokeRequired) Invoke((Action<object, EventArgs>)HiveAdminClient_Instance_Refreshing, sender, e);
+      else {
+        SetEnabledStateOfControls();
+      }
+    }
+
+    private void HiveAdminClient_Instance_Refreshed(object sender, EventArgs e) {
+      if (InvokeRequired) Invoke((Action<object, EventArgs>)HiveAdminClient_Instance_Refreshed, sender, e);
+      else {
+        OnContentChanged();
+      }
+    }
+
     private void ProjectResourcesView_Load(object sender, EventArgs e) {
 
@@ -382,5 +409,5 @@
         }
 
-          if (includedResources.Contains(newResource) && newIncludedResources.Contains(newResource)) {
+        if (includedResources.Contains(newResource) && newIncludedResources.Contains(newResource)) {
           newNode.Text += INCLUDED_TAG;
         } else if (addedIncludes.Contains(newResource)) {
@@ -421,4 +448,7 @@
       }
 
+      ExpandResourceNodesOfInterest(treeView.Nodes);
+
+      bool expandUngroupedGroupNode = false;
       var ungroupedSlaves = subResources.OfType<Slave>().OrderBy(x => x.Name);
       if(ungroupedSlaves.Any()) {
@@ -433,6 +463,28 @@
         foreach (var slave in ungroupedSlaves) {
           var slaveNode = new TreeNode(slave.Name) { Tag = slave };
+          if (newAssignedResources.Contains(slave)) {
+            slaveNode.Checked = true;
+            expandUngroupedGroupNode = true;
+          }
+
+          if (!HiveRoles.CheckAdminUserPermissions()) {
+            slaveNode.ForeColor = SystemColors.GrayText;
+            slaveNode.Text += IMMUTABLE_TAG;
+          } else {
+            if (addedAssignments.Contains(slave)) {
+              slaveNode.BackColor = addedAssignmentColor;
+              slaveNode.ForeColor = SystemColors.ControlText;
+              slaveNode.Text += ADDED_ASSIGNMENT_TAG;
+            } else if (removedAssignments.Contains(slave)) {
+              slaveNode.BackColor = removedAssignmentColor;
+              slaveNode.ForeColor = SystemColors.ControlText;
+              slaveNode.Text += REMOVED_ASSIGNMENT_TAG;
+              expandUngroupedGroupNode = true;
+            }
+          }
           ungroupedGroupNode.Nodes.Add(slaveNode);
         }
+
+        if(expandUngroupedGroupNode) ungroupedGroupNode.Expand();
         treeView.Nodes.Add(ungroupedGroupNode);
       } else if (ungroupedGroupNode != null) {
@@ -441,7 +493,5 @@
 
       treeView.BeforeCheck += treeView_BeforeCheck;
-      treeView.AfterCheck += treeView_AfterCheck;
-      
-      ExpandResourceNodesOfInterest(treeView.Nodes);
+      treeView.AfterCheck += treeView_AfterCheck;          
 
       return top;
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectView.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectView.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectView.cs	(revision 16235)
@@ -118,4 +118,5 @@
         endDateTimePicker.Enabled = !indefiniteCheckBox.Checked;
       }
+      SetEnabledStateOfControls();
       RegisterControlEvents();
     }
@@ -134,10 +135,12 @@
 
       if (Content != null) {
-        var parentProject = HiveAdminClient.Instance.GetAvailableProjectAncestors(Content.Id).LastOrDefault();
-        if (parentProject == null || parentProject.EndDate.HasValue) {
+        //var parentProject = HiveAdminClient.Instance.GetAvailableProjectAncestors(Content.Id).LastOrDefault();
+        var parentProject = HiveAdminClient.Instance.Projects.FirstOrDefault(x => x.Id == Content.ParentProjectId);
+        if ((!IsAdmin() && (parentProject == null || parentProject.EndDate.HasValue))
+           || (IsAdmin() && parentProject != null && parentProject.EndDate.HasValue)) {
           indefiniteCheckBox.Enabled = false;
         }
 
-        if (!IsAdmin() && !HiveAdminClient.Instance.CheckOwnershipOfParentProject(Content, UserInformation.Instance.User.Id)) {
+        if (Content.Id != Guid.Empty && !IsAdmin() && !HiveAdminClient.Instance.CheckOwnershipOfParentProject(Content, UserInformation.Instance.User.Id)) {
           ownerComboBox.Enabled = false;
           startDateTimePicker.Enabled = false;
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectsView.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectsView.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ProjectsView.cs	(revision 16235)
@@ -43,4 +43,5 @@
     private const string NOT_STORED_TAG = "*"; // " [not stored]";
     private const string CHANGES_NOT_STORED_TAG = "*"; // " [changes not stored]";
+    private const string INACTIVE_TAG = " [inactive]"; 
 
     private readonly Color selectedBackColor = Color.DodgerBlue;
@@ -106,31 +107,52 @@
         BuildProjectTree(Content);
       }
+      SetEnabledStateOfControls();
     }
 
     protected override void SetEnabledStateOfControls() {
-      base.SetEnabledStateOfControls();
-      bool selectedProjectExists = selectedProject != null && selectedProject.Id != Guid.Empty && Content.Contains(selectedProject);
-      bool projectIsNew = selectedProject != null && selectedProject.Id == Guid.Empty;
-      bool locked = Content == null || selectedProject == null || Locked || ReadOnly;
-      bool parentOwner = HiveAdminClient.Instance.CheckOwnershipOfParentProject(selectedProject, UserInformation.Instance.User.Id);
-      bool saveLocked = locked || (!IsAdmin() && selectedProject.OwnerUserId != UserInformation.Instance.User.Id && !parentOwner);
-      bool addLocked = saveLocked || projectIsNew || selectedProject.Id == Guid.Empty;
-      bool deleteLocked = locked || (!IsAdmin() && !parentOwner) || Content.Where(x => x.ParentProjectId == selectedProject.Id).Any();
-
-      var now = DateTime.Now;
-      if (!addLocked && (now < selectedProject.StartDate || now > selectedProject.EndDate)) addLocked = true;
+      base.SetEnabledStateOfControls();      
+
+      bool locked = Content == null || Locked || ReadOnly;      
+      bool parentOwner = selectedProject != null && HiveAdminClient.Instance.CheckOwnershipOfParentProject(selectedProject, UserInformation.Instance.User.Id);
+      bool selectedProjectDisabled = selectedProject == null 
+                                     || selectedProject != null && selectedProject.Id == Guid.Empty;
+
+      bool selectedProjectHasJobs =
+        !selectedProjectDisabled && HiveAdminClient.Instance.Jobs.ContainsKey(selectedProject.Id)
+                                 && HiveAdminClient.Instance.Jobs[selectedProject.Id] != null
+                                 && HiveAdminClient.Instance.Jobs[selectedProject.Id].Any();
+
+      bool addLocked = locked
+                       || (selectedProject == null && !IsAdmin())
+                       || (selectedProject != null && selectedProject.Id == Guid.Empty)
+                       || (selectedProject != null && !IsAdmin() && !parentOwner && selectedProject.OwnerUserId != UserInformation.Instance.User.Id)
+                       || (selectedProject != null && (DateTime.Now < selectedProject.StartDate || DateTime.Now > selectedProject.EndDate));
+
+      bool deleteLocked = locked
+                          || !Content.Any()
+                          || selectedProject == null
+                          || Content.Any(x => x.ParentProjectId == selectedProject.Id)
+                          || selectedProjectHasJobs
+                          || (!IsAdmin() && !parentOwner);
+
+      bool saveLocked = locked
+                        || !Content.Any()
+                        || selectedProject == null
+                        || (!IsAdmin() && !parentOwner && selectedProject.OwnerUserId != UserInformation.Instance.User.Id);
+
 
       addButton.Enabled = !addLocked;
       removeButton.Enabled = !deleteLocked;
       saveProjectButton.Enabled = !saveLocked;
+
       projectView.Enabled = !locked;
-      projectPermissionsView.Enabled = !locked;
-      projectResourcesView.Enabled = !locked;
-      projectJobsView.Enabled = !locked;
+      projectPermissionsView.Enabled = !locked && !selectedProjectDisabled;
+      projectResourcesView.Enabled = !locked && !selectedProjectDisabled;
+      projectJobsView.Enabled = !locked && !selectedProjectDisabled;
 
       projectView.Locked = locked;
-      projectPermissionsView.Locked = locked;
-      projectResourcesView.Locked = locked;
-      projectJobsView.Locked = locked;
+      projectPermissionsView.Locked = locked || selectedProjectDisabled;
+      projectResourcesView.Locked = locked || selectedProjectDisabled;
+      projectJobsView.Locked = locked || selectedProjectDisabled;
     }
     #endregion
@@ -254,37 +276,4 @@
       }
 
-      // double check of ChangeSelectedProject(..):
-      // if the user is no admin nor owner of a parent project
-      if (!IsAdmin() && !HiveAdminClient.Instance.CheckOwnershipOfParentProject(selectedProject, UserInformation.Instance.User.Id)) {
-        MessageBox.Show(
-          "Only admins and owners of parent projects are allowed to delete this project.",
-          "HeuristicLab Hive Administrator",
-          MessageBoxButtons.OK,
-          MessageBoxIcon.Error);
-        return;
-      }            
-
-
-      if (Content.Any(x => x.ParentProjectId == selectedProject.Id) 
-          || HiveAdminClient.Instance.ProjectDescendants[selectedProject.Id].Any()) {
-        MessageBox.Show(
-          "Only empty projects can be deleted.",
-          "HeuristicLab Hive Administrator",
-          MessageBoxButtons.OK,
-          MessageBoxIcon.Error);
-        return;
-      }
-
-      if (HiveAdminClient.Instance.Jobs.ContainsKey(selectedProject.Id) 
-        && HiveAdminClient.Instance.Jobs[selectedProject.Id] != null 
-        && HiveAdminClient.Instance.Jobs[selectedProject.Id].Any()) {
-        MessageBox.Show(
-          "There are " + HiveAdminClient.Instance.Jobs[selectedProject.Id].Count + " job(s) using this project and/or child-projects. It is necessary to delete them before the project.",
-          "HeuristicLab Hive Administrator",
-          MessageBoxButtons.OK,
-          MessageBoxIcon.Error);
-        return;
-      }
-
       var result = MessageBox.Show(
         "Do you really want to delete " + selectedProject.Name + "?",
@@ -297,11 +286,7 @@
           action: () => {
             RemoveProject(selectedProject);  
-          },
-          finallyCallback: () => {
-            removeButton.Enabled = true;
           });
-      } else {
-        removeButton.Enabled = true;
-      }
+      }
+      SetEnabledStateOfControls();
     }
 
@@ -492,8 +477,15 @@
       if (HiveAdminClient.Instance.DisabledParentProjects.Select(x => x.Id).Contains(p.Id)) {
         n.ForeColor = grayTextColor;
-      } else if (p.Id == Guid.Empty) {
-        n.Text += NOT_STORED_TAG;
-      } else if (p.Modified) {
-        n.Text += CHANGES_NOT_STORED_TAG;
+      } else {
+        if (p.Id == Guid.Empty) {
+          n.Text += NOT_STORED_TAG;
+        } else if (p.Modified) {
+          n.Text += CHANGES_NOT_STORED_TAG;
+        }
+
+        if (!IsActive(p)) {
+          n.ForeColor = grayTextColor;
+          n.Text += INACTIVE_TAG;
+        }
       }
     }
@@ -540,12 +532,9 @@
       try {
         if (project.Id != Guid.Empty) {
-          var projectsToSave = Content.Where(x => x.Id == Guid.Empty || x.Modified);
-          foreach (var p in projectsToSave)
-            p.Store();
-
           SelectedProject = HiveAdminClient.Instance.GetAvailableProjectAncestors(project.Id).LastOrDefault();
           HiveAdminClient.Delete(project);          
           UpdateProjects();
-        } else {
+        } else {          
+          SelectedProject = Content.FirstOrDefault(x => x.Id == project.ParentProjectId);
           Content.Remove(project);
         }
@@ -553,4 +542,10 @@
         ShowHiveInformationDialog();
       }
+    }
+
+    private bool IsActive(Project project) {
+      return DateTime.Now >= project.StartDate
+             && (project.EndDate == null
+                 || DateTime.Now < project.EndDate.Value);
     }
 
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ResourcesView.Designer.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ResourcesView.Designer.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ResourcesView.Designer.cs	(revision 16235)
@@ -164,4 +164,5 @@
       this.treeView.DragOver += new System.Windows.Forms.DragEventHandler(this.treeSlaveGroup_DragEnterOver);
       this.treeView.BeforeCheck += new System.Windows.Forms.TreeViewCancelEventHandler(this.treeSlaveGroup_BeforeCheck);
+      this.treeView.AfterCheck += new System.Windows.Forms.TreeViewEventHandler(this.treeSlaveGroup_AfterCheck);
       // 
       // tabSlaveGroup
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ResourcesView.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ResourcesView.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ResourcesView.cs	(revision 16235)
@@ -125,10 +125,22 @@
 
       HashSet<Guid> descendantResources = null;
+      bool selectedRDeleteLocked = selectedResource == null
+                              || (selectedResource.Id != Guid.Empty && (!HiveAdminClient.Instance.ResourceDescendants.TryGetValue(selectedResource.Id, out descendantResources) || descendantResources.Any()));
+
+      var nodes = GetCheckedNodes(treeView.Nodes).ToList();
+      var checkedResources = nodes.Select(x => x.Tag).OfType<Resource>().ToList();
+      bool checkedRDeleteLocked = false;
+      for (int i = 0; !checkedRDeleteLocked && i < checkedResources.Count; i++) {
+        if (checkedResources[i].Id != Guid.Empty &&
+            (!HiveAdminClient.Instance.ResourceDescendants.TryGetValue(checkedResources[i].Id, out descendantResources) ||
+             descendantResources.Any()))
+          checkedRDeleteLocked = true;
+      }
 
       bool deleteLocked = locked
-                       || !IsAdmin()
-                       || !Content.Any()
-                       || selectedResource == null
-                       || (selectedResource.Id != Guid.Empty && (!HiveAdminClient.Instance.ResourceDescendants.TryGetValue(selectedResource.Id, out descendantResources) || descendantResources.Any()));
+                          || !IsAdmin()
+                          || !Content.Any()
+                          || checkedResources.Any() && checkedRDeleteLocked
+                          || !checkedResources.Any() && selectedRDeleteLocked;
 
       bool saveLocked = locked
@@ -235,6 +247,8 @@
     }
 
-    private async void btnRemoveGroup_Click(object sender, EventArgs e) {
-      if (selectedResource == null) return;
+    private async void btnRemoveGroup_Click(object sender, EventArgs e) {      
+      var nodes = GetCheckedNodes(treeView.Nodes).ToList();
+      var checkedResources = nodes.Select(x => x.Tag).OfType<Resource>().ToList();
+      if (selectedResource == null && !checkedResources.Any()) return;
 
       lock (locker) {
@@ -243,18 +257,33 @@
       }
 
-      var result = MessageBox.Show(
-        "Do you really want to delete " + selectedResource.Name + "?",
-        "HeuristicLab Hive Administrator",
-        MessageBoxButtons.YesNo,
-        MessageBoxIcon.Question);
-      if (result == DialogResult.Yes) {
-        await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
-          action: () => {
-            RemoveResource(selectedResource);
-          });
-
-        OnContentChanged();
-        SetEnabledStateOfControls();
-      }
+      if (checkedResources.Count > 0) {
+        var result = MessageBox.Show(
+          "Do you really want to delete all " + checkedResources.Count + " checked resources?",
+          "HeuristicLab Hive Administrator",
+          MessageBoxButtons.YesNo,
+          MessageBoxIcon.Question);
+        if (result == DialogResult.Yes) {
+          await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
+            action: () => {
+              RemoveResource(checkedResources);
+            });
+        }
+      } else {
+        var res = checkedResources.Any() ? checkedResources.First() : selectedResource;
+        var result = MessageBox.Show(
+          "Do you really want to delete the selected resource " + res.Name + "?",
+          "HeuristicLab Hive Administrator",
+          MessageBoxButtons.YesNo,
+          MessageBoxIcon.Question);
+        if (result == DialogResult.Yes) {
+          await SecurityExceptionUtil.TryAsyncAndReportSecurityExceptions(
+            action: () => {
+              RemoveResource(res);
+            });
+        }
+      }
+
+      OnContentChanged();
+      SetEnabledStateOfControls();
     }
 
@@ -289,5 +318,5 @@
 
     private void treeSlaveGroup_BeforeCheck(object sender, TreeViewCancelEventArgs e) {
-      if (e.Node == ungroupedGroupNode) {
+      if (!IsAdmin() || e.Node == ungroupedGroupNode) {
         e.Cancel = true;
       } else {
@@ -297,4 +326,8 @@
         }
       }
+    }
+
+    private void treeSlaveGroup_AfterCheck(object sender, TreeViewEventArgs e) {
+      SetEnabledStateOfControls();
     }
 
@@ -535,10 +568,46 @@
         if (resource.Id != Guid.Empty) {
           SelectedResource = HiveAdminClient.Instance.GetAvailableResourceAncestors(resource.Id).LastOrDefault();
-          HiveAdminClient.Delete(resource);
+
+          // deal with all new, but not yet saved resources
+          var newResources = Content.Where(x => x.ParentResourceId == resource.Id).ToList();
+          if (newResources.Any(x => x.Id != Guid.Empty)) return;
+          foreach (var nr in newResources) Content.Remove(nr);
+
+          HiveAdminClient.Delete(resource);          
           UpdateResources();
         } else {
-          SelectedResource = null;
+          SelectedResource = Content.FirstOrDefault(x => x.Id == resource.ParentResourceId);
           Content.Remove(resource);
         }
+      } catch (AnonymousUserException) {
+        ShowHiveInformationDialog();
+      }
+    }
+
+    private void RemoveResource(IEnumerable<Resource> resources) {
+      if (resources == null || !resources.Any()) return;
+
+      var ids = resources.Select(x => x.Id).ToList();      
+      try {
+        bool update = false;
+        foreach (var r in resources) {          
+          if (r.Id != Guid.Empty)  {
+            if(r.Id == SelectedResource.Id)
+              SelectedResource = HiveAdminClient.Instance.GetAvailableResourceAncestors(r.Id).LastOrDefault();
+
+            // deal with all new, but not yet saved resources
+            var newResources = Content.Where(x => x.ParentResourceId == r.Id).ToList();
+            if (newResources.Any(x => x.Id != Guid.Empty)) return;
+            foreach (var nr in newResources) Content.Remove(nr);
+
+            HiveAdminClient.Delete(r);
+            update = true;
+          } else {
+            if (r.Id == SelectedResource.Id)
+              SelectedResource = Content.FirstOrDefault(x => x.Id == r.ParentResourceId);
+            Content.Remove(r);
+          }
+        }
+        if (update) UpdateResources();
       } catch (AnonymousUserException) {
         ShowHiveInformationDialog();
@@ -678,7 +747,11 @@
     private Dictionary<Guid, HashSet<Resource>> GetResourceDescendants() {
       var resourceDescendants = new Dictionary<Guid, HashSet<Resource>>();
+      //var resources = Content.Where(x => x.Id != Guid.Empty).Union(HiveAdminClient.Instance.DisabledParentResources).ToList();      
       var resources = Content.Union(HiveAdminClient.Instance.DisabledParentResources).ToList();
 
-      foreach (var r in resources) resourceDescendants.Add(r.Id, new HashSet<Resource>());
+      foreach (var r in resources) {
+        if(!resourceDescendants.ContainsKey(r.Id))
+          resourceDescendants.Add(r.Id, new HashSet<Resource>());
+      }
       foreach (var r in resources) {
         var parentResourceId = r.ParentResourceId;
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ScheduleView.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ScheduleView.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.Administrator/3.3/Views/ScheduleView.cs	(revision 16235)
@@ -227,8 +227,11 @@
       base.SetEnabledStateOfControls();
       bool enabled = Content != null && !Locked;
+      dtpFrom.Enabled = enabled;
+      dtpTo.Enabled = enabled;
+      chbade.Enabled = enabled;
       btCreate.Enabled = enabled;
-      btbDelete.Enabled = enabled;
+      btbDelete.Enabled = enabled;      
+      btnRecurrence.Enabled = enabled;
       btnClearCal.Enabled = enabled;
-      btnRecurrence.Enabled = enabled;
       btnSaveCal.Enabled = enabled;
     }
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.JobManager/3.3/Views/HiveResourceSelector.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.JobManager/3.3/Views/HiveResourceSelector.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.JobManager/3.3/Views/HiveResourceSelector.cs	(revision 16235)
@@ -26,4 +26,5 @@
 using System.Windows.Forms;
 using HeuristicLab.Collections;
+using HeuristicLab.Common;
 using HeuristicLab.Common.Resources;
 using HeuristicLab.Core;
@@ -263,28 +264,25 @@
       var node = resourcesTreeView.GetNodeAt(new Point(e.X, e.Y));
 
-      if (node == null || node == additionalNode) {
+      if (node == null && e.Button == MouseButtons.Left) {
         resourcesTreeView.SelectedNode = null;
         ExtractStatistics();
-      } else {
-        var r = (Resource)node.Tag;
-        if (!HiveClient.Instance.DisabledParentResources.Contains(r)) {
-          ExtractStatistics((Resource)node.Tag);
-        } else {
-          resourcesTreeView.SelectedNode = null;
-          ExtractStatistics();
-        } 
       }
     }
 
     private void resourcesTreeView_BeforeSelect(object sender, TreeViewCancelEventArgs e) {
-      if(e.Node == null || e.Node == additionalNode) {
+      if(e.Node == null) {
+        e.Cancel = true;
+        resourcesTreeView.SelectedNode = null;
+        ExtractStatistics();
+      } else if (e.Node == additionalNode) {
         e.Cancel = true;
       } else {
         var r = (Resource)e.Node.Tag;
-        if(r == null || HiveClient.Instance.DisabledParentResources.Contains(r)) {
+        if(r != null && !HiveClient.Instance.DisabledParentResources.Contains(r)) {
+          ExtractStatistics(r);
+        } else {
           e.Cancel = true;
         }
       }
-
     }
 
@@ -299,9 +297,4 @@
           || newIncludedResources.Contains(checkedResource)) {
           e.Cancel = true;
-
-          var selectedNode = resourcesTreeView.SelectedNode;
-          var selectedResource = (Resource)(selectedNode != null ? selectedNode.Tag : null);
-
-          ExtractStatistics(selectedResource);
         }
       }
@@ -317,5 +310,6 @@
 
       UpdateResourceTreeAfterCheck();
-      ExtractStatistics();
+      if(resourcesTreeView.SelectedNode == null)
+        ExtractStatistics();
       OnAssignedResourcesChanged();
     }
@@ -548,5 +542,6 @@
       resourcesTreeView.AfterCheck -= resourcesTreeView_AfterCheck;
 
-      var disabledParentResources = HiveClient.Instance.DisabledParentResources;
+      //var disabledParentResources = HiveClient.Instance.DisabledParentResources;
+      var disabledParentResources = HiveClient.Instance.GetDisabledResourceAncestors(resources);
       var mainResources = new HashSet<Resource>(resources.OfType<SlaveGroup>().Where(x => x.ParentResourceId == null));
       //var parentedMainResources = new HashSet<Resource>(resources.OfType<SlaveGroup>()
@@ -643,4 +638,5 @@
         additionalNode = new TreeNode(additionalSlavesGroupName) {
           ForeColor = SystemColors.GrayText,
+          ImageIndex = slaveGroupImageIndex,
           Tag = new SlaveGroup() {
             Name = additionalSlavesGroupName,
@@ -651,4 +647,23 @@
         foreach (var slave in singleSlaves.OrderBy(x => x.Name)) {
           var slaveNode = new TreeNode(slave.Name) { Tag = slave };
+
+          if (newAssignedResources.Select(x => x.Id).Contains(slave.Id)) {
+            slaveNode.Checked = true;
+            if (!addedAssignments.Select(x => x.Id).Contains(slave.Id) &&
+                !removedAssignments.Select(x => x.Id).Contains(slave.Id)) {
+              slaveNode.Text += SELECTED_TAG;
+            }
+          }
+
+          if (addedAssignments.Select(x => x.Id).Contains(slave.Id)) {
+            slaveNode.BackColor = addedAssignmentColor;
+            slaveNode.ForeColor = controlTextColor;
+            slaveNode.Text += ADDED_SELECTION_TAG;
+          } else if (removedAssignments.Select(x => x.Id).Contains(slave.Id)) {
+            slaveNode.BackColor = removedAssignmentColor;
+            slaveNode.ForeColor = controlTextColor;
+            slaveNode.Text += REMOVED_SELECTION_TAG;
+          }
+
           additionalNode.Nodes.Add(slaveNode);
         }
@@ -667,6 +682,7 @@
         Resource r = (Resource)n.Tag;
         if(n.Nodes.Count > 0) {
-          if(HiveClient.Instance.GetAvailableResourceDescendants(r.Id).OfType<SlaveGroup>().Any()
-            || HiveClient.Instance.GetAvailableResourceDescendants(r.Id).OfType<Slave>().Intersect(assignedResources.Union(newAssignedResources)).Any()) {
+          if(HiveClient.Instance.GetAvailableResourceDescendants(r.Id).OfType<SlaveGroup>().Any()            
+            || HiveClient.Instance.GetAvailableResourceDescendants(r.Id).OfType<Slave>().Intersect(assignedResources.Union(newAssignedResources)).Any()
+            || (n == additionalNode && additionalNode.Nodes.Count > 0 && additionalNode.Nodes.Cast<TreeNode>().Any(x => x.Checked))) {
             n.Expand();
             ExpandResourceNodesOfInterest(n.Nodes);
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.JobManager/3.3/Views/RefreshableHiveJobListView.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.JobManager/3.3/Views/RefreshableHiveJobListView.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.JobManager/3.3/Views/RefreshableHiveJobListView.cs	(revision 16235)
@@ -22,4 +22,5 @@
 using System;
 using System.Collections.Generic;
+using System.Linq;
 using System.Threading.Tasks;
 using System.Windows.Forms;
@@ -46,5 +47,5 @@
       this.itemsListView.FullRowSelect = true;
 
-      this.itemsListView.ListViewItemSorter = new ListViewItemComparer(new int[] { 2, 0 }, new SortOrder[] { SortOrder.Ascending, SortOrder.Ascending });
+      this.itemsListView.ListViewItemSorter = new ListViewItemComparer(new int[] { 2, 0 }, new SortOrder[] { SortOrder.Ascending, SortOrder.Ascending });      
 
       foreach (ColumnHeader c in this.itemsListView.Columns) {
@@ -63,5 +64,5 @@
       itemsListView.Sorting = sortOrder;
       itemsListView.Sort();
-      //AdjustListViewColumnSizes();
+      AdjustListViewColumnSizes();
     }
 
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.JobManager/3.3/Views/RefreshableHiveJobView.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.JobManager/3.3/Views/RefreshableHiveJobView.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive.JobManager/3.3/Views/RefreshableHiveJobView.cs	(revision 16235)
@@ -139,5 +139,7 @@
           }
 
+          // project look up
           if (Content.Job != null && Content.Job.ProjectId == Guid.Empty) {
+            projectNameTextBox.Text = string.Empty;
             if (HiveClient.Instance != null && HiveClient.Instance.Projects != null && HiveClient.Instance.Projects.Count == 1) {
               var p = HiveClient.Instance.Projects.FirstOrDefault();
@@ -145,27 +147,49 @@
                 hiveResourceSelectorDialog = new HiveResourceSelectorDialog(Content.Job.Id, Content.Job.ProjectId);
                 Content.Job.ProjectId = p.Id;
-                Content.Job.ResourceIds = HiveClient.Instance.GetAvailableResourcesForProject(p.Id).Select(x => x.Id).ToList();
+                var resources = HiveClient.Instance.GetAvailableResourcesForProject(p.Id).ToList();
+                Content.Job.ResourceIds = resources.Select(x => x.Id).ToList();
                 hiveResourceSelectorDialog.SelectedProjectId = Content.Job.ProjectId;
                 hiveResourceSelectorDialog.SelectedResourceIds = Content.Job.ResourceIds;
+
+                var cores = resources.Union(resources.SelectMany(x => HiveClient.Instance.GetAvailableResourceDescendants(x.Id)))
+                  .OfType<Slave>()
+                  .Distinct()
+                  .Sum(x => x.Cores);
+
+                projectNameTextBox.Text = HiveClient.Instance.GetProjectAncestry(Content.Job.ProjectId);
+                projectNameTextBox.Text += "   (" + (cores.HasValue ? cores.Value.ToString() : "0") + " cores)";
               }                
             }
-          }
-
-
-          nameTextBox.Text = Content.Job.Name;
-          descriptionTextBox.Text = Content.Job.Description;
-          executionTimeTextBox.Text = Content.ExecutionTime.ToString();
-          refreshAutomaticallyCheckBox.Checked = Content.RefreshAutomatically;
-
-          // project look up
-          if(Content.Job.ProjectId != null && Content.Job.ProjectId != Guid.Empty) {
-            if(selectedProject == null || selectedProject.Id != Content.Job.ProjectId) {
+          } else if (Content.Job != null && Content.Job.ProjectId != Guid.Empty) {
+            if (selectedProject == null || selectedProject.Id != Content.Job.ProjectId) {
               selectedProject = GetProject(Content.Job.ProjectId);
-              if (selectedProject != null) {
-                projectNameTextBox.Text = selectedProject.Name;
-              } else {
-                projectNameTextBox.Text = string.Empty;
-              }
+              hiveResourceSelectorDialog = null;
             }
+
+            if(hiveResourceSelectorDialog == null)
+              hiveResourceSelectorDialog = new HiveResourceSelectorDialog(Content.Job.Id, Content.Job.ProjectId);
+
+            if (selectedProject != null) {
+              projectNameTextBox.Text = HiveClient.Instance.GetProjectAncestry(selectedProject.Id);
+            } else {
+              projectNameTextBox.Text = string.Empty;
+            }
+
+            List<Resource> resources = null;
+            if (Content.Job.ResourceIds == null)
+              resources = HiveClient.Instance.GetAssignedResourcesForJob(Content.Job.Id).ToList();
+            else
+              resources = HiveClient.Instance.Resources.Where(x => Content.Job.ResourceIds.Contains(x.Id)).ToList();
+
+            Content.Job.ResourceIds = resources.Select(x => x.Id).ToList();
+            hiveResourceSelectorDialog.SelectedResourceIds = Content.Job.ResourceIds;
+
+            var cores = resources.Union(resources.SelectMany(x => HiveClient.Instance.GetAvailableResourceDescendants(x.Id)))
+              .OfType<Slave>()
+              .Distinct()
+              .Sum(x => x.Cores);
+
+            projectNameTextBox.Text += "   (" + (cores.HasValue ? cores.Value.ToString() : "0") + " cores)";
+
           } else {
             selectedProject = null;
@@ -173,4 +197,10 @@
             Content.Job.ResourceIds = null;
           }
+
+
+          nameTextBox.Text = Content.Job.Name;
+          descriptionTextBox.Text = Content.Job.Description;
+          executionTimeTextBox.Text = Content.ExecutionTime.ToString();
+          refreshAutomaticallyCheckBox.Checked = Content.RefreshAutomatically;
           
           logView.Content = Content.Log;
@@ -182,5 +212,5 @@
         SuppressEvents = false;
       }
-      hiveExperimentPermissionListView.Content = null; // has to be filled by refresh button
+      hiveExperimentPermissionListView.Content = null; // has to be filled by refresh
       Content_JobStatisticsChanged(this, EventArgs.Empty);
       Content_HiveExperimentChanged(this, EventArgs.Empty);
@@ -400,8 +430,18 @@
       if (hiveResourceSelectorDialog.ShowDialog(this) == DialogResult.OK) {
         selectedProject = hiveResourceSelectorDialog.SelectedProject;
-        if(selectedProject != null) {
-          projectNameTextBox.Text = selectedProject.Name;
+        if(selectedProject != null) {       
           Content.Job.ProjectId = selectedProject.Id;
           Content.Job.ResourceIds = hiveResourceSelectorDialog.SelectedResources.Select(x => x.Id).ToList();
+
+          var cores = hiveResourceSelectorDialog.SelectedResources
+            .Union(hiveResourceSelectorDialog.SelectedResources
+              .SelectMany(x => HiveClient.Instance.GetAvailableResourceDescendants(x.Id)))
+            .OfType<Slave>()
+            .Distinct()
+            .Sum(x => x.Cores);
+
+          projectNameTextBox.Text = HiveClient.Instance.GetProjectAncestry(selectedProject.Id) + "";
+          projectNameTextBox.Text += "   (" + (cores.HasValue ? cores.Value.ToString() : "0") + " cores)";
+
         } else {
           selectedProject = null;
@@ -501,17 +541,4 @@
     }
 
-    private void updateButton_Click2(object sender, EventArgs e) {
-      if (Content.ExecutionState == ExecutionState.Stopped) {
-        MessageBox.Show("Job cannot be updated once it stopped.", "HeuristicLab Hive Job Manager", MessageBoxButtons.OK, MessageBoxIcon.Information);
-        return;
-      }
-
-      HiveClient.UpdateJob(
-        (Exception ex) => ErrorHandling.ShowErrorDialog(this, "Update failed.", ex), 
-        Content, 
-        new CancellationToken());
-      UpdateSelectorDialog();
-    }
-
     private void updateButton_Click(object sender, EventArgs e) {
       if (Content.ExecutionState == ExecutionState.Stopped) {
@@ -556,5 +583,5 @@
       } else {
         startButton.Enabled = Content.IsControllable && Content.HiveTasks != null && Content.HiveTasks.Count > 0 
-          && Content.Job.ProjectId != null && Content.Job.ProjectId != Guid.Empty && Content.Job.ResourceIds != null  && Content.Job.ResourceIds.Any() 
+          && Content.Job.ProjectId != Guid.Empty && Content.Job.ResourceIds != null  && Content.Job.ResourceIds.Any() 
           && (Content.ExecutionState == ExecutionState.Prepared || Content.ExecutionState == ExecutionState.Paused) && !Content.IsProgressing;
         pauseButton.Enabled = Content.IsControllable && Content.ExecutionState == ExecutionState.Started && !Content.IsProgressing;
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive/3.3/HeuristicLab.Clients.Hive-3.3.csproj
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive/3.3/HeuristicLab.Clients.Hive-3.3.csproj	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive/3.3/HeuristicLab.Clients.Hive-3.3.csproj	(revision 16235)
@@ -197,4 +197,8 @@
   </ItemGroup>
   <ItemGroup>
+    <ProjectReference Include="..\..\HeuristicLab.Clients.Access\3.3\HeuristicLab.Clients.Access-3.3.csproj">
+      <Project>{494F87F4-0F25-4D33-A382-10CDB2174D48}</Project>
+      <Name>HeuristicLab.Clients.Access-3.3</Name>
+    </ProjectReference>
     <ProjectReference Include="..\..\HeuristicLab.Clients.Common\3.3\HeuristicLab.Clients.Common-3.3.csproj">
       <Project>{730A9104-D4D1-4360-966B-E49B7571DDA3}</Project>
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive/3.3/HiveAdminClient.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive/3.3/HiveAdminClient.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive/3.3/HiveAdminClient.cs	(revision 16235)
@@ -26,4 +26,5 @@
 using System.Collections.Generic;
 using System.Linq;
+using HeuristicLab.Clients.Access;
 
 namespace HeuristicLab.Clients.Hive {
@@ -70,6 +71,6 @@
     }
 
-    private Dictionary<Guid, HiveItemCollection<Job>> jobs;
-    public Dictionary<Guid, HiveItemCollection<Job>> Jobs {
+    private Dictionary<Guid, HiveItemCollection<RefreshableJob>> jobs;
+    public Dictionary<Guid, HiveItemCollection<RefreshableJob>> Jobs {
       get { return jobs; }
       set {
@@ -77,4 +78,9 @@
           jobs = value;
         }
+    }
+
+    private Dictionary<Guid, List<LightweightTask>> tasks;
+    public Dictionary<Guid, List<LightweightTask>> Tasks {
+      get { return tasks; }
     }
 
@@ -143,5 +149,6 @@
         projects = new ItemList<Project>();
         projectResourceAssignments = new ItemList<AssignedProjectResource>();
-        jobs = new Dictionary<Guid, HiveItemCollection<Job>>();
+        jobs = new Dictionary<Guid, HiveItemCollection<RefreshableJob>>();
+        tasks = new Dictionary<Guid, List<LightweightTask>>();
         projectNames = new Dictionary<Guid, string>();
         resourceNames = new Dictionary<Guid, string>();
@@ -160,11 +167,14 @@
             service.GetAssignedResourcesForProjectsAdministration(projectIds)
               .ForEach(a => projectResourceAssignments.Add(a));
-            projectIds.ForEach(p => jobs.Add(p, new HiveItemCollection<Job>()));
+            projectIds.ForEach(p => jobs.Add(p, new HiveItemCollection<RefreshableJob>()));
             var unsortedJobs = service.GetJobsByProjectIds(projectIds)
               .OrderBy(x => x.DateCreated).ToList();
 
-            unsortedJobs.Where(j => j.State == JobState.DeletionPending).ToList().ForEach(j => jobs[j.ProjectId].Add(j));
-            unsortedJobs.Where(j => j.State == JobState.StatisticsPending).ToList().ForEach(j => jobs[j.ProjectId].Add(j));
-            unsortedJobs.Where(j => j.State == JobState.Online).ToList().ForEach(j => jobs[j.ProjectId].Add(j));
+            unsortedJobs.Where(j => j.State == JobState.DeletionPending).ToList().ForEach(j => jobs[j.ProjectId].Add(new RefreshableJob(j)));
+            unsortedJobs.Where(j => j.State == JobState.StatisticsPending).ToList().ForEach(j => jobs[j.ProjectId].Add(new RefreshableJob(j)));
+            unsortedJobs.Where(j => j.State == JobState.Online).ToList().ForEach(j => jobs[j.ProjectId].Add(new RefreshableJob(j)));
+
+            foreach (var job in jobs.SelectMany(x => x.Value))
+              LoadLightweightJob(job);
 
             projectNames = service.GetProjectNames();
@@ -306,17 +316,62 @@
     public void RefreshJobs() {
       var projectIds = new List<Guid>();
-      jobs = new Dictionary<Guid, HiveItemCollection<Job>>();
+      jobs = new Dictionary<Guid, HiveItemCollection<RefreshableJob>>();
+      tasks = new Dictionary<Guid, List<LightweightTask>>();
 
       HiveServiceLocator.Instance.CallHiveService(service => {
         service.GetProjectsForAdministration().ForEach(p => projectIds.Add(p.Id));
         if(projectIds.Any()) {
-          projectIds.ForEach(p => jobs.Add(p, new HiveItemCollection<Job>()));
+          projectIds.ForEach(p => jobs.Add(p, new HiveItemCollection<RefreshableJob>()));
           var unsortedJobs = service.GetJobsByProjectIds(projectIds)
             .OrderBy(x => x.DateCreated).ToList();
-          unsortedJobs.Where(j => j.State == JobState.DeletionPending).ToList().ForEach(j => jobs[j.ProjectId].Add(j));
-          unsortedJobs.Where(j => j.State == JobState.StatisticsPending).ToList().ForEach(j => jobs[j.ProjectId].Add(j));
-          unsortedJobs.Where(j => j.State == JobState.Online).ToList().ForEach(j => jobs[j.ProjectId].Add(j));
+          
+          unsortedJobs.Where(j => j.State == JobState.DeletionPending).ToList().ForEach(j => jobs[j.ProjectId].Add(new RefreshableJob(j)));
+          unsortedJobs.Where(j => j.State == JobState.StatisticsPending).ToList().ForEach(j => jobs[j.ProjectId].Add(new RefreshableJob(j)));
+          unsortedJobs.Where(j => j.State == JobState.Online).ToList().ForEach(j => jobs[j.ProjectId].Add(new RefreshableJob(j)));
+
+          foreach(var job in jobs.SelectMany(x => x.Value))
+            LoadLightweightJob(job);
         }
       });
+    }
+
+    public void LoadLightweightJob(RefreshableJob refreshableJob) {
+      var job = refreshableJob.Job;
+      var lightweightTasks = HiveServiceLocator.Instance.CallHiveService(s => s.GetLightweightJobTasksWithoutStateLog(job.Id));
+
+      if (tasks.ContainsKey(job.Id)) {
+        tasks[job.Id].Clear();
+        tasks[job.Id].AddRange(lightweightTasks);
+      } else {
+        tasks.Add(job.Id, new List<LightweightTask>(lightweightTasks));        
+      }
+
+      if (lightweightTasks != null && lightweightTasks.Count > 0 && lightweightTasks.All(x => x.Id != Guid.Empty)) {
+        if (lightweightTasks.All(x =>
+          x.State == TaskState.Finished 
+          || x.State == TaskState.Aborted 
+          || x.State == TaskState.Failed)) {
+          refreshableJob.ExecutionState = ExecutionState.Stopped;
+          refreshableJob.RefreshAutomatically = false;
+        } else if (
+          lightweightTasks
+            .Where(x => x.ParentTaskId != null)
+            .All(x =>
+              x.State != TaskState.Waiting
+              || x.State != TaskState.Transferring
+              || x.State != TaskState.Calculating)
+          && lightweightTasks
+             .Where(x => x.ParentTaskId != null)
+             .Any(x => x.State == TaskState.Paused)) {
+          refreshableJob.ExecutionState = ExecutionState.Paused;
+          refreshableJob.RefreshAutomatically = false;
+        } else if (lightweightTasks.Any(x => x.State == TaskState.Calculating 
+                                  || x.State == TaskState.Transferring 
+                                  || x.State == TaskState.Waiting)) {
+          refreshableJob.ExecutionState = ExecutionState.Started;
+        }
+
+        refreshableJob.ExecutionTime = TimeSpan.FromMilliseconds(lightweightTasks.Sum(x => x.ExecutionTime.TotalMilliseconds));
+      }
     }
 
@@ -326,8 +381,8 @@
         var unsortedJobs = jobs.Values.ElementAt(i);
 
-        var sortedJobs = new HiveItemCollection<Job>();
-        sortedJobs.AddRange(unsortedJobs.Where(j => j.State == JobState.DeletionPending));
-        sortedJobs.AddRange(unsortedJobs.Where(j => j.State == JobState.StatisticsPending));
-        sortedJobs.AddRange(unsortedJobs.Where(j => j.State == JobState.Online));
+        var sortedJobs = new HiveItemCollection<RefreshableJob>();
+        sortedJobs.AddRange(unsortedJobs.Where(j => j.Job.State == JobState.DeletionPending));
+        sortedJobs.AddRange(unsortedJobs.Where(j => j.Job.State == JobState.StatisticsPending));
+        sortedJobs.AddRange(unsortedJobs.Where(j => j.Job.State == JobState.Online));
 
         jobs[projectId] = sortedJobs;
@@ -404,7 +459,49 @@
     }
 
-    public static void DeleteJobs(List<Guid> jobIds) {
-
+    public static void RemoveJobs(List<Guid> jobIds) {
       HiveServiceLocator.Instance.CallHiveService((s) => s.UpdateJobStates(jobIds, JobState.StatisticsPending));
+    }
+    #endregion
+
+    #region Job Handling
+
+    public static void ResumeJob(RefreshableJob refreshableJob) {
+      HiveServiceLocator.Instance.CallHiveService(service => {
+        var tasks = service.GetLightweightJobTasksWithoutStateLog(refreshableJob.Id);
+        foreach (var task in tasks) {
+          if (task.State == TaskState.Paused) {
+            service.RestartTask(task.Id);
+          }
+        }
+      });
+      refreshableJob.ExecutionState = ExecutionState.Started;
+    }
+
+    public static void PauseJob(RefreshableJob refreshableJob) {
+      HiveServiceLocator.Instance.CallHiveService(service => {
+        var tasks = service.GetLightweightJobTasksWithoutStateLog(refreshableJob.Id);
+        foreach (var task in tasks) {
+          if (task.State != TaskState.Finished && task.State != TaskState.Aborted && task.State != TaskState.Failed)
+            service.PauseTask(task.Id);
+        }
+      });
+      refreshableJob.ExecutionState = ExecutionState.Paused;
+    }
+
+    public static void StopJob(RefreshableJob refreshableJob) {
+      HiveServiceLocator.Instance.CallHiveService(service => {
+        var tasks = service.GetLightweightJobTasksWithoutStateLog(refreshableJob.Id);
+        foreach (var task in tasks) {
+          if (task.State != TaskState.Finished && task.State != TaskState.Aborted && task.State != TaskState.Failed)
+            service.StopTask(task.Id);
+        }
+      });
+      refreshableJob.ExecutionState = ExecutionState.Stopped;
+    }
+
+    public static void RemoveJob(RefreshableJob refreshableJob) {
+      HiveServiceLocator.Instance.CallHiveService((service) => {
+        service.UpdateJobState(refreshableJob.Id, JobState.StatisticsPending);
+      });
     }
     #endregion
@@ -436,4 +533,13 @@
       if (resourceDescendants.ContainsKey(id)) return resources.Where(x => resourceDescendants[id].Contains(x.Id));
       else return Enumerable.Empty<Resource>();
+    }
+
+    public IEnumerable<Resource> GetDisabledResourceAncestors(IEnumerable<Resource> availableResources) {
+      var missingParentIds = availableResources
+        .Where(x => x.ParentResourceId.HasValue)
+        .SelectMany(x => resourceAncestors[x.Id]).Distinct()
+        .Where(x => !availableResources.Select(y => y.Id).Contains(x));
+
+      return resources.OfType<SlaveGroup>().Union(disabledParentResources).Where(x => missingParentIds.Contains(x.Id));
     }
 
@@ -478,5 +584,11 @@
 
       if(projectAncestors.ContainsKey(pro.Id)) {
-        return GetAvailableProjectAncestors(pro.Id).Where(x => x.OwnerUserId == userId).Any();
+        return GetAvailableProjectAncestors(pro.Id).Any(x => x.OwnerUserId == userId);
+      }
+
+      if (pro.ParentProjectId != null && pro.ParentProjectId != Guid.Empty) {
+        var parent = projects.FirstOrDefault(x => x.Id == pro.ParentProjectId.Value);
+        if (parent != null)
+          return parent.OwnerUserId == userId || GetAvailableProjectAncestors(parent.Id).Any(x => x.OwnerUserId == userId);
       }
 
@@ -491,7 +603,13 @@
       // ... or the new parent is not stored yet
       // ... or there is not parental change
-      if (child == null 
-        || (parent != null && parent.Id == Guid.Empty)
-        || (parent != null && parent.Id == child.ParentProjectId)) {
+      if (child == null
+          || (parent != null && parent.Id == Guid.Empty)
+          || (parent != null && parent.Id == child.ParentProjectId)) {
+        changePossible = false;
+      } else if (parent == null && !IsAdmin()) {
+        // ... if parent is null, but user is no admin (only admins are allowed to create root projects)
+        changePossible = false;
+      } else if (parent != null && (!IsAdmin() && parent.OwnerUserId != UserInformation.Instance.User.Id && !CheckOwnershipOfParentProject(parent, UserInformation.Instance.User.Id))) {
+        // ... if the user is no admin nor owner of the new parent or grand..grandparents
         changePossible = false;
       } else if(parent != null && projectDescendants.ContainsKey(child.Id)) {
@@ -525,4 +643,13 @@
       return changePossible;
     }
+
+    public IEnumerable<Resource> GetAssignedResourcesForJob(Guid jobId) {
+      var assignedJobResource =  HiveServiceLocator.Instance.CallHiveService(service => service.GetAssignedResourcesForJob(jobId));
+      return Resources.Where(x => assignedJobResource.Select(y => y.ResourceId).Contains(x.Id));
+    }
+
+    private bool IsAdmin() {
+      return HiveRoles.CheckAdminUserPermissions();
+    }
     #endregion
   }
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive/3.3/HiveClient.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive/3.3/HiveClient.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive/3.3/HiveClient.cs	(revision 16235)
@@ -324,4 +324,13 @@
       return resources.Where(x => assignedProjectResources.Select(y => y.ResourceId).Contains(x.Id));
     }
+
+    public IEnumerable<Resource> GetDisabledResourceAncestors(IEnumerable<Resource> availableResources) {
+      var missingParentIds = availableResources
+        .Where(x => x.ParentResourceId.HasValue)
+        .SelectMany(x => resourceAncestors[x.Id]).Distinct()
+        .Where(x => !availableResources.Select(y => y.Id).Contains(x));
+
+      return resources.OfType<SlaveGroup>().Union(disabledParentResources).Where(x => missingParentIds.Contains(x.Id));
+    }
     #endregion
 
@@ -747,4 +756,9 @@
       return string.Join(" » ", projects.Select(x => ProjectNames[x]).ToArray());
     }
+
+    public IEnumerable<Resource> GetAssignedResourcesForJob(Guid jobId) {
+      var assignedJobResource = HiveServiceLocator.Instance.CallHiveService(service => service.GetAssignedResourcesForJob(jobId));
+      return Resources.Where(x => assignedJobResource.Select(y => y.ResourceId).Contains(x.Id));
+    }
   }
 }
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive/3.3/Plugin.cs.frame
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive/3.3/Plugin.cs.frame	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Clients.Hive/3.3/Plugin.cs.frame	(revision 16235)
@@ -30,4 +30,5 @@
   [PluginFile("HeuristicLab.Clients.Hive-3.3.dll", PluginFileType.Assembly)]
   [PluginDependency("HeuristicLab.Clients.Common", "3.3")]
+  [PluginDependency("HeuristicLab.Clients.Access", "3.3")]  
   [PluginDependency("HeuristicLab.Collections", "3.3")]
   [PluginDependency("HeuristicLab.Common", "3.3")]
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Optimization/3.3/MetaOptimizers/TimeLimitRun.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Optimization/3.3/MetaOptimizers/TimeLimitRun.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Optimization/3.3/MetaOptimizers/TimeLimitRun.cs	(revision 16235)
@@ -188,4 +188,5 @@
           TimeSpan.FromSeconds(15) });
       snapshotTimesIndex = 0;
+      snapshots = new RunCollection();
       Runs = new RunCollection { OptimizerName = Name };
       Initialize();
@@ -199,4 +200,5 @@
           TimeSpan.FromSeconds(15) });
       snapshotTimesIndex = 0;
+      snapshots = new RunCollection();
       Runs = new RunCollection { OptimizerName = Name };
       Initialize();
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/DerivativeCalculator.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/DerivativeCalculator.cs	(revision 16235)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/DerivativeCalculator.cs	(revision 16235)
@@ -0,0 +1,193 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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/>.
+ */
+#endregion
+
+using System;
+using System.Linq;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  public static class DerivativeCalculator {
+    public static ISymbolicExpressionTree Derive(ISymbolicExpressionTree tree, string variableName) {
+      var mainBranch = tree.Root.GetSubtree(0).GetSubtree(0);
+      var root = new ProgramRootSymbol().CreateTreeNode();
+      root.AddSubtree(new StartSymbol().CreateTreeNode());
+      var dTree = TreeSimplifier.GetSimplifiedTree(Derive(mainBranch, variableName));
+      // var dTree = Derive(mainBranch, variableName);
+      root.GetSubtree(0).AddSubtree(dTree);
+      return new SymbolicExpressionTree(root);
+    }
+
+    private static Constant constantSy = new Constant();
+    private static Addition addSy = new Addition();
+    private static Subtraction subSy = new Subtraction();
+    private static Multiplication mulSy = new Multiplication();
+    private static Division divSy = new Division();
+
+    public static ISymbolicExpressionTreeNode Derive(ISymbolicExpressionTreeNode branch, string variableName) {
+      if (branch.Symbol is Constant) {
+        return CreateConstant(0.0);
+      }
+      if (branch.Symbol is Variable) {
+        var varNode = branch as VariableTreeNode;
+        if (varNode.VariableName == variableName) {
+          return CreateConstant(varNode.Weight);
+        } else {
+          return CreateConstant(0.0);
+        }
+      }
+      if (branch.Symbol is Addition) {
+        var sum = addSy.CreateTreeNode();
+        foreach (var subTree in branch.Subtrees) {
+          sum.AddSubtree(Derive(subTree, variableName));
+        }
+        return sum;
+      }
+      if (branch.Symbol is Subtraction) {
+        var sum = subSy.CreateTreeNode();
+        foreach (var subTree in branch.Subtrees) {
+          sum.AddSubtree(Derive(subTree, variableName));
+        }
+        return sum;
+      }
+      if (branch.Symbol is Multiplication) {
+        // (f * g)' = f'*g + f*g'
+        // for multiple factors: (f * g * h)' = ((f*g) * h)' = (f*g)' * h + (f*g) * h' 
+
+        if (branch.SubtreeCount >= 2) {
+          var f = (ISymbolicExpressionTreeNode)branch.GetSubtree(0).Clone();
+          var g = (ISymbolicExpressionTreeNode)branch.GetSubtree(1).Clone();
+          var fprime = Derive(f, variableName);
+          var gprime = Derive(g, variableName);
+          var fgPrime = Sum(Product(f, gprime), Product(fprime, g));
+          for (int i = 2; i < branch.SubtreeCount; i++) {
+            var fg = Product((ISymbolicExpressionTreeNode)f.Clone(), (ISymbolicExpressionTreeNode)g.Clone());
+            var h = (ISymbolicExpressionTreeNode)branch.GetSubtree(i).Clone();
+            var hPrime = Derive(h, variableName);
+            fgPrime = Sum(Product(fgPrime, h), Product(fg, hPrime));
+          }
+          return fgPrime;
+        } else throw new ArgumentException();
+      }
+      if (branch.Symbol is Division) {
+        // (f/g)' = (f'g - g'f) / g²
+        if (branch.SubtreeCount == 1) {
+          var g = (ISymbolicExpressionTreeNode)branch.GetSubtree(0).Clone();
+          var gPrime = Product(CreateConstant(-1.0), Derive(g, variableName));
+          var sqrNode = new Square().CreateTreeNode();
+          sqrNode.AddSubtree(g);
+          return Div(gPrime, sqrNode);
+        } else if (branch.SubtreeCount == 2) {
+          var f = (ISymbolicExpressionTreeNode)branch.GetSubtree(0).Clone();
+          var g = (ISymbolicExpressionTreeNode)branch.GetSubtree(1).Clone();
+          var fprime = Derive(f, variableName);
+          var gprime = Derive(g, variableName);
+          var sqrNode = new Square().CreateTreeNode();
+          sqrNode.AddSubtree((ISymbolicExpressionTreeNode)branch.GetSubtree(1).Clone());
+          return Div(Subtract(Product(fprime, g), Product(f, gprime)), sqrNode);
+        } else throw new NotSupportedException();
+      }
+      if (branch.Symbol is Logarithm) {
+        var f = (ISymbolicExpressionTreeNode)branch.GetSubtree(0).Clone();
+        return Product(Div(CreateConstant(1.0), f), Derive(f, variableName));
+      }
+      if (branch.Symbol is Exponential) {
+        var f = (ISymbolicExpressionTreeNode)branch.Clone();
+        return Product(f, Derive(branch.GetSubtree(0), variableName));
+      }
+      if(branch.Symbol is Square) {
+        var f = (ISymbolicExpressionTreeNode)branch.GetSubtree(0).Clone();
+        return Product(Product(CreateConstant(2.0), f), Derive(f, variableName));
+      }     
+      if(branch.Symbol is SquareRoot) {
+        var f = (ISymbolicExpressionTreeNode)branch.Clone();
+        var u = (ISymbolicExpressionTreeNode)branch.GetSubtree(0).Clone();
+        return Product(Div(CreateConstant(1.0), Product(CreateConstant(2.0), f)), Derive(u, variableName));
+      }
+      if (branch.Symbol is Sine) {
+        var u = (ISymbolicExpressionTreeNode)branch.GetSubtree(0).Clone();
+        var cos = (new Cosine()).CreateTreeNode();
+        cos.AddSubtree(u);
+        return Product(cos, Derive(u, variableName));
+      }
+      if (branch.Symbol is Cosine) {
+        var u = (ISymbolicExpressionTreeNode)branch.GetSubtree(0).Clone();
+        var sin = (new Sine()).CreateTreeNode();
+        sin.AddSubtree(u);
+        return Product(CreateConstant(-1.0), Product(sin, Derive(u, variableName)));
+      }
+      throw new NotSupportedException(string.Format("Symbol {0} is not supported.", branch.Symbol));
+    }
+
+
+    private static ISymbolicExpressionTreeNode Product(ISymbolicExpressionTreeNode f, ISymbolicExpressionTreeNode g) {
+      var product = mulSy.CreateTreeNode();
+      product.AddSubtree(f);
+      product.AddSubtree(g);
+      return product;
+    }
+    private static ISymbolicExpressionTreeNode Div(ISymbolicExpressionTreeNode f, ISymbolicExpressionTreeNode g) {
+      var div = divSy.CreateTreeNode();
+      div.AddSubtree(f);
+      div.AddSubtree(g);
+      return div;
+    }
+
+    private static ISymbolicExpressionTreeNode Sum(ISymbolicExpressionTreeNode f, ISymbolicExpressionTreeNode g) {
+      var sum = addSy.CreateTreeNode();
+      sum.AddSubtree(f);
+      sum.AddSubtree(g);
+      return sum;
+    }
+    private static ISymbolicExpressionTreeNode Subtract(ISymbolicExpressionTreeNode f, ISymbolicExpressionTreeNode g) {
+      var sum = subSy.CreateTreeNode();
+      sum.AddSubtree(f);
+      sum.AddSubtree(g);
+      return sum;
+    }
+                          
+    private static ISymbolicExpressionTreeNode CreateConstant(double v) {
+      var constNode = (ConstantTreeNode)constantSy.CreateTreeNode();
+      constNode.Value = v;
+      return constNode;
+    }
+
+    public static bool IsCompatible(ISymbolicExpressionTree tree) {
+      var containsUnknownSymbol = (
+        from n in tree.Root.GetSubtree(0).IterateNodesPrefix()
+        where
+          !(n.Symbol is Variable) &&
+          !(n.Symbol is Constant) &&
+          !(n.Symbol is Addition) &&
+          !(n.Symbol is Subtraction) &&
+          !(n.Symbol is Multiplication) &&
+          !(n.Symbol is Division) &&
+          !(n.Symbol is Logarithm) &&
+          !(n.Symbol is Exponential) &&
+          !(n.Symbol is Square) &&
+          !(n.Symbol is SquareRoot) &&
+          !(n.Symbol is Sine) &&
+          !(n.Symbol is Cosine) &&
+          !(n.Symbol is StartSymbol)
+        select n).Any();
+      return !containsUnknownSymbol;
+    }
+  }
+}
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/TreeSimplifier.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/TreeSimplifier.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/TreeSimplifier.cs	(revision 16235)
@@ -1121,4 +1121,6 @@
         // $ * 1.0 => $
         return a;
+      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(0.0)) {
+        return MakeConstant(0);
       } else if (IsConstant(b) && IsVariableBase(a)) {
         // multiply constants into variables weights
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/HashExtensions.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/HashExtensions.cs	(revision 16235)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/HashExtensions.cs	(revision 16235)
@@ -0,0 +1,243 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  public static class SymbolicExpressionHashExtensions {
+    public sealed class HashNode<T> : IComparable<HashNode<T>>, IEquatable<HashNode<T>> where T : class {
+      public T Data;
+      public int Arity;
+      public int Size;
+      public bool IsCommutative;
+
+      public bool Enabled;
+      public int HashValue;           // the initial (fixed) hash value for this individual node/data
+      public int CalculatedHashValue; // the calculated hash value (taking into account the children hash values)
+
+      public Action<HashNode<T>[], int> Simplify;
+      public IComparer<T> Comparer;
+
+      public bool IsChild => Arity == 0;
+
+      public HashNode(IComparer<T> comparer) {
+        Comparer = comparer;
+      }
+
+      private HashNode() { }
+
+      public int CompareTo(HashNode<T> other) {
+        var res = Comparer.Compare(Data, other.Data);
+        return res == 0 ? CalculatedHashValue.CompareTo(other.CalculatedHashValue) : res;
+      }
+
+      public override string ToString() {
+        return $"{Data} {Arity} {Size} {CalculatedHashValue} {Enabled}";
+      }
+
+      public bool Equals(HashNode<T> other) {
+        return CalculatedHashValue.Equals(other.CalculatedHashValue);
+      }
+
+      public override bool Equals(object obj) {
+        var other = obj as HashNode<T>;
+        if (other != null)
+          return Equals(other);
+        return base.Equals(obj);
+      }
+
+      public override int GetHashCode() {
+        return CalculatedHashValue;
+      }
+
+      public static bool operator ==(HashNode<T> a, HashNode<T> b) {
+        return a.Equals(b);
+      }
+
+      public static bool operator !=(HashNode<T> a, HashNode<T> b) {
+        return !a.Equals(b);
+      }
+    }
+
+    public static int ComputeHash<T>(this HashNode<T>[] nodes, int i) where T : class {
+      var node = nodes[i];
+      var hashes = new int[node.Arity + 1];
+      int idx = 0;
+      foreach (int c in nodes.IterateChildren(i)) {
+        hashes[idx++] = nodes[c].CalculatedHashValue;
+      }
+      hashes[idx] = node.HashValue;
+      return HashUtil.JSHash(hashes);
+    }
+
+    public static HashNode<T>[] Simplify<T>(this HashNode<T>[] nodes) where T : class {
+      var reduced = nodes.Reduce();
+      reduced.Sort();
+
+      for (int i = 0; i < reduced.Length; ++i) {
+        var node = reduced[i];
+        if (node.IsChild) {
+          continue;
+        }
+        node.Simplify?.Invoke(reduced, i);
+      }
+      // detect if anything was simplified
+      var count = 0;
+      foreach (var node in reduced) {
+        if (!node.Enabled) { ++count; }
+      }
+      if (count == 0) {
+        return reduced;
+      }
+
+      var simplified = new HashNode<T>[reduced.Length - count];
+      int j = 0;
+      foreach (var node in reduced) {
+        if (node.Enabled) {
+          simplified[j++] = node;
+        }
+      }
+      simplified.UpdateNodeSizes();
+      simplified.Sort();
+      return simplified;
+    }
+
+    public static void Sort<T>(this HashNode<T>[] nodes) where T : class {
+      for (int i = 0; i < nodes.Length; ++i) {
+        var node = nodes[i];
+
+        if (node.IsChild) {
+          continue;
+        }
+
+        if (node.IsCommutative) { // only sort when the argument order does not matter
+          var arity = node.Arity;
+          var size = node.Size;
+
+          if (arity == size) { // all child nodes are terminals
+            Array.Sort(nodes, i - size, size);
+          } else { // i have some non-terminal children
+            var sorted = new HashNode<T>[size];
+            var indices = nodes.IterateChildren(i);
+            Array.Sort(indices, (a, b) => nodes[a].CompareTo(nodes[b]));
+
+            int idx = 0;
+            foreach (var j in indices) {
+              var child = nodes[j];
+              if (!child.IsChild) { // must copy complete subtree
+                Array.Copy(nodes, j - child.Size, sorted, idx, child.Size);
+                idx += child.Size;
+              }
+              sorted[idx++] = nodes[j];
+            }
+            Array.Copy(sorted, 0, nodes, i - size, size);
+          }
+        }
+        node.CalculatedHashValue = nodes.ComputeHash(i);
+      }
+    }
+
+    /// <summary>
+    /// Get a function node's child indices from left to right
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="nodes"></param>
+    /// <param name="i"></param>
+    /// <returns>An array containing child indices</returns>
+    public static int[] IterateChildren<T>(this HashNode<T>[] nodes, int i) where T : class {
+      var node = nodes[i];
+      var arity = node.Arity;
+      var children = new int[arity];
+      var idx = i - 1;
+      for (int j = 0; j < arity; ++j) {
+        while (!nodes[idx].Enabled) { --idx; } // skip nodes possibly disabled by simplification
+        children[j] = idx;
+        idx -= 1 + nodes[idx].Size;
+      }
+      return children;
+    }
+
+    public static void UpdateNodeSizes<T>(this HashNode<T>[] nodes) where T : class {
+      for (int i = 0; i < nodes.Length; ++i) {
+        var node = nodes[i];
+        if (node.IsChild) {
+          node.Size = 0;
+          continue;
+        }
+        node.Size = node.Arity;
+        foreach (int j in nodes.IterateChildren(i)) {
+          node.Size += nodes[j].Size;
+        }
+      }
+    }
+
+    /// <summary>
+    /// Reduce nodes of the same type according to arithmetic rules
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="g">The given grammar (controls symbol arities)</param>
+    /// <param name="nodes">The node array</param>
+    /// <param name="i">Parent index</param>
+    /// <param name="j">Child index</param>
+    private static void Reduce<T>(this HashNode<T>[] nodes, int i, int j) where T : class {
+      var p = nodes[i]; // parent node
+      var c = nodes[j]; // child node
+
+      if (c.IsChild)
+        return;
+
+      foreach (int k in nodes.IterateChildren(j)) {
+        if (nodes[k].IsChild) continue;
+        nodes.Reduce(j, k);
+      }
+
+      // handle commutative symbols (add, mul) 
+      if (p.IsCommutative && p.HashValue == c.HashValue) {
+        c.Enabled = false;
+        p.Arity += c.Arity - 1;
+      }
+    }
+
+    public static HashNode<T>[] Reduce<T>(this HashNode<T>[] nodes) where T : class {
+      nodes.UpdateNodeSizes();
+      int i = nodes.Length - 1;
+      foreach (int c in nodes.IterateChildren(i)) {
+        if (nodes[c].IsChild) continue;
+        nodes.Reduce(i, c);
+      }
+      int count = 0;
+      foreach (var node in nodes) {
+        if (!node.Enabled) { ++count; }
+      }
+      if (count == 0)
+        return nodes;
+
+      var reduced = new HashNode<T>[nodes.Length - count];
+      i = 0;
+      foreach (var node in nodes) {
+        if (node.Enabled) { reduced[i++] = node; }
+      }
+      reduced.UpdateNodeSizes();
+      return reduced;
+    }
+  }
+}
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/HashUtil.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/HashUtil.cs	(revision 16235)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/HashUtil.cs	(revision 16235)
@@ -0,0 +1,100 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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/>.
+ */
+#endregion
+
+using System;
+using System.Security.Cryptography;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  public static class HashUtil {
+    // This class contains some hash functions adapted from http://partow.net/programming/hashfunctions/index.html#AvailableHashFunctions
+
+    // A simple hash function from Robert Sedgwicks Algorithms in C book.I've added some simple optimizations to the algorithm in order to speed up its hashing process. 
+    public static int RSHash(int[] input) {
+      const int b = 378551;
+      int a = 63689;
+      int hash = 0;
+
+      foreach (var v in input) {
+        hash = (hash * a) + v;
+        a *= b;
+      }
+      return hash;
+    }
+
+    // A bitwise hash function written by Justin Sobel
+    public static int JSHash(int[] input) {
+      int hash = 1315423911;
+      for (int i = 0; i < input.Length; ++i)
+        hash ^= (hash << 5) + input[i] + (hash >> 2);
+      return hash;
+    }
+
+    // This hash function comes from Brian Kernighan and Dennis Ritchie's book "The C Programming Language". It is a simple hash function using a strange set of possible seeds which all constitute a pattern of 31....31...31 etc, it seems to be very similar to the DJB hash function. 
+    public static int BKDRHash(int[] input) {
+      const int seed = 131;
+      int hash = 0;
+      foreach (var v in input) {
+        hash = (hash * seed) + v;
+      }
+      return hash;
+    }
+
+    // This is the algorithm of choice which is used in the open source SDBM project. The hash function seems to have a good over-all distribution for many different data sets. It seems to work well in situations where there is a high variance in the MSBs of the elements in a data set. 
+    public static int SDBMHash(int[] input) {
+      int hash = 0;
+      foreach (var v in input) {
+        hash = v + (hash << 6) + (hash << 16) - hash;
+      }
+      return hash;
+    }
+
+    // An algorithm produced by Professor Daniel J. Bernstein and shown first to the world on the usenet newsgroup comp.lang.c. It is one of the most efficient hash functions ever published. 
+    public static int DJBHash(int[] input) {
+      int hash = 5381;
+      foreach (var v in input) {
+        hash = (hash << 5) + hash + v;
+      }
+      return hash;
+    }
+
+    // An algorithm proposed by Donald E.Knuth in The Art Of Computer Programming Volume 3, under the topic of sorting and search chapter 6.4. 
+    public static int DEKHash(int[] input) {
+      int hash = input.Length;
+      foreach (var v in input) {
+        hash = (hash << 5) ^ (hash >> 27) ^ v;
+      }
+      return hash;
+    }
+
+    public static int CryptoHash(HashAlgorithm ha, int[] input) {
+      return BitConverter.ToInt32(ha.ComputeHash(input.ToByteArray()), 0);
+    }
+
+    public static byte[] ToByteArray(this int[] input) {
+      const int size = sizeof(int);
+      var bytes = new byte[input.Length * sizeof(int)];
+      for (int i = 0; i < input.Length; ++i) {
+        Array.Copy(BitConverter.GetBytes(bytes[i]), 0, bytes, i * size, size);
+      }
+      return bytes;
+    }
+  }
+}
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/SymbolicExpressionTreeHash.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/SymbolicExpressionTreeHash.cs	(revision 16235)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/SymbolicExpressionTreeHash.cs	(revision 16235)
@@ -0,0 +1,270 @@
+﻿using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using static HeuristicLab.Problems.DataAnalysis.Symbolic.SymbolicExpressionHashExtensions;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  public static class SymbolicExpressionTreeHash {
+    private static readonly Addition add = new Addition();
+    private static readonly Subtraction sub = new Subtraction();
+    private static readonly Multiplication mul = new Multiplication();
+    private static readonly Division div = new Division();
+    private static readonly Logarithm log = new Logarithm();
+    private static readonly Exponential exp = new Exponential();
+    private static readonly Sine sin = new Sine();
+    private static readonly Cosine cos = new Cosine();
+    private static readonly Constant constant = new Constant();
+
+    private static readonly ISymbolicExpressionTreeNodeComparer comparer = new SymbolicExpressionTreeNodeComparer();
+
+    public static int ComputeHash(this ISymbolicExpressionTree tree) {
+      return ComputeHash(tree.Root.GetSubtree(0).GetSubtree(0));
+    }
+
+    public static Dictionary<ISymbolicExpressionTreeNode, int> ComputeNodeHashes(this ISymbolicExpressionTree tree) {
+      var root = tree.Root.GetSubtree(0).GetSubtree(0);
+      var nodes = root.MakeNodes();
+      nodes.UpdateNodeSizes();
+
+      for (int i = 0; i < nodes.Length; ++i) {
+        if (nodes[i].IsChild)
+          continue;
+        nodes[i].CalculatedHashValue = nodes.ComputeHash(i);
+      }
+      return nodes.ToDictionary(x => x.Data, x => x.CalculatedHashValue);
+    }
+
+    public static int ComputeHash(this ISymbolicExpressionTreeNode treeNode) {
+      var hashNodes = treeNode.MakeNodes();
+      var simplified = hashNodes.Simplify();
+      return ComputeHash(simplified);
+    }
+
+    public static int ComputeHash(this HashNode<ISymbolicExpressionTreeNode>[] nodes) {
+      int hash = 1315423911;
+      foreach (var node in nodes)
+        hash ^= (hash << 5) + node.CalculatedHashValue + (hash >> 2);
+      return hash;
+    }
+
+    public static HashNode<ISymbolicExpressionTreeNode> ToHashNode(this ISymbolicExpressionTreeNode node) {
+      var symbol = node.Symbol;
+      var name = symbol.Name;
+      if (symbol is Variable) {
+        var variableTreeNode = (VariableTreeNode)node;
+        name = variableTreeNode.VariableName;
+      }
+      var hash = name.GetHashCode();
+      var hashNode = new HashNode<ISymbolicExpressionTreeNode>(comparer) {
+        Data = node,
+        Arity = node.SubtreeCount,
+        Size = node.SubtreeCount,
+        IsCommutative = node.Symbol is Addition || node.Symbol is Multiplication,
+        Enabled = true,
+        HashValue = hash,
+        CalculatedHashValue = hash
+      };
+      if (symbol is Addition) {
+        hashNode.Simplify = SimplifyAddition;
+      } else if (symbol is Multiplication) {
+        hashNode.Simplify = SimplifyMultiplication;
+      } else if (symbol is Division) {
+        hashNode.Simplify = SimplifyDivision;
+      } else if (symbol is Logarithm || symbol is Exponential || symbol is Sine || symbol is Cosine) {
+        hashNode.Simplify = SimplifyUnaryNode;
+      } else if (symbol is Subtraction) {
+        hashNode.Simplify = SimplifyBinaryNode;
+      }
+      return hashNode;
+    }
+
+    public static HashNode<ISymbolicExpressionTreeNode>[] MakeNodes(this ISymbolicExpressionTreeNode node) {
+      return node.IterateNodesPostfix().Select(ToHashNode).ToArray();
+    }
+
+    #region parse a nodes array back into a tree
+    public static ISymbolicExpressionTree ToTree(this HashNode<ISymbolicExpressionTreeNode>[] nodes) {
+      var root = new ProgramRootSymbol().CreateTreeNode();
+      var start = new StartSymbol().CreateTreeNode();
+      root.AddSubtree(start);
+      start.AddSubtree(nodes.ToSubtree());
+      return new SymbolicExpressionTree(root);
+    }
+
+    public static ISymbolicExpressionTreeNode ToSubtree(this HashNode<ISymbolicExpressionTreeNode>[] nodes) {
+      var treeNodes = nodes.Select(x => x.Data.Symbol.CreateTreeNode()).ToArray();
+
+      for (int i = nodes.Length - 1; i >= 0; --i) {
+        var node = nodes[i];
+
+        if (node.IsChild) {
+          if (node.Data is VariableTreeNode variable) {
+            var variableTreeNode = (VariableTreeNode)treeNodes[i];
+            variableTreeNode.VariableName = variable.VariableName;
+            variableTreeNode.Weight = 1;
+          } else if (node.Data is ConstantTreeNode @const) {
+            var constantTreeNode = (ConstantTreeNode)treeNodes[i];
+            constantTreeNode.Value = @const.Value;
+          }
+          continue;
+        }
+
+        var treeNode = treeNodes[i];
+
+        foreach (var j in nodes.IterateChildren(i)) {
+          treeNode.AddSubtree(treeNodes[j]);
+        }
+      }
+
+      return treeNodes.Last();
+    }
+
+    private static T CreateTreeNode<T>(this ISymbol symbol) where T : class, ISymbolicExpressionTreeNode {
+      return (T)symbol.CreateTreeNode();
+    }
+    #endregion
+
+    #region tree simplification
+    // these simplification methods rely on the assumption that child nodes of the current node have already been simplified
+    // (in other words simplification should be applied in a bottom-up fashion) 
+    public static ISymbolicExpressionTree Simplify(ISymbolicExpressionTree tree) {
+      var root = tree.Root.GetSubtree(0).GetSubtree(0);
+      var nodes = root.MakeNodes();
+      var simplified = nodes.Simplify();
+      return simplified.ToTree();
+    }
+
+    public static void SimplifyAddition(HashNode<ISymbolicExpressionTreeNode>[] nodes, int i) {
+      // simplify additions of terms by eliminating terms with the same symbol and hash
+      var children = nodes.IterateChildren(i);
+
+      var curr = children[0];
+      var node = nodes[i];
+
+      foreach (var j in children.Skip(1)) {
+        if (nodes[j] == nodes[curr]) {
+          for (int k = j - nodes[j].Size; k <= j; ++k) {
+            nodes[k].Enabled = false;
+          }
+          node.Arity--;
+        } else {
+          curr = j;
+        }
+      }
+      if (node.Arity == 1) { // if the arity is 1 we don't need the addition node at all
+        node.Enabled = false;
+      }
+    }
+
+    // simplify multiplications by reducing constants and div terms  
+    public static void SimplifyMultiplication(HashNode<ISymbolicExpressionTreeNode>[] nodes, int i) {
+      var node = nodes[i];
+      var children = nodes.IterateChildren(i);
+
+      for (int j = 0; j < children.Length; ++j) {
+        var c = children[j];
+        var child = nodes[c];
+
+        if (!child.Enabled)
+          continue;
+
+        var symbol = child.Data.Symbol;
+        if (symbol is Constant) {
+          for (int k = j + 1; k < children.Length; ++k) {
+            var d = children[k];
+            if (nodes[d].Data.Symbol is Constant) {
+              ((ConstantTreeNode)child.Data).Value *= ((ConstantTreeNode)nodes[d].Data).Value;
+              nodes[d].Enabled = false;
+              node.Arity--;
+            } else {
+              break;
+            }
+          }
+        } else if (symbol is Division) {
+          var div = nodes[c];
+          var denominator =
+            div.Arity == 1 ?
+            nodes[c - 1] :                    // 1 / x is expressed as div(x) (with a single child)
+            nodes[c - nodes[c - 1].Size - 2]; // assume division always has arity 1 or 2
+
+          foreach (var d in children) {
+            if (nodes[d].Enabled && nodes[d] == denominator) {
+              nodes[c].Enabled = nodes[d].Enabled = denominator.Enabled = false;
+              node.Arity -= 2; // matching child + division node
+              break;
+            }
+          }
+        }
+
+        if (node.Arity == 0) { // if everything is simplified this node becomes constant
+          var constantTreeNode = constant.CreateTreeNode<ConstantTreeNode>();
+          constantTreeNode.Value = 1;
+          nodes[i] = constantTreeNode.ToHashNode();
+        } else if (node.Arity == 1) { // when i have only 1 arg left i can skip this node
+          node.Enabled = false;
+        }
+      }
+    }
+
+    public static void SimplifyDivision(HashNode<ISymbolicExpressionTreeNode>[] nodes, int i) {
+      var node = nodes[i];
+      var children = nodes.IterateChildren(i);
+
+      if (children.All(x => nodes[x].Data.Symbol is Constant)) {
+        var v = ((ConstantTreeNode)nodes[children.First()].Data).Value;
+        if (node.Arity == 1) {
+          v = 1 / v;
+        } else if (node.Arity > 1) {
+          foreach (var j in children.Skip(1)) {
+            v /= ((ConstantTreeNode)nodes[j].Data).Value;
+          }
+        }
+        var constantTreeNode = constant.CreateTreeNode<ConstantTreeNode>();
+        constantTreeNode.Value = v;
+        nodes[i] = constantTreeNode.ToHashNode();
+        return;
+      }
+
+      var nominator = nodes[children[0]];
+      foreach (var j in children.Skip(1)) {
+        var denominator = nodes[j];
+        if (nominator == denominator) {
+          // disable all the children of the division node (nominator and children + denominator and children)
+          nominator.Enabled = denominator.Enabled = false;
+          node.Arity -= 2; // nominator + denominator
+        }
+        if (node.Arity == 0) {
+          var constantTreeNode = constant.CreateTreeNode<ConstantTreeNode>();
+          constantTreeNode.Value = 1; // x / x = 1
+          nodes[i] = constantTreeNode.ToHashNode();
+        }
+      }
+    }
+
+    public static void SimplifyUnaryNode(HashNode<ISymbolicExpressionTreeNode>[] nodes, int i) {
+      // check if the child of the unary node is a constant, then the whole node can be simplified
+      var parent = nodes[i];
+      var child = nodes[i - 1];
+
+      var parentSymbol = parent.Data.Symbol;
+      var childSymbol = child.Data.Symbol;
+
+      if (childSymbol is Constant) {
+        nodes[i].Enabled = false;
+      } else if ((parentSymbol is Exponential && childSymbol is Logarithm) || (parentSymbol is Logarithm && childSymbol is Exponential)) {
+        child.Enabled = parent.Enabled = false;
+      }
+    }
+
+    public static void SimplifyBinaryNode(HashNode<ISymbolicExpressionTreeNode>[] nodes, int i) {
+      var children = nodes.IterateChildren(i);
+      if (children.All(x => nodes[x].Data.Symbol is Constant)) {
+        foreach (var j in children) {
+          nodes[j].Enabled = false;
+        }
+        nodes[i] = constant.CreateTreeNode().ToHashNode();
+      }
+    }
+    #endregion
+  }
+}
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj	(revision 16235)
@@ -139,4 +139,5 @@
     <Compile Include="Converters\LinearModelToTreeConverter.cs" />
     <Compile Include="Converters\TreeSimplifier.cs" />
+    <Compile Include="Converters\DerivativeCalculator.cs" />
     <Compile Include="Converters\TreeToAutoDiffTermConverter.cs" />
     <Compile Include="Formatters\InfixExpressionFormatter.cs" />
@@ -144,4 +145,7 @@
     <Compile Include="Formatters\SymbolicDataAnalysisExpressionMathematicaFormatter.cs" />
     <Compile Include="Formatters\SymbolicDataAnalysisExpressionCSharpFormatter.cs" />
+    <Compile Include="Hashing\HashExtensions.cs" />
+    <Compile Include="Hashing\HashUtil.cs" />
+    <Compile Include="Hashing\SymbolicExpressionTreeHash.cs" />
     <Compile Include="Importer\InfixExpressionParser.cs" />
     <Compile Include="Importer\SymbolicExpressionImporter.cs" />
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.DataAnalysis.Views/3.4/Classification/ClassificationSolutionVariableImpactsView.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.DataAnalysis.Views/3.4/Classification/ClassificationSolutionVariableImpactsView.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.DataAnalysis.Views/3.4/Classification/ClassificationSolutionVariableImpactsView.cs	(revision 16235)
@@ -60,5 +60,4 @@
       InitializeComponent();
 
-      //Little workaround. If you fill the ComboBox-Items in the other partial class, the UI-Designer will moan.
       this.sortByComboBox.Items.AddRange(Enum.GetValues(typeof(SortingCriteria)).Cast<object>().ToArray());
       this.sortByComboBox.SelectedItem = SortingCriteria.ImpactValue;
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/CF1.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/CF1.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/CF1.cs	(revision 16235)
@@ -22,6 +22,6 @@
 namespace HeuristicLab.Problems.Instances.DataAnalysis {
   public class CF1 : ResourceRegressionDataDescriptor {
-    public CF1(string resourceName) : base(resourceName) { }
-    public override string Name { get { return "CF1"; } }
+    public CF1() : base("CF1.csv") { }
+    public override string Name { get { return "CF1"; } }    
     public override string Description {
       get {
@@ -34,13 +34,17 @@
     protected override string TargetVariable { get { return "Cf1"; } }
     protected override string[] VariableNames {
-      get { return new string[] { "Partition", "Source1", "Source2", "x1", "Material_Cat", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "Material", "Grooving", "Oil", "x17", "x18", "x19", "x20", "x21", "x22", "Cf1"
- }; }
+      get {
+        return new string[] { "Partition", "Source1", "Source2", "x1", "Material_Cat", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "Material", "Grooving", "Oil", "x17", "x18", "x19", "x20", "x21", "x22", "Cf1"
+ };
+      }
     }
 
     protected override string[] AllowedInputVariables {
-      get { return new string[] { "Material_Cat",
+      get {
+        return new string[] { "Material_Cat",
         "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16",
         "Material", "Grooving", "Oil",
-        "x17", "x20", "x22" }; }
+        "x17", "x20", "x22" };
+      }
     }
     protected override int TrainingPartitionStart { get { return 0; } }
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/CF2.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/CF2.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/CF2.cs	(revision 16235)
@@ -22,5 +22,5 @@
 namespace HeuristicLab.Problems.Instances.DataAnalysis {
   public class CF2 : ResourceRegressionDataDescriptor {
-    public CF2(string resourceName) : base(resourceName) { }
+    public CF2() : base("CF2.csv") { }
     public override string Name { get { return "CF2"; } }
     public override string Description {
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/CF3.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/CF3.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/CF3.cs	(revision 16235)
@@ -22,5 +22,5 @@
 namespace HeuristicLab.Problems.Instances.DataAnalysis {
   public class CF3 : ResourceRegressionDataDescriptor {
-    public CF3(string resourceName) : base(resourceName) { }
+    public CF3() : base("CF3.csv") { }
     public override string Name { get { return "CF3"; } }
     public override string Description {
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/CF4.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/CF4.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/CF4.cs	(revision 16235)
@@ -22,5 +22,5 @@
 namespace HeuristicLab.Problems.Instances.DataAnalysis {
   public class CF4 : ResourceRegressionDataDescriptor {
-    public CF4(string resourceName) : base(resourceName) { }
+    public CF4() : base("CF4.csv") { }
     public override string Name { get { return "CF4"; } }
     public override string Description {
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/MibaFrictionRegressionInstanceProvider.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/MibaFrictionRegressionInstanceProvider.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/MibaFrictionRegressionInstanceProvider.cs	(revision 16235)
@@ -47,13 +47,13 @@
     public override IEnumerable<IDataDescriptor> GetDataDescriptors() {
       List<ResourceRegressionDataDescriptor> descriptorList = new List<ResourceRegressionDataDescriptor>();
-      descriptorList.Add(new CF1("CF1.csv"));
-      descriptorList.Add(new CF2("CF2.csv"));
-      descriptorList.Add(new CF3("CF3.csv"));
-      descriptorList.Add(new CF4("CF4.csv"));
-      descriptorList.Add(new NvhRating("NvhRating.csv"));
-      descriptorList.Add(new Temp1("Temp1.csv"));
-      descriptorList.Add(new Temp2("Temp2.csv"));
-      descriptorList.Add(new Wear1("Wear1.csv"));
-      descriptorList.Add(new Wear2("Wear2.csv"));
+      descriptorList.Add(new CF1());
+      descriptorList.Add(new CF2());
+      descriptorList.Add(new CF3());
+      descriptorList.Add(new CF4());
+      descriptorList.Add(new NvhRating());
+      descriptorList.Add(new Temp1());
+      descriptorList.Add(new Temp2());
+      descriptorList.Add(new Wear1());
+      descriptorList.Add(new Wear2());
 
       return descriptorList;
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/NvhRating.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/NvhRating.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/NvhRating.cs	(revision 16235)
@@ -22,5 +22,5 @@
 namespace HeuristicLab.Problems.Instances.DataAnalysis {
   public class NvhRating : ResourceRegressionDataDescriptor {
-    public NvhRating(string resourceName) : base(resourceName) { }
+    public NvhRating() : base("NvhRating.csv") { }
     public override string Name { get { return "NvhRating"; } }
     public override string Description {
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/Temp1.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/Temp1.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/Temp1.cs	(revision 16235)
@@ -22,5 +22,5 @@
 namespace HeuristicLab.Problems.Instances.DataAnalysis {
   public class Temp1 : ResourceRegressionDataDescriptor {
-    public Temp1(string resourceName) : base(resourceName) { }
+    public Temp1() : base("Temp1.csv") { }
     public override string Name { get { return "Temp1"; } }
     public override string Description {
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/Temp2.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/Temp2.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/Temp2.cs	(revision 16235)
@@ -22,5 +22,5 @@
 namespace HeuristicLab.Problems.Instances.DataAnalysis {
   public class Temp2 : ResourceRegressionDataDescriptor {
-    public Temp2(string resourceName) : base(resourceName) { }
+    public Temp2() : base("Temp2.csv") { }
     public override string Name { get { return "Temp2"; } }
     public override string Description {
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/Wear1.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/Wear1.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/Wear1.cs	(revision 16235)
@@ -22,5 +22,5 @@
 namespace HeuristicLab.Problems.Instances.DataAnalysis {
   public class Wear1 : ResourceRegressionDataDescriptor {
-    public Wear1(string resourceName) : base(resourceName) { }
+    public Wear1() : base("Wear1.csv") { }
     public override string Name { get { return "Wear1"; } }
     public override string Description {
@@ -33,4 +33,5 @@
     }
     protected override string TargetVariable { get { return "Wear1"; } }
+
     protected override string[] VariableNames {
       get { return new string[] { "Partition", "Source1", "Source2", "x1", "Material_Cat", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "Material", "Grooving", "Oil", "x17", "x18", "x19", "x20", "x21", "x22", "Wear1"
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/Wear2.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/Wear2.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/MibaFriction/Wear2.cs	(revision 16235)
@@ -22,5 +22,5 @@
 namespace HeuristicLab.Problems.Instances.DataAnalysis {
   public class Wear2 : ResourceRegressionDataDescriptor {
-    public Wear2(string resourceName) : base(resourceName) { }
+    public Wear2() : base("Wear2.csv") { }
     public override string Name { get { return "Wear2"; } }
     public override string Description {
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/RealWorld/ChemicalOne.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/RealWorld/ChemicalOne.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/RealWorld/ChemicalOne.cs	(revision 16235)
@@ -22,5 +22,5 @@
 namespace HeuristicLab.Problems.Instances.DataAnalysis {
   public class ChemicalOne : ResourceRegressionDataDescriptor {
-    public ChemicalOne(string resourceName) : base(resourceName) { }
+    public ChemicalOne() : base("Chemical-I.csv") { }
     public override string Name { get { return "Chemical-I"; } }
     public override string Description { get { return ""; } }
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/RealWorld/Housing.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/RealWorld/Housing.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/RealWorld/Housing.cs	(revision 16235)
@@ -22,5 +22,5 @@
 namespace HeuristicLab.Problems.Instances.DataAnalysis {
   public class Housing : ResourceRegressionDataDescriptor {
-    public Housing(string resourceName) : base(resourceName) { }
+    public Housing() : base("Housing.csv") { }
     public override string Name { get { return "Housing"; } }
     public override string Description { get { return ""; } }
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/RealWorld/Powermeter.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/RealWorld/Powermeter.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/RealWorld/Powermeter.cs	(revision 16235)
@@ -24,5 +24,5 @@
 namespace HeuristicLab.Problems.Instances.DataAnalysis {
   public class Powermeter : ResourceRegressionDataDescriptor {
-    public Powermeter(string resourceName) : base(resourceName) { }
+    public Powermeter() : base("Powermeter.txt") { }
     public override string Name { get { return "Powermeter"; } }
     public override string Description {
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/RealWorld/RealWorldRegressionInstanceProvider.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/RealWorld/RealWorldRegressionInstanceProvider.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/RealWorld/RealWorldRegressionInstanceProvider.cs	(revision 16235)
@@ -47,9 +47,9 @@
     public override IEnumerable<IDataDescriptor> GetDataDescriptors() {
       List<ResourceRegressionDataDescriptor> descriptorList = new List<ResourceRegressionDataDescriptor>();
-      descriptorList.Add(new ChemicalOne("Chemical-I.csv"));
-      descriptorList.Add(new Housing("Housing.csv"));
-      descriptorList.Add(new Tower("Tower.txt"));
-      descriptorList.Add(new Powermeter("Powermeter.txt"));
-      descriptorList.Add(new SARCOS("SARCOS - Inverse Dynamics.txt"));
+      descriptorList.Add(new ChemicalOne());
+      descriptorList.Add(new Housing());
+      descriptorList.Add(new Tower());
+      descriptorList.Add(new Powermeter());
+      descriptorList.Add(new SARCOS());
       return descriptorList;
     }
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/RealWorld/SARCOS.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/RealWorld/SARCOS.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/RealWorld/SARCOS.cs	(revision 16235)
@@ -24,5 +24,5 @@
 namespace HeuristicLab.Problems.Instances.DataAnalysis {
   public class SARCOS : ResourceRegressionDataDescriptor {
-    public SARCOS(string resourceName) : base(resourceName) { }
+    public SARCOS() : base("SARCOS - Inverse Dynamics.txt") { }
     public override string Name { get { return "SARCOS - Inverse Dynamics"; } }
     public override string Description {
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/RealWorld/Tower.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/RealWorld/Tower.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Problems.Instances.DataAnalysis/3.3/Regression/RealWorld/Tower.cs	(revision 16235)
@@ -24,5 +24,5 @@
 namespace HeuristicLab.Problems.Instances.DataAnalysis {
   public class Tower : ResourceRegressionDataDescriptor {
-    public Tower(string resourceName) : base(resourceName) { }
+    public Tower() : base("Tower.txt") { }
     public override string Name { get { return "Tower"; } }
     public override string Description {
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Services.Hive/3.3/HiveService.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Services.Hive/3.3/HiveService.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Services.Hive/3.3/HiveService.cs	(revision 16235)
@@ -355,7 +355,13 @@
         return pm.UseTransaction(() => {
           // check if user is granted to administer the requested projectId
-          var administrationGrantedProjects = projectDao
-            .GetAdministrationGrantedProjectsForUser(currentUserId)
-            .ToList();
+          bool isAdmin = RoleVerifier.IsInRole(HiveRoles.Administrator);
+          List<DA.Project> administrationGrantedProjects;
+          if (isAdmin) {
+            administrationGrantedProjects = projectDao.GetAll().ToList();
+          } else {
+            administrationGrantedProjects = projectDao
+              .GetAdministrationGrantedProjectsForUser(currentUserId)              
+              .ToList();
+          }
 
           if (administrationGrantedProjects.Select(x => x.ProjectId).Contains(projectId)) {
@@ -382,8 +388,14 @@
         return pm.UseTransaction(() => {
           // check for which of requested projectIds the user is granted to administer
-          var administrationGrantedProjectIds = projectDao
-            .GetAdministrationGrantedProjectsForUser(currentUserId)
-            .Select(x => x.ProjectId)
-            .ToList();
+          bool isAdmin = RoleVerifier.IsInRole(HiveRoles.Administrator);
+          List<Guid> administrationGrantedProjectIds;
+          if (isAdmin) {
+            administrationGrantedProjectIds = projectDao.GetAll().Select(x => x.ProjectId).ToList();
+          } else {
+            administrationGrantedProjectIds = projectDao
+              .GetAdministrationGrantedProjectsForUser(currentUserId)
+              .Select(x => x.ProjectId)
+              .ToList();
+          }
           var requestedAndGrantedProjectIds = projectIds.Intersect(administrationGrantedProjectIds);
 
@@ -470,5 +482,4 @@
             throw new InvalidOperationException(NO_JOB_UPDATE_POSSIBLE);
           }
-
 
           jobDto.CopyToEntity(job);
@@ -508,15 +519,19 @@
 
     public void UpdateJobState(Guid jobId, DT.JobState jobState) {
-      RoleVerifier.AuthenticateForAnyRole(HiveRoles.Administrator, HiveRoles.Client);
+      if (jobState != JobState.StatisticsPending) return; // only process requests for "StatisticsPending"
+
+      RoleVerifier.AuthenticateForAnyRole(HiveRoles.Administrator, HiveRoles.Client);
+      // check if user is an admin, or granted to administer a job-parenting project, or job owner
       AuthorizationManager.AuthorizeForJob(jobId, DT.Permission.Full);
+
       var pm = PersistenceManager;
       using (new PerformanceLogger("UpdateJobState")) {
-        var jobDao = pm.JobDao;
+        var jobDao = pm.JobDao;        
         pm.UseTransaction(() => {
           var job = jobDao.GetById(jobId);
-          if (job != null) {
+          if (job != null) {            
+
+            // note: allow solely state changes from "Online" to "StatisticsPending" = deletion request by user for HiveStatisticGenerator            
             var jobStateEntity = jobState.ToEntity();
-            // note: allow solely state changes from "Online" to "StatisticsPending" = deletion request by user for HiveStatisticGenerator
-            // and from "StatisticsPending" to "DeletionPending" = deletion request by HiveStatisticGenerator for EventManager
             if (job.State == DA.JobState.Online && jobStateEntity == DA.JobState.StatisticsPending) {
               job.State = jobStateEntity;
@@ -528,7 +543,4 @@
               }
               pm.SubmitChanges();
-            } else if (job.State == DA.JobState.StatisticsPending && jobStateEntity == DA.JobState.DeletionPending) {
-              job.State = jobStateEntity;
-              pm.SubmitChanges();
             }
           }
@@ -541,6 +553,7 @@
 
       RoleVerifier.AuthenticateForAnyRole(HiveRoles.Administrator, HiveRoles.Client);
-      bool isAdministrator = RoleVerifier.IsInRole(HiveRoles.Administrator);
-      var currentUserId = UserManager.CurrentUserId;
+      // check if user is an admin, or granted to administer a job-parenting project, or job owner
+      foreach (var jobId in jobIds)
+          AuthorizationManager.AuthorizeForJob(jobId, DT.Permission.Full);
 
       var pm = PersistenceManager;
@@ -553,22 +566,16 @@
             if (job != null) {
 
-              var administrationGrantedProjects = projectDao
-                .GetAdministrationGrantedProjectsForUser(currentUserId)
-                .ToList();
-
-              // check if user is granted to administer the job-parenting project
-              if (isAdministrator || administrationGrantedProjects.Contains(job.Project)) {
-                // note: allow solely state changes from "Online" to "StatisticsPending" = deletion request by user for HiveStatisticGenerator
-                if (job.State == DA.JobState.Online) {
-                  job.State = DA.JobState.StatisticsPending;
-                  foreach (var task in job.Tasks
-                  .Where(x => x.State == DA.TaskState.Waiting
-                    || x.State == DA.TaskState.Paused
-                    || x.State == DA.TaskState.Offline)) {
-                    task.State = DA.TaskState.Aborted;
-                  }
-                  pm.SubmitChanges();
+              // note: allow solely state changes from "Online" to "StatisticsPending" = deletion request by user for HiveStatisticGenerator
+              var jobStateEntity = jobState.ToEntity();
+              if (job.State == DA.JobState.Online && jobStateEntity == DA.JobState.StatisticsPending) {
+                job.State = jobStateEntity;
+                foreach (var task in job.Tasks
+                .Where(x => x.State == DA.TaskState.Waiting
+                  || x.State == DA.TaskState.Paused
+                  || x.State == DA.TaskState.Offline)) {
+                  task.State = DA.TaskState.Aborted;
                 }
-              }
+                pm.SubmitChanges();
+              }              
             }
           }
@@ -1242,5 +1249,5 @@
 
           var assignedResources = project.AssignedProjectResources.Select(x => x.ResourceId).ToArray();
-          if (!isParent) resourceIds = assignedResources.ToList();
+          if (!isParent && !isAdmin) resourceIds = assignedResources.ToList();
           var removedAssignments = assignedResources.Except(resourceIds);
 
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Services.Hive/3.3/Manager/AuthorizationManager.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Services.Hive/3.3/Manager/AuthorizationManager.cs	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Services.Hive/3.3/Manager/AuthorizationManager.cs	(revision 16235)
@@ -38,4 +38,5 @@
     private const string NOT_AUTHORIZED_PROJECTRESOURCE = "Selected project is not authorized to access the requested resource";
     private const string USER_NOT_IDENTIFIED = "User could not be identified";
+    private const string JOB_NOT_EXISTENT = "Queried job could not be found";
     private const string TASK_NOT_EXISTENT = "Queried task could not be found";
     private const string PROJECT_NOT_EXISTENT = "Queried project could not be found";
@@ -60,9 +61,19 @@
     public void AuthorizeForTask(Guid taskId, DT.Permission requiredPermission) {
       if (ServiceLocator.Instance.RoleVerifier.IsInRole(HiveRoles.Slave)) return; // slave-users can access all tasks
+      if (ServiceLocator.Instance.RoleVerifier.IsInRole(HiveRoles.Administrator)) return; // administrator can access all tasks
+      var currentUserId = UserManager.CurrentUserId;
       var pm = PersistenceManager;
       var taskDao = pm.TaskDao;
+      var projectDao = pm.ProjectDao;
       pm.UseTransaction(() => {
         var task = taskDao.GetById(taskId);
         if (task == null) throw new SecurityException(TASK_NOT_EXISTENT);
+
+        // check if user is granted to administer a job-parenting project
+        var administrationGrantedProjects = projectDao
+          .GetAdministrationGrantedProjectsForUser(currentUserId)
+          .ToList();
+        if (administrationGrantedProjects.Contains(task.Job.Project)) return;
+
         AuthorizeJob(pm, task.JobId, requiredPermission);
       });
@@ -70,6 +81,19 @@
 
     public void AuthorizeForJob(Guid jobId, DT.Permission requiredPermission) {
-      var pm = PersistenceManager;
-      pm.UseTransaction(() => {
+      if (ServiceLocator.Instance.RoleVerifier.IsInRole(HiveRoles.Administrator)) return; // administrator can access all jobs
+      var currentUserId = UserManager.CurrentUserId;
+      var pm = PersistenceManager;
+      var jobDao = pm.JobDao;
+      var projectDao = pm.ProjectDao;
+      pm.UseTransaction(() => {
+        var job = jobDao.GetById(jobId);
+        if(job == null) throw new SecurityException(JOB_NOT_EXISTENT);
+
+        // check if user is granted to administer a job-parenting project
+        var administrationGrantedProjects = projectDao
+          .GetAdministrationGrantedProjectsForUser(currentUserId)
+          .ToList();
+        if (administrationGrantedProjects.Contains(job.Project)) return;
+
         AuthorizeJob(pm, jobId, requiredPermission);
       });
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4/DeriveTest.cs
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4/DeriveTest.cs	(revision 16235)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4/DeriveTest.cs	(revision 16235)
@@ -0,0 +1,88 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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/>.
+ */
+#endregion
+
+
+using System;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Tests {
+
+
+  [TestClass]
+  public class DerivativeTest {
+    [TestMethod]
+    [TestCategory("Problems.DataAnalysis.Symbolic")]
+    [TestProperty("Time", "short")]
+    public void DeriveExpressions() {
+      var formatter = new InfixExpressionFormatter();
+      var parser = new InfixExpressionParser();
+      Assert.AreEqual("0", Derive("3", "x"));
+      Assert.AreEqual("1", Derive("x", "x"));
+      Assert.AreEqual("10", Derive("10*x", "x"));
+      Assert.AreEqual("10", Derive("x*10", "x"));
+      Assert.AreEqual("(2*'x')", Derive("x*x", "x"));
+      Assert.AreEqual("((('x' * 'x') * 2) + ('x' * 'x'))", Derive("x*x*x", "x")); // simplifier does not merge (x*x)*2 + x*x  to 3*x*x
+      Assert.AreEqual("0", Derive("10*x", "y"));
+      Assert.AreEqual("20", Derive("10*x+20*y", "y"));
+      Assert.AreEqual("6", Derive("2*3*x", "x"));
+      Assert.AreEqual("(10*'y')", Derive("10*x*y+20*y", "x"));
+      Assert.AreEqual("(1 / (SQR('x') * (-1)))",  Derive("1/x", "x"));
+      Assert.AreEqual("('y' / (SQR('x') * (-1)))", Derive("y/x", "x"));
+      Assert.AreEqual("((((-2*'x') + (-1)) * ('a' + 'b')) / SQR(('x' + ('x' * 'x'))))",
+        Derive("(a+b)/(x+x*x)", "x"));
+      Assert.AreEqual("((((-2*'x') + (-1)) * ('a' + 'b')) / SQR(('x' + SQR('x'))))", Derive("(a+b)/(x+SQR(x))", "x"));
+      Assert.AreEqual("EXP('x')", Derive("exp(x)", "x"));
+      Assert.AreEqual("(EXP((3*'x')) * 3)", Derive("exp(3*x)", "x"));
+      Assert.AreEqual("(1 / 'x')", Derive("log(x)", "x"));
+      Assert.AreEqual("(1 / 'x')", Derive("log(3*x)", "x"));   // 3 * 1/(3*x)
+      Assert.AreEqual("(1 / ('x' + (0.333333333333333*'y')))", Derive("log(3*x+y)", "x"));  // simplifier does not try to keep fractions
+      Assert.AreEqual("(1 / (SQRT(((3*'x') + 'y')) * 0.666666666666667))", Derive("sqrt(3*x+y)", "x"));   // 3 / (2 * sqrt(3*x+y)) = 1 / ((2/3) * sqrt(3*x+y)) 
+      Assert.AreEqual("(COS((3*'x')) * 3)", Derive("sin(3*x)", "x"));
+      Assert.AreEqual("(SIN((3*'x')) * (-3))", Derive("cos(3*x)", "x"));
+
+
+      // special case: Inv(x) using only one argument to the division symbol
+      // f(x) = 1/x
+      var root = new ProgramRootSymbol().CreateTreeNode();
+      var start = new StartSymbol().CreateTreeNode();
+      var div = new Division().CreateTreeNode();
+      var varNode = (VariableTreeNode)(new Variable().CreateTreeNode());
+      varNode.Weight = 1.0;
+      varNode.VariableName = "x";
+      div.AddSubtree(varNode);
+      start.AddSubtree(div);
+      root.AddSubtree(start);
+      var t = new SymbolicExpressionTree(root);
+      Assert.AreEqual("(1 / (SQR('x') * (-1)))", 
+        formatter.Format(DerivativeCalculator.Derive(t, "x")));
+    }
+
+    private string Derive(string expr, string variable) {
+      var parser = new InfixExpressionParser();
+      var formatter = new InfixExpressionFormatter();
+
+      var t = parser.Parse(expr);
+      var tPrime = DerivativeCalculator.Derive(t, variable);
+
+      return formatter.Format(tPrime);
+    }
+  }
+}
Index: branches/2931_OR-Tools_LP_MIP/HeuristicLab.Tests/HeuristicLab.Tests.csproj
===================================================================
--- branches/2931_OR-Tools_LP_MIP/HeuristicLab.Tests/HeuristicLab.Tests.csproj	(revision 16234)
+++ branches/2931_OR-Tools_LP_MIP/HeuristicLab.Tests/HeuristicLab.Tests.csproj	(revision 16235)
@@ -587,4 +587,5 @@
     <Compile Include="HeuristicLab.Problems.DataAnalysis-3.4\StatisticCalculatorsTest.cs" />
     <Compile Include="HeuristicLab.Problems.DataAnalysis-3.4\VariableImpactCalculationTest.cs" />
+    <Compile Include="HeuristicLab.Problems.DataAnalysis.Symbolic-3.4\DeriveTest.cs" />
     <Compile Include="HeuristicLab.Problems.DataAnalysis.Symbolic-3.4\InfixExpressionParserTest.cs" />
     <Compile Include="HeuristicLab.Problems.DataAnalysis.Symbolic-3.4\SymbolicExpressionTreeBottomUpSimilarityCalculatorTest.cs" />
