Index: /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/ExtensionMethods/TreeNodeExtensions.cs
===================================================================
--- /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/ExtensionMethods/TreeNodeExtensions.cs	(revision 7910)
+++ /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/ExtensionMethods/TreeNodeExtensions.cs	(revision 7910)
@@ -0,0 +1,35 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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.Collections.Generic;
+using System.Windows.Forms;
+
+namespace HeuristicLab.Clients.Hive.JobManager.ExtensionMethods {
+  public static class TreeNodeExtensions {
+    public static IEnumerable<TreeNode> DescendantNodes(this TreeNode root) {
+      foreach (TreeNode node in root.Nodes) {
+        yield return node;
+        foreach (TreeNode child in node.DescendantNodes())
+          yield return child;
+      }
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/HeuristicLab.Clients.Hive.JobManager-3.3.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/HeuristicLab.Clients.Hive.JobManager-3.3.csproj	(revision 7909)
+++ /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/HeuristicLab.Clients.Hive.JobManager-3.3.csproj	(revision 7910)
@@ -96,4 +96,5 @@
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="ExtensionMethods\TreeNodeExtensions.cs" />
     <Compile Include="Plugin.cs" />
     <Compile Include="Views\HiveJobManagerView.cs">
@@ -115,4 +116,16 @@
     <Compile Include="Views\HiveJobPermissionView.Designer.cs">
       <DependentUpon>HiveJobPermissionView.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Views\HiveResourceSelector.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Views\HiveResourceSelector.Designer.cs">
+      <DependentUpon>HiveResourceSelector.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Views\HiveResourceSelectorDialog.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="Views\HiveResourceSelectorDialog.Designer.cs">
+      <DependentUpon>HiveResourceSelectorDialog.cs</DependentUpon>
     </Compile>
     <Compile Include="Views\RefreshableHiveJobListView.cs">
Index: /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/Views/HiveResourceSelector.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/Views/HiveResourceSelector.Designer.cs	(revision 7910)
+++ /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/Views/HiveResourceSelector.Designer.cs	(revision 7910)
@@ -0,0 +1,163 @@
+﻿namespace HeuristicLab.Clients.Hive.JobManager.Views {
+  partial class HiveResourceSelector {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Component Designer generated code
+
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      this.components = new System.ComponentModel.Container();
+      System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(HiveResourceSelector));
+      this.resourcesGroupBox = new System.Windows.Forms.GroupBox();
+      this.splitContainer = new System.Windows.Forms.SplitContainer();
+      this.resourcesTreeView = new System.Windows.Forms.TreeView();
+      this.imageList = new System.Windows.Forms.ImageList(this.components);
+      this.searchLabel = new System.Windows.Forms.Label();
+      this.searchTextBox = new System.Windows.Forms.TextBox();
+      this.descriptionTextBox = new System.Windows.Forms.TextBox();
+      this.toolTip = new System.Windows.Forms.ToolTip(this.components);
+      this.resourcesGroupBox.SuspendLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
+      this.splitContainer.Panel1.SuspendLayout();
+      this.splitContainer.Panel2.SuspendLayout();
+      this.splitContainer.SuspendLayout();
+      this.SuspendLayout();
+      // 
+      // resourcesGroupBox
+      // 
+      this.resourcesGroupBox.Controls.Add(this.splitContainer);
+      this.resourcesGroupBox.Dock = System.Windows.Forms.DockStyle.Fill;
+      this.resourcesGroupBox.Location = new System.Drawing.Point(0, 0);
+      this.resourcesGroupBox.Name = "resourcesGroupBox";
+      this.resourcesGroupBox.Size = new System.Drawing.Size(308, 365);
+      this.resourcesGroupBox.TabIndex = 0;
+      this.resourcesGroupBox.TabStop = false;
+      this.resourcesGroupBox.Text = "Available Resources";
+      // 
+      // splitContainer
+      // 
+      this.splitContainer.Dock = System.Windows.Forms.DockStyle.Fill;
+      this.splitContainer.Location = new System.Drawing.Point(3, 16);
+      this.splitContainer.Name = "splitContainer";
+      this.splitContainer.Orientation = System.Windows.Forms.Orientation.Horizontal;
+      // 
+      // splitContainer.Panel1
+      // 
+      this.splitContainer.Panel1.Controls.Add(this.resourcesTreeView);
+      this.splitContainer.Panel1.Controls.Add(this.searchLabel);
+      this.splitContainer.Panel1.Controls.Add(this.searchTextBox);
+      // 
+      // splitContainer.Panel2
+      // 
+      this.splitContainer.Panel2.Controls.Add(this.descriptionTextBox);
+      this.splitContainer.Size = new System.Drawing.Size(302, 346);
+      this.splitContainer.SplitterDistance = 219;
+      this.splitContainer.TabIndex = 0;
+      // 
+      // resourcesTreeView
+      // 
+      this.resourcesTreeView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+            | System.Windows.Forms.AnchorStyles.Left)
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.resourcesTreeView.CheckBoxes = true;
+      this.resourcesTreeView.HideSelection = false;
+      this.resourcesTreeView.ImageIndex = 0;
+      this.resourcesTreeView.ImageList = this.imageList;
+      this.resourcesTreeView.Location = new System.Drawing.Point(3, 29);
+      this.resourcesTreeView.Name = "resourcesTreeView";
+      this.resourcesTreeView.SelectedImageIndex = 0;
+      this.resourcesTreeView.ShowNodeToolTips = true;
+      this.resourcesTreeView.Size = new System.Drawing.Size(296, 196);
+      this.resourcesTreeView.TabIndex = 2;
+      this.resourcesTreeView.AfterCheck += new System.Windows.Forms.TreeViewEventHandler(this.resourcesTreeView_AfterCheck);
+      this.resourcesTreeView.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.resourcesTreeView_AfterSelect);
+      // 
+      // imageList
+      // 
+      this.imageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth8Bit;
+      this.imageList.ImageSize = new System.Drawing.Size(16, 16);
+      this.imageList.TransparentColor = System.Drawing.Color.Transparent;
+      // 
+      // searchLabel
+      // 
+      this.searchLabel.Image = HeuristicLab.Common.Resources.VSImageLibrary.Zoom;
+      this.searchLabel.Location = new System.Drawing.Point(3, 3);
+      this.searchLabel.Name = "searchLabel";
+      this.searchLabel.Size = new System.Drawing.Size(20, 20);
+      this.searchLabel.TabIndex = 0;
+      this.toolTip.SetToolTip(this.searchLabel, "Enter string to search for resources");
+      // 
+      // searchTextBox
+      // 
+      this.searchTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.searchTextBox.Location = new System.Drawing.Point(29, 3);
+      this.searchTextBox.Name = "searchTextBox";
+      this.searchTextBox.Size = new System.Drawing.Size(270, 20);
+      this.searchTextBox.TabIndex = 1;
+      this.toolTip.SetToolTip(this.searchTextBox, "Enter string to search for resources");
+      this.searchTextBox.TextChanged += new System.EventHandler(this.searchTextBox_TextChanged);
+      // 
+      // descriptionTextBox
+      // 
+      this.descriptionTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+            | System.Windows.Forms.AnchorStyles.Left)
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.descriptionTextBox.Font = new System.Drawing.Font("Courier New", 8.25F);
+      this.descriptionTextBox.Location = new System.Drawing.Point(3, 3);
+      this.descriptionTextBox.Multiline = true;
+      this.descriptionTextBox.Name = "descriptionTextBox";
+      this.descriptionTextBox.ReadOnly = true;
+      this.descriptionTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
+      this.descriptionTextBox.Size = new System.Drawing.Size(296, 108);
+      this.descriptionTextBox.TabIndex = 0;
+      this.descriptionTextBox.WordWrap = false;
+      // 
+      // HiveResourceSelector
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Controls.Add(this.resourcesGroupBox);
+      this.Name = "HiveResourceSelector";
+      this.Size = new System.Drawing.Size(308, 365);
+      this.resourcesGroupBox.ResumeLayout(false);
+      this.splitContainer.Panel1.ResumeLayout(false);
+      this.splitContainer.Panel1.PerformLayout();
+      this.splitContainer.Panel2.ResumeLayout(false);
+      this.splitContainer.Panel2.PerformLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).EndInit();
+      this.splitContainer.ResumeLayout(false);
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+    protected System.Windows.Forms.GroupBox resourcesGroupBox;
+    protected System.Windows.Forms.SplitContainer splitContainer;
+    protected System.Windows.Forms.Label searchLabel;
+    protected System.Windows.Forms.TextBox searchTextBox;
+    protected System.Windows.Forms.TreeView resourcesTreeView;
+    protected System.Windows.Forms.TextBox descriptionTextBox;
+    protected System.Windows.Forms.ImageList imageList;
+    protected System.Windows.Forms.ToolTip toolTip;
+
+  }
+}
Index: /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/Views/HiveResourceSelector.cs
===================================================================
--- /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/Views/HiveResourceSelector.cs	(revision 7910)
+++ /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/Views/HiveResourceSelector.cs	(revision 7910)
@@ -0,0 +1,334 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+using HeuristicLab.Clients.Hive.JobManager.ExtensionMethods;
+using HeuristicLab.Core;
+using HeuristicLab.Core.Views;
+using HeuristicLab.MainForm;
+using HeuristicLab.MainForm.WindowsForms;
+
+namespace HeuristicLab.Clients.Hive.JobManager.Views {
+  public partial class HiveResourceSelector : ItemView, IDisposable {
+    private const int slaveImageIndex = 0;
+    private const int slaveGroupImageIndex = 1;
+    private string currentSearchString;
+    private ISet<TreeNode> mainTreeNodes;
+    private ISet<TreeNode> filteredTreeNodes;
+    private ISet<TreeNode> nodeStore;
+
+    private ISet<Resource> selectedResources;
+    public ISet<Resource> SelectedResources {
+      get { return selectedResources; }
+      set { selectedResources = value; }
+    }
+
+    private ProgressView progressView;
+    public ProgressView ProgressView {
+      get { return progressView; }
+      set { progressView = value; }
+    }
+
+    public new IItemList<Resource> Content {
+      get { return (IItemList<Resource>)base.Content; }
+      set { base.Content = value; }
+    }
+
+    public HiveResourceSelector() {
+      InitializeComponent();
+      mainTreeNodes = new HashSet<TreeNode>();
+      filteredTreeNodes = new HashSet<TreeNode>();
+      nodeStore = new HashSet<TreeNode>();
+      selectedResources = new HashSet<Resource>();
+      imageList.Images.Add(HeuristicLab.Common.Resources.VSImageLibrary.MonitorLarge);
+      imageList.Images.Add(HeuristicLab.Common.Resources.VSImageLibrary.NetworkCenterLarge);
+    }
+
+    public void StartProgressView() {
+      if (InvokeRequired) {
+        Invoke(new Action(StartProgressView));
+      } else {
+        if (progressView == null) {
+          IProgress prog = new Progress();
+          prog.Status = "Downloading resources. Please be patient.";
+          progressView = new ProgressView(this, prog);
+        }
+      }
+    }
+
+    public void FinishProgressView() {
+      if (InvokeRequired) {
+        Invoke(new Action(FinishProgressView));
+      } else {
+        if (progressView != null) {
+          progressView.Finish();
+          progressView = null;
+          SetEnabledStateOfControls();
+        }
+      }
+    }
+
+    protected override void OnContentChanged() {
+      base.OnContentChanged();
+      selectedResources = new HashSet<Resource>(Content.Where(x => selectedResources.Any(y => x.Id == y.Id)));
+      UpdateMainTree();
+      ExtractStatistics();
+    }
+
+    #region MainTree Methods
+    private void UpdateMainTree() {
+      mainTreeNodes.Clear();
+
+      foreach (Resource g in Content) {
+        if (g.GetType() == typeof(SlaveGroup)) {
+          //root node
+          if (g.ParentResourceId == null) {
+            TreeNode tn = new TreeNode();
+            tn.ImageIndex = slaveGroupImageIndex;
+            tn.SelectedImageIndex = tn.ImageIndex;
+
+            tn.Tag = g;
+            tn.Text = g.Name;
+            tn.Checked = selectedResources.Any(x => x.Id == g.Id);
+
+            BuildMainTree(tn);
+            mainTreeNodes.Add(tn);
+          }
+        }
+      }
+      UpdateFilteredTree();
+    }
+
+    private void BuildMainTree(TreeNode tn) {
+      foreach (Resource r in Content.Where(s => s.ParentResourceId != null && s.ParentResourceId == ((Resource)tn.Tag).Id)) {
+        TreeNode stn = new TreeNode(r.Name);
+        if (r is Slave) stn.ImageIndex = slaveImageIndex;
+        else if (r is SlaveGroup) stn.ImageIndex = slaveGroupImageIndex;
+        stn.SelectedImageIndex = stn.ImageIndex;
+        stn.Tag = r;
+        stn.Checked = selectedResources.Any(x => x.Id == r.Id);
+        tn.Nodes.Add(stn);
+        mainTreeNodes.Add(stn);
+
+        BuildMainTree(stn);
+      }
+    }
+    #endregion
+
+    #region FilteredTree Methods
+    private void UpdateFilteredTree() {
+      filteredTreeNodes.Clear();
+      foreach (TreeNode n in mainTreeNodes) {
+        n.BackColor = SystemColors.Window;
+        if (currentSearchString == null || ((Resource)n.Tag).Name.ToLower().Contains(currentSearchString)) {
+          n.BackColor = string.IsNullOrEmpty(currentSearchString) ? SystemColors.Window : Color.LightBlue;
+          filteredTreeNodes.Add(n);
+          TraverseParentNodes(n);
+        }
+      }
+      UpdateResourceTree();
+    }
+
+    private void TraverseParentNodes(TreeNode node) {
+      if (node != null) {
+        for (TreeNode parent = node.Parent; parent != null; parent = parent.Parent)
+          filteredTreeNodes.Add(parent);
+      }
+    }
+    #endregion
+
+    #region ResourceTree Methods
+    private void UpdateResourceTree() {
+      resourcesTreeView.Nodes.Clear();
+      nodeStore.Clear();
+
+      foreach (TreeNode node in filteredTreeNodes) {
+        var clone = nodeStore.SingleOrDefault(x => ((Resource)x.Tag).Id == ((Resource)node.Tag).Id);
+        if (clone == null) {
+          clone = (TreeNode)node.Clone();
+          nodeStore.Add(clone);
+          clone.Nodes.Clear();
+        }
+        foreach (TreeNode child in node.Nodes)
+          if (filteredTreeNodes.Any(x => ((Resource)x.Tag).Id == ((Resource)child.Tag).Id)) {
+            var childClone = nodeStore.SingleOrDefault(x => ((Resource)x.Tag).Id == ((Resource)child.Tag).Id);
+            if (childClone == null) {
+              childClone = (TreeNode)child.Clone();
+              nodeStore.Add(childClone);
+              childClone.Nodes.Clear();
+            }
+            clone.Nodes.Add(childClone);
+          }
+      }
+      resourcesTreeView.Nodes.AddRange(nodeStore.Where(x => ((Resource)x.Tag).ParentResourceId == null).ToArray());
+      if (string.IsNullOrEmpty(currentSearchString)) ExpandSlaveGroupNodes();
+      else resourcesTreeView.ExpandAll();
+    }
+    #endregion
+
+    #region Events
+    private void resourcesTreeView_AfterCheck(object sender, TreeViewEventArgs e) {
+      if (e.Action != TreeViewAction.Unknown) {
+        if (e.Node.Checked) {
+          IncludeChildNodes(mainTreeNodes.SingleOrDefault(x => ((Resource)x.Tag).Id == ((Resource)e.Node.Tag).Id));
+          IncludeParentNodes(mainTreeNodes.SingleOrDefault(x => ((Resource)x.Tag).Id == ((Resource)e.Node.Tag).Id));
+        } else {
+          ExcludeChildNodes(mainTreeNodes.SingleOrDefault(x => ((Resource)x.Tag).Id == ((Resource)e.Node.Tag).Id));
+          ExcludeParentNodes(mainTreeNodes.SingleOrDefault(x => ((Resource)x.Tag).Id == ((Resource)e.Node.Tag).Id));
+        }
+        ExtractStatistics();
+      }
+    }
+
+    private void resourcesTreeView_AfterSelect(object sender, TreeViewEventArgs e) {
+      if (e.Action != TreeViewAction.Unknown) {
+        ExtractStatistics(e.Node);
+      }
+    }
+
+    private void searchTextBox_TextChanged(object sender, System.EventArgs e) {
+      currentSearchString = searchTextBox.Text.ToLower();
+      UpdateFilteredTree();
+    }
+    #endregion
+
+    #region Helpers
+    private void IncludeChildNodes(TreeNode node) {
+      if (node != null) {
+        node.Checked = true;
+        selectedResources.Add((Resource)node.Tag);
+        AdjustNodeCheckedState(node);
+        foreach (TreeNode n in node.Nodes) IncludeChildNodes(n);
+      }
+    }
+
+    private void IncludeParentNodes(TreeNode node) {
+      if (node != null && node.Parent != null) {
+        TreeNode parent = node.Parent;
+        if (parent.Nodes.OfType<TreeNode>().All(x => x.Checked)) {
+          parent.Checked = true;
+          selectedResources.Add((Resource)parent.Tag);
+          AdjustNodeCheckedState(parent);
+          IncludeParentNodes(parent);
+        }
+      }
+    }
+
+    private void ExcludeChildNodes(TreeNode node) {
+      if (node != null) {
+        node.Checked = false;
+        selectedResources.Remove((Resource)node.Tag);
+        AdjustNodeCheckedState(node);
+        foreach (TreeNode n in node.Nodes) ExcludeChildNodes(n);
+      }
+    }
+
+    private void ExcludeParentNodes(TreeNode node) {
+      if (node != null) {
+        node.Checked = false;
+        selectedResources.Remove((Resource)node.Tag);
+        AdjustNodeCheckedState(node);
+        ExcludeParentNodes(node.Parent);
+      }
+    }
+
+    private void AdjustNodeCheckedState(TreeNode node) {
+      var filterdNode = filteredTreeNodes.SingleOrDefault(x => ((Resource)x.Tag).Id == ((Resource)node.Tag).Id);
+      var storedNode = nodeStore.SingleOrDefault(x => ((Resource)x.Tag).Id == ((Resource)node.Tag).Id);
+      if (filterdNode != null) filterdNode.Checked = node.Checked;
+      if (storedNode != null) storedNode.Checked = node.Checked;
+    }
+
+    private void ExpandSlaveGroupNodes() {
+      foreach (TreeNode n in nodeStore.Where(x => x.Tag is SlaveGroup)) {
+        TreeNode[] children = new TreeNode[n.Nodes.Count];
+        n.Nodes.CopyTo(children, 0);
+        if (children.Any(x => x.Tag is SlaveGroup)) n.Expand();
+      }
+    }
+
+    private void ExtractStatistics(TreeNode treeNode = null) {
+      StringBuilder sb = new StringBuilder();
+      Resource resource = treeNode == null ? null : treeNode.Tag as Resource;
+      ISet<Resource> resources = treeNode == null ? selectedResources : new HashSet<Resource>(treeNode.DescendantNodes().Select(x => x.Tag as Resource)); ;
+      IEnumerable<SlaveGroup> slaveGroups = resources.OfType<SlaveGroup>();
+      IEnumerable<Slave> slaves = resources.OfType<Slave>();
+      int cpuSpeed = 0, cores = 0, freeCores = 0, memory = 0, freeMemory = 0;
+      string contextString = treeNode == null ? "Selected" : "Included";
+
+      if (resources.Any() || resource != null) {
+        foreach (Slave s in slaves) {
+          cpuSpeed += s.CpuSpeed.GetValueOrDefault();
+          cores += s.Cores.GetValueOrDefault();
+          freeCores += s.FreeCores.GetValueOrDefault();
+          memory += s.Memory.GetValueOrDefault();
+          freeMemory += s.FreeMemory.GetValueOrDefault();
+        }
+        if (resource != null) {
+          if (resource is SlaveGroup) sb.Append("Slave group: ");
+          else if (resource is Slave) {
+            sb.Append("Slave: ");
+            if (!resources.Any()) {
+              Slave s = resource as Slave;
+              cpuSpeed = s.CpuSpeed.GetValueOrDefault();
+              cores = s.Cores.GetValueOrDefault();
+              freeCores = s.FreeCores.GetValueOrDefault();
+              memory = s.Memory.GetValueOrDefault();
+              freeMemory = s.FreeMemory.GetValueOrDefault();
+            }
+          }
+          sb.AppendLine(string.Format("{0}", resource.Name));
+        }
+        if (resource == null || resource is SlaveGroup) {
+          if (resources.Any()) {
+            sb.AppendFormat("{0} slave groups ({1}): ", contextString, slaveGroups.Count());
+            foreach (SlaveGroup sg in slaveGroups) sb.AppendFormat("{0}; ", sg.Name);
+            sb.AppendLine();
+            sb.AppendFormat("{0} slaves ({1}): ", contextString, slaves.Count());
+            foreach (Slave s in slaves) sb.AppendFormat("{0}; ", s.Name);
+            sb.AppendLine();
+          } else {
+            sb.Append("The selection does not inlcude any further resources.");
+          }
+        }
+        sb.AppendLine();
+        sb.AppendLine(string.Format("CPU speed: {0} MHz", cpuSpeed));
+        if (resources.Any()) sb.AppendLine(string.Format("Avg. CPU speed: {0:0.00} MHz", (double)cpuSpeed / resources.Count()));
+        sb.AppendLine(string.Format("Cores: {0}", cores));
+        sb.AppendLine(string.Format("Free cores: {0}", freeCores));
+        if (resources.Any()) sb.AppendLine(string.Format("Avg. free cores: {0:0.00}", (double)freeCores / resources.Count()));
+        sb.AppendLine(string.Format("Memory: {0} MB", memory));
+        sb.AppendFormat("Free memory: {0} MB", freeMemory);
+        if (resources.Any()) sb.Append(string.Format("{0}Avg. free memory: {1:0.00} MB", Environment.NewLine, (double)freeMemory / resources.Count()));
+      } else {
+        sb.Append("No resources selected.");
+      }
+
+      descriptionTextBox.Text = sb.ToString();
+    }
+    #endregion
+  }
+}
Index: /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/Views/HiveResourceSelectorDialog.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/Views/HiveResourceSelectorDialog.Designer.cs	(revision 7910)
+++ /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/Views/HiveResourceSelectorDialog.Designer.cs	(revision 7910)
@@ -0,0 +1,111 @@
+﻿namespace HeuristicLab.Clients.Hive.JobManager.Views {
+  partial class HiveResourceSelectorDialog {
+    /// <summary>
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary>
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Windows Form Designer generated code
+
+    /// <summary>
+    /// Required method for Designer support - do not modify
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(HiveResourceSelectorDialog));
+      this.okButton = new System.Windows.Forms.Button();
+      this.cancelButton = new System.Windows.Forms.Button();
+      this.refreshButton = new System.Windows.Forms.Button();
+      this.hiveResourceSelector = new HeuristicLab.Clients.Hive.JobManager.Views.HiveResourceSelector();
+      this.SuspendLayout();
+      // 
+      // okButton
+      // 
+      this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+      this.okButton.DialogResult = System.Windows.Forms.DialogResult.OK;
+      this.okButton.Location = new System.Drawing.Point(405, 609);
+      this.okButton.Name = "okButton";
+      this.okButton.Size = new System.Drawing.Size(75, 23);
+      this.okButton.TabIndex = 1;
+      this.okButton.Text = "&OK";
+      this.okButton.UseVisualStyleBackColor = true;
+      // 
+      // cancelButton
+      // 
+      this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+      this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+      this.cancelButton.Location = new System.Drawing.Point(486, 609);
+      this.cancelButton.Name = "cancelButton";
+      this.cancelButton.Size = new System.Drawing.Size(75, 23);
+      this.cancelButton.TabIndex = 2;
+      this.cancelButton.Text = "&Cancel";
+      this.cancelButton.UseVisualStyleBackColor = true;
+      // 
+      // refreshButton
+      // 
+      this.refreshButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+      this.refreshButton.Image = HeuristicLab.Common.Resources.VSImageLibrary.Refresh;
+      this.refreshButton.Location = new System.Drawing.Point(12, 608);
+      this.refreshButton.Name = "refreshButton";
+      this.refreshButton.Size = new System.Drawing.Size(24, 24);
+      this.refreshButton.TabIndex = 3;
+      this.refreshButton.UseVisualStyleBackColor = true;
+      this.refreshButton.Click += new System.EventHandler(this.refreshButton_Click);
+      // 
+      // hiveResourceSelector
+      // 
+      this.hiveResourceSelector.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+            | System.Windows.Forms.AnchorStyles.Left)
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.hiveResourceSelector.Caption = "View";
+      this.hiveResourceSelector.Content = null;
+      this.hiveResourceSelector.Location = new System.Drawing.Point(12, 12);
+      this.hiveResourceSelector.Name = "hiveResourceSelector";
+      this.hiveResourceSelector.ProgressView = null;
+      this.hiveResourceSelector.ReadOnly = false;
+      this.hiveResourceSelector.Size = new System.Drawing.Size(549, 591);
+      this.hiveResourceSelector.TabIndex = 0;
+      // 
+      // HiveResourceSelectorDialog
+      // 
+      this.AcceptButton = this.okButton;
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.CancelButton = this.cancelButton;
+      this.ClientSize = new System.Drawing.Size(573, 644);
+      this.Controls.Add(this.refreshButton);
+      this.Controls.Add(this.hiveResourceSelector);
+      this.Controls.Add(this.cancelButton);
+      this.Controls.Add(this.okButton);
+      this.MaximizeBox = false;
+      this.MinimizeBox = false;
+      this.Name = "HiveResourceSelectorDialog";
+      this.ShowIcon = false;
+      this.ShowInTaskbar = false;
+      this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+      this.Text = "Select Resources";
+      this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.HiveResourceSelectorDialog_FormClosing);
+      this.Load += new System.EventHandler(this.HiveResourceSelectorDialog_Load);
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+    protected System.Windows.Forms.Button okButton;
+    protected System.Windows.Forms.Button cancelButton;
+    protected HiveResourceSelector hiveResourceSelector;
+    protected System.Windows.Forms.Button refreshButton;
+  }
+}
Index: /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/Views/HiveResourceSelectorDialog.cs
===================================================================
--- /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/Views/HiveResourceSelectorDialog.cs	(revision 7910)
+++ /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/Views/HiveResourceSelectorDialog.cs	(revision 7910)
@@ -0,0 +1,70 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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.Collections.Generic;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.Clients.Hive.JobManager.Views {
+  public partial class HiveResourceSelectorDialog : Form {
+    public HiveResourceSelector HiveResourceSelector {
+      get { return hiveResourceSelector; }
+    }
+
+    public HiveResourceSelectorDialog() {
+      InitializeComponent();
+    }
+
+    public ISet<Resource> GetSelectedResources() { return hiveResourceSelector.SelectedResources; }
+
+    private void HiveResourceSelectorDialog_Load(object sender, System.EventArgs e) {
+      HiveAdminClient.Instance.Refreshed += new System.EventHandler(Instance_Refreshed);
+      DownloadResources();
+    }
+
+    private void HiveResourceSelectorDialog_FormClosing(object sender, FormClosingEventArgs e) {
+      HiveAdminClient.Instance.Refreshed -= new System.EventHandler(Instance_Refreshed);
+    }
+
+    void Instance_Refreshed(object sender, System.EventArgs e) {
+      hiveResourceSelector.Content = HiveAdminClient.Instance.Resources;
+    }
+
+    private void refreshButton_Click(object sender, System.EventArgs e) {
+      DownloadResources();
+    }
+
+    private void DownloadResources() {
+      var task = System.Threading.Tasks.Task.Factory.StartNew(DownloadResourcesAsync);
+      task.ContinueWith(t => {
+        hiveResourceSelector.FinishProgressView();
+        ErrorHandling.ShowErrorDialog(this, "An error occurred while downloading the tasks.", t.Exception);
+      }, TaskContinuationOptions.OnlyOnFaulted);
+    }
+
+    private void DownloadResourcesAsync() {
+      hiveResourceSelector.StartProgressView();
+      HiveAdminClient.Instance.Refresh();
+      hiveResourceSelector.FinishProgressView();
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/Views/RefreshableHiveJobView.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/Views/RefreshableHiveJobView.Designer.cs	(revision 7909)
+++ /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/Views/RefreshableHiveJobView.Designer.cs	(revision 7910)
@@ -58,4 +58,5 @@
       this.calculatingLabel = new System.Windows.Forms.Label();
       this.jobsLabel = new System.Windows.Forms.Label();
+      this.searchButton = new System.Windows.Forms.Button();
       this.tabControl.SuspendLayout();
       this.tasksTabPage.SuspendLayout();
@@ -70,6 +71,6 @@
       // 
       this.tabControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
-                  | System.Windows.Forms.AnchorStyles.Left)
-                  | System.Windows.Forms.AnchorStyles.Right)));
+            | System.Windows.Forms.AnchorStyles.Left)
+            | System.Windows.Forms.AnchorStyles.Right)));
       this.tabControl.Controls.Add(this.tasksTabPage);
       this.tabControl.Controls.Add(this.permissionTabPage);
@@ -98,6 +99,6 @@
       this.jobsTreeView.AllowDrop = true;
       this.jobsTreeView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
-                  | System.Windows.Forms.AnchorStyles.Left)
-                  | System.Windows.Forms.AnchorStyles.Right)));
+            | System.Windows.Forms.AnchorStyles.Left)
+            | System.Windows.Forms.AnchorStyles.Right)));
       this.jobsTreeView.Caption = "ItemTree View";
       this.jobsTreeView.Content = null;
@@ -136,6 +137,6 @@
       // 
       this.hiveExperimentPermissionListView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
-                  | System.Windows.Forms.AnchorStyles.Left)
-                  | System.Windows.Forms.AnchorStyles.Right)));
+            | System.Windows.Forms.AnchorStyles.Left)
+            | System.Windows.Forms.AnchorStyles.Right)));
       this.hiveExperimentPermissionListView.Caption = "HiveExperimentPermissionList View";
       this.hiveExperimentPermissionListView.Content = null;
@@ -162,6 +163,6 @@
       // 
       this.runCollectionViewHost.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
-                  | System.Windows.Forms.AnchorStyles.Left)
-                  | System.Windows.Forms.AnchorStyles.Right)));
+            | System.Windows.Forms.AnchorStyles.Left)
+            | System.Windows.Forms.AnchorStyles.Right)));
       this.runCollectionViewHost.Caption = "View";
       this.runCollectionViewHost.Content = null;
@@ -188,6 +189,6 @@
       // 
       this.stateLogViewHost.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
-                  | System.Windows.Forms.AnchorStyles.Left)
-                  | System.Windows.Forms.AnchorStyles.Right)));
+            | System.Windows.Forms.AnchorStyles.Left)
+            | System.Windows.Forms.AnchorStyles.Right)));
       this.stateLogViewHost.Caption = "StateLog View";
       this.stateLogViewHost.Content = null;
@@ -214,6 +215,6 @@
       // 
       this.logView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
-                  | System.Windows.Forms.AnchorStyles.Left)
-                  | System.Windows.Forms.AnchorStyles.Right)));
+            | System.Windows.Forms.AnchorStyles.Left)
+            | System.Windows.Forms.AnchorStyles.Right)));
       this.logView.Caption = "Log View";
       this.logView.Content = null;
@@ -305,8 +306,8 @@
       // 
       this.resourceNamesTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
-                  | System.Windows.Forms.AnchorStyles.Right)));
+            | System.Windows.Forms.AnchorStyles.Right)));
       this.resourceNamesTextBox.Location = new System.Drawing.Point(70, 52);
       this.resourceNamesTextBox.Name = "resourceNamesTextBox";
-      this.resourceNamesTextBox.Size = new System.Drawing.Size(415, 20);
+      this.resourceNamesTextBox.Size = new System.Drawing.Size(385, 20);
       this.resourceNamesTextBox.TabIndex = 2;
       this.resourceNamesTextBox.Validated += new System.EventHandler(this.resourceNamesTextBox_Validated);
@@ -324,5 +325,5 @@
       // 
       this.nameTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
-                  | System.Windows.Forms.AnchorStyles.Right)));
+            | System.Windows.Forms.AnchorStyles.Right)));
       this.nameTextBox.Location = new System.Drawing.Point(70, 27);
       this.nameTextBox.Name = "nameTextBox";
@@ -346,5 +347,5 @@
       this.isPrivilegedCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
       this.isPrivilegedCheckBox.AutoSize = true;
-      this.isPrivilegedCheckBox.Location = new System.Drawing.Point(491, 53);
+      this.isPrivilegedCheckBox.Location = new System.Drawing.Point(491, 54);
       this.isPrivilegedCheckBox.Name = "isPrivilegedCheckBox";
       this.isPrivilegedCheckBox.Size = new System.Drawing.Size(72, 17);
@@ -385,5 +386,5 @@
       // 
       this.finishedTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
-                  | System.Windows.Forms.AnchorStyles.Right)));
+            | System.Windows.Forms.AnchorStyles.Right)));
       this.finishedTextBox.Location = new System.Drawing.Point(74, 64);
       this.finishedTextBox.Name = "finishedTextBox";
@@ -394,5 +395,5 @@
       // 
       this.calculatingTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
-                  | System.Windows.Forms.AnchorStyles.Right)));
+            | System.Windows.Forms.AnchorStyles.Right)));
       this.calculatingTextBox.Location = new System.Drawing.Point(74, 40);
       this.calculatingTextBox.Name = "calculatingTextBox";
@@ -403,5 +404,5 @@
       // 
       this.jobsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
-                  | System.Windows.Forms.AnchorStyles.Right)));
+            | System.Windows.Forms.AnchorStyles.Right)));
       this.jobsTextBox.Location = new System.Drawing.Point(74, 16);
       this.jobsTextBox.Name = "jobsTextBox";
@@ -436,8 +437,20 @@
       this.jobsLabel.Text = "Waiting:";
       // 
+      // searchButton
+      // 
+      this.searchButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+      this.searchButton.Image = HeuristicLab.Common.Resources.VSImageLibrary.Zoom;
+      this.searchButton.Location = new System.Drawing.Point(461, 50);
+      this.searchButton.Name = "searchButton";
+      this.searchButton.Size = new System.Drawing.Size(24, 24);
+      this.searchButton.TabIndex = 26;
+      this.searchButton.UseVisualStyleBackColor = true;
+      this.searchButton.Click += new System.EventHandler(this.searchButton_Click);
+      // 
       // RefreshableHiveJobView
       // 
       this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
       this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Controls.Add(this.searchButton);
       this.Controls.Add(this.isPrivilegedCheckBox);
       this.Controls.Add(this.infoGroupBox);
@@ -504,4 +517,5 @@
     private System.Windows.Forms.TabPage runsTabPage;
     private MainForm.WindowsForms.ViewHost runCollectionViewHost;
+    private System.Windows.Forms.Button searchButton;
 
   }
Index: /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/Views/RefreshableHiveJobView.cs
===================================================================
--- /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/Views/RefreshableHiveJobView.cs	(revision 7909)
+++ /trunk/sources/HeuristicLab.Clients.Hive.JobManager/3.3/Views/RefreshableHiveJobView.cs	(revision 7910)
@@ -23,4 +23,5 @@
 using System.ComponentModel;
 using System.Linq;
+using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
@@ -42,4 +43,5 @@
   public partial class RefreshableHiveJobView : HeuristicLab.Core.Views.ItemView {
     private ProgressView progressView;
+    private HiveResourceSelectorDialog hiveResourceSelectorDialog;
 
     public new RefreshableJob Content {
@@ -149,4 +151,5 @@
         this.nameTextBox.ReadOnly = !Content.IsControllable || Content.ExecutionState != ExecutionState.Prepared || alreadyUploaded;
         this.resourceNamesTextBox.ReadOnly = !Content.IsControllable || Content.ExecutionState != ExecutionState.Prepared || alreadyUploaded;
+        this.searchButton.Enabled = Content.IsControllable && !(Content.ExecutionState != ExecutionState.Prepared || alreadyUploaded);
         this.jobsTreeView.ReadOnly = !Content.IsControllable || Content.ExecutionState != ExecutionState.Prepared || alreadyUploaded;
 
@@ -332,4 +335,17 @@
 
     #region Control events
+    private void searchButton_Click(object sender, EventArgs e) {
+      if (hiveResourceSelectorDialog == null)
+        hiveResourceSelectorDialog = new HiveResourceSelectorDialog();
+      if (hiveResourceSelectorDialog.ShowDialog(this) == DialogResult.OK) {
+        StringBuilder sb = new StringBuilder();
+        foreach (Resource resource in hiveResourceSelectorDialog.GetSelectedResources()) {
+          sb.Append(resource.Name);
+          sb.Append("; ");
+        }
+        resourceNamesTextBox.Text = sb.ToString();
+      }
+    }
+
     private void startButton_Click(object sender, EventArgs e) {
       if (nameTextBox.Text.Trim() == string.Empty) {
Index: /trunk/sources/HeuristicLab.Services.Hive/3.3/HiveService.cs
===================================================================
--- /trunk/sources/HeuristicLab.Services.Hive/3.3/HiveService.cs	(revision 7909)
+++ /trunk/sources/HeuristicLab.Services.Hive/3.3/HiveService.cs	(revision 7910)
@@ -334,4 +334,5 @@
       });
     }
+
     public IEnumerable<JobPermission> GetJobPermissions(Guid jobId) {
       authen.AuthenticateForAnyRole(HiveRoles.Administrator, HiveRoles.Client);
@@ -495,10 +496,10 @@
 
     public IEnumerable<Slave> GetSlaves() {
-      authen.AuthenticateForAnyRole(HiveRoles.Administrator);
+      authen.AuthenticateForAnyRole(HiveRoles.Administrator, HiveRoles.Client);
       return dao.GetSlaves(x => true);
     }
 
     public IEnumerable<SlaveGroup> GetSlaveGroups() {
-      authen.AuthenticateForAnyRole(HiveRoles.Administrator);
+      authen.AuthenticateForAnyRole(HiveRoles.Administrator, HiveRoles.Client);
       return dao.GetSlaveGroups(x => true);
     }
