Index: stable/HeuristicLab.Scripting/3.3/CSharpScript.cs
===================================================================
--- stable/HeuristicLab.Scripting/3.3/CSharpScript.cs	(revision 10892)
+++ stable/HeuristicLab.Scripting/3.3/CSharpScript.cs	(revision 10892)
@@ -0,0 +1,165 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2014 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Linq;
+using System.Reflection;
+using System.Threading;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Scripting {
+  [Item("C# Script", "An empty C# script.")]
+  [Creatable("Scripts")]
+  [StorableClass]
+  public class CSharpScript : Script, IStorableContent {
+    #region Constants
+    protected const string ExecuteMethodName = "Execute";
+    protected override string CodeTemplate {
+      get {
+        return @"// use 'vars' to access variables in the script's variable store (e.g. vars.x = 5)
+// use 'vars.Contains(string)' to check if a variable exists
+// use 'vars.Clear()' to remove all variables
+// use 'foreach (KeyValuePair<string, object> v in vars) { ... }' to iterate over all variables
+
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+
+public class MyScript : HeuristicLab.Scripting.CSharpScriptBase {
+  public override void Main() {
+    // type your code here
+  }
+
+  // implement further classes and methods
+
+}";
+      }
+    }
+    #endregion
+
+    #region Fields & Properties
+    private CSharpScriptBase compiledScript;
+
+    public string Filename { get; set; }
+
+    [Storable]
+    private VariableStore variableStore;
+    public VariableStore VariableStore {
+      get { return variableStore; }
+    }
+    #endregion
+
+    #region Construction & Initialization
+    [StorableConstructor]
+    protected CSharpScript(bool deserializing) : base(deserializing) { }
+    protected CSharpScript(CSharpScript original, Cloner cloner)
+      : base(original, cloner) {
+      variableStore = new VariableStore();
+    }
+    public CSharpScript() {
+      variableStore = new VariableStore();
+      Code = CodeTemplate;
+    }
+    public CSharpScript(string code)
+      : base(code) {
+      variableStore = new VariableStore();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CSharpScript(this, cloner);
+    }
+    #endregion
+
+    protected virtual void RegisterScriptEvents() {
+      if (compiledScript != null)
+        compiledScript.ConsoleOutputChanged += CompiledScriptOnConsoleOutputChanged;
+    }
+
+    protected virtual void DeregisterScriptEvents() {
+      if (compiledScript != null)
+        compiledScript.ConsoleOutputChanged -= CompiledScriptOnConsoleOutputChanged;
+    }
+
+    #region Compilation
+
+    public override Assembly Compile() {
+      DeregisterScriptEvents();
+      compiledScript = null;
+      var assembly = base.Compile();
+      var types = assembly.GetTypes();
+      compiledScript = (CSharpScriptBase)Activator.CreateInstance(types.Single(x => typeof(CSharpScriptBase).IsAssignableFrom(x)));
+      RegisterScriptEvents();
+      return assembly;
+    }
+    #endregion
+
+    private Thread scriptThread;
+    public virtual void Execute() {
+      if (compiledScript == null) return;
+      scriptThread = new Thread(() => {
+        Exception ex = null;
+        try {
+          OnScriptExecutionStarted();
+          compiledScript.Execute(VariableStore);
+        } catch (ThreadAbortException) {
+          // the execution was cancelled by the user
+        } catch (Exception e) {
+          ex = e;
+        } finally {
+          OnScriptExecutionFinished(ex);
+        }
+      });
+      scriptThread.Start();
+    }
+
+    public virtual void Kill() {
+      if (scriptThread.IsAlive)
+        scriptThread.Abort();
+    }
+
+    protected virtual void CompiledScriptOnConsoleOutputChanged(object sender, EventArgs<string> e) {
+      OnConsoleOutputChanged(e.Value);
+    }
+
+    public event EventHandler ScriptExecutionStarted;
+    protected virtual void OnScriptExecutionStarted() {
+      var handler = ScriptExecutionStarted;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+
+    public event EventHandler<EventArgs<Exception>> ScriptExecutionFinished;
+    protected virtual void OnScriptExecutionFinished(Exception e) {
+      var handler = ScriptExecutionFinished;
+      if (handler != null) handler(this, new EventArgs<Exception>(e));
+    }
+
+    public event EventHandler<EventArgs<string>> ConsoleOutputChanged;
+    protected virtual void OnConsoleOutputChanged(string args) {
+      var handler = ConsoleOutputChanged;
+      if (handler != null) handler(this, new EventArgs<string>(args));
+    }
+  }
+}
Index: stable/HeuristicLab.Scripting/3.3/CSharpScriptBase.cs
===================================================================
--- stable/HeuristicLab.Scripting/3.3/CSharpScriptBase.cs	(revision 10892)
+++ stable/HeuristicLab.Scripting/3.3/CSharpScriptBase.cs	(revision 10892)
@@ -0,0 +1,108 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2014 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.IO;
+using System.Text;
+using HeuristicLab.Common;
+
+namespace HeuristicLab.Scripting {
+  public abstract class CSharpScriptBase {
+    protected dynamic vars;
+
+    private readonly EventWriter console;
+    protected EventWriter Console {
+      get { return console; }
+    }
+
+    protected CSharpScriptBase() {
+      console = new EventWriter(this);
+    }
+
+    public abstract void Main();
+
+    internal void Execute(VariableStore variableStore) {
+      vars = new Variables(variableStore);
+      Main();
+    }
+
+    protected internal event EventHandler<EventArgs<string>> ConsoleOutputChanged;
+    private void OnConsoleOutputChanged(string args) {
+      var handler = ConsoleOutputChanged;
+      if (handler != null) handler(null, new EventArgs<string>(args));
+    }
+
+    protected class EventWriter : TextWriter {
+      private readonly CSharpScriptBase script;
+
+      public EventWriter(CSharpScriptBase script) {
+        this.script = script;
+      }
+
+      public override Encoding Encoding {
+        get { return Encoding.UTF8; }
+      }
+
+      #region Write/WriteLine Overrides
+      #region Write
+      public override void Write(bool value) { script.OnConsoleOutputChanged(value.ToString()); }
+      public override void Write(char value) { script.OnConsoleOutputChanged(value.ToString()); }
+      public override void Write(char[] buffer) { script.OnConsoleOutputChanged(new string(buffer)); }
+      public override void Write(char[] buffer, int index, int count) { script.OnConsoleOutputChanged(new string(buffer, index, count)); }
+      public override void Write(decimal value) { script.OnConsoleOutputChanged(value.ToString()); }
+      public override void Write(double value) { script.OnConsoleOutputChanged(value.ToString()); }
+      public override void Write(float value) { script.OnConsoleOutputChanged(value.ToString()); }
+      public override void Write(int value) { script.OnConsoleOutputChanged(value.ToString()); }
+      public override void Write(long value) { script.OnConsoleOutputChanged(value.ToString()); }
+      public override void Write(object value) { script.OnConsoleOutputChanged(value.ToString()); }
+      public override void Write(string value) { script.OnConsoleOutputChanged(value); }
+      public override void Write(string format, object arg0) { script.OnConsoleOutputChanged(string.Format(format, arg0)); }
+      public override void Write(string format, object arg0, object arg1) { script.OnConsoleOutputChanged(string.Format(format, arg0, arg0)); }
+      public override void Write(string format, object arg0, object arg1, object arg2) { script.OnConsoleOutputChanged(string.Format(format, arg0, arg1, arg2)); }
+      public override void Write(string format, params object[] arg) { script.OnConsoleOutputChanged(string.Format(format, arg)); }
+      public override void Write(uint value) { script.OnConsoleOutputChanged(value.ToString()); }
+      public override void Write(ulong value) { script.OnConsoleOutputChanged(value.ToString()); }
+      #endregion
+
+      #region WriteLine
+      public override void WriteLine() { script.OnConsoleOutputChanged(Environment.NewLine); }
+      public override void WriteLine(bool value) { script.OnConsoleOutputChanged(value + Environment.NewLine); }
+      public override void WriteLine(char value) { script.OnConsoleOutputChanged(value + Environment.NewLine); }
+      public override void WriteLine(char[] buffer) { script.OnConsoleOutputChanged(new string(buffer) + Environment.NewLine); }
+      public override void WriteLine(char[] buffer, int index, int count) { script.OnConsoleOutputChanged(new string(buffer, index, count) + Environment.NewLine); }
+      public override void WriteLine(decimal value) { script.OnConsoleOutputChanged(value + Environment.NewLine); }
+      public override void WriteLine(double value) { script.OnConsoleOutputChanged(value + Environment.NewLine); }
+      public override void WriteLine(float value) { script.OnConsoleOutputChanged(value + Environment.NewLine); }
+      public override void WriteLine(int value) { script.OnConsoleOutputChanged(value + Environment.NewLine); }
+      public override void WriteLine(long value) { script.OnConsoleOutputChanged(value + Environment.NewLine); }
+      public override void WriteLine(object value) { script.OnConsoleOutputChanged(value + Environment.NewLine); }
+      public override void WriteLine(string value) { script.OnConsoleOutputChanged(value + Environment.NewLine); }
+      public override void WriteLine(string format, object arg0) { script.OnConsoleOutputChanged(string.Format(format, arg0) + Environment.NewLine); }
+      public override void WriteLine(string format, object arg0, object arg1) { script.OnConsoleOutputChanged(string.Format(format, arg0, arg1) + Environment.NewLine); }
+      public override void WriteLine(string format, object arg0, object arg1, object arg2) { script.OnConsoleOutputChanged(string.Format(format, arg0, arg1, arg2) + Environment.NewLine); }
+      public override void WriteLine(string format, params object[] arg) { script.OnConsoleOutputChanged(string.Format(format, arg) + Environment.NewLine); }
+      public override void WriteLine(uint value) { script.OnConsoleOutputChanged(value + Environment.NewLine); }
+      public override void WriteLine(ulong value) { script.OnConsoleOutputChanged(value + Environment.NewLine); }
+      #endregion
+      #endregion
+    }
+  }
+}
Index: stable/HeuristicLab.Scripting/3.3/HeuristicLab.Scripting-3.3.csproj
===================================================================
--- trunk/sources/HeuristicLab.Scripting/3.3/HeuristicLab.Scripting-3.3.csproj	(revision 10512)
+++ stable/HeuristicLab.Scripting/3.3/HeuristicLab.Scripting-3.3.csproj	(revision 10892)
@@ -85,8 +85,10 @@
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="CSharpScript.cs" />
+    <Compile Include="Variables.cs" />
     <Compile Include="VariableStore.cs" />
     <None Include="Plugin.cs.frame" />
     <Compile Include="Script.cs" />
-    <Compile Include="UserScriptBase.cs" />
+    <Compile Include="CSharpScriptBase.cs" />
     <Compile Include="Plugin.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
Index: stable/HeuristicLab.Scripting/3.3/Script.cs
===================================================================
--- trunk/sources/HeuristicLab.Scripting/3.3/Script.cs	(revision 10512)
+++ stable/HeuristicLab.Scripting/3.3/Script.cs	(revision 10892)
@@ -29,6 +29,4 @@
 using System.Reflection;
 using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading;
 using HeuristicLab.Common;
 using HeuristicLab.Common.Resources;
@@ -38,43 +36,13 @@
 
 namespace HeuristicLab.Scripting {
-  [Item("Script", "An empty C# script.")]
-  [Creatable("Scripts")]
   [StorableClass]
-  public sealed class Script : NamedItem, IStorableContent {
-    #region Constants
-    private const string ExecuteMethodName = "Execute";
-    private const string CodeTemplate =
-@"// use 'vars' to access global variables in the variable store
-
-using System;
-using System.Linq;
-using System.Collections.Generic;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-
-public class UserScript : HeuristicLab.Scripting.UserScriptBase {
-  public override void Main() {
-    // type your code here
-  }
-
-  // further classes and methods
-
-}";
-    #endregion
+  public class Script : NamedItem {
+    protected virtual string CodeTemplate {
+      get { return string.Empty; }
+    }
 
     #region Fields & Properties
-    private UserScriptBase compiledScript;
-
-    public string Filename { get; set; }
-
     public static new Image StaticItemImage {
       get { return VSImageLibrary.Script; }
-    }
-
-    [Storable]
-    private VariableStore variableStore;
-    public VariableStore VariableStore {
-      get { return variableStore; }
     }
 
@@ -86,12 +54,6 @@
         if (value == code) return;
         code = value;
-        compiledScript = null;
         OnCodeChanged();
       }
-    }
-
-    private string compilationUnitCode;
-    public string CompilationUnitCode {
-      get { return compilationUnitCode; }
     }
 
@@ -108,18 +70,18 @@
     #region Construction & Initialization
     [StorableConstructor]
-    private Script(bool deserializing) : base(deserializing) { }
-    private Script(Script original, Cloner cloner)
+    protected Script(bool deserializing) : base(deserializing) { }
+    protected Script(Script original, Cloner cloner)
       : base(original, cloner) {
       code = original.code;
-      variableStore = new VariableStore();
-      compilationUnitCode = original.compilationUnitCode;
       if (original.compileErrors != null)
         compileErrors = new CompilerErrorCollection(original.compileErrors);
     }
-
     public Script()
-      : base("Script", "A HeuristicLab script.") {
-      code = CodeTemplate;
-      variableStore = new VariableStore();
+      : base("Script", "An empty script.") {
+      code = string.Empty;
+    }
+    public Script(string code)
+      : this() {
+      this.code = code;
     }
 
@@ -129,22 +91,15 @@
     #endregion
 
-    private void RegisterScriptEvents() {
-      if (compiledScript == null) return;
-      compiledScript.ConsoleOutputChanged += compiledScript_ConsoleOutputChanged;
+    #region Compilation
+    protected virtual CSharpCodeProvider CodeProvider {
+      get {
+        return new CSharpCodeProvider(
+          new Dictionary<string, string> {
+                {"CompilerVersion", "v4.0"}, // support C# 4.0 syntax
+              });
+      }
     }
 
-    private void DeregisterScriptEvents() {
-      if (compiledScript == null) return;
-      compiledScript.ConsoleOutputChanged -= compiledScript_ConsoleOutputChanged;
-    }
-
-    #region Compilation
-    private CSharpCodeProvider codeProvider =
-      new CSharpCodeProvider(
-        new Dictionary<string, string> {
-          { "CompilerVersion", "v4.0" },  // support C# 4.0 syntax
-        });
-
-    private CompilerResults DoCompile() {
+    protected virtual CompilerResults DoCompile() {
       var parameters = new CompilerParameters {
         GenerateExecutable = false,
@@ -159,5 +114,5 @@
       var unit = CreateCompilationUnit();
       var writer = new StringWriter();
-      codeProvider.GenerateCodeFromCompileUnit(
+      CodeProvider.GenerateCodeFromCompileUnit(
         unit,
         writer,
@@ -166,11 +121,9 @@
           IndentString = "  ",
         });
-      compilationUnitCode = writer.ToString();
-      return codeProvider.CompileAssemblyFromDom(parameters, unit);
+      return CodeProvider.CompileAssemblyFromDom(parameters, unit);
     }
 
-    public void Compile() {
+    public virtual Assembly Compile() {
       var results = DoCompile();
-      compiledScript = null;
       CompileErrors = results.Errors;
       if (results.Errors.HasErrors) {
@@ -181,18 +134,12 @@
             .AppendLine(error.ErrorText);
         }
-        throw new Exception(string.Format(
-          "Compilation of \"{0}\" failed:{1}{2}",
-          Name, Environment.NewLine,
-          sb.ToString()));
+        throw new Exception(string.Format("Compilation of \"{0}\" failed:{1}{2}",
+          Name, Environment.NewLine, sb.ToString()));
       } else {
-        var assembly = results.CompiledAssembly;
-        var types = assembly.GetTypes();
-        DeregisterScriptEvents();
-        compiledScript = (UserScriptBase)Activator.CreateInstance(types[0]);
-        RegisterScriptEvents();
+        return results.CompiledAssembly;
       }
     }
 
-    public IEnumerable<Assembly> GetAssemblies() {
+    public virtual IEnumerable<Assembly> GetAssemblies() {
       var assemblies = new List<Assembly>();
       foreach (var a in AppDomain.CurrentDomain.GetAssemblies()) {
@@ -210,58 +157,12 @@
     }
 
-    private readonly Regex SafeTypeNameCharRegex = new Regex("[_a-zA-Z0-9]+");
-    private readonly Regex SafeTypeNameRegex = new Regex("[_a-zA-Z][_a-zA-Z0-9]*");
-
-    private CodeCompileUnit CreateCompilationUnit() {
+    protected virtual CodeCompileUnit CreateCompilationUnit() {
       var unit = new CodeSnippetCompileUnit(code);
       return unit;
     }
-
-    public string CompiledTypeName {
-      get {
-        var sb = new StringBuilder();
-        var strings = SafeTypeNameCharRegex.Matches(Name)
-                                           .Cast<Match>()
-                                           .Select(m => m.Value);
-        foreach (string s in strings)
-          sb.Append(s);
-        return SafeTypeNameRegex.Match(sb.ToString()).Value;
-      }
-    }
     #endregion
 
-    private Thread scriptThread;
-    public void Execute() {
-      if (compiledScript == null) return;
-      var executeMethod = typeof(UserScriptBase).GetMethod(ExecuteMethodName, BindingFlags.NonPublic | BindingFlags.Instance);
-      if (executeMethod != null) {
-        scriptThread = new Thread(() => {
-          Exception ex = null;
-          try {
-            OnScriptExecutionStarted();
-            executeMethod.Invoke(compiledScript, new[] { VariableStore });
-          } catch (ThreadAbortException) {
-            // the execution was cancelled by the user
-          } catch (TargetInvocationException e) {
-            ex = e.InnerException;
-          } finally {
-            OnScriptExecutionFinished(ex);
-          }
-        });
-        scriptThread.Start();
-      }
-    }
-
-    public void Kill() {
-      if (scriptThread.IsAlive)
-        scriptThread.Abort();
-    }
-
-    private void compiledScript_ConsoleOutputChanged(object sender, EventArgs<string> e) {
-      OnConsoleOutputChanged(e.Value);
-    }
-
     public event EventHandler CodeChanged;
-    private void OnCodeChanged() {
+    protected virtual void OnCodeChanged() {
       var handler = CodeChanged;
       if (handler != null) handler(this, EventArgs.Empty);
@@ -269,26 +170,8 @@
 
     public event EventHandler CompileErrorsChanged;
-    private void OnCompileErrorsChanged() {
+    protected virtual void OnCompileErrorsChanged() {
       var handler = CompileErrorsChanged;
       if (handler != null) handler(this, EventArgs.Empty);
     }
-
-    public event EventHandler ScriptExecutionStarted;
-    private void OnScriptExecutionStarted() {
-      var handler = ScriptExecutionStarted;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-
-    public event EventHandler<EventArgs<Exception>> ScriptExecutionFinished;
-    private void OnScriptExecutionFinished(Exception e) {
-      var handler = ScriptExecutionFinished;
-      if (handler != null) handler(this, new EventArgs<Exception>(e));
-    }
-
-    public event EventHandler<EventArgs<string>> ConsoleOutputChanged;
-    private void OnConsoleOutputChanged(string args) {
-      var handler = ConsoleOutputChanged;
-      if (handler != null) handler(this, new EventArgs<string>(args));
-    }
   }
 }
Index: stable/HeuristicLab.Scripting/3.3/UserScriptBase.cs
===================================================================
--- trunk/sources/HeuristicLab.Scripting/3.3/UserScriptBase.cs	(revision 10512)
+++ stable/HeuristicLab.Scripting/3.3/UserScriptBase.cs	(revision 10892)
@@ -52,41 +52,4 @@
       var handler = ConsoleOutputChanged;
       if (handler != null) handler(null, new EventArgs<string>(args));
-    }
-
-    protected class Variables : DynamicObject, IEnumerable<KeyValuePair<string, object>> {
-      private readonly VariableStore variableStore;
-
-      public ICollection<string> Keys {
-        get { return variableStore.Keys; }
-      }
-
-      public ICollection<object> Values {
-        get { return variableStore.Values; }
-      }
-
-      public Variables(VariableStore variableStore) {
-        this.variableStore = variableStore;
-      }
-
-      public override bool TryGetMember(GetMemberBinder binder, out object result) {
-        return variableStore.TryGetValue(binder.Name, out result);
-      }
-
-      public override bool TrySetMember(SetMemberBinder binder, object value) {
-        variableStore[binder.Name] = value;
-        return true;
-      }
-
-      public bool Contains(string variableName) {
-        return variableStore.ContainsKey(variableName);
-      }
-
-      public IEnumerator<KeyValuePair<string, object>> GetEnumerator() {
-        return variableStore.GetEnumerator();
-      }
-
-      IEnumerator IEnumerable.GetEnumerator() {
-        return GetEnumerator();
-      }
     }
 
Index: stable/HeuristicLab.Scripting/3.3/Variables.cs
===================================================================
--- stable/HeuristicLab.Scripting/3.3/Variables.cs	(revision 10892)
+++ stable/HeuristicLab.Scripting/3.3/Variables.cs	(revision 10892)
@@ -0,0 +1,38 @@
+﻿using System.Collections;
+using System.Collections.Generic;
+using System.Dynamic;
+
+namespace HeuristicLab.Scripting {
+  public class Variables : DynamicObject, IEnumerable<KeyValuePair<string, object>> {
+    private readonly VariableStore variableStore;
+
+    public Variables(VariableStore variableStore) {
+      this.variableStore = variableStore;
+    }
+
+    public override bool TryGetMember(GetMemberBinder binder, out object result) {
+      return variableStore.TryGetValue(binder.Name, out result);
+    }
+
+    public override bool TrySetMember(SetMemberBinder binder, object value) {
+      variableStore[binder.Name] = value;
+      return true;
+    }
+
+    public bool Contains(string variableName) {
+      return variableStore.ContainsKey(variableName);
+    }
+
+    public void Clear() {
+      variableStore.Clear();
+    }
+
+    public IEnumerator<KeyValuePair<string, object>> GetEnumerator() {
+      return variableStore.GetEnumerator();
+    }
+
+    IEnumerator IEnumerable.GetEnumerator() {
+      return GetEnumerator();
+    }
+  }
+}
