Index: /trunk/sources/HeuristicLab.Common.Resources/3.3/HeuristicLab.Common.Resources-3.3.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Common.Resources/3.3/HeuristicLab.Common.Resources-3.3.csproj	(revision 9078)
+++ /trunk/sources/HeuristicLab.Common.Resources/3.3/HeuristicLab.Common.Resources-3.3.csproj	(revision 9079)
@@ -430,6 +430,6 @@
   </ItemGroup>
   <ItemGroup>
+    <None Include="Resources\VS2010ImageLibrary\camera.png" />
     <None Include="Resources\VS2010ImageLibrary\VS2010ImageLibrary_Actions_SaveAsHH.png" />
-    <None Include="Resources\SaveAs.bmp" />
     <Content Include="Resources\VS2008ImageLibrary\VS2008ImageLibrary_Actions_Checkout.png" />
     <Content Include="Resources\VS2008ImageLibrary\VS2008ImageLibrary_Actions_Clone.png" />
@@ -500,5 +500,5 @@
   -->
   <PropertyGroup>
-   <PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+    <PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
 set ProjectDir=$(ProjectDir)
 set SolutionDir=$(SolutionDir)
@@ -507,5 +507,5 @@
 call PreBuildEvent.cmd
 </PreBuildEvent>
-<PreBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">
+    <PreBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">
 export ProjectDir=$(ProjectDir)
 export SolutionDir=$(SolutionDir)
Index: /trunk/sources/HeuristicLab.Common.Resources/3.3/VSImageLibrary.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Common.Resources/3.3/VSImageLibrary.Designer.cs	(revision 9078)
+++ /trunk/sources/HeuristicLab.Common.Resources/3.3/VSImageLibrary.Designer.cs	(revision 9079)
@@ -2,5 +2,5 @@
 // <auto-generated>
 //     This code was generated by a tool.
-//     Runtime Version:4.0.30319.269
+//     Runtime Version:4.0.30319.17929
 //
 //     Changes to this file may cause incorrect behavior and will be lost if
@@ -61,4 +61,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap ActualSize {
             get {
@@ -68,4 +71,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Add {
             get {
@@ -75,4 +81,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap ArrowDown {
             get {
@@ -82,4 +91,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap ArrowUp {
             get {
@@ -89,4 +101,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Assembly {
             get {
@@ -96,4 +111,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap BatchRunPaused {
             get {
@@ -103,4 +121,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap BatchRunPrepared {
             get {
@@ -110,4 +131,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap BatchRunStarted {
             get {
@@ -117,4 +141,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap BatchRunStopped {
             get {
@@ -124,4 +151,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Breakpoint {
             get {
@@ -131,4 +161,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap BreakpointActive {
             get {
@@ -138,4 +171,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap BreakpointInactive {
             get {
@@ -145,4 +181,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Cab {
             get {
@@ -152,4 +191,17 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
+        public static System.Drawing.Bitmap Camera {
+            get {
+                object obj = ResourceManager.GetObject("Camera", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Checkout {
             get {
@@ -159,4 +211,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Class {
             get {
@@ -166,4 +221,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Clone {
             get {
@@ -173,4 +231,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Collapse {
             get {
@@ -180,4 +241,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Comment {
             get {
@@ -187,4 +251,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Component {
             get {
@@ -194,4 +261,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Constant {
             get {
@@ -201,4 +271,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Control {
             get {
@@ -208,4 +281,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Copy {
             get {
@@ -215,4 +291,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Cut {
             get {
@@ -222,4 +301,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Database {
             get {
@@ -229,4 +311,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap DatabaseModified {
             get {
@@ -236,4 +321,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Delegate {
             get {
@@ -243,4 +331,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Delete {
             get {
@@ -250,4 +341,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap DeleteFolder {
             get {
@@ -257,4 +351,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Disconnect {
             get {
@@ -264,4 +361,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap DisplayInColor {
             get {
@@ -271,4 +371,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap DisplayInColorVertical {
             get {
@@ -278,4 +381,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Document {
             get {
@@ -285,4 +391,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Drive {
             get {
@@ -292,4 +401,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Edit {
             get {
@@ -299,4 +411,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap EditBrightnessContrast {
             get {
@@ -306,4 +421,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap EditInformation {
             get {
@@ -313,4 +431,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap EditTable {
             get {
@@ -320,4 +441,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Enum {
             get {
@@ -327,4 +451,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap EnumItem {
             get {
@@ -334,4 +461,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Error {
             get {
@@ -341,4 +471,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Event {
             get {
@@ -348,4 +481,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Exception {
             get {
@@ -355,4 +491,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap ExecutablePaused {
             get {
@@ -362,4 +501,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap ExecutablePrepared {
             get {
@@ -369,4 +511,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap ExecutableStarted {
             get {
@@ -376,4 +521,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap ExecutableStopped {
             get {
@@ -383,4 +531,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Expand {
             get {
@@ -390,4 +541,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap ExperimentPaused {
             get {
@@ -397,4 +551,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap ExperimentPrepared {
             get {
@@ -404,4 +561,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap ExperimentStarted {
             get {
@@ -411,4 +571,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap ExperimentStopped {
             get {
@@ -418,4 +581,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Field {
             get {
@@ -425,4 +591,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap File {
             get {
@@ -432,4 +601,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Filter {
             get {
@@ -439,4 +611,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap FlagBlue {
             get {
@@ -446,4 +621,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap FlagGreen {
             get {
@@ -453,4 +631,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap FlagRed {
             get {
@@ -460,4 +641,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap FormulaEvaluator {
             get {
@@ -467,4 +651,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Function {
             get {
@@ -474,4 +661,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Gradient {
             get {
@@ -481,4 +671,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Graph {
             get {
@@ -488,4 +681,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Help {
             get {
@@ -495,4 +691,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap HiddenField {
             get {
@@ -502,4 +701,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap HighPriorityLarge {
             get {
@@ -509,4 +711,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Image {
             get {
@@ -516,4 +721,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Information {
             get {
@@ -523,4 +731,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap InformationLarge {
             get {
@@ -530,4 +741,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Install {
             get {
@@ -537,4 +751,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Interface {
             get {
@@ -544,4 +761,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Internet {
             get {
@@ -551,4 +771,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Library {
             get {
@@ -558,4 +781,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Macro {
             get {
@@ -565,4 +791,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Map {
             get {
@@ -572,4 +801,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap MapItem {
             get {
@@ -579,4 +811,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Method {
             get {
@@ -586,4 +821,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap MethodOverload {
             get {
@@ -593,4 +831,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Module {
             get {
@@ -600,4 +841,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap MonitorLarge {
             get {
@@ -607,4 +851,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap MoveFirst {
             get {
@@ -614,4 +861,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap MoveLast {
             get {
@@ -621,4 +871,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap MoveNext {
             get {
@@ -628,4 +881,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap MovePrevious {
             get {
@@ -635,4 +891,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Namespace {
             get {
@@ -642,4 +901,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap NetworkCenterLarge {
             get {
@@ -649,4 +911,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap NetworkConnections {
             get {
@@ -656,4 +921,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap NewDocument {
             get {
@@ -663,4 +931,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap NewFolder {
             get {
@@ -670,4 +941,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Nothing {
             get {
@@ -677,4 +951,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Object {
             get {
@@ -684,4 +961,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Open {
             get {
@@ -691,4 +971,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Operator {
             get {
@@ -698,4 +981,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap OrgChart {
             get {
@@ -705,4 +991,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Paste {
             get {
@@ -712,4 +1001,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Pause {
             get {
@@ -719,4 +1011,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Performance {
             get {
@@ -726,4 +1021,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap PieChart {
             get {
@@ -733,4 +1031,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Play {
             get {
@@ -740,4 +1041,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Pointer {
             get {
@@ -747,4 +1051,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Print {
             get {
@@ -754,4 +1061,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap PrintPreview {
             get {
@@ -761,4 +1071,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Properties {
             get {
@@ -768,4 +1081,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap ProtectForm {
             get {
@@ -775,4 +1091,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap PublishToWeb {
             get {
@@ -782,4 +1101,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap RadialChart {
             get {
@@ -789,4 +1111,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Redo {
             get {
@@ -796,4 +1121,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Refresh {
             get {
@@ -803,4 +1131,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap RefreshDocument {
             get {
@@ -810,4 +1141,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Remove {
             get {
@@ -817,4 +1151,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Restart {
             get {
@@ -824,4 +1161,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Save {
             get {
@@ -831,4 +1171,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap SaveAll {
             get {
@@ -838,4 +1181,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap SaveAs {
             get {
@@ -845,4 +1191,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Script {
             get {
@@ -852,4 +1201,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Sort {
             get {
@@ -859,4 +1211,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap SortUp {
             get {
@@ -866,4 +1221,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Statistics {
             get {
@@ -873,4 +1231,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Stop {
             get {
@@ -880,4 +1241,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Structure {
             get {
@@ -887,4 +1251,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Table {
             get {
@@ -894,4 +1261,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Template {
             get {
@@ -901,4 +1271,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Timer {
             get {
@@ -908,4 +1281,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap TrackBar {
             get {
@@ -915,4 +1291,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Type {
             get {
@@ -922,4 +1301,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap TypeDef {
             get {
@@ -929,4 +1311,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Undo {
             get {
@@ -936,4 +1321,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Union {
             get {
@@ -943,4 +1331,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap User {
             get {
@@ -950,4 +1341,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap UserAccounts {
             get {
@@ -957,4 +1351,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap ValueType {
             get {
@@ -964,4 +1361,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Warning {
             get {
@@ -971,4 +1371,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Windows {
             get {
@@ -978,4 +1381,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap Zoom {
             get {
@@ -985,4 +1391,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap ZoomIn {
             get {
@@ -992,4 +1401,7 @@
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
         public static System.Drawing.Bitmap ZoomOut {
             get {
Index: /trunk/sources/HeuristicLab.Common.Resources/3.3/VSImageLibrary.resx
===================================================================
--- /trunk/sources/HeuristicLab.Common.Resources/3.3/VSImageLibrary.resx	(revision 9078)
+++ /trunk/sources/HeuristicLab.Common.Resources/3.3/VSImageLibrary.resx	(revision 9079)
@@ -521,3 +521,6 @@
     <value>Resources\VS2010ImageLibrary\VS2010ImageLibrary_Actions_SaveAsHH.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
+  <data name="Camera" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\VS2010ImageLibrary\camera.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
 </root>
Index: /trunk/sources/HeuristicLab.Common/3.3/HeuristicLab.Common-3.3.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Common/3.3/HeuristicLab.Common-3.3.csproj	(revision 9078)
+++ /trunk/sources/HeuristicLab.Common/3.3/HeuristicLab.Common-3.3.csproj	(revision 9079)
@@ -135,4 +135,5 @@
     <Compile Include="Plugin.cs" />
     <Compile Include="ReferenceEqualityComparer.cs" />
+    <Compile Include="TimeSpanHelper.cs" />
     <Compile Include="TypeEqualityComparer.cs" />
     <Compile Include="TypeExtensions.cs" />
@@ -180,5 +181,5 @@
   -->
   <PropertyGroup>
-   <PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+    <PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
 set ProjectDir=$(ProjectDir)
 set SolutionDir=$(SolutionDir)
@@ -187,5 +188,5 @@
 call PreBuildEvent.cmd
 </PreBuildEvent>
-<PreBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">
+    <PreBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">
 export ProjectDir=$(ProjectDir)
 export SolutionDir=$(SolutionDir)
Index: /trunk/sources/HeuristicLab.Common/3.3/TimeSpanHelper.cs
===================================================================
--- /trunk/sources/HeuristicLab.Common/3.3/TimeSpanHelper.cs	(revision 9079)
+++ /trunk/sources/HeuristicLab.Common/3.3/TimeSpanHelper.cs	(revision 9079)
@@ -0,0 +1,97 @@
+﻿#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.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace HeuristicLab.Common {
+  public static class TimeSpanHelper {
+    public static bool TryGetFromNaturalFormat(string text, out TimeSpan result) {
+      result = TimeSpan.Zero;
+
+      var matches = Regex.Matches(text, @"(\d+)[ \t]*([a-zA-Z]+)");
+      if (matches.Count == 0) return false;
+
+      foreach (Match match in matches) {
+        var number = match.Groups[1].Value;
+        var unit = match.Groups[2].Value;
+
+        double value;
+        if (!double.TryParse(number, out value))
+          return false;
+
+        switch (unit) {
+          case "d":
+          case "day":
+          case "days": result = result.Add(TimeSpan.FromDays(value)); break;
+          case "h":
+          case "hour":
+          case "hours": result = result.Add(TimeSpan.FromHours(value)); break;
+          case "min":
+          case "minute":
+          case "minutes": result = result.Add(TimeSpan.FromMinutes(value)); break;
+          case "s":
+          case "second":
+          case "seconds": result = result.Add(TimeSpan.FromSeconds(value)); break;
+          default: return false;
+        }
+      }
+      return true;
+    }
+
+    public static string FormatNatural(TimeSpan ts, bool abbrevUnit = false, bool composite = false) {
+      if (!composite) {
+        if (ts.TotalSeconds < 180) return ts.TotalSeconds + (abbrevUnit ? "s" : " seconds");
+        if (ts.TotalMinutes < 180) return ts.TotalMinutes + (abbrevUnit ? "min" : " minutes");
+        if (ts.TotalHours < 96) return ts.TotalHours + (abbrevUnit ? "h" : " hours");
+        return ts.TotalDays + (abbrevUnit ? "d" : " days");
+      } else {
+        var sb = new StringBuilder();
+        if (ts.TotalDays > 0) {
+          var absDays = (int)Math.Floor(ts.TotalDays);
+          sb.Append(absDays);
+          sb.Append(abbrevUnit ? "d" : ((absDays > 1) ? " days" : " day"));
+        }
+        if (ts.Hours > 0) {
+          if (sb.Length > 0) sb.Append(" ");
+          sb.Append(ts.Hours);
+          sb.Append(abbrevUnit ? "h" : ((ts.Hours > 1) ? " hours" : " hour"));
+        }
+        if (ts.Minutes > 0) {
+          if (sb.Length > 0) sb.Append(" ");
+          sb.Append(ts.Minutes);
+          sb.Append(abbrevUnit ? "min" : ((ts.Minutes > 1) ? " minutes" : " minute"));
+        }
+        if (ts.Seconds > 0) {
+          if (sb.Length > 0) sb.Append(" ");
+          sb.Append(ts.Seconds);
+          sb.Append(abbrevUnit ? "s" : ((ts.Minutes > 1) ? " seconds" : " second"));
+        }
+        return sb.ToString();
+      }
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.MainForm.WindowsForms/3.3/Dialogs/DefineArithmeticProgressionDialog.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.MainForm.WindowsForms/3.3/Dialogs/DefineArithmeticProgressionDialog.Designer.cs	(revision 9079)
+++ /trunk/sources/HeuristicLab.MainForm.WindowsForms/3.3/Dialogs/DefineArithmeticProgressionDialog.Designer.cs	(revision 9079)
@@ -0,0 +1,185 @@
+﻿#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
+
+namespace HeuristicLab.MainForm.WindowsForms {
+  partial class DefineArithmeticProgressionDialog {
+    /// <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() {
+      this.components = new System.ComponentModel.Container();
+      this.stepSizeTextBox = new System.Windows.Forms.TextBox();
+      this.maximumTextBox = new System.Windows.Forms.TextBox();
+      this.minimumTextBox = new System.Windows.Forms.TextBox();
+      this.stepSizeLabel = new System.Windows.Forms.Label();
+      this.maximumLabel = new System.Windows.Forms.Label();
+      this.minimumLabel = new System.Windows.Forms.Label();
+      this.cancelButton = new System.Windows.Forms.Button();
+      this.okButton = new System.Windows.Forms.Button();
+      this.errorProvider = new System.Windows.Forms.ErrorProvider(this.components);
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit();
+      this.SuspendLayout();
+      // 
+      // stepSizeTextBox
+      // 
+      this.stepSizeTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.stepSizeTextBox.Location = new System.Drawing.Point(75, 64);
+      this.stepSizeTextBox.Name = "stepSizeTextBox";
+      this.stepSizeTextBox.Size = new System.Drawing.Size(184, 20);
+      this.stepSizeTextBox.TabIndex = 11;
+      this.stepSizeTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.textBox_Validating);
+      // 
+      // maximumTextBox
+      // 
+      this.maximumTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.maximumTextBox.Location = new System.Drawing.Point(75, 38);
+      this.maximumTextBox.Name = "maximumTextBox";
+      this.maximumTextBox.Size = new System.Drawing.Size(184, 20);
+      this.maximumTextBox.TabIndex = 9;
+      this.maximumTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.textBox_Validating);
+      // 
+      // minimumTextBox
+      // 
+      this.minimumTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.minimumTextBox.Location = new System.Drawing.Point(75, 12);
+      this.minimumTextBox.Name = "minimumTextBox";
+      this.minimumTextBox.Size = new System.Drawing.Size(184, 20);
+      this.minimumTextBox.TabIndex = 7;
+      this.minimumTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.textBox_Validating);
+      // 
+      // stepSizeLabel
+      // 
+      this.stepSizeLabel.AutoSize = true;
+      this.stepSizeLabel.Location = new System.Drawing.Point(15, 67);
+      this.stepSizeLabel.Name = "stepSizeLabel";
+      this.stepSizeLabel.Size = new System.Drawing.Size(53, 13);
+      this.stepSizeLabel.TabIndex = 10;
+      this.stepSizeLabel.Text = "Step size:";
+      // 
+      // maximumLabel
+      // 
+      this.maximumLabel.AutoSize = true;
+      this.maximumLabel.Location = new System.Drawing.Point(15, 41);
+      this.maximumLabel.Name = "maximumLabel";
+      this.maximumLabel.Size = new System.Drawing.Size(54, 13);
+      this.maximumLabel.TabIndex = 8;
+      this.maximumLabel.Text = "Maximum:";
+      // 
+      // minimumLabel
+      // 
+      this.minimumLabel.AutoSize = true;
+      this.minimumLabel.Location = new System.Drawing.Point(15, 15);
+      this.minimumLabel.Name = "minimumLabel";
+      this.minimumLabel.Size = new System.Drawing.Size(51, 13);
+      this.minimumLabel.TabIndex = 6;
+      this.minimumLabel.Text = "Minimum:";
+      // 
+      // 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(184, 96);
+      this.cancelButton.Name = "cancelButton";
+      this.cancelButton.Size = new System.Drawing.Size(75, 23);
+      this.cancelButton.TabIndex = 12;
+      this.cancelButton.Text = "&Cancel";
+      this.cancelButton.UseVisualStyleBackColor = true;
+      // 
+      // 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(103, 96);
+      this.okButton.Name = "okButton";
+      this.okButton.Size = new System.Drawing.Size(75, 23);
+      this.okButton.TabIndex = 12;
+      this.okButton.Text = "&OK";
+      this.okButton.UseVisualStyleBackColor = true;
+      // 
+      // errorProvider
+      // 
+      this.errorProvider.ContainerControl = this;
+      // 
+      // DefineArithmeticProgressionDialog
+      // 
+      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(271, 131);
+      this.Controls.Add(this.okButton);
+      this.Controls.Add(this.cancelButton);
+      this.Controls.Add(this.stepSizeTextBox);
+      this.Controls.Add(this.maximumTextBox);
+      this.Controls.Add(this.minimumTextBox);
+      this.Controls.Add(this.stepSizeLabel);
+      this.Controls.Add(this.maximumLabel);
+      this.Controls.Add(this.minimumLabel);
+      this.MaximizeBox = false;
+      this.MinimizeBox = false;
+      this.Name = "DefineArithmeticProgressionDialog";
+      this.ShowIcon = false;
+      this.ShowInTaskbar = false;
+      this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+      this.Text = "Generate Values";
+      this.TopMost = true;
+      this.Load += new System.EventHandler(this.DefineArithmeticProgressionDialog_Load);
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).EndInit();
+      this.ResumeLayout(false);
+      this.PerformLayout();
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.TextBox stepSizeTextBox;
+    private System.Windows.Forms.TextBox maximumTextBox;
+    private System.Windows.Forms.TextBox minimumTextBox;
+    private System.Windows.Forms.Label stepSizeLabel;
+    private System.Windows.Forms.Label maximumLabel;
+    private System.Windows.Forms.Label minimumLabel;
+    private System.Windows.Forms.Button cancelButton;
+    private System.Windows.Forms.Button okButton;
+    private System.Windows.Forms.ErrorProvider errorProvider;
+  }
+}
Index: /trunk/sources/HeuristicLab.MainForm.WindowsForms/3.3/Dialogs/DefineArithmeticProgressionDialog.cs
===================================================================
--- /trunk/sources/HeuristicLab.MainForm.WindowsForms/3.3/Dialogs/DefineArithmeticProgressionDialog.cs	(revision 9079)
+++ /trunk/sources/HeuristicLab.MainForm.WindowsForms/3.3/Dialogs/DefineArithmeticProgressionDialog.cs	(revision 9079)
@@ -0,0 +1,116 @@
+﻿#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.ComponentModel;
+using System.Globalization;
+using System.Linq;
+using System.Windows.Forms;
+using HeuristicLab.Common;
+
+namespace HeuristicLab.MainForm.WindowsForms {
+  public partial class DefineArithmeticProgressionDialog : Form {
+    private bool allowOnlyInteger;
+
+    public double Minimum { get; private set; }
+    public double Maximum { get; private set; }
+    public double Step { get; private set; }
+
+    public IEnumerable<double> Values {
+      get { return EnumerateProgression().Reverse(); }
+    }
+
+    public DefineArithmeticProgressionDialog() {
+      InitializeComponent();
+      Icon = HeuristicLab.Common.Resources.HeuristicLab.Icon;
+      Minimum = 0; Maximum = 100; Step = 10;
+    }
+    public DefineArithmeticProgressionDialog(bool allowOnlyInteger)
+      : this() {
+      this.allowOnlyInteger = allowOnlyInteger;
+    }
+    public DefineArithmeticProgressionDialog(bool allowOnlyInteger, double minimum, double maximum, double step)
+      : this(allowOnlyInteger) {
+      Minimum = minimum;
+      Maximum = maximum;
+      Step = step;
+    }
+
+    private void DefineArithmeticProgressionDialog_Load(object sender, System.EventArgs e) {
+      minimumTextBox.Text = Minimum.ToString();
+      maximumTextBox.Text = Maximum.ToString();
+      stepSizeTextBox.Text = Step.ToString();
+    }
+
+    private void textBox_Validating(object sender, CancelEventArgs e) {
+      var textBox = (TextBox)sender;
+      double value = 0;
+      if (allowOnlyInteger) {
+        int intValue;
+        if (!int.TryParse(textBox.Text, out intValue)) {
+          errorProvider.SetError(textBox, "Please enter a valid integer value.");
+          e.Cancel = true;
+          return;
+        } else {
+          value = intValue;
+          errorProvider.SetError(textBox, null);
+        }
+      } else {
+        if (!double.TryParse(textBox.Text, NumberStyles.Float, CultureInfo.CurrentCulture.NumberFormat, out value)) {
+          errorProvider.SetError(textBox, "Please enter a valid double value.");
+          e.Cancel = true;
+          return;
+        } else errorProvider.SetError(textBox, null);
+      }
+      if (textBox == minimumTextBox) Minimum = value;
+      else if (textBox == maximumTextBox) Maximum = value;
+      else if (textBox == stepSizeTextBox) Step = value;
+      okButton.Enabled = IsValid();
+    }
+
+    private bool IsValid() {
+      return Minimum <= Maximum && Step >= 0;
+    }
+
+    private IEnumerable<double> EnumerateProgression() {
+      double value = Maximum;
+      bool minimumIncluded = false;
+      int i = 1;
+      while (value >= Minimum) {
+        if (value.IsAlmost(Minimum)) {
+          yield return Minimum;
+          minimumIncluded = true;
+        } else yield return value;
+
+        if (Step == 0) break; // a step size of 0 will only output maximum and minimum
+        if (allowOnlyInteger) {
+          value = (int)Maximum - i * (int)Step;
+        } else {
+          value = Maximum - i * Step;
+        }
+        i++;
+      }
+      if (!minimumIncluded) {
+        yield return Minimum;
+      }
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.MainForm.WindowsForms/3.3/Dialogs/DefineArithmeticProgressionTimeDialog.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.MainForm.WindowsForms/3.3/Dialogs/DefineArithmeticProgressionTimeDialog.Designer.cs	(revision 9079)
+++ /trunk/sources/HeuristicLab.MainForm.WindowsForms/3.3/Dialogs/DefineArithmeticProgressionTimeDialog.Designer.cs	(revision 9079)
@@ -0,0 +1,185 @@
+﻿#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
+
+namespace HeuristicLab.MainForm.WindowsForms {
+  partial class DefineArithmeticTimeSpanProgressionDialog {
+    /// <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() {
+      this.components = new System.ComponentModel.Container();
+      this.stepSizeTextBox = new System.Windows.Forms.TextBox();
+      this.maximumTextBox = new System.Windows.Forms.TextBox();
+      this.minimumTextBox = new System.Windows.Forms.TextBox();
+      this.stepSizeLabel = new System.Windows.Forms.Label();
+      this.maximumLabel = new System.Windows.Forms.Label();
+      this.minimumLabel = new System.Windows.Forms.Label();
+      this.cancelButton = new System.Windows.Forms.Button();
+      this.okButton = new System.Windows.Forms.Button();
+      this.errorProvider = new System.Windows.Forms.ErrorProvider(this.components);
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit();
+      this.SuspendLayout();
+      // 
+      // stepSizeTextBox
+      // 
+      this.stepSizeTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.stepSizeTextBox.Location = new System.Drawing.Point(75, 64);
+      this.stepSizeTextBox.Name = "stepSizeTextBox";
+      this.stepSizeTextBox.Size = new System.Drawing.Size(184, 20);
+      this.stepSizeTextBox.TabIndex = 11;
+      this.stepSizeTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.textBox_Validating);
+      // 
+      // maximumTextBox
+      // 
+      this.maximumTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.maximumTextBox.Location = new System.Drawing.Point(75, 38);
+      this.maximumTextBox.Name = "maximumTextBox";
+      this.maximumTextBox.Size = new System.Drawing.Size(184, 20);
+      this.maximumTextBox.TabIndex = 9;
+      this.maximumTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.textBox_Validating);
+      // 
+      // minimumTextBox
+      // 
+      this.minimumTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.minimumTextBox.Location = new System.Drawing.Point(75, 12);
+      this.minimumTextBox.Name = "minimumTextBox";
+      this.minimumTextBox.Size = new System.Drawing.Size(184, 20);
+      this.minimumTextBox.TabIndex = 7;
+      this.minimumTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.textBox_Validating);
+      // 
+      // stepSizeLabel
+      // 
+      this.stepSizeLabel.AutoSize = true;
+      this.stepSizeLabel.Location = new System.Drawing.Point(15, 67);
+      this.stepSizeLabel.Name = "stepSizeLabel";
+      this.stepSizeLabel.Size = new System.Drawing.Size(53, 13);
+      this.stepSizeLabel.TabIndex = 10;
+      this.stepSizeLabel.Text = "Step size:";
+      // 
+      // maximumLabel
+      // 
+      this.maximumLabel.AutoSize = true;
+      this.maximumLabel.Location = new System.Drawing.Point(15, 41);
+      this.maximumLabel.Name = "maximumLabel";
+      this.maximumLabel.Size = new System.Drawing.Size(54, 13);
+      this.maximumLabel.TabIndex = 8;
+      this.maximumLabel.Text = "Maximum:";
+      // 
+      // minimumLabel
+      // 
+      this.minimumLabel.AutoSize = true;
+      this.minimumLabel.Location = new System.Drawing.Point(15, 15);
+      this.minimumLabel.Name = "minimumLabel";
+      this.minimumLabel.Size = new System.Drawing.Size(51, 13);
+      this.minimumLabel.TabIndex = 6;
+      this.minimumLabel.Text = "Minimum:";
+      // 
+      // 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(184, 96);
+      this.cancelButton.Name = "cancelButton";
+      this.cancelButton.Size = new System.Drawing.Size(75, 23);
+      this.cancelButton.TabIndex = 12;
+      this.cancelButton.Text = "&Cancel";
+      this.cancelButton.UseVisualStyleBackColor = true;
+      // 
+      // 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(103, 96);
+      this.okButton.Name = "okButton";
+      this.okButton.Size = new System.Drawing.Size(75, 23);
+      this.okButton.TabIndex = 12;
+      this.okButton.Text = "&OK";
+      this.okButton.UseVisualStyleBackColor = true;
+      // 
+      // errorProvider
+      // 
+      this.errorProvider.ContainerControl = this;
+      // 
+      // DefineArithmeticProgressionDialog
+      // 
+      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(271, 131);
+      this.Controls.Add(this.okButton);
+      this.Controls.Add(this.cancelButton);
+      this.Controls.Add(this.stepSizeTextBox);
+      this.Controls.Add(this.maximumTextBox);
+      this.Controls.Add(this.minimumTextBox);
+      this.Controls.Add(this.stepSizeLabel);
+      this.Controls.Add(this.maximumLabel);
+      this.Controls.Add(this.minimumLabel);
+      this.MaximizeBox = false;
+      this.MinimizeBox = false;
+      this.Name = "DefineArithmeticProgressionDialog";
+      this.ShowIcon = false;
+      this.ShowInTaskbar = false;
+      this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+      this.Text = "Generate Values";
+      this.TopMost = true;
+      this.Load += new System.EventHandler(this.DefineArithmeticTimeSpanProgressionDialog_Load);
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).EndInit();
+      this.ResumeLayout(false);
+      this.PerformLayout();
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.TextBox stepSizeTextBox;
+    private System.Windows.Forms.TextBox maximumTextBox;
+    private System.Windows.Forms.TextBox minimumTextBox;
+    private System.Windows.Forms.Label stepSizeLabel;
+    private System.Windows.Forms.Label maximumLabel;
+    private System.Windows.Forms.Label minimumLabel;
+    private System.Windows.Forms.Button cancelButton;
+    private System.Windows.Forms.Button okButton;
+    private System.Windows.Forms.ErrorProvider errorProvider;
+  }
+}
Index: /trunk/sources/HeuristicLab.MainForm.WindowsForms/3.3/Dialogs/DefineArithmeticProgressionTimeDialog.cs
===================================================================
--- /trunk/sources/HeuristicLab.MainForm.WindowsForms/3.3/Dialogs/DefineArithmeticProgressionTimeDialog.cs	(revision 9079)
+++ /trunk/sources/HeuristicLab.MainForm.WindowsForms/3.3/Dialogs/DefineArithmeticProgressionTimeDialog.cs	(revision 9079)
@@ -0,0 +1,92 @@
+﻿#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.ComponentModel;
+using System.Globalization;
+using System.Linq;
+using System.Windows.Forms;
+using HeuristicLab.Common;
+
+namespace HeuristicLab.MainForm.WindowsForms {
+  public partial class DefineArithmeticTimeSpanProgressionDialog : Form {
+    public TimeSpan Minimum { get; private set; }
+    public TimeSpan Maximum { get; private set; }
+    public TimeSpan Step { get; private set; }
+
+    public IEnumerable<TimeSpan> Values {
+      get { return EnumerateProgression().Reverse(); }
+    }
+
+    public DefineArithmeticTimeSpanProgressionDialog() {
+      InitializeComponent();
+      Icon = HeuristicLab.Common.Resources.HeuristicLab.Icon;
+      Minimum = TimeSpan.Zero; Maximum = TimeSpan.FromSeconds(60); Step = TimeSpan.FromSeconds(10);
+    }
+    public DefineArithmeticTimeSpanProgressionDialog(TimeSpan minimum, TimeSpan maximum, TimeSpan step)
+      : this() {
+      Minimum = minimum;
+      Maximum = maximum;
+      Step = step;
+    }
+
+    private void DefineArithmeticTimeSpanProgressionDialog_Load(object sender, System.EventArgs e) {
+      minimumTextBox.Text = TimeSpanHelper.FormatNatural(Minimum, true);
+      maximumTextBox.Text = TimeSpanHelper.FormatNatural(Maximum, true);
+      stepSizeTextBox.Text = TimeSpanHelper.FormatNatural(Step, true);
+    }
+
+    private void textBox_Validating(object sender, CancelEventArgs e) {
+      var textBox = (TextBox)sender;
+      TimeSpan value;
+      errorProvider.SetError(textBox, String.Empty);
+      if (!TimeSpanHelper.TryGetFromNaturalFormat(textBox.Text, out value)) {
+        errorProvider.SetError(textBox, "Please enter a valid timespan.");
+        e.Cancel = true;
+        return;
+      }
+      if (textBox == minimumTextBox) Minimum = value;
+      else if (textBox == maximumTextBox) Maximum = value;
+      else if (textBox == stepSizeTextBox) Step = value;
+      okButton.Enabled = IsValid();
+    }
+
+    private bool IsValid() {
+      return Minimum <= Maximum && Step >= TimeSpan.Zero;
+    }
+
+    private IEnumerable<TimeSpan> EnumerateProgression() {
+      var value = Maximum;
+      var minimumIncluded = false;
+      while (value >= Minimum) {
+        if (value == Minimum) minimumIncluded = true;
+        yield return value;
+
+        if (Step == TimeSpan.Zero) break; // a step size of 0 will only output maximum and minimum
+        value = value.Subtract(Step);
+      }
+      if (!minimumIncluded) {
+        yield return Minimum;
+      }
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.MainForm.WindowsForms/3.3/HeuristicLab.MainForm.WindowsForms-3.3.csproj
===================================================================
--- /trunk/sources/HeuristicLab.MainForm.WindowsForms/3.3/HeuristicLab.MainForm.WindowsForms-3.3.csproj	(revision 9078)
+++ /trunk/sources/HeuristicLab.MainForm.WindowsForms/3.3/HeuristicLab.MainForm.WindowsForms-3.3.csproj	(revision 9079)
@@ -126,4 +126,16 @@
       <DependentUpon>DragOverTabControl.cs</DependentUpon>
     </Compile>
+    <Compile Include="Dialogs\DefineArithmeticProgressionTimeDialog.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="Dialogs\DefineArithmeticProgressionTimeDialog.Designer.cs">
+      <DependentUpon>DefineArithmeticProgressionTimeDialog.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Dialogs\DefineArithmeticProgressionDialog.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="Dialogs\DefineArithmeticProgressionDialog.Designer.cs">
+      <DependentUpon>DefineArithmeticProgressionDialog.cs</DependentUpon>
+    </Compile>
     <Compile Include="Plugin.cs" />
     <Compile Include="Views\AsynchronousContentView.cs">
@@ -254,4 +266,5 @@
     </BootstrapperPackage>
   </ItemGroup>
+  <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
Index: /trunk/sources/HeuristicLab.Optimization.Views/3.3/HeuristicLab.Optimization.Views-3.3.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Optimization.Views/3.3/HeuristicLab.Optimization.Views-3.3.csproj	(revision 9078)
+++ /trunk/sources/HeuristicLab.Optimization.Views/3.3/HeuristicLab.Optimization.Views-3.3.csproj	(revision 9079)
@@ -263,4 +263,10 @@
       <DependentUpon>RunCollectionDataTableView.cs</DependentUpon>
     </Compile>
+    <Compile Include="TimeLimitRunView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="TimeLimitRunView.Designer.cs">
+      <DependentUpon>TimeLimitRunView.cs</DependentUpon>
+    </Compile>
     <Compile Include="UserDefinedAlgorithmView.cs">
       <SubType>UserControl</SubType>
Index: /trunk/sources/HeuristicLab.Optimization.Views/3.3/TimeLimitRunView.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization.Views/3.3/TimeLimitRunView.Designer.cs	(revision 9079)
+++ /trunk/sources/HeuristicLab.Optimization.Views/3.3/TimeLimitRunView.Designer.cs	(revision 9079)
@@ -0,0 +1,361 @@
+﻿#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
+
+namespace HeuristicLab.Optimization.Views {
+  partial class TimeLimitRunView {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    #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() {
+      System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TimeLimitRunView));
+      this.timeLimitLabel = new System.Windows.Forms.Label();
+      this.timeLimitTextBox = new System.Windows.Forms.TextBox();
+      this.label1 = new System.Windows.Forms.Label();
+      this.snapshotsTextBox = new System.Windows.Forms.TextBox();
+      this.storeAlgorithmInEachSnapshotCheckBox = new System.Windows.Forms.CheckBox();
+      this.tabControl = new HeuristicLab.MainForm.WindowsForms.DragOverTabControl();
+      this.algorithmTabPage = new System.Windows.Forms.TabPage();
+      this.algorithmViewHost = new HeuristicLab.MainForm.WindowsForms.ViewHost();
+      this.openAlgorithmButton = new System.Windows.Forms.Button();
+      this.newAlgorithmButton = new System.Windows.Forms.Button();
+      this.snapshotsTabPage = new System.Windows.Forms.TabPage();
+      this.snapshotsView = new HeuristicLab.Optimization.Views.RunCollectionView();
+      this.runsTabPage = new System.Windows.Forms.TabPage();
+      this.runsView = new HeuristicLab.Optimization.Views.RunCollectionView();
+      this.openFileDialog = new System.Windows.Forms.OpenFileDialog();
+      this.snapshotButton = new System.Windows.Forms.Button();
+      this.sequenceButton = new System.Windows.Forms.Button();
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit();
+      this.tabControl.SuspendLayout();
+      this.algorithmTabPage.SuspendLayout();
+      this.snapshotsTabPage.SuspendLayout();
+      this.runsTabPage.SuspendLayout();
+      this.SuspendLayout();
+      // 
+      // startButton
+      // 
+      this.startButton.Location = new System.Drawing.Point(0, 440);
+      this.startButton.TabIndex = 9;
+      this.toolTip.SetToolTip(this.startButton, "Start/Resume Optimizer");
+      // 
+      // executionTimeTextBox
+      // 
+      this.executionTimeTextBox.Location = new System.Drawing.Point(412, 444);
+      // 
+      // executionTimeLabel
+      // 
+      this.executionTimeLabel.Location = new System.Drawing.Point(323, 447);
+      // 
+      // pauseButton
+      // 
+      this.pauseButton.Location = new System.Drawing.Point(30, 440);
+      this.pauseButton.TabIndex = 10;
+      this.toolTip.SetToolTip(this.pauseButton, "Pause Optimizer");
+      // 
+      // stopButton
+      // 
+      this.stopButton.Location = new System.Drawing.Point(60, 440);
+      this.stopButton.TabIndex = 11;
+      this.toolTip.SetToolTip(this.stopButton, "Stop Optimizer");
+      // 
+      // resetButton
+      // 
+      this.resetButton.Location = new System.Drawing.Point(90, 440);
+      this.resetButton.TabIndex = 12;
+      this.toolTip.SetToolTip(this.resetButton, "Reset Optimizer");
+      // 
+      // nameTextBox
+      // 
+      this.errorProvider.SetIconAlignment(this.nameTextBox, System.Windows.Forms.ErrorIconAlignment.MiddleLeft);
+      this.errorProvider.SetIconPadding(this.nameTextBox, 2);
+      this.nameTextBox.Location = new System.Drawing.Point(69, 0);
+      this.nameTextBox.Size = new System.Drawing.Size(455, 20);
+      // 
+      // infoLabel
+      // 
+      this.infoLabel.Location = new System.Drawing.Point(530, 3);
+      // 
+      // timeLimitLabel
+      // 
+      this.timeLimitLabel.AutoSize = true;
+      this.timeLimitLabel.Location = new System.Drawing.Point(3, 29);
+      this.timeLimitLabel.Name = "timeLimitLabel";
+      this.timeLimitLabel.Size = new System.Drawing.Size(53, 13);
+      this.timeLimitLabel.TabIndex = 3;
+      this.timeLimitLabel.Text = "Time limit:";
+      // 
+      // timeLimitTextBox
+      // 
+      this.timeLimitTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.timeLimitTextBox.Location = new System.Drawing.Point(69, 26);
+      this.timeLimitTextBox.Name = "timeLimitTextBox";
+      this.timeLimitTextBox.Size = new System.Drawing.Size(455, 20);
+      this.timeLimitTextBox.TabIndex = 4;
+      this.timeLimitTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.timeLimitTextBox_Validating);
+      // 
+      // label1
+      // 
+      this.label1.AutoSize = true;
+      this.label1.Location = new System.Drawing.Point(3, 55);
+      this.label1.Name = "label1";
+      this.label1.Size = new System.Drawing.Size(60, 13);
+      this.label1.TabIndex = 5;
+      this.label1.Text = "Snapshots:";
+      // 
+      // snapshotsTextBox
+      // 
+      this.snapshotsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.snapshotsTextBox.Location = new System.Drawing.Point(69, 52);
+      this.snapshotsTextBox.Name = "snapshotsTextBox";
+      this.snapshotsTextBox.Size = new System.Drawing.Size(175, 20);
+      this.snapshotsTextBox.TabIndex = 6;
+      this.snapshotsTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.snapshotsTextBox_Validating);
+      // 
+      // storeAlgorithmInEachSnapshotCheckBox
+      // 
+      this.storeAlgorithmInEachSnapshotCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+      this.storeAlgorithmInEachSnapshotCheckBox.AutoSize = true;
+      this.storeAlgorithmInEachSnapshotCheckBox.Location = new System.Drawing.Point(340, 54);
+      this.storeAlgorithmInEachSnapshotCheckBox.Name = "storeAlgorithmInEachSnapshotCheckBox";
+      this.storeAlgorithmInEachSnapshotCheckBox.Size = new System.Drawing.Size(184, 17);
+      this.storeAlgorithmInEachSnapshotCheckBox.TabIndex = 7;
+      this.storeAlgorithmInEachSnapshotCheckBox.Text = "Store Algorithm in Each Snapshot";
+      this.storeAlgorithmInEachSnapshotCheckBox.UseVisualStyleBackColor = true;
+      this.storeAlgorithmInEachSnapshotCheckBox.CheckedChanged += new System.EventHandler(this.storeAlgorithmInEachSnapshotCheckBox_CheckedChanged);
+      // 
+      // tabControl
+      // 
+      this.tabControl.AllowDrop = true;
+      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)));
+      this.tabControl.Controls.Add(this.algorithmTabPage);
+      this.tabControl.Controls.Add(this.snapshotsTabPage);
+      this.tabControl.Controls.Add(this.runsTabPage);
+      this.tabControl.Location = new System.Drawing.Point(0, 78);
+      this.tabControl.Name = "tabControl";
+      this.tabControl.SelectedIndex = 0;
+      this.tabControl.Size = new System.Drawing.Size(546, 356);
+      this.tabControl.TabIndex = 8;
+      // 
+      // algorithmTabPage
+      // 
+      this.algorithmTabPage.AllowDrop = true;
+      this.algorithmTabPage.Controls.Add(this.algorithmViewHost);
+      this.algorithmTabPage.Controls.Add(this.openAlgorithmButton);
+      this.algorithmTabPage.Controls.Add(this.newAlgorithmButton);
+      this.algorithmTabPage.Location = new System.Drawing.Point(4, 22);
+      this.algorithmTabPage.Name = "algorithmTabPage";
+      this.algorithmTabPage.Padding = new System.Windows.Forms.Padding(3);
+      this.algorithmTabPage.Size = new System.Drawing.Size(538, 330);
+      this.algorithmTabPage.TabIndex = 1;
+      this.algorithmTabPage.Text = "Algorithm";
+      this.algorithmTabPage.UseVisualStyleBackColor = true;
+      this.algorithmTabPage.DragDrop += new System.Windows.Forms.DragEventHandler(this.algorithmTabPage_DragDrop);
+      this.algorithmTabPage.DragEnter += new System.Windows.Forms.DragEventHandler(this.algorithmTabPage_DragEnterOver);
+      this.algorithmTabPage.DragOver += new System.Windows.Forms.DragEventHandler(this.algorithmTabPage_DragEnterOver);
+      // 
+      // algorithmViewHost
+      // 
+      this.algorithmViewHost.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.algorithmViewHost.Caption = "View";
+      this.algorithmViewHost.Content = null;
+      this.algorithmViewHost.Enabled = false;
+      this.algorithmViewHost.Location = new System.Drawing.Point(6, 36);
+      this.algorithmViewHost.Name = "algorithmViewHost";
+      this.algorithmViewHost.ReadOnly = false;
+      this.algorithmViewHost.Size = new System.Drawing.Size(526, 288);
+      this.algorithmViewHost.TabIndex = 2;
+      this.algorithmViewHost.ViewsLabelVisible = true;
+      this.algorithmViewHost.ViewType = null;
+      // 
+      // openAlgorithmButton
+      // 
+      this.openAlgorithmButton.Image = HeuristicLab.Common.Resources.VSImageLibrary.Open;
+      this.openAlgorithmButton.Location = new System.Drawing.Point(36, 6);
+      this.openAlgorithmButton.Name = "openAlgorithmButton";
+      this.openAlgorithmButton.Size = new System.Drawing.Size(24, 24);
+      this.openAlgorithmButton.TabIndex = 1;
+      this.toolTip.SetToolTip(this.openAlgorithmButton, "Open Optimizer");
+      this.openAlgorithmButton.UseVisualStyleBackColor = true;
+      this.openAlgorithmButton.Click += new System.EventHandler(this.openAlgorithmButton_Click);
+      // 
+      // newAlgorithmButton
+      // 
+      this.newAlgorithmButton.Image = HeuristicLab.Common.Resources.VSImageLibrary.NewDocument;
+      this.newAlgorithmButton.Location = new System.Drawing.Point(6, 6);
+      this.newAlgorithmButton.Name = "newAlgorithmButton";
+      this.newAlgorithmButton.Size = new System.Drawing.Size(24, 24);
+      this.newAlgorithmButton.TabIndex = 0;
+      this.toolTip.SetToolTip(this.newAlgorithmButton, "New Optimizer");
+      this.newAlgorithmButton.UseVisualStyleBackColor = true;
+      this.newAlgorithmButton.Click += new System.EventHandler(this.newAlgorithmButton_Click);
+      // 
+      // snapshotsTabPage
+      // 
+      this.snapshotsTabPage.Controls.Add(this.snapshotsView);
+      this.snapshotsTabPage.Location = new System.Drawing.Point(4, 22);
+      this.snapshotsTabPage.Name = "snapshotsTabPage";
+      this.snapshotsTabPage.Padding = new System.Windows.Forms.Padding(3);
+      this.snapshotsTabPage.Size = new System.Drawing.Size(538, 330);
+      this.snapshotsTabPage.TabIndex = 2;
+      this.snapshotsTabPage.Text = "Snapshots";
+      this.snapshotsTabPage.UseVisualStyleBackColor = true;
+      // 
+      // snapshotsView
+      // 
+      this.snapshotsView.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.snapshotsView.Caption = "RunCollection View";
+      this.snapshotsView.Content = null;
+      this.snapshotsView.Location = new System.Drawing.Point(6, 6);
+      this.snapshotsView.Name = "snapshotsView";
+      this.snapshotsView.ReadOnly = false;
+      this.snapshotsView.Size = new System.Drawing.Size(526, 317);
+      this.snapshotsView.TabIndex = 0;
+      // 
+      // runsTabPage
+      // 
+      this.runsTabPage.Controls.Add(this.runsView);
+      this.runsTabPage.Location = new System.Drawing.Point(4, 22);
+      this.runsTabPage.Name = "runsTabPage";
+      this.runsTabPage.Size = new System.Drawing.Size(538, 330);
+      this.runsTabPage.TabIndex = 3;
+      this.runsTabPage.Text = "Runs";
+      this.runsTabPage.UseVisualStyleBackColor = true;
+      // 
+      // runsView
+      // 
+      this.runsView.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.runsView.Caption = "RunCollection View";
+      this.runsView.Content = null;
+      this.runsView.Location = new System.Drawing.Point(6, 6);
+      this.runsView.Name = "runsView";
+      this.runsView.ReadOnly = false;
+      this.runsView.Size = new System.Drawing.Size(526, 317);
+      this.runsView.TabIndex = 1;
+      // 
+      // openFileDialog
+      // 
+      this.openFileDialog.DefaultExt = "hl";
+      this.openFileDialog.FileName = "Optimizer";
+      this.openFileDialog.Filter = "HeuristicLab Files|*.hl|All Files|*.*";
+      this.openFileDialog.Title = "Open Optimizer";
+      // 
+      // snapshotButton
+      // 
+      this.snapshotButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+      this.snapshotButton.Location = new System.Drawing.Point(120, 440);
+      this.snapshotButton.Name = "snapshotButton";
+      this.snapshotButton.Size = new System.Drawing.Size(24, 24);
+      this.snapshotButton.TabIndex = 13;
+      this.snapshotButton.Text = "Snapshot";
+      this.toolTip.SetToolTip(this.snapshotButton, "Create Snapshot");
+      this.snapshotButton.UseVisualStyleBackColor = true;
+      this.snapshotButton.Click += new System.EventHandler(this.snapshotButton_Click);
+      // 
+      // sequenceButton
+      // 
+      this.sequenceButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+      this.sequenceButton.Location = new System.Drawing.Point(250, 50);
+      this.sequenceButton.Name = "sequenceButton";
+      this.sequenceButton.Size = new System.Drawing.Size(75, 23);
+      this.sequenceButton.TabIndex = 16;
+      this.sequenceButton.Text = "Sequence...";
+      this.sequenceButton.UseVisualStyleBackColor = true;
+      this.sequenceButton.Click += new System.EventHandler(this.sequenceButton_Click);
+      // 
+      // TimeLimitRunView
+      // 
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
+      this.Controls.Add(this.sequenceButton);
+      this.Controls.Add(this.snapshotButton);
+      this.Controls.Add(this.tabControl);
+      this.Controls.Add(this.timeLimitTextBox);
+      this.Controls.Add(this.timeLimitLabel);
+      this.Controls.Add(this.label1);
+      this.Controls.Add(this.snapshotsTextBox);
+      this.Controls.Add(this.storeAlgorithmInEachSnapshotCheckBox);
+      this.Name = "TimeLimitRunView";
+      this.Size = new System.Drawing.Size(549, 464);
+      this.Controls.SetChildIndex(this.storeAlgorithmInEachSnapshotCheckBox, 0);
+      this.Controls.SetChildIndex(this.snapshotsTextBox, 0);
+      this.Controls.SetChildIndex(this.label1, 0);
+      this.Controls.SetChildIndex(this.timeLimitLabel, 0);
+      this.Controls.SetChildIndex(this.timeLimitTextBox, 0);
+      this.Controls.SetChildIndex(this.tabControl, 0);
+      this.Controls.SetChildIndex(this.nameLabel, 0);
+      this.Controls.SetChildIndex(this.nameTextBox, 0);
+      this.Controls.SetChildIndex(this.infoLabel, 0);
+      this.Controls.SetChildIndex(this.resetButton, 0);
+      this.Controls.SetChildIndex(this.stopButton, 0);
+      this.Controls.SetChildIndex(this.pauseButton, 0);
+      this.Controls.SetChildIndex(this.executionTimeLabel, 0);
+      this.Controls.SetChildIndex(this.executionTimeTextBox, 0);
+      this.Controls.SetChildIndex(this.startButton, 0);
+      this.Controls.SetChildIndex(this.snapshotButton, 0);
+      this.Controls.SetChildIndex(this.sequenceButton, 0);
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).EndInit();
+      this.tabControl.ResumeLayout(false);
+      this.algorithmTabPage.ResumeLayout(false);
+      this.snapshotsTabPage.ResumeLayout(false);
+      this.runsTabPage.ResumeLayout(false);
+      this.ResumeLayout(false);
+      this.PerformLayout();
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.Label timeLimitLabel;
+    private System.Windows.Forms.TextBox timeLimitTextBox;
+    private System.Windows.Forms.Label label1;
+    private System.Windows.Forms.TextBox snapshotsTextBox;
+    private System.Windows.Forms.CheckBox storeAlgorithmInEachSnapshotCheckBox;
+    private MainForm.WindowsForms.DragOverTabControl tabControl;
+    private System.Windows.Forms.TabPage algorithmTabPage;
+    private MainForm.WindowsForms.ViewHost algorithmViewHost;
+    private System.Windows.Forms.Button openAlgorithmButton;
+    private System.Windows.Forms.Button newAlgorithmButton;
+    private System.Windows.Forms.TabPage snapshotsTabPage;
+    private RunCollectionView snapshotsView;
+    private System.Windows.Forms.TabPage runsTabPage;
+    private RunCollectionView runsView;
+    private System.Windows.Forms.OpenFileDialog openFileDialog;
+    private System.Windows.Forms.Button snapshotButton;
+    private System.Windows.Forms.Button sequenceButton;
+  }
+}
Index: /trunk/sources/HeuristicLab.Optimization.Views/3.3/TimeLimitRunView.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization.Views/3.3/TimeLimitRunView.cs	(revision 9079)
+++ /trunk/sources/HeuristicLab.Optimization.Views/3.3/TimeLimitRunView.cs	(revision 9079)
@@ -0,0 +1,310 @@
+﻿#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.ComponentModel;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Windows.Forms;
+using HeuristicLab.Collections;
+using HeuristicLab.Common;
+using HeuristicLab.Common.Resources;
+using HeuristicLab.Core;
+using HeuristicLab.Core.Views;
+using HeuristicLab.MainForm;
+using HeuristicLab.MainForm.WindowsForms;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.Optimization.Views {
+  [View("TimeLimit Run View")]
+  [Content(typeof(TimeLimitRun), IsDefaultView = true)]
+  public partial class TimeLimitRunView : IOptimizerView {
+    protected TypeSelectorDialog algorithmTypeSelectorDialog;
+    protected virtual bool SuppressEvents { get; set; }
+
+    public new TimeLimitRun Content {
+      get { return (TimeLimitRun)base.Content; }
+      set { base.Content = value; }
+    }
+
+    public TimeLimitRunView() {
+      InitializeComponent();
+      snapshotButton.Text = String.Empty;
+      snapshotButton.Image = VSImageLibrary.Camera;
+    }
+
+    protected override void Dispose(bool disposing) {
+      if (disposing) {
+        if (algorithmTypeSelectorDialog != null) algorithmTypeSelectorDialog.Dispose();
+        if (components != null) components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    protected override void DeregisterContentEvents() {
+      Content.PropertyChanged -= Content_PropertyChanged;
+      Content.SnapshotTimes.ItemsAdded -= Content_SnapshotTimes_Changed;
+      Content.SnapshotTimes.ItemsMoved -= Content_SnapshotTimes_Changed;
+      Content.SnapshotTimes.ItemsRemoved -= Content_SnapshotTimes_Changed;
+      Content.SnapshotTimes.ItemsReplaced -= Content_SnapshotTimes_Changed;
+      Content.SnapshotTimes.CollectionReset -= Content_SnapshotTimes_Changed;
+      base.DeregisterContentEvents();
+    }
+    protected override void RegisterContentEvents() {
+      base.RegisterContentEvents();
+      Content.PropertyChanged += Content_PropertyChanged;
+      Content.SnapshotTimes.ItemsAdded += Content_SnapshotTimes_Changed;
+      Content.SnapshotTimes.ItemsMoved += Content_SnapshotTimes_Changed;
+      Content.SnapshotTimes.ItemsRemoved += Content_SnapshotTimes_Changed;
+      Content.SnapshotTimes.ItemsReplaced += Content_SnapshotTimes_Changed;
+      Content.SnapshotTimes.CollectionReset += Content_SnapshotTimes_Changed;
+    }
+
+    protected override void OnContentChanged() {
+      base.OnContentChanged();
+      SuppressEvents = true;
+      try {
+        if (Content == null) {
+          timeLimitTextBox.Text = TimeSpanHelper.FormatNatural(TimeSpan.FromSeconds(60));
+          snapshotsTextBox.Text = String.Empty;
+          storeAlgorithmInEachSnapshotCheckBox.Checked = false;
+          algorithmViewHost.Content = null;
+          snapshotsView.Content = null;
+          runsView.Content = null;
+        } else {
+          timeLimitTextBox.Text = TimeSpanHelper.FormatNatural(Content.MaximumExecutionTime);
+          snapshotsTextBox.Text = String.Join(" ; ", Content.SnapshotTimes.Select(x => TimeSpanHelper.FormatNatural(x, true)));
+          storeAlgorithmInEachSnapshotCheckBox.Checked = Content.StoreAlgorithmInEachSnapshot;
+          algorithmViewHost.Content = Content.Algorithm;
+          snapshotsView.Content = Content.Snapshots;
+          runsView.Content = Content.Runs;
+        }
+      } finally { SuppressEvents = false; }
+    }
+
+    protected override void SetEnabledStateOfControls() {
+      base.SetEnabledStateOfControls();
+      timeLimitTextBox.Enabled = Content != null && !ReadOnly;
+      snapshotsTextBox.Enabled = Content != null && !ReadOnly;
+      storeAlgorithmInEachSnapshotCheckBox.Enabled = Content != null && !ReadOnly;
+      newAlgorithmButton.Enabled = Content != null && !ReadOnly;
+      openAlgorithmButton.Enabled = Content != null && !ReadOnly;
+      algorithmViewHost.Enabled = Content != null;
+      snapshotsView.Enabled = Content != null;
+      runsView.Enabled = Content != null;
+    }
+
+    protected override void SetEnabledStateOfExecutableButtons() {
+      base.SetEnabledStateOfExecutableButtons();
+      snapshotButton.Enabled = Content != null && Content.Algorithm != null && Content.ExecutionState == ExecutionState.Paused;
+    }
+
+    protected override void OnClosed(FormClosedEventArgs e) {
+      if ((Content != null) && (Content.ExecutionState == ExecutionState.Started)) {
+        //The content must be stopped if no other view showing the content is available
+        var optimizers = MainFormManager.MainForm.Views.OfType<IContentView>().Where(v => v != this).Select(v => v.Content).OfType<IAlgorithm>();
+        if (!optimizers.Contains(Content.Algorithm)) {
+          var nestedOptimizers = optimizers.SelectMany(opt => opt.NestedOptimizers);
+          if (!nestedOptimizers.Contains(Content)) Content.Stop();
+        }
+      }
+      base.OnClosed(e);
+    }
+
+    #region Event Handlers
+    #region Content events
+    private void Content_PropertyChanged(object sender, PropertyChangedEventArgs e) {
+      switch (e.PropertyName) {
+        case "MaximumExecutionTime":
+          SuppressEvents = true;
+          try {
+            timeLimitTextBox.Text = TimeSpanHelper.FormatNatural(Content.MaximumExecutionTime);
+          } finally { SuppressEvents = false; }
+          break;
+        case "SnapshotTimes":
+          SuppressEvents = true;
+          try {
+            if (Content.SnapshotTimes.Any())
+              snapshotsTextBox.Text = String.Join(" ; ", Content.SnapshotTimes.Select(x => TimeSpanHelper.FormatNatural(x, true)));
+            else snapshotsTextBox.Text = String.Empty;
+            Content.SnapshotTimes.ItemsAdded += Content_SnapshotTimes_Changed;
+            Content.SnapshotTimes.ItemsMoved += Content_SnapshotTimes_Changed;
+            Content.SnapshotTimes.ItemsRemoved += Content_SnapshotTimes_Changed;
+            Content.SnapshotTimes.ItemsReplaced += Content_SnapshotTimes_Changed;
+            Content.SnapshotTimes.CollectionReset += Content_SnapshotTimes_Changed;
+          } finally { SuppressEvents = false; }
+          break;
+        case "StoreAlgorithmInEachSnapshot":
+          SuppressEvents = true;
+          try {
+            storeAlgorithmInEachSnapshotCheckBox.Checked = Content.StoreAlgorithmInEachSnapshot;
+          } finally { SuppressEvents = false; }
+          break;
+        case "Algorithm":
+          SuppressEvents = true;
+          try {
+            algorithmViewHost.Content = Content.Algorithm;
+          } finally { SuppressEvents = false; }
+          break;
+        case "Snapshots":
+          SuppressEvents = true;
+          try {
+            snapshotsView.Content = Content.Snapshots;
+          } finally { SuppressEvents = false; }
+          break;
+        case "Runs":
+          SuppressEvents = true;
+          try {
+            runsView.Content = Content.Runs;
+          } finally { SuppressEvents = false; }
+          break;
+      }
+    }
+
+    private void Content_SnapshotTimes_Changed(object sender, EventArgs e) {
+      SuppressEvents = true;
+      try {
+        if (Content.SnapshotTimes.Any())
+          snapshotsTextBox.Text = string.Join(" ; ", Content.SnapshotTimes.Select(x => TimeSpanHelper.FormatNatural(x, true)));
+        else snapshotsTextBox.Text = String.Empty;
+      } finally { SuppressEvents = false; }
+    }
+    #endregion
+
+    #region Control events
+    private void timeLimitTextBox_Validating(object sender, CancelEventArgs e) {
+      if (SuppressEvents) return;
+      TimeSpan ts;
+      if (!TimeSpanHelper.TryGetFromNaturalFormat(timeLimitTextBox.Text, out ts)) {
+        e.Cancel = true;
+        errorProvider.SetError(timeLimitTextBox, "Please enter a valid time span, e.g. 60, 20s, 45 seconds, 3h, 1 hour, 4 d, 2 days");
+      } else {
+        Content.MaximumExecutionTime = ts;
+        e.Cancel = false;
+        errorProvider.SetError(timeLimitTextBox, null);
+      }
+    }
+
+    private void snapshotsTextBox_Validating(object sender, CancelEventArgs e) {
+      if (SuppressEvents) return;
+      e.Cancel = false;
+      errorProvider.SetError(snapshotsTextBox, null);
+
+      var snapshotTimes = new ObservableList<TimeSpan>();
+      var matches = Regex.Matches(snapshotsTextBox.Text, @"(\d+[ \t]*\w+)");
+      foreach (Match m in matches) {
+        TimeSpan value;
+        if (!TimeSpanHelper.TryGetFromNaturalFormat(m.Value, out value)) {
+          e.Cancel = !snapshotsTextBox.ReadOnly && snapshotsTextBox.Enabled; // don't cancel an operation that cannot be edited
+          errorProvider.SetError(snapshotsTextBox, "Error parsing " + m.Value + ", please provide a valid time span, e.g. 60, 20s, 45 seconds, 3h, 1 hour, 4 d, 2 days");
+          return;
+        } else {
+          snapshotTimes.Add(value);
+        }
+      }
+      Content.SnapshotTimes = snapshotTimes;
+    }
+
+    private void storeAlgorithmInEachSnapshotCheckBox_CheckedChanged(object sender, EventArgs e) {
+      if (SuppressEvents) return;
+      SuppressEvents = true;
+      try {
+        Content.StoreAlgorithmInEachSnapshot = storeAlgorithmInEachSnapshotCheckBox.Checked;
+      } finally { SuppressEvents = false; }
+    }
+
+    private void newAlgorithmButton_Click(object sender, EventArgs e) {
+      if (algorithmTypeSelectorDialog == null) {
+        algorithmTypeSelectorDialog = new TypeSelectorDialog { Caption = "Select Algorithm" };
+        algorithmTypeSelectorDialog.TypeSelector.Caption = "Available Algorithms";
+        algorithmTypeSelectorDialog.TypeSelector.Configure(typeof(IAlgorithm), false, true);
+      }
+      if (algorithmTypeSelectorDialog.ShowDialog(this) == DialogResult.OK) {
+        try {
+          Content.Algorithm = (IAlgorithm)algorithmTypeSelectorDialog.TypeSelector.CreateInstanceOfSelectedType();
+        } catch (Exception ex) {
+          ErrorHandling.ShowErrorDialog(this, ex);
+        }
+      }
+    }
+
+    private void openAlgorithmButton_Click(object sender, EventArgs e) {
+      openFileDialog.Title = "Open Algorithm";
+      if (openFileDialog.ShowDialog(this) == DialogResult.OK) {
+        newAlgorithmButton.Enabled = openAlgorithmButton.Enabled = false;
+        algorithmViewHost.Enabled = false;
+
+        ContentManager.LoadAsync(openFileDialog.FileName, delegate(IStorableContent content, Exception error) {
+          try {
+            if (error != null) throw error;
+            var algorithm = content as IAlgorithm;
+            if (algorithm == null)
+              MessageBox.Show(this, "The selected file does not contain an algorithm.", "Invalid File", MessageBoxButtons.OK, MessageBoxIcon.Error);
+            else
+              Content.Algorithm = algorithm;
+          } catch (Exception ex) {
+            ErrorHandling.ShowErrorDialog(this, ex);
+          } finally {
+            Invoke(new Action(delegate() {
+              algorithmViewHost.Enabled = true;
+              newAlgorithmButton.Enabled = openAlgorithmButton.Enabled = true;
+            }));
+          }
+        });
+      }
+    }
+
+    private void algorithmTabPage_DragEnterOver(object sender, DragEventArgs e) {
+      e.Effect = DragDropEffects.None;
+      if (!ReadOnly && (e.Data.GetData(Constants.DragDropDataFormat) is IAlgorithm)) {
+        if ((e.KeyState & 32) == 32) e.Effect = DragDropEffects.Link;  // ALT key
+        else if ((e.KeyState & 4) == 4) e.Effect = DragDropEffects.Move;  // SHIFT key
+        else if (e.AllowedEffect.HasFlag(DragDropEffects.Copy)) e.Effect = DragDropEffects.Copy;
+        else if (e.AllowedEffect.HasFlag(DragDropEffects.Move)) e.Effect = DragDropEffects.Move;
+        else if (e.AllowedEffect.HasFlag(DragDropEffects.Link)) e.Effect = DragDropEffects.Link;
+      }
+    }
+
+    private void algorithmTabPage_DragDrop(object sender, DragEventArgs e) {
+      if (e.Effect != DragDropEffects.None) {
+        var algorithm = e.Data.GetData(Constants.DragDropDataFormat) as IAlgorithm;
+        if (e.Effect.HasFlag(DragDropEffects.Copy)) algorithm = (IAlgorithm)algorithm.Clone();
+        Content.Algorithm = algorithm;
+      }
+    }
+
+    private void snapshotButton_Click(object sender, EventArgs e) {
+      Content.Snapshot();
+    }
+
+    private void sequenceButton_Click(object sender, EventArgs e) {
+      using (var dialog = new DefineArithmeticTimeSpanProgressionDialog(TimeSpan.FromSeconds(1), Content.MaximumExecutionTime, TimeSpan.FromSeconds(1))) {
+        if (dialog.ShowDialog() == DialogResult.OK) {
+          if (dialog.Values.Any())
+            Content.SnapshotTimes = new ObservableList<TimeSpan>(dialog.Values);
+          else Content.SnapshotTimes = new ObservableList<TimeSpan>();
+        }
+      }
+    }
+    #endregion
+    #endregion
+  }
+}
Index: unk/sources/HeuristicLab.Optimization/3.3/BatchRun.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/BatchRun.cs	(revision 9078)
+++ 	(revision )
@@ -1,454 +1,0 @@
-#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 HeuristicLab.Collections;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Optimization {
-  internal enum BatchRunAction { None, Prepare, Start, Pause, Stop };
-
-  /// <summary>
-  /// A run in which an optimizer is executed a given number of times.
-  /// </summary>
-  [Item("Batch Run", "A run in which an optimizer is executed a given number of times.")]
-  [Creatable("Testing & Analysis")]
-  [StorableClass]
-  public sealed class BatchRun : NamedItem, IOptimizer, IStorableContent {
-    public string Filename { get; set; }
-
-    public static new Image StaticItemImage {
-      get { return HeuristicLab.Common.Resources.VSImageLibrary.Event; }
-    }
-    public override Image ItemImage {
-      get {
-        if (ExecutionState == ExecutionState.Prepared) return HeuristicLab.Common.Resources.VSImageLibrary.BatchRunPrepared;
-        else if (ExecutionState == ExecutionState.Started) return HeuristicLab.Common.Resources.VSImageLibrary.BatchRunStarted;
-        else if (ExecutionState == ExecutionState.Paused) return HeuristicLab.Common.Resources.VSImageLibrary.BatchRunPaused;
-        else if (ExecutionState == ExecutionState.Stopped) return HeuristicLab.Common.Resources.VSImageLibrary.BatchRunStopped;
-        else return base.ItemImage;
-      }
-    }
-
-    [Storable]
-    private ExecutionState executionState;
-    public ExecutionState ExecutionState {
-      get { return executionState; }
-      private set {
-        if (executionState != value) {
-          executionState = value;
-          OnExecutionStateChanged();
-          OnItemImageChanged();
-        }
-      }
-    }
-
-    [Storable]
-    private TimeSpan executionTime;
-    public TimeSpan ExecutionTime {
-      get {
-        if ((Optimizer != null) && (Optimizer.ExecutionState != ExecutionState.Stopped))
-          return executionTime + Optimizer.ExecutionTime;
-        else
-          return executionTime;
-      }
-      private set {
-        executionTime = value;
-        OnExecutionTimeChanged();
-      }
-    }
-
-    [Storable]
-    private TimeSpan runsExecutionTime;
-
-    [Storable]
-    private IOptimizer optimizer;
-    public IOptimizer Optimizer {
-      get { return optimizer; }
-      set {
-        if (optimizer != value) {
-          if (optimizer != null) {
-            DeregisterOptimizerEvents();
-            IEnumerable<IRun> runs = optimizer.Runs;
-            optimizer = null; //necessary to avoid removing the runs from the old optimizer
-            Runs.RemoveRange(runs);
-          }
-          optimizer = value;
-          if (optimizer != null) {
-            RegisterOptimizerEvents();
-            Runs.AddRange(optimizer.Runs);
-          }
-          OnOptimizerChanged();
-          Prepare();
-        }
-      }
-    }
-    // BackwardsCompatibility3.3
-    #region Backwards compatible code (remove with 3.4)
-    [Storable(AllowOneWay = true)]
-    private IAlgorithm algorithm {
-      set { optimizer = value; }
-    }
-    #endregion
-
-    [Storable]
-    private int repetitions;
-    public int Repetitions {
-      get { return repetitions; }
-      set {
-        if (repetitions != value) {
-          repetitions = value;
-          OnRepetitionsChanged();
-          if ((Optimizer != null) && (Optimizer.ExecutionState == ExecutionState.Stopped))
-            Prepare();
-        }
-      }
-    }
-    [Storable]
-    private int repetitionsCounter;
-    public int RepetitionsCounter {
-      get { return repetitionsCounter; }
-      private set {
-        if (value != repetitionsCounter) {
-          repetitionsCounter = value;
-          OnRepetitionsCounterChanged();
-        }
-      }
-    }
-
-    [Storable]
-    private RunCollection runs;
-    public RunCollection Runs {
-      get { return runs; }
-      private set {
-        if (value == null) throw new ArgumentNullException();
-        if (runs != value) {
-          if (runs != null) DeregisterRunsEvents();
-          runs = value;
-          if (runs != null) RegisterRunsEvents();
-        }
-      }
-    }
-
-    public IEnumerable<IOptimizer> NestedOptimizers {
-      get {
-        if (Optimizer == null) yield break;
-
-        yield return Optimizer;
-        foreach (IOptimizer opt in Optimizer.NestedOptimizers)
-          yield return opt;
-      }
-    }
-
-    private BatchRunAction batchRunAction = BatchRunAction.None;
-
-    public BatchRun()
-      : base() {
-      name = ItemName;
-      description = ItemDescription;
-      executionState = ExecutionState.Stopped;
-      executionTime = TimeSpan.Zero;
-      runsExecutionTime = TimeSpan.Zero;
-      repetitions = 10;
-      repetitionsCounter = 0;
-      Runs = new RunCollection { OptimizerName = Name };
-    }
-    public BatchRun(string name)
-      : base(name) {
-      description = ItemDescription;
-      executionState = ExecutionState.Stopped;
-      executionTime = TimeSpan.Zero;
-      runsExecutionTime = TimeSpan.Zero;
-      repetitions = 10;
-      repetitionsCounter = 0;
-      Runs = new RunCollection { OptimizerName = Name };
-    }
-    public BatchRun(string name, string description)
-      : base(name, description) {
-      executionState = ExecutionState.Stopped;
-      executionTime = TimeSpan.Zero;
-      runsExecutionTime = TimeSpan.Zero;
-      repetitions = 10;
-      repetitionsCounter = 0;
-      Runs = new RunCollection { OptimizerName = Name };
-    }
-    [StorableConstructor]
-    private BatchRun(bool deserializing) : base(deserializing) { }
-    [StorableHook(HookType.AfterDeserialization)]
-    private void AfterDeserialization() {
-      Initialize();
-    }
-
-    private BatchRun(BatchRun original, Cloner cloner)
-      : base(original, cloner) {
-      executionState = original.executionState;
-      executionTime = original.executionTime;
-      runsExecutionTime = original.runsExecutionTime;
-      optimizer = cloner.Clone(original.optimizer);
-      repetitions = original.repetitions;
-      repetitionsCounter = original.repetitionsCounter;
-      runs = cloner.Clone(original.runs);
-      batchRunAction = original.batchRunAction;
-      Initialize();
-    }
-    public override IDeepCloneable Clone(Cloner cloner) {
-      if (ExecutionState == ExecutionState.Started) throw new InvalidOperationException(string.Format("Clone not allowed in execution state \"{0}\".", ExecutionState));
-      return new BatchRun(this, cloner);
-    }
-
-    private void Initialize() {
-      if (optimizer != null) RegisterOptimizerEvents();
-      if (runs != null) RegisterRunsEvents();
-    }
-
-    public void Prepare() {
-      Prepare(false);
-    }
-    public void Prepare(bool clearRuns) {
-      if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused) && (ExecutionState != ExecutionState.Stopped))
-        throw new InvalidOperationException(string.Format("Prepare not allowed in execution state \"{0}\".", ExecutionState));
-      if (Optimizer != null) {
-        ExecutionTime = TimeSpan.Zero;
-        RepetitionsCounter = 0;
-        if (clearRuns) runs.Clear();
-        batchRunAction = BatchRunAction.Prepare;
-        // a race-condition may occur when the optimizer has changed the state by itself in the meantime
-        try { Optimizer.Prepare(clearRuns); }
-        catch (InvalidOperationException) { }
-      } else {
-        ExecutionState = ExecutionState.Stopped;
-      }
-    }
-    public void Start() {
-      if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused))
-        throw new InvalidOperationException(string.Format("Start not allowed in execution state \"{0}\".", ExecutionState));
-      if (Optimizer == null) return;
-      batchRunAction = BatchRunAction.Start;
-      if (Optimizer.ExecutionState == ExecutionState.Stopped) Optimizer.Prepare();
-      // a race-condition may occur when the optimizer has changed the state by itself in the meantime
-      try { Optimizer.Start(); }
-      catch (InvalidOperationException) { }
-    }
-    public void Pause() {
-      if (ExecutionState != ExecutionState.Started)
-        throw new InvalidOperationException(string.Format("Pause not allowed in execution state \"{0}\".", ExecutionState));
-      if (Optimizer == null) return;
-      batchRunAction = BatchRunAction.Pause;
-      if (Optimizer.ExecutionState != ExecutionState.Started) return;
-      // a race-condition may occur when the optimizer has changed the state by itself in the meantime
-      try { Optimizer.Pause(); }
-      catch (InvalidOperationException) { }
-    }
-    public void Stop() {
-      if ((ExecutionState != ExecutionState.Started) && (ExecutionState != ExecutionState.Paused))
-        throw new InvalidOperationException(string.Format("Stop not allowed in execution state \"{0}\".", ExecutionState));
-      if (Optimizer == null) return;
-      batchRunAction = BatchRunAction.Stop;
-      if (Optimizer.ExecutionState != ExecutionState.Started && Optimizer.ExecutionState != ExecutionState.Paused) {
-        OnStopped();
-        return;
-      }
-      // a race-condition may occur when the optimizer has changed the state by itself in the meantime
-      try { Optimizer.Stop(); }
-      catch (InvalidOperationException) { }
-    }
-
-    #region Events
-    protected override void OnNameChanged() {
-      base.OnNameChanged();
-      runs.OptimizerName = Name;
-    }
-
-    public event EventHandler ExecutionStateChanged;
-    private void OnExecutionStateChanged() {
-      EventHandler handler = ExecutionStateChanged;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler ExecutionTimeChanged;
-    private void OnExecutionTimeChanged() {
-      EventHandler handler = ExecutionTimeChanged;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler OptimizerChanged;
-    private void OnOptimizerChanged() {
-      EventHandler handler = OptimizerChanged;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler RepetitionsChanged;
-    private void OnRepetitionsChanged() {
-      EventHandler handler = RepetitionsChanged;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler RepetetionsCounterChanged;
-    private void OnRepetitionsCounterChanged() {
-      EventHandler handler = RepetetionsCounterChanged;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler Prepared;
-    private void OnPrepared() {
-      batchRunAction = BatchRunAction.None;
-      ExecutionState = ExecutionState.Prepared;
-      EventHandler handler = Prepared;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler Started;
-    private void OnStarted() {
-      // no reset of BatchRunAction.Started, because we need to differ which of the two was started by the user
-      ExecutionState = ExecutionState.Started;
-      EventHandler handler = Started;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler Paused;
-    private void OnPaused() {
-      batchRunAction = BatchRunAction.None;
-      ExecutionState = ExecutionState.Paused;
-      EventHandler handler = Paused;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler Stopped;
-    private void OnStopped() {
-      batchRunAction = BatchRunAction.None;
-      ExecutionState = ExecutionState.Stopped;
-      EventHandler handler = Stopped;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler<EventArgs<Exception>> ExceptionOccurred;
-    private void OnExceptionOccurred(Exception exception) {
-      EventHandler<EventArgs<Exception>> handler = ExceptionOccurred;
-      if (handler != null) handler(this, new EventArgs<Exception>(exception));
-    }
-
-    private void RegisterOptimizerEvents() {
-      optimizer.ExceptionOccurred += new EventHandler<EventArgs<Exception>>(Optimizer_ExceptionOccurred);
-      optimizer.ExecutionTimeChanged += new EventHandler(Optimizer_ExecutionTimeChanged);
-      optimizer.Paused += new EventHandler(Optimizer_Paused);
-      optimizer.Prepared += new EventHandler(Optimizer_Prepared);
-      optimizer.Started += new EventHandler(Optimizer_Started);
-      optimizer.Stopped += new EventHandler(Optimizer_Stopped);
-      optimizer.Runs.CollectionReset += new CollectionItemsChangedEventHandler<IRun>(Optimizer_Runs_CollectionReset);
-      optimizer.Runs.ItemsAdded += new CollectionItemsChangedEventHandler<IRun>(Optimizer_Runs_ItemsAdded);
-      optimizer.Runs.ItemsRemoved += new CollectionItemsChangedEventHandler<IRun>(Optimizer_Runs_ItemsRemoved);
-    }
-    private void DeregisterOptimizerEvents() {
-      optimizer.ExceptionOccurred -= new EventHandler<EventArgs<Exception>>(Optimizer_ExceptionOccurred);
-      optimizer.ExecutionTimeChanged -= new EventHandler(Optimizer_ExecutionTimeChanged);
-      optimizer.Paused -= new EventHandler(Optimizer_Paused);
-      optimizer.Prepared -= new EventHandler(Optimizer_Prepared);
-      optimizer.Started -= new EventHandler(Optimizer_Started);
-      optimizer.Stopped -= new EventHandler(Optimizer_Stopped);
-      optimizer.Runs.CollectionReset -= new CollectionItemsChangedEventHandler<IRun>(Optimizer_Runs_CollectionReset);
-      optimizer.Runs.ItemsAdded -= new CollectionItemsChangedEventHandler<IRun>(Optimizer_Runs_ItemsAdded);
-      optimizer.Runs.ItemsRemoved -= new CollectionItemsChangedEventHandler<IRun>(Optimizer_Runs_ItemsRemoved);
-    }
-    private void Optimizer_ExceptionOccurred(object sender, EventArgs<Exception> e) {
-      OnExceptionOccurred(e.Value);
-    }
-    private void Optimizer_ExecutionTimeChanged(object sender, EventArgs e) {
-      OnExecutionTimeChanged();
-    }
-    private void Optimizer_Paused(object sender, EventArgs e) {
-      if (ExecutionState == ExecutionState.Started) {
-        OnPaused();
-      }
-    }
-    private void Optimizer_Prepared(object sender, EventArgs e) {
-      if (batchRunAction == BatchRunAction.Prepare || ExecutionState == ExecutionState.Stopped) {
-        ExecutionTime = TimeSpan.Zero;
-        runsExecutionTime = TimeSpan.Zero;
-        RepetitionsCounter = 0;
-        OnPrepared();
-      }
-    }
-    private void Optimizer_Started(object sender, EventArgs e) {
-      if (ExecutionState != ExecutionState.Started)
-        OnStarted();
-    }
-    private void Optimizer_Stopped(object sender, EventArgs e) {
-      RepetitionsCounter++;
-      ExecutionTime += runsExecutionTime;
-      runsExecutionTime = TimeSpan.Zero;
-
-      if (batchRunAction == BatchRunAction.Stop) OnStopped();
-      else if (repetitionsCounter >= repetitions) OnStopped();
-      else if (batchRunAction == BatchRunAction.Pause) OnPaused();
-      else if (batchRunAction == BatchRunAction.Start) {
-        Optimizer.Prepare();
-        Optimizer.Start();
-      } else if (executionState == ExecutionState.Started) {
-        // if the batch run hasn't been started but the inner optimizer was run then pause
-        OnPaused();
-      } else OnStopped();
-    }
-    private void Optimizer_Runs_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRun> e) {
-      Runs.RemoveRange(e.OldItems);
-      Runs.AddRange(e.Items);
-    }
-    private void Optimizer_Runs_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IRun> e) {
-      Runs.AddRange(e.Items);
-    }
-    private void Optimizer_Runs_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRun> e) {
-      Runs.RemoveRange(e.Items);
-    }
-
-    private void RegisterRunsEvents() {
-      runs.CollectionReset += new CollectionItemsChangedEventHandler<IRun>(Runs_CollectionReset);
-      runs.ItemsAdded += new CollectionItemsChangedEventHandler<IRun>(Runs_ItemsAdded);
-      runs.ItemsRemoved += new CollectionItemsChangedEventHandler<IRun>(Runs_ItemsRemoved);
-    }
-
-    private void DeregisterRunsEvents() {
-      runs.CollectionReset -= new CollectionItemsChangedEventHandler<IRun>(Runs_CollectionReset);
-      runs.ItemsAdded -= new CollectionItemsChangedEventHandler<IRun>(Runs_ItemsAdded);
-      runs.ItemsRemoved -= new CollectionItemsChangedEventHandler<IRun>(Runs_ItemsRemoved);
-    }
-    private void Runs_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRun> e) {
-      if (Optimizer != null) Optimizer.Runs.RemoveRange(e.OldItems);
-      foreach (IRun run in e.Items) {
-        IItem item;
-        run.Results.TryGetValue("Execution Time", out item);
-        TimeSpanValue executionTime = item as TimeSpanValue;
-        if (executionTime != null) ExecutionTime += executionTime.Value;
-      }
-    }
-    private void Runs_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IRun> e) {
-      foreach (IRun run in e.Items) {
-        IItem item;
-        run.Results.TryGetValue("Execution Time", out item);
-        TimeSpanValue executionTime = item as TimeSpanValue;
-        if (executionTime != null) {
-          if (Optimizer.ExecutionState == ExecutionState.Started)
-            runsExecutionTime += executionTime.Value;
-          else
-            ExecutionTime += executionTime.Value;
-        }
-      }
-    }
-    private void Runs_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRun> e) {
-      if (Optimizer != null) Optimizer.Runs.RemoveRange(e.Items);
-    }
-    #endregion
-  }
-}
Index: unk/sources/HeuristicLab.Optimization/3.3/Experiment.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/Experiment.cs	(revision 9078)
+++ 	(revision )
@@ -1,412 +1,0 @@
-#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 HeuristicLab.Collections;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Optimization {
-  /// <summary>
-  /// An experiment which contains multiple algorithms, batch runs or other experiments.
-  /// </summary>
-  [Item("Experiment", "An experiment which contains multiple algorithms, batch runs or other experiments.")]
-  [Creatable("Testing & Analysis")]
-  [StorableClass]
-  public sealed class Experiment : NamedItem, IOptimizer, IStorableContent {
-    public string Filename { get; set; }
-
-    public static new Image StaticItemImage {
-      get { return HeuristicLab.Common.Resources.VSImageLibrary.Event; }
-    }
-    public override Image ItemImage {
-      get {
-        if (ExecutionState == ExecutionState.Prepared) return HeuristicLab.Common.Resources.VSImageLibrary.ExperimentPrepared;
-        else if (ExecutionState == ExecutionState.Started) return HeuristicLab.Common.Resources.VSImageLibrary.ExperimentStarted;
-        else if (ExecutionState == ExecutionState.Paused) return HeuristicLab.Common.Resources.VSImageLibrary.ExperimentPaused;
-        else if (ExecutionState == ExecutionState.Stopped) return HeuristicLab.Common.Resources.VSImageLibrary.ExperimentStopped;
-        else return base.ItemImage;
-      }
-    }
-
-    [Storable]
-    private ExecutionState executionState;
-    public ExecutionState ExecutionState {
-      get { return executionState; }
-      private set {
-        if (executionState != value) {
-          executionState = value;
-          OnExecutionStateChanged();
-          OnItemImageChanged();
-        }
-      }
-    }
-
-    [Storable]
-    private TimeSpan executionTime;
-    public TimeSpan ExecutionTime {
-      get { return executionTime; }
-      private set {
-        executionTime = value;
-        OnExecutionTimeChanged();
-      }
-    }
-
-    [Storable]
-    private OptimizerList optimizers;
-    public OptimizerList Optimizers {
-      get { return optimizers; }
-    }
-
-    [Storable]
-    private RunCollection runs;
-    public RunCollection Runs {
-      get { return runs; }
-      private set {
-        if (value == null) throw new ArgumentNullException();
-        if (runs != value) {
-          if (runs != null) DeregisterRunsEvents();
-          runs = value;
-          if (runs != null) RegisterRunsEvents();
-        }
-      }
-    }
-
-    public IEnumerable<IOptimizer> NestedOptimizers {
-      get {
-        if (Optimizers == null) yield break;
-
-        foreach (IOptimizer opt in Optimizers) {
-          yield return opt;
-          foreach (IOptimizer nestedOpt in opt.NestedOptimizers)
-            yield return nestedOpt;
-        }
-      }
-    }
-
-    private bool experimentStarted = false;
-    private bool experimentStopped = false;
-
-    public Experiment()
-      : base() {
-      name = ItemName;
-      description = ItemDescription;
-      executionState = ExecutionState.Stopped;
-      executionTime = TimeSpan.Zero;
-      optimizers = new OptimizerList();
-      Runs = new RunCollection { OptimizerName = Name };
-      Initialize();
-    }
-    public Experiment(string name)
-      : base(name) {
-      description = ItemDescription;
-      executionState = ExecutionState.Stopped;
-      executionTime = TimeSpan.Zero;
-      optimizers = new OptimizerList();
-      Runs = new RunCollection { OptimizerName = Name };
-      Initialize();
-    }
-    public Experiment(string name, string description)
-      : base(name, description) {
-      executionState = ExecutionState.Stopped;
-      executionTime = TimeSpan.Zero;
-      optimizers = new OptimizerList();
-      Runs = new RunCollection { OptimizerName = Name };
-      Initialize();
-    }
-    [StorableConstructor]
-    private Experiment(bool deserializing) : base(deserializing) { }
-    [StorableHook(HookType.AfterDeserialization)]
-    private void AfterDeserialization() {
-      Initialize();
-    }
-    private Experiment(Experiment original, Cloner cloner)
-      : base(original, cloner) {
-      executionState = original.executionState;
-      executionTime = original.executionTime;
-      optimizers = cloner.Clone(original.optimizers);
-      runs = cloner.Clone(original.runs);
-
-      experimentStarted = original.experimentStarted;
-      experimentStopped = original.experimentStopped;
-      Initialize();
-    }
-    public override IDeepCloneable Clone(Cloner cloner) {
-      if (ExecutionState == ExecutionState.Started) throw new InvalidOperationException(string.Format("Clone not allowed in execution state \"{0}\".", ExecutionState));
-      return new Experiment(this, cloner);
-    }
-
-    private void Initialize() {
-      RegisterOptimizersEvents();
-      foreach (IOptimizer optimizer in optimizers)
-        RegisterOptimizerEvents(optimizer);
-      if (runs != null) RegisterRunsEvents();
-    }
-
-    public void Prepare() {
-      Prepare(false);
-    }
-    public void Prepare(bool clearRuns) {
-      if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused) && (ExecutionState != ExecutionState.Stopped))
-        throw new InvalidOperationException(string.Format("Prepare not allowed in execution state \"{0}\".", ExecutionState));
-      if (Optimizers.Count == 0) return;
-
-      if (clearRuns) runs.Clear();
-
-      experimentStarted = false;
-      experimentStopped = false;
-      foreach (IOptimizer optimizer in Optimizers.Where(x => x.ExecutionState != ExecutionState.Started)) {
-        // a race-condition may occur when the optimizer has changed the state by itself in the meantime
-        try { optimizer.Prepare(clearRuns); }
-        catch (InvalidOperationException) { }
-      }
-    }
-    public void Start() {
-      if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused))
-        throw new InvalidOperationException(string.Format("Start not allowed in execution state \"{0}\".", ExecutionState));
-      if (Optimizers.Count == 0) return;
-
-      experimentStarted = true;
-      experimentStopped = false;
-      IOptimizer optimizer = Optimizers.FirstOrDefault(x => (x.ExecutionState == ExecutionState.Prepared) || (x.ExecutionState == ExecutionState.Paused));
-      if (optimizer != null) {
-        // a race-condition may occur when the optimizer has changed the state by itself in the meantime
-        try { optimizer.Start(); }
-        catch (InvalidOperationException) { }
-      }
-    }
-    public void Pause() {
-      if (ExecutionState != ExecutionState.Started)
-        throw new InvalidOperationException(string.Format("Pause not allowed in execution state \"{0}\".", ExecutionState));
-      if (Optimizers.Count == 0) return;
-
-      experimentStarted = false;
-      experimentStopped = false;
-      foreach (IOptimizer optimizer in Optimizers.Where(x => x.ExecutionState == ExecutionState.Started)) {
-        // a race-condition may occur when the optimizer has changed the state by itself in the meantime
-        try { optimizer.Pause(); }
-        catch (InvalidOperationException) { }
-      }
-    }
-    public void Stop() {
-      if ((ExecutionState != ExecutionState.Started) && (ExecutionState != ExecutionState.Paused))
-        throw new InvalidOperationException(string.Format("Stop not allowed in execution state \"{0}\".", ExecutionState));
-      if (Optimizers.Count == 0) return;
-
-      experimentStarted = false;
-      experimentStopped = true;
-      if (Optimizers.Any(x => (x.ExecutionState == ExecutionState.Started) || (x.ExecutionState == ExecutionState.Paused))) {
-        foreach (var optimizer in Optimizers.Where(x => (x.ExecutionState == ExecutionState.Started) || (x.ExecutionState == ExecutionState.Paused))) {
-          // a race-condition may occur when the optimizer has changed the state by itself in the meantime
-          try { optimizer.Stop(); }
-          catch (InvalidOperationException) { }
-        }
-      } else {
-        OnStopped();
-      }
-    }
-
-    #region Events
-    protected override void OnNameChanged() {
-      base.OnNameChanged();
-      Runs.OptimizerName = Name;
-    }
-
-    public event EventHandler ExecutionStateChanged;
-    private void OnExecutionStateChanged() {
-      EventHandler handler = ExecutionStateChanged;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler ExecutionTimeChanged;
-    private void OnExecutionTimeChanged() {
-      EventHandler handler = ExecutionTimeChanged;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler Prepared;
-    private void OnPrepared() {
-      ExecutionState = ExecutionState.Prepared;
-      EventHandler handler = Prepared;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler Started;
-    private void OnStarted() {
-      ExecutionState = ExecutionState.Started;
-      EventHandler handler = Started;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler Paused;
-    private void OnPaused() {
-      ExecutionState = ExecutionState.Paused;
-      EventHandler handler = Paused;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler Stopped;
-    private void OnStopped() {
-      ExecutionState = ExecutionState.Stopped;
-      EventHandler handler = Stopped;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler<EventArgs<Exception>> ExceptionOccurred;
-    private void OnExceptionOccurred(Exception exception) {
-      EventHandler<EventArgs<Exception>> handler = ExceptionOccurred;
-      if (handler != null) handler(this, new EventArgs<Exception>(exception));
-    }
-
-    private void RegisterOptimizersEvents() {
-      Optimizers.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_CollectionReset);
-      Optimizers.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsAdded);
-      Optimizers.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsRemoved);
-      Optimizers.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsReplaced);
-    }
-    private void DeregisterOptimizersEvents() {
-      Optimizers.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_CollectionReset);
-      Optimizers.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsAdded);
-      Optimizers.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsRemoved);
-      Optimizers.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsReplaced);
-    }
-    private void Optimizers_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>> e) {
-      foreach (IndexedItem<IOptimizer> item in e.OldItems)
-        RemoveOptimizer(item.Value);
-      foreach (IndexedItem<IOptimizer> item in e.Items)
-        AddOptimizer(item.Value);
-    }
-    private void Optimizers_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>> e) {
-      foreach (IndexedItem<IOptimizer> item in e.Items)
-        AddOptimizer(item.Value);
-    }
-    private void Optimizers_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>> e) {
-      foreach (IndexedItem<IOptimizer> item in e.Items)
-        RemoveOptimizer(item.Value);
-    }
-    private void Optimizers_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>> e) {
-      foreach (IndexedItem<IOptimizer> item in e.OldItems)
-        RemoveOptimizer(item.Value);
-      foreach (IndexedItem<IOptimizer> item in e.Items)
-        AddOptimizer(item.Value);
-    }
-    private void AddOptimizer(IOptimizer optimizer) {
-      RegisterOptimizerEvents(optimizer);
-      Runs.AddRange(optimizer.Runs);
-      optimizer.Prepare();
-      if (ExecutionState == ExecutionState.Stopped && optimizer.ExecutionState == ExecutionState.Prepared)
-        OnPrepared();
-    }
-    private void RemoveOptimizer(IOptimizer optimizer) {
-      DeregisterOptimizerEvents(optimizer);
-      Runs.RemoveRange(optimizer.Runs);
-      if (ExecutionState == ExecutionState.Prepared && !optimizers.Any(opt => opt.ExecutionState == ExecutionState.Prepared))
-        OnStopped();
-    }
-
-    private void RegisterOptimizerEvents(IOptimizer optimizer) {
-      optimizer.ExceptionOccurred += new EventHandler<EventArgs<Exception>>(optimizer_ExceptionOccurred);
-      optimizer.ExecutionTimeChanged += new EventHandler(optimizer_ExecutionTimeChanged);
-      optimizer.Paused += new EventHandler(optimizer_Paused);
-      optimizer.Prepared += new EventHandler(optimizer_Prepared);
-      optimizer.Started += new EventHandler(optimizer_Started);
-      optimizer.Stopped += new EventHandler(optimizer_Stopped);
-      optimizer.Runs.CollectionReset += new CollectionItemsChangedEventHandler<IRun>(optimizer_Runs_CollectionReset);
-      optimizer.Runs.ItemsAdded += new CollectionItemsChangedEventHandler<IRun>(optimizer_Runs_ItemsAdded);
-      optimizer.Runs.ItemsRemoved += new CollectionItemsChangedEventHandler<IRun>(optimizer_Runs_ItemsRemoved);
-    }
-    private void DeregisterOptimizerEvents(IOptimizer optimizer) {
-      optimizer.ExceptionOccurred -= new EventHandler<EventArgs<Exception>>(optimizer_ExceptionOccurred);
-      optimizer.ExecutionTimeChanged -= new EventHandler(optimizer_ExecutionTimeChanged);
-      optimizer.Paused -= new EventHandler(optimizer_Paused);
-      optimizer.Prepared -= new EventHandler(optimizer_Prepared);
-      optimizer.Started -= new EventHandler(optimizer_Started);
-      optimizer.Stopped -= new EventHandler(optimizer_Stopped);
-      optimizer.Runs.CollectionReset -= new CollectionItemsChangedEventHandler<IRun>(optimizer_Runs_CollectionReset);
-      optimizer.Runs.ItemsAdded -= new CollectionItemsChangedEventHandler<IRun>(optimizer_Runs_ItemsAdded);
-      optimizer.Runs.ItemsRemoved -= new CollectionItemsChangedEventHandler<IRun>(optimizer_Runs_ItemsRemoved);
-    }
-
-    private readonly object locker = new object();
-    private void optimizer_ExceptionOccurred(object sender, EventArgs<Exception> e) {
-      lock (locker)
-        OnExceptionOccurred(e.Value);
-    }
-    private void optimizer_ExecutionTimeChanged(object sender, EventArgs e) {
-      lock (locker)
-        ExecutionTime = Optimizers.Aggregate(TimeSpan.Zero, (t, o) => t + o.ExecutionTime);
-    }
-    private void optimizer_Paused(object sender, EventArgs e) {
-      lock (locker)
-        if (Optimizers.All(x => x.ExecutionState != ExecutionState.Started)) OnPaused();
-    }
-    private void optimizer_Prepared(object sender, EventArgs e) {
-      lock (locker)
-        if (Optimizers.All(x => x.ExecutionState == ExecutionState.Prepared)) OnPrepared();
-    }
-    private void optimizer_Started(object sender, EventArgs e) {
-      lock (locker)
-        if (ExecutionState != ExecutionState.Started) OnStarted();
-    }
-    private void optimizer_Stopped(object sender, EventArgs e) {
-      lock (locker) {
-        if (experimentStopped) {
-          if (Optimizers.All(x => (x.ExecutionState == ExecutionState.Stopped) || (x.ExecutionState == ExecutionState.Prepared))) OnStopped();
-        } else {
-          if (experimentStarted && Optimizers.Any(x => (x.ExecutionState == ExecutionState.Prepared) || (x.ExecutionState == ExecutionState.Paused))) {
-            Optimizers.First(x => (x.ExecutionState == ExecutionState.Prepared) || (x.ExecutionState == ExecutionState.Paused)).Start();
-          } else if (Optimizers.All(x => x.ExecutionState == ExecutionState.Stopped)) OnStopped();
-          else if (Optimizers.Any(x => (x.ExecutionState == ExecutionState.Prepared) || (x.ExecutionState == ExecutionState.Paused)) && Optimizers.All(o => o.ExecutionState != ExecutionState.Started)) OnPaused();
-        }
-      }
-    }
-    private void optimizer_Runs_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRun> e) {
-      lock (locker) {
-        Runs.RemoveRange(e.OldItems);
-        Runs.AddRange(e.Items);
-      }
-    }
-    private void optimizer_Runs_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IRun> e) {
-      lock (locker)
-        Runs.AddRange(e.Items);
-    }
-    private void optimizer_Runs_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRun> e) {
-      lock (locker)
-        Runs.RemoveRange(e.Items);
-    }
-
-    private void RegisterRunsEvents() {
-      runs.CollectionReset += new CollectionItemsChangedEventHandler<IRun>(Runs_CollectionReset);
-      runs.ItemsRemoved += new CollectionItemsChangedEventHandler<IRun>(Runs_ItemsRemoved);
-    }
-    private void DeregisterRunsEvents() {
-      runs.CollectionReset -= new CollectionItemsChangedEventHandler<IRun>(Runs_CollectionReset);
-      runs.ItemsRemoved -= new CollectionItemsChangedEventHandler<IRun>(Runs_ItemsRemoved);
-    }
-    private void Runs_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRun> e) {
-      foreach (IOptimizer optimizer in Optimizers)
-        optimizer.Runs.RemoveRange(e.OldItems);
-    }
-    private void Runs_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRun> e) {
-      foreach (IOptimizer optimizer in Optimizers)
-        optimizer.Runs.RemoveRange(e.Items);
-    }
-    #endregion
-  }
-}
Index: /trunk/sources/HeuristicLab.Optimization/3.3/HeuristicLab.Optimization-3.3.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/HeuristicLab.Optimization-3.3.csproj	(revision 9078)
+++ /trunk/sources/HeuristicLab.Optimization/3.3/HeuristicLab.Optimization-3.3.csproj	(revision 9079)
@@ -121,4 +121,7 @@
     <Compile Include="Interfaces\ISimilarityBasedOperator.cs" />
     <Compile Include="Interfaces\ISolutionSimilarityCalculator.cs" />
+    <Compile Include="MetaOptimizers\BatchRun.cs" />
+    <Compile Include="MetaOptimizers\Experiment.cs" />
+    <Compile Include="MetaOptimizers\TimeLimitRun.cs" />
     <Compile Include="RunCollectionModification\RunCollectionRunRemover.cs" />
     <Compile Include="Plugin.cs" />
@@ -130,5 +133,4 @@
     <None Include="Plugin.cs.frame" />
     <Compile Include="Algorithms\Algorithm.cs" />
-    <Compile Include="BatchRun.cs" />
     <Compile Include="RunCollectionModification\Calculator.cs" />
     <Compile Include="Interfaces\IDiscreteDoubleMatrixModifier.cs" />
@@ -173,5 +175,4 @@
     <Compile Include="RunCollectionConstraints\IRunCollectionConstraint.cs" />
     <Compile Include="OptimizerList.cs" />
-    <Compile Include="Experiment.cs" />
     <Compile Include="Interfaces\IOptimizer.cs" />
     <Compile Include="RunCollection.cs" />
@@ -281,5 +282,5 @@
   -->
   <PropertyGroup>
-   <PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+    <PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
 set ProjectDir=$(ProjectDir)
 set SolutionDir=$(SolutionDir)
@@ -288,5 +289,5 @@
 call PreBuildEvent.cmd
 </PreBuildEvent>
-<PreBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">
+    <PreBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">
 export ProjectDir=$(ProjectDir)
 export SolutionDir=$(SolutionDir)
Index: /trunk/sources/HeuristicLab.Optimization/3.3/MetaOptimizers/BatchRun.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/MetaOptimizers/BatchRun.cs	(revision 9079)
+++ /trunk/sources/HeuristicLab.Optimization/3.3/MetaOptimizers/BatchRun.cs	(revision 9079)
@@ -0,0 +1,450 @@
+#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 HeuristicLab.Collections;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Optimization {
+  internal enum BatchRunAction { None, Prepare, Start, Pause, Stop };
+
+  /// <summary>
+  /// A run in which an optimizer is executed a given number of times.
+  /// </summary>
+  [Item("Batch Run", "A run in which an optimizer is executed a given number of times.")]
+  [Creatable("Testing & Analysis")]
+  [StorableClass]
+  public sealed class BatchRun : NamedItem, IOptimizer, IStorableContent {
+    public string Filename { get; set; }
+
+    public static new Image StaticItemImage {
+      get { return HeuristicLab.Common.Resources.VSImageLibrary.Event; }
+    }
+    public override Image ItemImage {
+      get {
+        if (ExecutionState == ExecutionState.Prepared) return HeuristicLab.Common.Resources.VSImageLibrary.BatchRunPrepared;
+        else if (ExecutionState == ExecutionState.Started) return HeuristicLab.Common.Resources.VSImageLibrary.BatchRunStarted;
+        else if (ExecutionState == ExecutionState.Paused) return HeuristicLab.Common.Resources.VSImageLibrary.BatchRunPaused;
+        else if (ExecutionState == ExecutionState.Stopped) return HeuristicLab.Common.Resources.VSImageLibrary.BatchRunStopped;
+        else return base.ItemImage;
+      }
+    }
+
+    [Storable]
+    private ExecutionState executionState;
+    public ExecutionState ExecutionState {
+      get { return executionState; }
+      private set {
+        if (executionState != value) {
+          executionState = value;
+          OnExecutionStateChanged();
+          OnItemImageChanged();
+        }
+      }
+    }
+
+    [Storable]
+    private TimeSpan executionTime;
+    public TimeSpan ExecutionTime {
+      get {
+        if ((Optimizer != null) && (Optimizer.ExecutionState != ExecutionState.Stopped))
+          return executionTime + Optimizer.ExecutionTime;
+        else
+          return executionTime;
+      }
+      private set {
+        executionTime = value;
+        OnExecutionTimeChanged();
+      }
+    }
+
+    [Storable]
+    private TimeSpan runsExecutionTime;
+
+    [Storable]
+    private IOptimizer optimizer;
+    public IOptimizer Optimizer {
+      get { return optimizer; }
+      set {
+        if (optimizer != value) {
+          if (optimizer != null) {
+            DeregisterOptimizerEvents();
+            IEnumerable<IRun> runs = optimizer.Runs;
+            optimizer = null; //necessary to avoid removing the runs from the old optimizer
+            Runs.RemoveRange(runs);
+          }
+          optimizer = value;
+          if (optimizer != null) {
+            RegisterOptimizerEvents();
+            Runs.AddRange(optimizer.Runs);
+          }
+          OnOptimizerChanged();
+          Prepare();
+        }
+      }
+    }
+    // BackwardsCompatibility3.3
+    #region Backwards compatible code (remove with 3.4)
+    [Storable(AllowOneWay = true)]
+    private IAlgorithm algorithm {
+      set { optimizer = value; }
+    }
+    #endregion
+
+    [Storable]
+    private int repetitions;
+    public int Repetitions {
+      get { return repetitions; }
+      set {
+        if (repetitions != value) {
+          repetitions = value;
+          OnRepetitionsChanged();
+          if ((Optimizer != null) && (Optimizer.ExecutionState == ExecutionState.Stopped))
+            Prepare();
+        }
+      }
+    }
+    [Storable]
+    private int repetitionsCounter;
+    public int RepetitionsCounter {
+      get { return repetitionsCounter; }
+      private set {
+        if (value != repetitionsCounter) {
+          repetitionsCounter = value;
+          OnRepetitionsCounterChanged();
+        }
+      }
+    }
+
+    [Storable]
+    private RunCollection runs;
+    public RunCollection Runs {
+      get { return runs; }
+      private set {
+        if (value == null) throw new ArgumentNullException();
+        if (runs != value) {
+          if (runs != null) DeregisterRunsEvents();
+          runs = value;
+          if (runs != null) RegisterRunsEvents();
+        }
+      }
+    }
+
+    public IEnumerable<IOptimizer> NestedOptimizers {
+      get {
+        if (Optimizer == null) yield break;
+
+        yield return Optimizer;
+        foreach (IOptimizer opt in Optimizer.NestedOptimizers)
+          yield return opt;
+      }
+    }
+
+    private BatchRunAction batchRunAction = BatchRunAction.None;
+
+    public BatchRun()
+      : base() {
+      name = ItemName;
+      description = ItemDescription;
+      executionState = ExecutionState.Stopped;
+      executionTime = TimeSpan.Zero;
+      runsExecutionTime = TimeSpan.Zero;
+      repetitions = 10;
+      repetitionsCounter = 0;
+      Runs = new RunCollection { OptimizerName = Name };
+    }
+    public BatchRun(string name)
+      : base(name) {
+      description = ItemDescription;
+      executionState = ExecutionState.Stopped;
+      executionTime = TimeSpan.Zero;
+      runsExecutionTime = TimeSpan.Zero;
+      repetitions = 10;
+      repetitionsCounter = 0;
+      Runs = new RunCollection { OptimizerName = Name };
+    }
+    public BatchRun(string name, string description)
+      : base(name, description) {
+      executionState = ExecutionState.Stopped;
+      executionTime = TimeSpan.Zero;
+      runsExecutionTime = TimeSpan.Zero;
+      repetitions = 10;
+      repetitionsCounter = 0;
+      Runs = new RunCollection { OptimizerName = Name };
+    }
+    [StorableConstructor]
+    private BatchRun(bool deserializing) : base(deserializing) { }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      Initialize();
+    }
+
+    private BatchRun(BatchRun original, Cloner cloner)
+      : base(original, cloner) {
+      executionState = original.executionState;
+      executionTime = original.executionTime;
+      runsExecutionTime = original.runsExecutionTime;
+      optimizer = cloner.Clone(original.optimizer);
+      repetitions = original.repetitions;
+      repetitionsCounter = original.repetitionsCounter;
+      runs = cloner.Clone(original.runs);
+      batchRunAction = original.batchRunAction;
+      Initialize();
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      if (ExecutionState == ExecutionState.Started) throw new InvalidOperationException(string.Format("Clone not allowed in execution state \"{0}\".", ExecutionState));
+      return new BatchRun(this, cloner);
+    }
+
+    private void Initialize() {
+      if (optimizer != null) RegisterOptimizerEvents();
+      if (runs != null) RegisterRunsEvents();
+    }
+
+    public void Prepare() {
+      Prepare(false);
+    }
+    public void Prepare(bool clearRuns) {
+      if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused) && (ExecutionState != ExecutionState.Stopped))
+        throw new InvalidOperationException(string.Format("Prepare not allowed in execution state \"{0}\".", ExecutionState));
+      if (Optimizer != null) {
+        ExecutionTime = TimeSpan.Zero;
+        RepetitionsCounter = 0;
+        if (clearRuns) runs.Clear();
+        batchRunAction = BatchRunAction.Prepare;
+        // a race-condition may occur when the optimizer has changed the state by itself in the meantime
+        try { Optimizer.Prepare(clearRuns); } catch (InvalidOperationException) { }
+      } else {
+        ExecutionState = ExecutionState.Stopped;
+      }
+    }
+    public void Start() {
+      if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused))
+        throw new InvalidOperationException(string.Format("Start not allowed in execution state \"{0}\".", ExecutionState));
+      if (Optimizer == null) return;
+      batchRunAction = BatchRunAction.Start;
+      if (Optimizer.ExecutionState == ExecutionState.Stopped) Optimizer.Prepare();
+      // a race-condition may occur when the optimizer has changed the state by itself in the meantime
+      try { Optimizer.Start(); } catch (InvalidOperationException) { }
+    }
+    public void Pause() {
+      if (ExecutionState != ExecutionState.Started)
+        throw new InvalidOperationException(string.Format("Pause not allowed in execution state \"{0}\".", ExecutionState));
+      if (Optimizer == null) return;
+      batchRunAction = BatchRunAction.Pause;
+      if (Optimizer.ExecutionState != ExecutionState.Started) return;
+      // a race-condition may occur when the optimizer has changed the state by itself in the meantime
+      try { Optimizer.Pause(); } catch (InvalidOperationException) { }
+    }
+    public void Stop() {
+      if ((ExecutionState != ExecutionState.Started) && (ExecutionState != ExecutionState.Paused))
+        throw new InvalidOperationException(string.Format("Stop not allowed in execution state \"{0}\".", ExecutionState));
+      if (Optimizer == null) return;
+      batchRunAction = BatchRunAction.Stop;
+      if (Optimizer.ExecutionState != ExecutionState.Started && Optimizer.ExecutionState != ExecutionState.Paused) {
+        OnStopped();
+        return;
+      }
+      // a race-condition may occur when the optimizer has changed the state by itself in the meantime
+      try { Optimizer.Stop(); } catch (InvalidOperationException) { }
+    }
+
+    #region Events
+    protected override void OnNameChanged() {
+      base.OnNameChanged();
+      runs.OptimizerName = Name;
+    }
+
+    public event EventHandler ExecutionStateChanged;
+    private void OnExecutionStateChanged() {
+      EventHandler handler = ExecutionStateChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler ExecutionTimeChanged;
+    private void OnExecutionTimeChanged() {
+      EventHandler handler = ExecutionTimeChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler OptimizerChanged;
+    private void OnOptimizerChanged() {
+      EventHandler handler = OptimizerChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler RepetitionsChanged;
+    private void OnRepetitionsChanged() {
+      EventHandler handler = RepetitionsChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler RepetetionsCounterChanged;
+    private void OnRepetitionsCounterChanged() {
+      EventHandler handler = RepetetionsCounterChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler Prepared;
+    private void OnPrepared() {
+      batchRunAction = BatchRunAction.None;
+      ExecutionState = ExecutionState.Prepared;
+      EventHandler handler = Prepared;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler Started;
+    private void OnStarted() {
+      // no reset of BatchRunAction.Started, because we need to differ which of the two was started by the user
+      ExecutionState = ExecutionState.Started;
+      EventHandler handler = Started;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler Paused;
+    private void OnPaused() {
+      batchRunAction = BatchRunAction.None;
+      ExecutionState = ExecutionState.Paused;
+      EventHandler handler = Paused;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler Stopped;
+    private void OnStopped() {
+      batchRunAction = BatchRunAction.None;
+      ExecutionState = ExecutionState.Stopped;
+      EventHandler handler = Stopped;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler<EventArgs<Exception>> ExceptionOccurred;
+    private void OnExceptionOccurred(Exception exception) {
+      EventHandler<EventArgs<Exception>> handler = ExceptionOccurred;
+      if (handler != null) handler(this, new EventArgs<Exception>(exception));
+    }
+
+    private void RegisterOptimizerEvents() {
+      optimizer.ExceptionOccurred += new EventHandler<EventArgs<Exception>>(Optimizer_ExceptionOccurred);
+      optimizer.ExecutionTimeChanged += new EventHandler(Optimizer_ExecutionTimeChanged);
+      optimizer.Paused += new EventHandler(Optimizer_Paused);
+      optimizer.Prepared += new EventHandler(Optimizer_Prepared);
+      optimizer.Started += new EventHandler(Optimizer_Started);
+      optimizer.Stopped += new EventHandler(Optimizer_Stopped);
+      optimizer.Runs.CollectionReset += new CollectionItemsChangedEventHandler<IRun>(Optimizer_Runs_CollectionReset);
+      optimizer.Runs.ItemsAdded += new CollectionItemsChangedEventHandler<IRun>(Optimizer_Runs_ItemsAdded);
+      optimizer.Runs.ItemsRemoved += new CollectionItemsChangedEventHandler<IRun>(Optimizer_Runs_ItemsRemoved);
+    }
+    private void DeregisterOptimizerEvents() {
+      optimizer.ExceptionOccurred -= new EventHandler<EventArgs<Exception>>(Optimizer_ExceptionOccurred);
+      optimizer.ExecutionTimeChanged -= new EventHandler(Optimizer_ExecutionTimeChanged);
+      optimizer.Paused -= new EventHandler(Optimizer_Paused);
+      optimizer.Prepared -= new EventHandler(Optimizer_Prepared);
+      optimizer.Started -= new EventHandler(Optimizer_Started);
+      optimizer.Stopped -= new EventHandler(Optimizer_Stopped);
+      optimizer.Runs.CollectionReset -= new CollectionItemsChangedEventHandler<IRun>(Optimizer_Runs_CollectionReset);
+      optimizer.Runs.ItemsAdded -= new CollectionItemsChangedEventHandler<IRun>(Optimizer_Runs_ItemsAdded);
+      optimizer.Runs.ItemsRemoved -= new CollectionItemsChangedEventHandler<IRun>(Optimizer_Runs_ItemsRemoved);
+    }
+    private void Optimizer_ExceptionOccurred(object sender, EventArgs<Exception> e) {
+      OnExceptionOccurred(e.Value);
+    }
+    private void Optimizer_ExecutionTimeChanged(object sender, EventArgs e) {
+      OnExecutionTimeChanged();
+    }
+    private void Optimizer_Paused(object sender, EventArgs e) {
+      if (ExecutionState == ExecutionState.Started) {
+        OnPaused();
+      }
+    }
+    private void Optimizer_Prepared(object sender, EventArgs e) {
+      if (batchRunAction == BatchRunAction.Prepare || ExecutionState == ExecutionState.Stopped) {
+        ExecutionTime = TimeSpan.Zero;
+        runsExecutionTime = TimeSpan.Zero;
+        RepetitionsCounter = 0;
+        OnPrepared();
+      }
+    }
+    private void Optimizer_Started(object sender, EventArgs e) {
+      if (ExecutionState != ExecutionState.Started)
+        OnStarted();
+    }
+    private void Optimizer_Stopped(object sender, EventArgs e) {
+      RepetitionsCounter++;
+      ExecutionTime += runsExecutionTime;
+      runsExecutionTime = TimeSpan.Zero;
+
+      if (batchRunAction == BatchRunAction.Stop) OnStopped();
+      else if (repetitionsCounter >= repetitions) OnStopped();
+      else if (batchRunAction == BatchRunAction.Pause) OnPaused();
+      else if (batchRunAction == BatchRunAction.Start) {
+        Optimizer.Prepare();
+        Optimizer.Start();
+      } else if (executionState == ExecutionState.Started) {
+        // if the batch run hasn't been started but the inner optimizer was run then pause
+        OnPaused();
+      } else OnStopped();
+    }
+    private void Optimizer_Runs_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRun> e) {
+      Runs.RemoveRange(e.OldItems);
+      Runs.AddRange(e.Items);
+    }
+    private void Optimizer_Runs_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IRun> e) {
+      Runs.AddRange(e.Items);
+    }
+    private void Optimizer_Runs_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRun> e) {
+      Runs.RemoveRange(e.Items);
+    }
+
+    private void RegisterRunsEvents() {
+      runs.CollectionReset += new CollectionItemsChangedEventHandler<IRun>(Runs_CollectionReset);
+      runs.ItemsAdded += new CollectionItemsChangedEventHandler<IRun>(Runs_ItemsAdded);
+      runs.ItemsRemoved += new CollectionItemsChangedEventHandler<IRun>(Runs_ItemsRemoved);
+    }
+
+    private void DeregisterRunsEvents() {
+      runs.CollectionReset -= new CollectionItemsChangedEventHandler<IRun>(Runs_CollectionReset);
+      runs.ItemsAdded -= new CollectionItemsChangedEventHandler<IRun>(Runs_ItemsAdded);
+      runs.ItemsRemoved -= new CollectionItemsChangedEventHandler<IRun>(Runs_ItemsRemoved);
+    }
+    private void Runs_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRun> e) {
+      if (Optimizer != null) Optimizer.Runs.RemoveRange(e.OldItems);
+      foreach (IRun run in e.Items) {
+        IItem item;
+        run.Results.TryGetValue("Execution Time", out item);
+        TimeSpanValue executionTime = item as TimeSpanValue;
+        if (executionTime != null) ExecutionTime += executionTime.Value;
+      }
+    }
+    private void Runs_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IRun> e) {
+      foreach (IRun run in e.Items) {
+        IItem item;
+        run.Results.TryGetValue("Execution Time", out item);
+        TimeSpanValue executionTime = item as TimeSpanValue;
+        if (executionTime != null) {
+          if (Optimizer.ExecutionState == ExecutionState.Started)
+            runsExecutionTime += executionTime.Value;
+          else
+            ExecutionTime += executionTime.Value;
+        }
+      }
+    }
+    private void Runs_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRun> e) {
+      if (Optimizer != null) Optimizer.Runs.RemoveRange(e.Items);
+    }
+    #endregion
+  }
+}
Index: /trunk/sources/HeuristicLab.Optimization/3.3/MetaOptimizers/Experiment.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/MetaOptimizers/Experiment.cs	(revision 9079)
+++ /trunk/sources/HeuristicLab.Optimization/3.3/MetaOptimizers/Experiment.cs	(revision 9079)
@@ -0,0 +1,408 @@
+#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 HeuristicLab.Collections;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Optimization {
+  /// <summary>
+  /// An experiment which contains multiple algorithms, batch runs or other experiments.
+  /// </summary>
+  [Item("Experiment", "An experiment which contains multiple algorithms, batch runs or other experiments.")]
+  [Creatable("Testing & Analysis")]
+  [StorableClass]
+  public sealed class Experiment : NamedItem, IOptimizer, IStorableContent {
+    public string Filename { get; set; }
+
+    public static new Image StaticItemImage {
+      get { return HeuristicLab.Common.Resources.VSImageLibrary.Event; }
+    }
+    public override Image ItemImage {
+      get {
+        if (ExecutionState == ExecutionState.Prepared) return HeuristicLab.Common.Resources.VSImageLibrary.ExperimentPrepared;
+        else if (ExecutionState == ExecutionState.Started) return HeuristicLab.Common.Resources.VSImageLibrary.ExperimentStarted;
+        else if (ExecutionState == ExecutionState.Paused) return HeuristicLab.Common.Resources.VSImageLibrary.ExperimentPaused;
+        else if (ExecutionState == ExecutionState.Stopped) return HeuristicLab.Common.Resources.VSImageLibrary.ExperimentStopped;
+        else return base.ItemImage;
+      }
+    }
+
+    [Storable]
+    private ExecutionState executionState;
+    public ExecutionState ExecutionState {
+      get { return executionState; }
+      private set {
+        if (executionState != value) {
+          executionState = value;
+          OnExecutionStateChanged();
+          OnItemImageChanged();
+        }
+      }
+    }
+
+    [Storable]
+    private TimeSpan executionTime;
+    public TimeSpan ExecutionTime {
+      get { return executionTime; }
+      private set {
+        executionTime = value;
+        OnExecutionTimeChanged();
+      }
+    }
+
+    [Storable]
+    private OptimizerList optimizers;
+    public OptimizerList Optimizers {
+      get { return optimizers; }
+    }
+
+    [Storable]
+    private RunCollection runs;
+    public RunCollection Runs {
+      get { return runs; }
+      private set {
+        if (value == null) throw new ArgumentNullException();
+        if (runs != value) {
+          if (runs != null) DeregisterRunsEvents();
+          runs = value;
+          if (runs != null) RegisterRunsEvents();
+        }
+      }
+    }
+
+    public IEnumerable<IOptimizer> NestedOptimizers {
+      get {
+        if (Optimizers == null) yield break;
+
+        foreach (IOptimizer opt in Optimizers) {
+          yield return opt;
+          foreach (IOptimizer nestedOpt in opt.NestedOptimizers)
+            yield return nestedOpt;
+        }
+      }
+    }
+
+    private bool experimentStarted = false;
+    private bool experimentStopped = false;
+
+    public Experiment()
+      : base() {
+      name = ItemName;
+      description = ItemDescription;
+      executionState = ExecutionState.Stopped;
+      executionTime = TimeSpan.Zero;
+      optimizers = new OptimizerList();
+      Runs = new RunCollection { OptimizerName = Name };
+      Initialize();
+    }
+    public Experiment(string name)
+      : base(name) {
+      description = ItemDescription;
+      executionState = ExecutionState.Stopped;
+      executionTime = TimeSpan.Zero;
+      optimizers = new OptimizerList();
+      Runs = new RunCollection { OptimizerName = Name };
+      Initialize();
+    }
+    public Experiment(string name, string description)
+      : base(name, description) {
+      executionState = ExecutionState.Stopped;
+      executionTime = TimeSpan.Zero;
+      optimizers = new OptimizerList();
+      Runs = new RunCollection { OptimizerName = Name };
+      Initialize();
+    }
+    [StorableConstructor]
+    private Experiment(bool deserializing) : base(deserializing) { }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      Initialize();
+    }
+    private Experiment(Experiment original, Cloner cloner)
+      : base(original, cloner) {
+      executionState = original.executionState;
+      executionTime = original.executionTime;
+      optimizers = cloner.Clone(original.optimizers);
+      runs = cloner.Clone(original.runs);
+
+      experimentStarted = original.experimentStarted;
+      experimentStopped = original.experimentStopped;
+      Initialize();
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      if (ExecutionState == ExecutionState.Started) throw new InvalidOperationException(string.Format("Clone not allowed in execution state \"{0}\".", ExecutionState));
+      return new Experiment(this, cloner);
+    }
+
+    private void Initialize() {
+      RegisterOptimizersEvents();
+      foreach (IOptimizer optimizer in optimizers)
+        RegisterOptimizerEvents(optimizer);
+      if (runs != null) RegisterRunsEvents();
+    }
+
+    public void Prepare() {
+      Prepare(false);
+    }
+    public void Prepare(bool clearRuns) {
+      if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused) && (ExecutionState != ExecutionState.Stopped))
+        throw new InvalidOperationException(string.Format("Prepare not allowed in execution state \"{0}\".", ExecutionState));
+      if (Optimizers.Count == 0) return;
+
+      if (clearRuns) runs.Clear();
+
+      experimentStarted = false;
+      experimentStopped = false;
+      foreach (IOptimizer optimizer in Optimizers.Where(x => x.ExecutionState != ExecutionState.Started)) {
+        // a race-condition may occur when the optimizer has changed the state by itself in the meantime
+        try { optimizer.Prepare(clearRuns); } catch (InvalidOperationException) { }
+      }
+    }
+    public void Start() {
+      if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused))
+        throw new InvalidOperationException(string.Format("Start not allowed in execution state \"{0}\".", ExecutionState));
+      if (Optimizers.Count == 0) return;
+
+      experimentStarted = true;
+      experimentStopped = false;
+      IOptimizer optimizer = Optimizers.FirstOrDefault(x => (x.ExecutionState == ExecutionState.Prepared) || (x.ExecutionState == ExecutionState.Paused));
+      if (optimizer != null) {
+        // a race-condition may occur when the optimizer has changed the state by itself in the meantime
+        try { optimizer.Start(); } catch (InvalidOperationException) { }
+      }
+    }
+    public void Pause() {
+      if (ExecutionState != ExecutionState.Started)
+        throw new InvalidOperationException(string.Format("Pause not allowed in execution state \"{0}\".", ExecutionState));
+      if (Optimizers.Count == 0) return;
+
+      experimentStarted = false;
+      experimentStopped = false;
+      foreach (IOptimizer optimizer in Optimizers.Where(x => x.ExecutionState == ExecutionState.Started)) {
+        // a race-condition may occur when the optimizer has changed the state by itself in the meantime
+        try { optimizer.Pause(); } catch (InvalidOperationException) { }
+      }
+    }
+    public void Stop() {
+      if ((ExecutionState != ExecutionState.Started) && (ExecutionState != ExecutionState.Paused))
+        throw new InvalidOperationException(string.Format("Stop not allowed in execution state \"{0}\".", ExecutionState));
+      if (Optimizers.Count == 0) return;
+
+      experimentStarted = false;
+      experimentStopped = true;
+      if (Optimizers.Any(x => (x.ExecutionState == ExecutionState.Started) || (x.ExecutionState == ExecutionState.Paused))) {
+        foreach (var optimizer in Optimizers.Where(x => (x.ExecutionState == ExecutionState.Started) || (x.ExecutionState == ExecutionState.Paused))) {
+          // a race-condition may occur when the optimizer has changed the state by itself in the meantime
+          try { optimizer.Stop(); } catch (InvalidOperationException) { }
+        }
+      } else {
+        OnStopped();
+      }
+    }
+
+    #region Events
+    protected override void OnNameChanged() {
+      base.OnNameChanged();
+      Runs.OptimizerName = Name;
+    }
+
+    public event EventHandler ExecutionStateChanged;
+    private void OnExecutionStateChanged() {
+      EventHandler handler = ExecutionStateChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler ExecutionTimeChanged;
+    private void OnExecutionTimeChanged() {
+      EventHandler handler = ExecutionTimeChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler Prepared;
+    private void OnPrepared() {
+      ExecutionState = ExecutionState.Prepared;
+      EventHandler handler = Prepared;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler Started;
+    private void OnStarted() {
+      ExecutionState = ExecutionState.Started;
+      EventHandler handler = Started;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler Paused;
+    private void OnPaused() {
+      ExecutionState = ExecutionState.Paused;
+      EventHandler handler = Paused;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler Stopped;
+    private void OnStopped() {
+      ExecutionState = ExecutionState.Stopped;
+      EventHandler handler = Stopped;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler<EventArgs<Exception>> ExceptionOccurred;
+    private void OnExceptionOccurred(Exception exception) {
+      EventHandler<EventArgs<Exception>> handler = ExceptionOccurred;
+      if (handler != null) handler(this, new EventArgs<Exception>(exception));
+    }
+
+    private void RegisterOptimizersEvents() {
+      Optimizers.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_CollectionReset);
+      Optimizers.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsAdded);
+      Optimizers.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsRemoved);
+      Optimizers.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsReplaced);
+    }
+    private void DeregisterOptimizersEvents() {
+      Optimizers.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_CollectionReset);
+      Optimizers.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsAdded);
+      Optimizers.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsRemoved);
+      Optimizers.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<IOptimizer>>(Optimizers_ItemsReplaced);
+    }
+    private void Optimizers_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>> e) {
+      foreach (IndexedItem<IOptimizer> item in e.OldItems)
+        RemoveOptimizer(item.Value);
+      foreach (IndexedItem<IOptimizer> item in e.Items)
+        AddOptimizer(item.Value);
+    }
+    private void Optimizers_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>> e) {
+      foreach (IndexedItem<IOptimizer> item in e.Items)
+        AddOptimizer(item.Value);
+    }
+    private void Optimizers_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>> e) {
+      foreach (IndexedItem<IOptimizer> item in e.Items)
+        RemoveOptimizer(item.Value);
+    }
+    private void Optimizers_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>> e) {
+      foreach (IndexedItem<IOptimizer> item in e.OldItems)
+        RemoveOptimizer(item.Value);
+      foreach (IndexedItem<IOptimizer> item in e.Items)
+        AddOptimizer(item.Value);
+    }
+    private void AddOptimizer(IOptimizer optimizer) {
+      RegisterOptimizerEvents(optimizer);
+      Runs.AddRange(optimizer.Runs);
+      optimizer.Prepare();
+      if (ExecutionState == ExecutionState.Stopped && optimizer.ExecutionState == ExecutionState.Prepared)
+        OnPrepared();
+    }
+    private void RemoveOptimizer(IOptimizer optimizer) {
+      DeregisterOptimizerEvents(optimizer);
+      Runs.RemoveRange(optimizer.Runs);
+      if (ExecutionState == ExecutionState.Prepared && !optimizers.Any(opt => opt.ExecutionState == ExecutionState.Prepared))
+        OnStopped();
+    }
+
+    private void RegisterOptimizerEvents(IOptimizer optimizer) {
+      optimizer.ExceptionOccurred += new EventHandler<EventArgs<Exception>>(optimizer_ExceptionOccurred);
+      optimizer.ExecutionTimeChanged += new EventHandler(optimizer_ExecutionTimeChanged);
+      optimizer.Paused += new EventHandler(optimizer_Paused);
+      optimizer.Prepared += new EventHandler(optimizer_Prepared);
+      optimizer.Started += new EventHandler(optimizer_Started);
+      optimizer.Stopped += new EventHandler(optimizer_Stopped);
+      optimizer.Runs.CollectionReset += new CollectionItemsChangedEventHandler<IRun>(optimizer_Runs_CollectionReset);
+      optimizer.Runs.ItemsAdded += new CollectionItemsChangedEventHandler<IRun>(optimizer_Runs_ItemsAdded);
+      optimizer.Runs.ItemsRemoved += new CollectionItemsChangedEventHandler<IRun>(optimizer_Runs_ItemsRemoved);
+    }
+    private void DeregisterOptimizerEvents(IOptimizer optimizer) {
+      optimizer.ExceptionOccurred -= new EventHandler<EventArgs<Exception>>(optimizer_ExceptionOccurred);
+      optimizer.ExecutionTimeChanged -= new EventHandler(optimizer_ExecutionTimeChanged);
+      optimizer.Paused -= new EventHandler(optimizer_Paused);
+      optimizer.Prepared -= new EventHandler(optimizer_Prepared);
+      optimizer.Started -= new EventHandler(optimizer_Started);
+      optimizer.Stopped -= new EventHandler(optimizer_Stopped);
+      optimizer.Runs.CollectionReset -= new CollectionItemsChangedEventHandler<IRun>(optimizer_Runs_CollectionReset);
+      optimizer.Runs.ItemsAdded -= new CollectionItemsChangedEventHandler<IRun>(optimizer_Runs_ItemsAdded);
+      optimizer.Runs.ItemsRemoved -= new CollectionItemsChangedEventHandler<IRun>(optimizer_Runs_ItemsRemoved);
+    }
+
+    private readonly object locker = new object();
+    private void optimizer_ExceptionOccurred(object sender, EventArgs<Exception> e) {
+      lock (locker)
+        OnExceptionOccurred(e.Value);
+    }
+    private void optimizer_ExecutionTimeChanged(object sender, EventArgs e) {
+      lock (locker)
+        ExecutionTime = Optimizers.Aggregate(TimeSpan.Zero, (t, o) => t + o.ExecutionTime);
+    }
+    private void optimizer_Paused(object sender, EventArgs e) {
+      lock (locker)
+        if (Optimizers.All(x => x.ExecutionState != ExecutionState.Started)) OnPaused();
+    }
+    private void optimizer_Prepared(object sender, EventArgs e) {
+      lock (locker)
+        if (Optimizers.All(x => x.ExecutionState == ExecutionState.Prepared)) OnPrepared();
+    }
+    private void optimizer_Started(object sender, EventArgs e) {
+      lock (locker)
+        if (ExecutionState != ExecutionState.Started) OnStarted();
+    }
+    private void optimizer_Stopped(object sender, EventArgs e) {
+      lock (locker) {
+        if (experimentStopped) {
+          if (Optimizers.All(x => (x.ExecutionState == ExecutionState.Stopped) || (x.ExecutionState == ExecutionState.Prepared))) OnStopped();
+        } else {
+          if (experimentStarted && Optimizers.Any(x => (x.ExecutionState == ExecutionState.Prepared) || (x.ExecutionState == ExecutionState.Paused))) {
+            Optimizers.First(x => (x.ExecutionState == ExecutionState.Prepared) || (x.ExecutionState == ExecutionState.Paused)).Start();
+          } else if (Optimizers.All(x => x.ExecutionState == ExecutionState.Stopped)) OnStopped();
+          else if (Optimizers.Any(x => (x.ExecutionState == ExecutionState.Prepared) || (x.ExecutionState == ExecutionState.Paused)) && Optimizers.All(o => o.ExecutionState != ExecutionState.Started)) OnPaused();
+        }
+      }
+    }
+    private void optimizer_Runs_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRun> e) {
+      lock (locker) {
+        Runs.RemoveRange(e.OldItems);
+        Runs.AddRange(e.Items);
+      }
+    }
+    private void optimizer_Runs_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IRun> e) {
+      lock (locker)
+        Runs.AddRange(e.Items);
+    }
+    private void optimizer_Runs_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRun> e) {
+      lock (locker)
+        Runs.RemoveRange(e.Items);
+    }
+
+    private void RegisterRunsEvents() {
+      runs.CollectionReset += new CollectionItemsChangedEventHandler<IRun>(Runs_CollectionReset);
+      runs.ItemsRemoved += new CollectionItemsChangedEventHandler<IRun>(Runs_ItemsRemoved);
+    }
+    private void DeregisterRunsEvents() {
+      runs.CollectionReset -= new CollectionItemsChangedEventHandler<IRun>(Runs_CollectionReset);
+      runs.ItemsRemoved -= new CollectionItemsChangedEventHandler<IRun>(Runs_ItemsRemoved);
+    }
+    private void Runs_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRun> e) {
+      foreach (IOptimizer optimizer in Optimizers)
+        optimizer.Runs.RemoveRange(e.OldItems);
+    }
+    private void Runs_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRun> e) {
+      foreach (IOptimizer optimizer in Optimizers)
+        optimizer.Runs.RemoveRange(e.Items);
+    }
+    #endregion
+  }
+}
Index: /trunk/sources/HeuristicLab.Optimization/3.3/MetaOptimizers/TimeLimitRun.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/MetaOptimizers/TimeLimitRun.cs	(revision 9079)
+++ /trunk/sources/HeuristicLab.Optimization/3.3/MetaOptimizers/TimeLimitRun.cs	(revision 9079)
@@ -0,0 +1,402 @@
+﻿#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.ComponentModel;
+using System.Drawing;
+using System.Linq;
+using System.Threading.Tasks;
+using HeuristicLab.Collections;
+using HeuristicLab.Common;
+using HeuristicLab.Common.Resources;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Optimization {
+  internal enum TimeLimitedRunAction { None, Prepare, Start, Pause, Stop };
+
+  /// <summary>
+  /// A run in which an algorithm is executed for a certain maximum time only.
+  /// </summary>
+  [Item("TimeLimit Run", "A run in which an optimizer is executed a certain maximum time.")]
+  [Creatable("Testing & Analysis")]
+  [StorableClass]
+  public sealed class TimeLimitRun : NamedItem, IOptimizer, IStorableContent, INotifyPropertyChanged {
+    public string Filename { get; set; }
+
+    #region ItemImage
+    public static new Image StaticItemImage {
+      get { return VSImageLibrary.Event; }
+    }
+    public override Image ItemImage {
+      get { return (Algorithm != null) ? Algorithm.ItemImage : VSImageLibrary.ExecutableStopped; }
+    }
+    #endregion
+
+    private bool pausedForSnapshot = false;
+    private bool pausedForTermination = false;
+
+    [Storable]
+    private TimeSpan maximumExecutionTime;
+    public TimeSpan MaximumExecutionTime {
+      get { return maximumExecutionTime; }
+      set {
+        if (maximumExecutionTime == value) return;
+        maximumExecutionTime = value;
+        OnPropertyChanged("MaximumExecutionTime");
+      }
+    }
+
+    [Storable]
+    private int snapshotTimesIndex;
+    [Storable]
+    private ObservableList<TimeSpan> snapshotTimes;
+    public ObservableList<TimeSpan> SnapshotTimes {
+      get { return snapshotTimes; }
+      set {
+        if (snapshotTimes == value) return;
+        snapshotTimes = value;
+        snapshotTimes.Sort();
+        FindNextSnapshotTimeIndex(ExecutionTime);
+        OnPropertyChanged("SnapshotTimes");
+      }
+    }
+
+    [Storable]
+    private bool storeAlgorithmInEachSnapshot;
+    [Storable]
+    public bool StoreAlgorithmInEachSnapshot {
+      get { return storeAlgorithmInEachSnapshot; }
+      set {
+        if (storeAlgorithmInEachSnapshot == value) return;
+        storeAlgorithmInEachSnapshot = value;
+        OnPropertyChanged("StoreAlgorithmInEachSnapshot");
+      }
+    }
+
+    [Storable]
+    private RunCollection snapshots;
+    public RunCollection Snapshots {
+      get { return snapshots; }
+      set {
+        if (snapshots == value) return;
+        snapshots = value;
+        OnPropertyChanged("Snapshots");
+      }
+    }
+
+    #region Inherited Properties
+    public ExecutionState ExecutionState {
+      get { return (Algorithm != null) ? Algorithm.ExecutionState : ExecutionState.Stopped; }
+    }
+
+    public TimeSpan ExecutionTime {
+      get { return (Algorithm != null) ? Algorithm.ExecutionTime : TimeSpan.FromSeconds(0); }
+    }
+
+    [Storable]
+    private IAlgorithm algorithm;
+    public IAlgorithm Algorithm {
+      get { return algorithm; }
+      set {
+        if (algorithm == value) return;
+        if (algorithm != null) DeregisterAlgorithmEvents();
+        algorithm = value;
+        if (algorithm != null) {
+          RegisterAlgorithmEvents();
+        }
+        OnPropertyChanged("Algorithm");
+        Prepare();
+      }
+    }
+
+    [Storable]
+    private RunCollection runs;
+    public RunCollection Runs {
+      get { return runs; }
+      private set {
+        if (value == null) throw new ArgumentNullException();
+        if (runs == value) return;
+        runs = value;
+        OnPropertyChanged("Runs");
+      }
+    }
+
+    public IEnumerable<IOptimizer> NestedOptimizers {
+      get {
+        if (Algorithm == null) yield break;
+        yield return Algorithm;
+        foreach (var opt in Algorithm.NestedOptimizers)
+          yield return opt;
+      }
+    }
+    #endregion
+
+    [StorableConstructor]
+    private TimeLimitRun(bool deserializing) : base(deserializing) { }
+    private TimeLimitRun(TimeLimitRun original, Cloner cloner)
+      : base(original, cloner) {
+      maximumExecutionTime = original.maximumExecutionTime;
+      snapshotTimes = new ObservableList<TimeSpan>(original.snapshotTimes);
+      snapshotTimesIndex = original.snapshotTimesIndex;
+      snapshots = cloner.Clone(original.snapshots);
+      storeAlgorithmInEachSnapshot = original.storeAlgorithmInEachSnapshot;
+      algorithm = cloner.Clone(original.algorithm);
+      runs = cloner.Clone(original.runs);
+
+      Initialize();
+    }
+    public TimeLimitRun()
+      : base() {
+      name = ItemName;
+      description = ItemDescription;
+      maximumExecutionTime = TimeSpan.FromMinutes(.5);
+      snapshotTimes = new ObservableList<TimeSpan>(new[] {
+          TimeSpan.FromSeconds(5),
+          TimeSpan.FromSeconds(10),
+          TimeSpan.FromSeconds(15) });
+      snapshotTimesIndex = 0;
+      snapshots = new RunCollection();
+      Runs = new RunCollection { OptimizerName = Name };
+      Initialize();
+    }
+    public TimeLimitRun(string name)
+      : base(name) {
+      description = ItemDescription;
+      maximumExecutionTime = TimeSpan.FromMinutes(.5);
+      snapshotTimes = new ObservableList<TimeSpan>(new[] {
+          TimeSpan.FromSeconds(5),
+          TimeSpan.FromSeconds(10),
+          TimeSpan.FromSeconds(15) });
+      snapshotTimesIndex = 0;
+      Runs = new RunCollection { OptimizerName = Name };
+      Initialize();
+    }
+    public TimeLimitRun(string name, string description)
+      : base(name, description) {
+      maximumExecutionTime = TimeSpan.FromMinutes(.5);
+      snapshotTimes = new ObservableList<TimeSpan>(new[] {
+          TimeSpan.FromSeconds(5),
+          TimeSpan.FromSeconds(10),
+          TimeSpan.FromSeconds(15) });
+      snapshotTimesIndex = 0;
+      Runs = new RunCollection { OptimizerName = Name };
+      Initialize();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      if (ExecutionState == ExecutionState.Started) throw new InvalidOperationException(string.Format("Clone not allowed in execution state \"{0}\".", ExecutionState));
+      return new TimeLimitRun(this, cloner);
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      Initialize();
+    }
+
+    private void Initialize() {
+      if (algorithm != null) RegisterAlgorithmEvents();
+      snapshotTimes.ItemsAdded += snapshotTimes_Changed;
+      snapshotTimes.ItemsMoved += snapshotTimes_Changed;
+      snapshotTimes.ItemsRemoved += snapshotTimes_Changed;
+      snapshotTimes.ItemsReplaced += snapshotTimes_Changed;
+      snapshotTimes.CollectionReset += snapshotTimes_Changed;
+    }
+
+    private void snapshotTimes_Changed(object sender, CollectionItemsChangedEventArgs<IndexedItem<TimeSpan>> e) {
+      if (e.Items.Any()) snapshotTimes.Sort();
+      FindNextSnapshotTimeIndex(ExecutionTime);
+    }
+
+    public void Snapshot() {
+      if (Algorithm == null || Algorithm.ExecutionState != ExecutionState.Paused) throw new InvalidOperationException("Snapshot not allowed in execution states other than Paused");
+      Task.Factory.StartNew(MakeSnapshot);
+    }
+
+    public void Prepare() {
+      Prepare(false);
+    }
+    public void Prepare(bool clearRuns) {
+      Algorithm.Prepare(clearRuns);
+    }
+    public void Start() {
+      Algorithm.Start();
+    }
+    public void Pause() {
+      Algorithm.Pause();
+    }
+    public void Stop() {
+      Algorithm.Stop();
+    }
+
+    #region Events
+    protected override void OnNameChanged() {
+      base.OnNameChanged();
+      runs.OptimizerName = Name;
+    }
+
+    public event PropertyChangedEventHandler PropertyChanged;
+    private void OnPropertyChanged(string property) {
+      var handler = PropertyChanged;
+      if (handler != null) handler(this, new PropertyChangedEventArgs(property));
+    }
+
+    #region IExecutable Events
+    public event EventHandler ExecutionStateChanged;
+    private void OnExecutionStateChanged() {
+      var handler = ExecutionStateChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler ExecutionTimeChanged;
+    private void OnExecutionTimeChanged() {
+      var handler = ExecutionTimeChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler Prepared;
+    private void OnPrepared() {
+      var handler = Prepared;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler Started;
+    private void OnStarted() {
+      var handler = Started;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler Paused;
+    private void OnPaused() {
+      var handler = Paused;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler Stopped;
+    private void OnStopped() {
+      var handler = Stopped;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler<EventArgs<Exception>> ExceptionOccurred;
+    private void OnExceptionOccurred(Exception exception) {
+      var handler = ExceptionOccurred;
+      if (handler != null) handler(this, new EventArgs<Exception>(exception));
+    }
+    #endregion
+
+    #region Algorithm Events
+    private void RegisterAlgorithmEvents() {
+      algorithm.ExceptionOccurred += Algorithm_ExceptionOccurred;
+      algorithm.ExecutionTimeChanged += Algorithm_ExecutionTimeChanged;
+      algorithm.ExecutionStateChanged += Algorithm_ExecutionStateChanged;
+      algorithm.Paused += Algorithm_Paused;
+      algorithm.Prepared += Algorithm_Prepared;
+      algorithm.Started += Algorithm_Started;
+      algorithm.Stopped += Algorithm_Stopped;
+    }
+    private void DeregisterAlgorithmEvents() {
+      algorithm.ExceptionOccurred -= Algorithm_ExceptionOccurred;
+      algorithm.ExecutionTimeChanged -= Algorithm_ExecutionTimeChanged;
+      algorithm.ExecutionStateChanged -= Algorithm_ExecutionStateChanged;
+      algorithm.Paused -= Algorithm_Paused;
+      algorithm.Prepared -= Algorithm_Prepared;
+      algorithm.Started -= Algorithm_Started;
+      algorithm.Stopped -= Algorithm_Stopped;
+    }
+    private void Algorithm_ExceptionOccurred(object sender, EventArgs<Exception> e) {
+      OnExceptionOccurred(e.Value);
+    }
+    private void Algorithm_ExecutionTimeChanged(object sender, EventArgs e) {
+      if (snapshotTimesIndex < SnapshotTimes.Count && ExecutionTime >= SnapshotTimes[snapshotTimesIndex]
+        && !pausedForSnapshot) {
+        pausedForSnapshot = true;
+        Algorithm.Pause();
+      }
+      if (ExecutionTime >= MaximumExecutionTime && !pausedForTermination) {
+        pausedForTermination = true;
+        if (!pausedForSnapshot) Algorithm.Pause();
+      }
+      OnExecutionTimeChanged();
+    }
+    private void Algorithm_ExecutionStateChanged(object sender, EventArgs e) {
+      OnExecutionStateChanged();
+    }
+    private void Algorithm_Paused(object sender, EventArgs e) {
+      var action = pausedForTermination ? ExecutionState.Stopped : (pausedForSnapshot ? ExecutionState.Started : ExecutionState.Paused);
+      if (pausedForSnapshot || pausedForTermination) {
+        pausedForSnapshot = pausedForTermination = false;
+        MakeSnapshot();
+        FindNextSnapshotTimeIndex(ExecutionTime);
+      }
+      OnPaused();
+      if (action == ExecutionState.Started) Algorithm.Start();
+      else if (action == ExecutionState.Stopped) Algorithm.Stop();
+    }
+    private void Algorithm_Prepared(object sender, EventArgs e) {
+      snapshotTimesIndex = 0;
+      snapshots.Clear();
+      OnPrepared();
+    }
+    private void Algorithm_Started(object sender, EventArgs e) {
+      OnStarted();
+    }
+    private void Algorithm_Stopped(object sender, EventArgs e) {
+      var cloner = new Cloner();
+      var algRun = cloner.Clone(Algorithm.Runs.Last());
+      var clonedSnapshots = cloner.Clone(snapshots);
+      algRun.Results.Add("TimeLimitRunSnapshots", clonedSnapshots);
+      Runs.Add(algRun);
+      Algorithm.Runs.Clear();
+      OnStopped();
+    }
+    #endregion
+    #endregion
+
+    private void FindNextSnapshotTimeIndex(TimeSpan reference) {
+      var index = 0;
+      while (index < snapshotTimes.Count && snapshotTimes[index] <= reference) {
+        index++;
+      };
+      snapshotTimesIndex = index;
+    }
+
+    private void MakeSnapshot() {
+      string time = Math.Round(ExecutionTime.TotalSeconds, 1).ToString("0.0");
+      string runName = "Snapshot " + time + "s " + algorithm.Name;
+      Run run;
+      if (StoreAlgorithmInEachSnapshot) {
+        var temporarilySetStoreFlag = !Algorithm.StoreAlgorithmInEachRun;
+        if (temporarilySetStoreFlag) Algorithm.StoreAlgorithmInEachRun = true;
+        run = new Run(runName, Algorithm);
+        if (temporarilySetStoreFlag) Algorithm.StoreAlgorithmInEachRun = false;
+      } else {
+        // duplicate code of Run.Initialize - necessary, because Algorithm property doesn't have a setter
+        run = new Run() { Name = runName };
+        var parameters = new Dictionary<string, IItem>();
+        var results = new Dictionary<string, IItem>();
+        algorithm.CollectParameterValues(parameters);
+        algorithm.CollectResultValues(results);
+        var cloner = new Cloner();
+        foreach (var kvp in parameters.Select(x => new KeyValuePair<string, IItem>(x.Key, cloner.Clone(x.Value))).ToDictionary(x => x.Key, x => x.Value))
+          run.Parameters.Add(kvp);
+        foreach (var kvp in results.Select(x => new KeyValuePair<string, IItem>(x.Key, cloner.Clone(x.Value))).ToDictionary(x => x.Key, x => x.Value))
+          run.Results.Add(kvp);
+      }
+      snapshots.Add(run);
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.Optimizer/3.3/CreateExperimentDialog.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimizer/3.3/CreateExperimentDialog.cs	(revision 9078)
+++ /trunk/sources/HeuristicLab.Optimizer/3.3/CreateExperimentDialog.cs	(revision 9079)
@@ -30,4 +30,5 @@
 using HeuristicLab.Core;
 using HeuristicLab.Data;
+using HeuristicLab.MainForm.WindowsForms;
 using HeuristicLab.Optimization;
 using HeuristicLab.Parameters;
Index: unk/sources/HeuristicLab.Optimizer/3.3/DefineArithmeticProgressionDialog.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimizer/3.3/DefineArithmeticProgressionDialog.Designer.cs	(revision 9078)
+++ 	(revision )
@@ -1,185 +1,0 @@
-﻿#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
-
-namespace HeuristicLab.Optimizer {
-  partial class DefineArithmeticProgressionDialog {
-    /// <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() {
-      this.components = new System.ComponentModel.Container();
-      this.stepSizeTextBox = new System.Windows.Forms.TextBox();
-      this.maximumTextBox = new System.Windows.Forms.TextBox();
-      this.minimumTextBox = new System.Windows.Forms.TextBox();
-      this.stepSizeLabel = new System.Windows.Forms.Label();
-      this.maximumLabel = new System.Windows.Forms.Label();
-      this.minimumLabel = new System.Windows.Forms.Label();
-      this.cancelButton = new System.Windows.Forms.Button();
-      this.okButton = new System.Windows.Forms.Button();
-      this.errorProvider = new System.Windows.Forms.ErrorProvider(this.components);
-      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit();
-      this.SuspendLayout();
-      // 
-      // stepSizeTextBox
-      // 
-      this.stepSizeTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.stepSizeTextBox.Location = new System.Drawing.Point(75, 64);
-      this.stepSizeTextBox.Name = "stepSizeTextBox";
-      this.stepSizeTextBox.Size = new System.Drawing.Size(184, 20);
-      this.stepSizeTextBox.TabIndex = 11;
-      this.stepSizeTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.textBox_Validating);
-      // 
-      // maximumTextBox
-      // 
-      this.maximumTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.maximumTextBox.Location = new System.Drawing.Point(75, 38);
-      this.maximumTextBox.Name = "maximumTextBox";
-      this.maximumTextBox.Size = new System.Drawing.Size(184, 20);
-      this.maximumTextBox.TabIndex = 9;
-      this.maximumTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.textBox_Validating);
-      // 
-      // minimumTextBox
-      // 
-      this.minimumTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.minimumTextBox.Location = new System.Drawing.Point(75, 12);
-      this.minimumTextBox.Name = "minimumTextBox";
-      this.minimumTextBox.Size = new System.Drawing.Size(184, 20);
-      this.minimumTextBox.TabIndex = 7;
-      this.minimumTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.textBox_Validating);
-      // 
-      // stepSizeLabel
-      // 
-      this.stepSizeLabel.AutoSize = true;
-      this.stepSizeLabel.Location = new System.Drawing.Point(15, 67);
-      this.stepSizeLabel.Name = "stepSizeLabel";
-      this.stepSizeLabel.Size = new System.Drawing.Size(53, 13);
-      this.stepSizeLabel.TabIndex = 10;
-      this.stepSizeLabel.Text = "Step size:";
-      // 
-      // maximumLabel
-      // 
-      this.maximumLabel.AutoSize = true;
-      this.maximumLabel.Location = new System.Drawing.Point(15, 41);
-      this.maximumLabel.Name = "maximumLabel";
-      this.maximumLabel.Size = new System.Drawing.Size(54, 13);
-      this.maximumLabel.TabIndex = 8;
-      this.maximumLabel.Text = "Maximum:";
-      // 
-      // minimumLabel
-      // 
-      this.minimumLabel.AutoSize = true;
-      this.minimumLabel.Location = new System.Drawing.Point(15, 15);
-      this.minimumLabel.Name = "minimumLabel";
-      this.minimumLabel.Size = new System.Drawing.Size(51, 13);
-      this.minimumLabel.TabIndex = 6;
-      this.minimumLabel.Text = "Minimum:";
-      // 
-      // 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(184, 96);
-      this.cancelButton.Name = "cancelButton";
-      this.cancelButton.Size = new System.Drawing.Size(75, 23);
-      this.cancelButton.TabIndex = 12;
-      this.cancelButton.Text = "&Cancel";
-      this.cancelButton.UseVisualStyleBackColor = true;
-      // 
-      // 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(103, 96);
-      this.okButton.Name = "okButton";
-      this.okButton.Size = new System.Drawing.Size(75, 23);
-      this.okButton.TabIndex = 12;
-      this.okButton.Text = "&OK";
-      this.okButton.UseVisualStyleBackColor = true;
-      // 
-      // errorProvider
-      // 
-      this.errorProvider.ContainerControl = this;
-      // 
-      // DefineArithmeticProgressionDialog
-      // 
-      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(271, 131);
-      this.Controls.Add(this.okButton);
-      this.Controls.Add(this.cancelButton);
-      this.Controls.Add(this.stepSizeTextBox);
-      this.Controls.Add(this.maximumTextBox);
-      this.Controls.Add(this.minimumTextBox);
-      this.Controls.Add(this.stepSizeLabel);
-      this.Controls.Add(this.maximumLabel);
-      this.Controls.Add(this.minimumLabel);
-      this.MaximizeBox = false;
-      this.MinimizeBox = false;
-      this.Name = "DefineArithmeticProgressionDialog";
-      this.ShowIcon = false;
-      this.ShowInTaskbar = false;
-      this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
-      this.Text = "Generate Values";
-      this.TopMost = true;
-      this.Load += new System.EventHandler(this.DefineArithmeticProgressionDialog_Load);
-      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).EndInit();
-      this.ResumeLayout(false);
-      this.PerformLayout();
-
-    }
-
-    #endregion
-
-    private System.Windows.Forms.TextBox stepSizeTextBox;
-    private System.Windows.Forms.TextBox maximumTextBox;
-    private System.Windows.Forms.TextBox minimumTextBox;
-    private System.Windows.Forms.Label stepSizeLabel;
-    private System.Windows.Forms.Label maximumLabel;
-    private System.Windows.Forms.Label minimumLabel;
-    private System.Windows.Forms.Button cancelButton;
-    private System.Windows.Forms.Button okButton;
-    private System.Windows.Forms.ErrorProvider errorProvider;
-  }
-}
Index: unk/sources/HeuristicLab.Optimizer/3.3/DefineArithmeticProgressionDialog.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimizer/3.3/DefineArithmeticProgressionDialog.cs	(revision 9078)
+++ 	(revision )
@@ -1,116 +1,0 @@
-﻿#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.ComponentModel;
-using System.Globalization;
-using System.Linq;
-using System.Windows.Forms;
-using HeuristicLab.Common;
-
-namespace HeuristicLab.Optimizer {
-  public partial class DefineArithmeticProgressionDialog : Form {
-    private bool allowOnlyInteger;
-
-    public double Minimum { get; private set; }
-    public double Maximum { get; private set; }
-    public double Step { get; private set; }
-
-    public IEnumerable<double> Values {
-      get { return EnumerateProgression().Reverse(); }
-    }
-
-    public DefineArithmeticProgressionDialog() {
-      InitializeComponent();
-      Icon = HeuristicLab.Common.Resources.HeuristicLab.Icon;
-      Minimum = 0; Maximum = 100; Step = 10;
-    }
-    public DefineArithmeticProgressionDialog(bool allowOnlyInteger)
-      : this() {
-      this.allowOnlyInteger = allowOnlyInteger;
-    }
-    public DefineArithmeticProgressionDialog(bool allowOnlyInteger, double minimum, double maximum, double step)
-      : this(allowOnlyInteger) {
-      Minimum = minimum;
-      Maximum = maximum;
-      Step = step;
-    }
-
-    private void DefineArithmeticProgressionDialog_Load(object sender, System.EventArgs e) {
-      minimumTextBox.Text = Minimum.ToString();
-      maximumTextBox.Text = Maximum.ToString();
-      stepSizeTextBox.Text = Step.ToString();
-    }
-
-    private void textBox_Validating(object sender, CancelEventArgs e) {
-      var textBox = (TextBox)sender;
-      double value = 0;
-      if (allowOnlyInteger) {
-        int intValue;
-        if (!int.TryParse(textBox.Text, out intValue)) {
-          errorProvider.SetError(textBox, "Please enter a valid integer value.");
-          e.Cancel = true;
-          return;
-        } else {
-          value = intValue;
-          errorProvider.SetError(textBox, null);
-        }
-      } else {
-        if (!double.TryParse(textBox.Text, NumberStyles.Float, CultureInfo.CurrentCulture.NumberFormat, out value)) {
-          errorProvider.SetError(textBox, "Please enter a valid double value.");
-          e.Cancel = true;
-          return;
-        } else errorProvider.SetError(textBox, null);
-      }
-      if (textBox == minimumTextBox) Minimum = value;
-      else if (textBox == maximumTextBox) Maximum = value;
-      else if (textBox == stepSizeTextBox) Step = value;
-      okButton.Enabled = IsValid();
-    }
-
-    private bool IsValid() {
-      return Minimum <= Maximum && Step >= 0;
-    }
-
-    private IEnumerable<double> EnumerateProgression() {
-      double value = Maximum;
-      bool minimumIncluded = false;
-      int i = 1;
-      while (value >= Minimum) {
-        if (value.IsAlmost(Minimum)) {
-          yield return Minimum;
-          minimumIncluded = true;
-        } else yield return value;
-        
-        if (Step == 0) break; // a step size of 0 will only output maximum and minimum
-        if (allowOnlyInteger) {
-          value = (int)Maximum - i * (int)Step;
-        } else {
-          value = Maximum - i * Step;
-        }
-        i++;
-      }
-      if (!minimumIncluded) {
-        yield return Minimum;
-      }
-    }
-  }
-}
Index: /trunk/sources/HeuristicLab.Optimizer/3.3/HeuristicLab.Optimizer-3.3.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Optimizer/3.3/HeuristicLab.Optimizer-3.3.csproj	(revision 9078)
+++ /trunk/sources/HeuristicLab.Optimizer/3.3/HeuristicLab.Optimizer-3.3.csproj	(revision 9079)
@@ -128,10 +128,4 @@
     <EmbeddedResource Include="Documents\RAPGA_JSSP.hl" />
     <None Include="Plugin.cs.frame" />
-    <Compile Include="DefineArithmeticProgressionDialog.cs">
-      <SubType>Form</SubType>
-    </Compile>
-    <Compile Include="DefineArithmeticProgressionDialog.Designer.cs">
-      <DependentUpon>DefineArithmeticProgressionDialog.cs</DependentUpon>
-    </Compile>
     <Compile Include="OptimizerSingleDocumentMainForm.cs">
       <SubType>Form</SubType>
