Index: trunk/sources/HeuristicLab.DataAnalysis/3.3/DataFormatException.cs
===================================================================
--- trunk/sources/HeuristicLab.DataAnalysis/3.3/DataFormatException.cs	(revision 1904)
+++ trunk/sources/HeuristicLab.DataAnalysis/3.3/DataFormatException.cs	(revision 1904)
@@ -0,0 +1,42 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2008 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;
+
+namespace HeuristicLab.DataAnalysis {
+  public class DataFormatException : Exception{
+    private int line;
+    public int Line {
+      get { return line; }
+    }
+    private string token;
+    public string Token {
+      get { return token; }
+    }
+    public DataFormatException(string message, string token, int line) : base(message+"\nToken: " + token + " (line: " + line + ")"){
+      this.token = token;
+      this.line = line;
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.DataAnalysis/3.3/Dataset.cs
===================================================================
--- trunk/sources/HeuristicLab.DataAnalysis/3.3/Dataset.cs	(revision 1904)
+++ trunk/sources/HeuristicLab.DataAnalysis/3.3/Dataset.cs	(revision 1904)
@@ -0,0 +1,349 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2008 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.Xml;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using System.Globalization;
+using System.Text;
+
+namespace HeuristicLab.DataAnalysis {
+  public sealed class Dataset : ItemBase {
+
+    private string name;
+    private double[] samples;
+    private int rows;
+    private int columns;
+    private Dictionary<int, Dictionary<int, double>>[] cachedMeans;
+    private Dictionary<int, Dictionary<int, double>>[] cachedRanges;
+    private double[] scalingFactor;
+    private double[] scalingOffset;
+
+    public string Name {
+      get { return name; }
+      set { name = value; }
+    }
+
+    public int Rows {
+      get { return rows; }
+      set { rows = value; }
+    }
+
+    public int Columns {
+      get { return columns; }
+      set {
+        columns = value;
+        if (variableNames == null || variableNames.Length != columns) {
+          variableNames = new string[columns];
+        }
+      }
+    }
+
+    public double[] ScalingFactor {
+      get { return scalingFactor; }
+    }
+    public double[] ScalingOffset {
+      get { return scalingOffset; }
+    }
+
+    public double GetValue(int i, int j) {
+      return samples[columns * i + j];
+    }
+
+    public void SetValue(int i, int j, double v) {
+      if (v != samples[columns * i + j]) {
+        samples[columns * i + j] = v;
+        CreateDictionaries();
+        FireChanged();
+      }
+    }
+
+    public double[] Samples {
+      get { return samples; }
+      set {
+        scalingFactor = new double[columns];
+        scalingOffset = new double[columns];
+        for (int i = 0; i < scalingFactor.Length; i++) {
+          scalingFactor[i] = 1.0;
+          scalingOffset[i] = 0.0;
+        }
+        samples = value;
+        CreateDictionaries();
+        FireChanged();
+      }
+    }
+
+    private string[] variableNames;
+
+    public Dataset() {
+      Name = "-";
+      variableNames = new string[] { "Var0" };
+      Columns = 1;
+      Rows = 1;
+      Samples = new double[1];
+      scalingOffset = new double[] { 0.0 };
+      scalingFactor = new double[] { 1.0 };
+    }
+
+    private void CreateDictionaries() {
+      // keep a means and ranges dictionary for each column (possible target variable) of the dataset.
+      cachedMeans = new Dictionary<int, Dictionary<int, double>>[columns];
+      cachedRanges = new Dictionary<int, Dictionary<int, double>>[columns];
+      for (int i = 0; i < columns; i++) {
+        cachedMeans[i] = new Dictionary<int, Dictionary<int, double>>();
+        cachedRanges[i] = new Dictionary<int, Dictionary<int, double>>();
+      }
+    }
+
+    public string GetVariableName(int variableIndex) {
+      return variableNames[variableIndex];
+    }
+
+    public void SetVariableName(int variableIndex, string name) {
+      variableNames[variableIndex] = name;
+    }
+
+
+    public override IView CreateView() {
+      return new DatasetView(this);
+    }
+
+    public override object Clone(IDictionary<Guid, object> clonedObjects) {
+      Dataset clone = new Dataset();
+      clonedObjects.Add(Guid, clone);
+      double[] cloneSamples = new double[rows * columns];
+      Array.Copy(samples, cloneSamples, samples.Length);
+      clone.rows = rows;
+      clone.columns = columns;
+      clone.Samples = cloneSamples;
+      clone.Name = Name;
+      clone.variableNames = new string[variableNames.Length];
+      Array.Copy(variableNames, clone.variableNames, variableNames.Length);
+      Array.Copy(scalingFactor, clone.scalingFactor, columns);
+      Array.Copy(scalingOffset, clone.scalingOffset, columns);
+      return clone;
+    }
+
+    public override XmlNode GetXmlNode(string name, XmlDocument document, IDictionary<Guid, IStorable> persistedObjects) {
+      XmlNode node = base.GetXmlNode(name, document, persistedObjects);
+      XmlAttribute problemName = document.CreateAttribute("Name");
+      problemName.Value = Name;
+      node.Attributes.Append(problemName);
+      XmlAttribute dim1 = document.CreateAttribute("Dimension1");
+      dim1.Value = rows.ToString(CultureInfo.InvariantCulture.NumberFormat);
+      node.Attributes.Append(dim1);
+      XmlAttribute dim2 = document.CreateAttribute("Dimension2");
+      dim2.Value = columns.ToString(CultureInfo.InvariantCulture.NumberFormat);
+      node.Attributes.Append(dim2);
+      XmlAttribute variableNames = document.CreateAttribute("VariableNames");
+      variableNames.Value = GetVariableNamesString();
+      node.Attributes.Append(variableNames);
+      XmlAttribute scalingFactorsAttribute = document.CreateAttribute("ScalingFactors");
+      scalingFactorsAttribute.Value = GetString(scalingFactor);
+      node.Attributes.Append(scalingFactorsAttribute);
+      XmlAttribute scalingOffsetsAttribute = document.CreateAttribute("ScalingOffsets");
+      scalingOffsetsAttribute.Value = GetString(scalingOffset);
+      node.Attributes.Append(scalingOffsetsAttribute);
+      node.InnerText = ToString(CultureInfo.InvariantCulture.NumberFormat);
+      return node;
+    }
+
+    public override void Populate(XmlNode node, IDictionary<Guid, IStorable> restoredObjects) {
+      base.Populate(node, restoredObjects);
+      Name = node.Attributes["Name"].Value;
+      rows = int.Parse(node.Attributes["Dimension1"].Value, CultureInfo.InvariantCulture.NumberFormat);
+      columns = int.Parse(node.Attributes["Dimension2"].Value, CultureInfo.InvariantCulture.NumberFormat);
+
+      variableNames = ParseVariableNamesString(node.Attributes["VariableNames"].Value);
+      if (node.Attributes["ScalingFactors"] != null)
+        scalingFactor = ParseDoubleString(node.Attributes["ScalingFactors"].Value);
+      else {
+        scalingFactor = new double[columns]; // compatibility with old serialization format
+        for (int i = 0; i < scalingFactor.Length; i++) scalingFactor[i] = 1.0;
+      }
+      if (node.Attributes["ScalingOffsets"] != null)
+        scalingOffset = ParseDoubleString(node.Attributes["ScalingOffsets"].Value);
+      else {
+        scalingOffset = new double[columns]; // compatibility with old serialization format
+        for (int i = 0; i < scalingOffset.Length; i++) scalingOffset[i] = 0.0;
+      }
+
+      string[] tokens = node.InnerText.Split(';');
+      if (tokens.Length != rows * columns) throw new FormatException();
+      samples = new double[rows * columns];
+      for (int row = 0; row < rows; row++) {
+        for (int column = 0; column < columns; column++) {
+          if (double.TryParse(tokens[row * columns + column], NumberStyles.Float, CultureInfo.InvariantCulture.NumberFormat, out samples[row * columns + column]) == false) {
+            throw new FormatException("Can't parse " + tokens[row * columns + column] + " as double value.");
+          }
+        }
+      }
+      CreateDictionaries();
+    }
+
+    public override string ToString() {
+      return ToString(CultureInfo.CurrentCulture.NumberFormat);
+    }
+
+    private string ToString(NumberFormatInfo format) {
+      StringBuilder builder = new StringBuilder();
+      for (int row = 0; row < rows; row++) {
+        for (int column = 0; column < columns; column++) {
+          builder.Append(";");
+          builder.Append(samples[row * columns + column].ToString("r", format));
+        }
+      }
+      if (builder.Length > 0) builder.Remove(0, 1);
+      return builder.ToString();
+    }
+
+    private string GetVariableNamesString() {
+      string s = "";
+      for (int i = 0; i < variableNames.Length; i++) {
+        s += variableNames[i] + "; ";
+      }
+
+      if (variableNames.Length > 0) {
+        s = s.TrimEnd(';', ' ');
+      }
+      return s;
+    }
+    private string GetString(double[] xs) {
+      string s = "";
+      for (int i = 0; i < xs.Length; i++) {
+        s += xs[i].ToString("r", CultureInfo.InvariantCulture) + "; ";
+      }
+
+      if (xs.Length > 0) {
+        s = s.TrimEnd(';', ' ');
+      }
+      return s;
+    }
+
+    private string[] ParseVariableNamesString(string p) {
+      p = p.Trim();
+      string[] tokens = p.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
+      for (int i = 0; i < tokens.Length; i++) tokens[i] = tokens[i].Trim();
+      return tokens;
+    }
+    private double[] ParseDoubleString(string s) {
+      s = s.Trim();
+      string[] ss = s.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
+      double[] xs = new double[ss.Length];
+      for (int i = 0; i < xs.Length; i++) {
+        xs[i] = double.Parse(ss[i], CultureInfo.InvariantCulture);
+      }
+      return xs;
+    }
+
+    public double GetMean(int column) {
+      return GetMean(column, 0, Rows);
+    }
+
+    public double GetMean(int column, int from, int to) {
+      if (!cachedMeans[column].ContainsKey(from) || !cachedMeans[column][from].ContainsKey(to)) {
+        double[] values = new double[to - from];
+        for (int sample = from; sample < to; sample++) {
+          values[sample - from] = GetValue(sample, column);
+        }
+        double mean = Statistics.Mean(values);
+        if (!cachedMeans[column].ContainsKey(from)) cachedMeans[column][from] = new Dictionary<int, double>();
+        cachedMeans[column][from][to] = mean;
+        return mean;
+      } else {
+        return cachedMeans[column][from][to];
+      }
+    }
+
+    public double GetRange(int column) {
+      return GetRange(column, 0, Rows);
+    }
+
+    public double GetRange(int column, int from, int to) {
+      if (!cachedRanges[column].ContainsKey(from) || !cachedRanges[column][from].ContainsKey(to)) {
+        double[] values = new double[to - from];
+        for (int sample = from; sample < to; sample++) {
+          values[sample - from] = GetValue(sample, column);
+        }
+        double range = Statistics.Range(values);
+        if (!cachedRanges[column].ContainsKey(from)) cachedRanges[column][from] = new Dictionary<int, double>();
+        cachedRanges[column][from][to] = range;
+        return range;
+      } else {
+        return cachedRanges[column][from][to];
+      }
+    }
+
+    public double GetMaximum(int column) {
+      double max = Double.NegativeInfinity;
+      for (int i = 0; i < Rows; i++) {
+        double val = GetValue(i, column);
+        if (!double.IsNaN(val) && val > max) max = val;
+      }
+      return max;
+    }
+
+    public double GetMinimum(int column) {
+      double min = Double.PositiveInfinity;
+      for (int i = 0; i < Rows; i++) {
+        double val = GetValue(i, column);
+        if (!double.IsNaN(val) && val < min) min = val;
+      }
+      return min;
+    }
+
+    internal void ScaleVariable(int column) {
+      if (scalingFactor[column] == 1.0 && scalingOffset[column] == 0.0) {
+        double min = GetMinimum(column);
+        double max = GetMaximum(column);
+        double range = max - min;
+        if (range == 0) ScaleVariable(column, 1.0, -min);
+        else ScaleVariable(column, 1.0 / range, -min);
+      }
+      CreateDictionaries();
+      FireChanged();
+    }
+
+    internal void ScaleVariable(int column, double factor, double offset) {
+      scalingFactor[column] = factor;
+      scalingOffset[column] = offset;
+      for (int i = 0; i < Rows; i++) {
+        double origValue = samples[i * columns + column];
+        samples[i * columns + column] = (origValue + offset) * factor;
+      }
+      CreateDictionaries();
+      FireChanged();
+    }
+
+    internal void UnscaleVariable(int column) {
+      if (scalingFactor[column] != 1.0 || scalingOffset[column] != 0.0) {
+        for (int i = 0; i < rows; i++) {
+          double scaledValue = samples[i * columns + column];
+          samples[i * columns + column] = scaledValue / scalingFactor[column] - scalingOffset[column];
+        }
+        scalingFactor[column] = 1.0;
+        scalingOffset[column] = 0.0;
+      }
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.DataAnalysis/3.3/DatasetParser.cs
===================================================================
--- trunk/sources/HeuristicLab.DataAnalysis/3.3/DatasetParser.cs	(revision 1904)
+++ trunk/sources/HeuristicLab.DataAnalysis/3.3/DatasetParser.cs	(revision 1904)
@@ -0,0 +1,414 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2008 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.Globalization;
+using System.IO;
+using HeuristicLab.Data;
+
+namespace HeuristicLab.DataAnalysis {
+  public class DatasetParser {
+    private const string PROBLEMNAME = "PROBLEMNAME";
+    private const string VARIABLENAMES = "VARIABLENAMES";
+    private const string TARGETVARIABLE = "TARGETVARIABLE";
+    private const string MAXIMUMTREEHEIGHT = "MAXIMUMTREEHEIGHT";
+    private const string MAXIMUMTREESIZE = "MAXIMUMTREESIZE";
+    private const string TRAININGSAMPLESSTART = "TRAININGSAMPLESSTART";
+    private const string TRAININGSAMPLESEND = "TRAININGSAMPLESEND";
+    private const string VALIDATIONSAMPLESSTART = "VALIDATIONSAMPLESSTART";
+    private const string VALIDATIONSAMPLESEND = "VALIDATIONSAMPLESEND";
+    private const string TESTSAMPLESSTART = "TESTSAMPLESSTART";
+    private const string TESTSAMPLESEND = "TESTSAMPLESEND";
+    private const string NONINPUTVARIABLES = "NONINPUTVARIABLES";
+    private Tokenizer tokenizer;
+    private Dictionary<string, List<Token>> metadata;
+    private List<List<double>> samplesList;
+
+    private int rows;
+    public int Rows {
+      get { return rows; }
+      set { rows = value; }
+    }
+
+    private int columns;
+    public int Columns {
+      get { return columns; }
+      set { columns = value; }
+    }
+
+    private double[] samples;
+    public double[] Samples {
+      get {
+        return samples;
+      }
+    }
+
+    public string ProblemName {
+      get {
+        if (metadata.ContainsKey(PROBLEMNAME)) {
+          return metadata[PROBLEMNAME][0].stringValue;
+        } else return "-";
+      }
+    }
+
+    public string[] VariableNames {
+      get {
+        if (metadata.ContainsKey(VARIABLENAMES)) {
+          List<Token> nameList = metadata[VARIABLENAMES];
+          string[] names = new string[nameList.Count];
+          for (int i = 0; i < names.Length; i++) {
+            names[i] = nameList[i].stringValue;
+          }
+          return names;
+        } else {
+          string[] names = new string[columns];
+          for (int i = 0; i < names.Length; i++) {
+            names[i] = "X" + i.ToString("000");
+          }
+          return names;
+        }
+      }
+    }
+
+    public int TargetVariable {
+      get {
+        if (metadata.ContainsKey(TARGETVARIABLE)) {
+          return metadata[TARGETVARIABLE][0].intValue;
+        } else return 0; // default is the first column
+      }
+    }
+
+    public int MaxTreeHeight {
+      get {
+        if (metadata.ContainsKey(MAXIMUMTREEHEIGHT)) {
+          return metadata[MAXIMUMTREEHEIGHT][0].intValue;
+        } else return 0;
+      }
+    }
+
+    public int MaxTreeSize {
+      get {
+        if (metadata.ContainsKey(MAXIMUMTREESIZE)) {
+          return metadata[MAXIMUMTREESIZE][0].intValue;
+        } else return 0;
+      }
+    }
+
+    public int TrainingSamplesStart {
+      get {
+        if (metadata.ContainsKey(TRAININGSAMPLESSTART)) {
+          return metadata[TRAININGSAMPLESSTART][0].intValue;
+        } else return 0;
+      }
+    }
+
+    public int TrainingSamplesEnd {
+      get {
+        if (metadata.ContainsKey(TRAININGSAMPLESEND)) {
+          return metadata[TRAININGSAMPLESEND][0].intValue;
+        } else return rows;
+      }
+    }
+    public int ValidationSamplesStart {
+      get {
+        if (metadata.ContainsKey(VALIDATIONSAMPLESSTART)) {
+          return metadata[VALIDATIONSAMPLESSTART][0].intValue;
+        } else return 0;
+      }
+    }
+
+    public int ValidationSamplesEnd {
+      get {
+        if (metadata.ContainsKey(VALIDATIONSAMPLESEND)) {
+          return metadata[VALIDATIONSAMPLESEND][0].intValue;
+        } else return rows;
+      }
+    }
+    public int TestSamplesStart {
+      get {
+        if (metadata.ContainsKey(TESTSAMPLESSTART)) {
+          return metadata[TESTSAMPLESSTART][0].intValue;
+        } else return 0;
+      }
+    }
+
+    public int TestSamplesEnd {
+      get {
+        if (metadata.ContainsKey(TESTSAMPLESEND)) {
+          return metadata[TESTSAMPLESEND][0].intValue;
+        } else return rows;
+      }
+    }
+
+    public List<int> NonInputVariables {
+      get {
+        List<int> disallowedVariables = new List<int>();
+        if (metadata.ContainsKey(NONINPUTVARIABLES)) {
+          foreach (Token t in metadata[NONINPUTVARIABLES]) {
+            disallowedVariables.Add(t.intValue);
+          }
+        }
+        return disallowedVariables;
+      }
+    }
+
+    public DatasetParser() {
+      this.metadata = new Dictionary<string, List<Token>>();
+      samplesList = new List<List<double>>();
+    }
+
+    public void Reset() {
+      metadata.Clear();
+      samplesList.Clear();
+    }
+
+    public void Import(string importFileName, bool strict) {
+      TryParse(importFileName, strict);
+      // translate the list of samples into a DoubleMatrixData item
+      samples = new double[samplesList.Count * samplesList[0].Count];
+      rows = samplesList.Count;
+      columns = samplesList[0].Count;
+
+      int i = 0;
+      int j = 0;
+      foreach (List<double> row in samplesList) {
+        j = 0;
+        foreach (double element in row) {
+          samples[i * columns + j] = element;
+          j++;
+        }
+        i++;
+      }
+    }
+
+    private void TryParse(string importFileName, bool strict) {
+      Exception lastEx = null;
+      NumberFormatInfo[] possibleFormats = new NumberFormatInfo[] { NumberFormatInfo.InvariantInfo, CultureInfo.GetCultureInfo("de-DE").NumberFormat, NumberFormatInfo.CurrentInfo };
+      foreach (NumberFormatInfo numberFormat in possibleFormats) {
+        using (StreamReader reader = new StreamReader(importFileName)) {
+          tokenizer = new Tokenizer(reader, numberFormat);
+          try {
+            // parse the file
+            Parse(strict);
+            return; // parsed without errors -> return;
+          }
+          catch (DataFormatException ex) {
+            lastEx = ex;
+          }
+        }
+      }
+      // all number formats threw an exception -> rethrow the last exception
+      throw lastEx;
+    }
+
+    #region tokenizer
+    internal enum TokenTypeEnum {
+      At, Assign, NewLine, String, Double, Int, WhiteSpace
+    }
+
+    internal class Token {
+      public TokenTypeEnum type;
+      public string stringValue;
+      public double doubleValue;
+      public int intValue;
+
+      public Token(TokenTypeEnum type, string value) {
+        this.type = type;
+        stringValue = value;
+        doubleValue = 0.0;
+        intValue = 0;
+      }
+
+      public override string ToString() {
+        return stringValue;
+      }
+    }
+
+
+    class Tokenizer {
+      private StreamReader reader;
+      private List<Token> tokens;
+      private string[] separators = new string[] { "@", "=", ";", "\t" };
+      private NumberFormatInfo numberFormatInfo;
+
+      public int CurrentLineNumber = 0;
+      public string CurrentLine;
+
+      public static Token NewlineToken = new Token(TokenTypeEnum.NewLine, "\n");
+      public static Token AtToken = new Token(TokenTypeEnum.At, "@");
+      public static Token AssignmentToken = new Token(TokenTypeEnum.Assign, "=");
+      public static Token SeparatorToken = new Token(TokenTypeEnum.WhiteSpace, "");
+      public string[] Separators {
+        get { return separators; }
+        set { separators = value; }
+      }
+
+
+      public Tokenizer(StreamReader reader, NumberFormatInfo numberFormatInfo) {
+        this.reader = reader;
+        this.numberFormatInfo = numberFormatInfo;
+        tokens = new List<Token>();
+        ReadNextTokens();
+      }
+
+      private void ReadNextTokens() {
+        if (!reader.EndOfStream) {
+          CurrentLine = reader.ReadLine();
+          Token[] newTokens = Array.ConvertAll(CurrentLine.Split(separators, StringSplitOptions.None), delegate(string str) {
+            return MakeToken(str.Trim());
+          });
+
+          foreach (Token tok in newTokens) {
+            if (tok != SeparatorToken) tokens.Add(tok);
+          }
+          tokens.Add(NewlineToken);
+          CurrentLineNumber++;
+        }
+      }
+
+      private Token MakeToken(string strToken) {
+        Token token = new Token(TokenTypeEnum.String, strToken);
+
+        // try to parse as a number first
+        if (int.TryParse(strToken, NumberStyles.Integer, numberFormatInfo, out token.intValue)) {
+          token.type = TokenTypeEnum.Int;
+          return token;
+        } else if (double.TryParse(strToken, NumberStyles.Float, numberFormatInfo, out token.doubleValue)) {
+          token.type = TokenTypeEnum.Double;
+          return token;
+        } else if (String.IsNullOrEmpty(strToken)) {
+          token.type = TokenTypeEnum.WhiteSpace;
+          return token;
+        }
+        // couldn't parse the token as an int or float number so return a string token
+        return token;
+      }
+
+      public Token Peek() {
+        return tokens[0];
+      }
+
+      public Token Next() {
+        Token next = tokens[0];
+        tokens.RemoveAt(0);
+        if (tokens.Count == 0) {
+          ReadNextTokens();
+        }
+        return next;
+      }
+
+      public bool HasNext() {
+        return tokens.Count > 0 || !reader.EndOfStream;
+      }
+    }
+    #endregion
+
+    #region parsing
+    private void Parse(bool strict) {
+      ParseMetaData(strict);
+      if (!tokenizer.HasNext()) Error("Couldn't parse data values. Probably because of incorrect number format (the parser expects english number format with a '.' as decimal separator).", "", tokenizer.CurrentLineNumber);
+      ParseSampleData(strict);
+      if (samplesList.Count == 0) Error("Couldn't parse data values. Probably because of incorrect number format (the parser expects english number format with a '.' as decimal separator).", "", tokenizer.CurrentLineNumber);
+    }
+
+    private void ParseSampleData(bool strict) {
+      List<double> row = new List<double>();
+      while (tokenizer.HasNext()) {
+        Token current = tokenizer.Next();
+        if (current.type == TokenTypeEnum.WhiteSpace) {
+          row.Add(double.NaN);
+        } else if (current.type == TokenTypeEnum.Double) {
+          // just take the value
+          row.Add(current.doubleValue);
+        } else if (current.type == TokenTypeEnum.Int) {
+          // translate the int value to double
+          row.Add((double)current.intValue);
+        } else if (current == Tokenizer.NewlineToken) {
+          // when parsing strictly all rows have to have the same number of values            
+          if (strict) {
+            // the first row defines how many samples are needed
+            if (samplesList.Count > 0 && samplesList[0].Count != row.Count) {
+              Error("The first row of the dataset has " + samplesList[0].Count + " columns." +
+                "\nLine " + tokenizer.CurrentLineNumber + " has " + row.Count + " columns.", "", tokenizer.CurrentLineNumber);
+            }
+          } else if (samplesList.Count > 0) {
+            // when we are not strict then fill or drop elements as needed
+            if (samplesList[0].Count > row.Count) {
+              // fill with NAN
+              for (int i = row.Count; i < samplesList[0].Count; i++) {
+                row.Add(double.NaN);
+              }
+            } else if (samplesList[0].Count < row.Count) {
+              // drop last k elements where k = n - length of first row
+              row.RemoveRange(samplesList[0].Count - 1, row.Count - samplesList[0].Count);
+            }
+          }
+
+          // add the current row to the collection of rows and start a new row
+          samplesList.Add(row);
+          row = new List<double>();
+        } else {
+          // found an unexpected token => return false when parsing strictly
+          // when we are parsing non-strictly we also allow unreadable values inserting NAN instead
+          if (strict) {
+            Error("Unexpected token.", current.stringValue, tokenizer.CurrentLineNumber);
+          } else {
+            row.Add(double.NaN);
+          }
+        }
+      }
+    }
+
+    private void ParseMetaData(bool strict) {
+      while (tokenizer.HasNext() && (tokenizer.Peek().type == TokenTypeEnum.WhiteSpace || tokenizer.Peek().type == TokenTypeEnum.String)) {
+        while (tokenizer.HasNext() && tokenizer.Peek().type == TokenTypeEnum.WhiteSpace) tokenizer.Next();
+        Token nameToken = tokenizer.Next();
+        if (nameToken.type != TokenTypeEnum.String)
+          Error("Expected a variable name.", nameToken.stringValue, tokenizer.CurrentLineNumber);
+
+        List<Token> tokens = new List<Token>();
+        Token valueToken;
+        while (tokenizer.HasNext() && tokenizer.Peek().type == TokenTypeEnum.WhiteSpace) valueToken = tokenizer.Next();
+        valueToken = tokenizer.Next();
+        while (valueToken != Tokenizer.NewlineToken) {
+          tokens.Add(valueToken);
+          while (tokenizer.HasNext() && tokenizer.Peek().type == TokenTypeEnum.WhiteSpace) tokenizer.Next();
+          valueToken = tokenizer.Next();
+        }
+
+        metadata[nameToken.stringValue] = tokens;
+      }
+    }
+
+    private void Expect(Token expectedToken) {
+      Token actualToken = tokenizer.Next();
+      if (actualToken != expectedToken) {
+        Error("Expected: " + expectedToken, actualToken.stringValue, tokenizer.CurrentLineNumber);
+      }
+    }
+
+    private void Error(string message, string token, int lineNumber) {
+      throw new DataFormatException("Error while parsing.\n" + message, token, lineNumber);
+    }
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.DataAnalysis/3.3/DatasetShuffler.cs
===================================================================
--- trunk/sources/HeuristicLab.DataAnalysis/3.3/DatasetShuffler.cs	(revision 1904)
+++ trunk/sources/HeuristicLab.DataAnalysis/3.3/DatasetShuffler.cs	(revision 1904)
@@ -0,0 +1,58 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2008 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 HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Random;
+
+namespace HeuristicLab.DataAnalysis {
+  public class DatasetShuffler : OperatorBase {
+    public DatasetShuffler()
+      : base() {
+      AddVariableInfo(new VariableInfo("Dataset", "Dataset which should be shuffled (random row order)", typeof(Dataset), VariableKind.In | VariableKind.Out));
+      AddVariableInfo(new VariableInfo("Random", "Randomizer", typeof(MersenneTwister), VariableKind.In));
+    }
+
+    public override IOperation Apply(IScope scope) {
+      Dataset dataset = GetVariableValue<Dataset>("Dataset", scope, true);
+      MersenneTwister tw = GetVariableValue<MersenneTwister>("Random", scope, true);
+
+      for(int i = 0; i < dataset.Rows - 1; i++) {
+        int j = tw.Next(i, dataset.Rows);
+        ExchangeRows(dataset, i, j);
+      }
+
+      return null;
+    }
+
+    private void ExchangeRows(Dataset dataset, int i, int j) {
+      for(int k = 0; k < dataset.Columns; k++) {
+        double temp = dataset.GetValue(i, k);
+        dataset.SetValue(i, k, dataset.GetValue(j, k));
+        dataset.SetValue(j, k, temp);
+      }
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.DataAnalysis/3.3/DatasetView.cs
===================================================================
--- trunk/sources/HeuristicLab.DataAnalysis/3.3/DatasetView.cs	(revision 1904)
+++ trunk/sources/HeuristicLab.DataAnalysis/3.3/DatasetView.cs	(revision 1904)
@@ -0,0 +1,171 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2008 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.Windows.Forms;
+using HeuristicLab.Core;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.DataAnalysis {
+  public partial class DatasetView : EditorBase {
+    public Dataset Dataset {
+      get { return (Dataset)Item; }
+      set {
+        Item = value;
+        Refresh();
+      }
+    }
+    public DatasetView()
+      : base() {
+      InitializeComponent();
+      DiscoveryService discovery = new DiscoveryService();
+      IDatasetManipulator[] manipuators = discovery.GetInstances<IDatasetManipulator>();
+      contextMenuStrip.Items.Add(new ToolStripSeparator());
+      foreach(IDatasetManipulator manipulator in manipuators) {
+        contextMenuStrip.Items.Add(new ToolStripButton(manipulator.Action,null , delegate(object source, EventArgs args) 
+          { 
+            manipulator.Execute(Dataset);
+            Refresh();
+          }));
+      }
+      
+      // format all cells with the round-trip formatter to make sure that values that are exported and imported to
+      // another C# app (HL2) have the same numeric value
+      dataGridView.DefaultCellStyle.Format = "r";
+    }
+
+    public DatasetView(Dataset dataset)
+      : this() {
+      this.Dataset = dataset;
+    }
+
+    protected override void UpdateControls() {
+      base.UpdateControls();
+      if (Dataset != null) {
+        // DataGridView is bitching around. When it's columnCount (maybe also rowCount) is changed it creates
+        // new column objects and they have SortMode set to 'automatic'. However this is not allowed if the
+        // selectionmode is set to 'ColumnHeaderSelect' at the same time, resulting in an exception.
+        // A solution is to set the SelectionMode to CellSelect before any changes. After the columns
+        // have been updated (and their SortMode set to 'NotSortable') we switch back to SelectionMode=ColumnHeaderSelect.
+        dataGridView.SelectionMode = DataGridViewSelectionMode.CellSelect;
+        dataGridView.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.DisableResizing;
+        int rows = Dataset.Rows;
+        int columns = Dataset.Columns;
+        nameTextBox.Text = Dataset.Name;
+        rowsTextBox.Text = rows + "";
+        columnsTextBox.Text = columns + "";
+        dataGridView.ColumnCount = columns;
+        dataGridView.RowCount = rows;
+        for (int i = 0; i < rows; i++) {
+          for (int j = 0; j < columns; j++) {
+            dataGridView.Rows[i].Cells[j].Value = Dataset.GetValue(i, j);
+            dataGridView.Rows[i].HeaderCell.Value = i.ToString();
+          }
+        }
+        for (int i = 0; i < columns; i++) {
+          dataGridView.Columns[i].SortMode = DataGridViewColumnSortMode.NotSortable; // SortMode has to be NotSortable to allow ColumnHeaderSelect
+          dataGridView.Columns[i].Name = GetColumnName(i);
+        }
+        dataGridView.SelectionMode = DataGridViewSelectionMode.ColumnHeaderSelect; // switch back to column selection
+        dataGridView.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders;
+      } else {
+        rowsTextBox.Text = "1";
+        columnsTextBox.Text = "1";
+        dataGridView.ColumnCount = 1;
+        dataGridView.RowCount = 1;
+      }
+    }
+
+    private void dataGridView_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) {
+      if (ValidateData((string)e.FormattedValue)) {
+        SetArrayElement(e.RowIndex, e.ColumnIndex, (string)e.FormattedValue);
+        e.Cancel = false;
+      } else {
+        e.Cancel = true;
+      }
+    }
+
+
+    private void SetArrayElement(int row, int column, string element) {
+      double result;
+      double.TryParse(element, out result);
+      if (result != Dataset.GetValue(row, column)) {
+        Dataset.SetValue(row, column, result);
+      }
+    }
+
+    private bool ValidateData(string element) {
+      double result;
+      return element != null && double.TryParse(element, out result);
+    }
+
+    private void scaleValuesToolStripMenuItem_Click(object sender, EventArgs e) {
+      foreach(DataGridViewColumn column in dataGridView.SelectedColumns) {
+        Dataset.ScaleVariable(column.Index);
+        column.Name = GetColumnName(column.Index) + " [scaled]";
+      }
+      Refresh();
+    }
+
+    private void originalValuesToolStripMenuItem_Click(object sender, EventArgs e) {
+      foreach(DataGridViewColumn column in dataGridView.SelectedColumns) {
+        Dataset.UnscaleVariable(column.Index);
+        column.Name = GetColumnName(column.Index);
+      }
+      Refresh();      
+    }
+
+    private string GetColumnName(int index) {
+      if(Dataset.Columns == dataGridView.Columns.Count) {
+        return Dataset.GetVariableName(index);
+      } else {
+        return "Var " + index;
+      }
+    }
+
+    private void showScalingToolStripMenuItem_Click(object sender, EventArgs e) {
+      ManualScalingControl scalingControl = new ManualScalingControl(false);
+      double[,] scalingParameters = new double[2, Dataset.Columns];
+      for(int i = 0; i < Dataset.Columns; i++) {
+        scalingParameters[0, i] = Dataset.ScalingFactor[i];
+        scalingParameters[1, i] = Dataset.ScalingOffset[i];
+      }
+      scalingControl.Data = scalingParameters;
+      scalingControl.ShowDialog();
+    }
+
+    private void scaleValuesmanuallyToolStripMenuItem_Click(object sender, EventArgs e) {
+      ManualScalingControl scalingControl = new ManualScalingControl(true);
+      double[,] scalingParameters = new double[2, Dataset.Columns];
+      for(int i = 0; i < Dataset.Columns; i++) {
+        scalingParameters[0, i] = Dataset.ScalingFactor[i];
+        scalingParameters[1, i] = Dataset.ScalingOffset[i];
+      }
+      scalingControl.Data = scalingParameters;
+      if(scalingControl.ShowDialog() == DialogResult.OK) {
+        for(int i = 0; i < Dataset.Columns; i++) {
+          Dataset.ScaleVariable(i, scalingControl.Data[0, i], scalingControl.Data[1, i]);
+        }
+      }
+      Refresh();
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.DataAnalysis/3.3/DatasetView.designer.cs
===================================================================
--- trunk/sources/HeuristicLab.DataAnalysis/3.3/DatasetView.designer.cs	(revision 1904)
+++ trunk/sources/HeuristicLab.DataAnalysis/3.3/DatasetView.designer.cs	(revision 1904)
@@ -0,0 +1,212 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2008 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.DataAnalysis {
+  partial class DatasetView {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Component Designer generated code
+
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      this.components = new System.ComponentModel.Container();
+      System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
+      this.rowsTextBox = new System.Windows.Forms.TextBox();
+      this.columnsTextBox = new System.Windows.Forms.TextBox();
+      this.dataGridView = new System.Windows.Forms.DataGridView();
+      this.contextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
+      this.scaleValuesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+      this.scaleValuesmanuallyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+      this.showScalingToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+      this.originalValuesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+      this.rowsLabel = new System.Windows.Forms.Label();
+      this.columnsLabel = new System.Windows.Forms.Label();
+      this.nameLabel = new System.Windows.Forms.Label();
+      this.nameTextBox = new System.Windows.Forms.TextBox();
+      ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).BeginInit();
+      this.contextMenuStrip.SuspendLayout();
+      this.SuspendLayout();
+      // 
+      // rowsTextBox
+      // 
+      this.rowsTextBox.Location = new System.Drawing.Point(50, 29);
+      this.rowsTextBox.Name = "rowsTextBox";
+      this.rowsTextBox.ReadOnly = true;
+      this.rowsTextBox.Size = new System.Drawing.Size(100, 20);
+      this.rowsTextBox.TabIndex = 1;
+      // 
+      // columnsTextBox
+      // 
+      this.columnsTextBox.Location = new System.Drawing.Point(217, 29);
+      this.columnsTextBox.Name = "columnsTextBox";
+      this.columnsTextBox.ReadOnly = true;
+      this.columnsTextBox.Size = new System.Drawing.Size(100, 20);
+      this.columnsTextBox.TabIndex = 2;
+      // 
+      // dataGridView
+      // 
+      this.dataGridView.AllowUserToAddRows = false;
+      this.dataGridView.AllowUserToDeleteRows = false;
+      this.dataGridView.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.dataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
+      this.dataGridView.ContextMenuStrip = this.contextMenuStrip;
+      this.dataGridView.Location = new System.Drawing.Point(3, 55);
+      this.dataGridView.Name = "dataGridView";
+      dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight;
+      dataGridViewCellStyle1.BackColor = System.Drawing.SystemColors.Control;
+      dataGridViewCellStyle1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+      dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.WindowText;
+      dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
+      dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
+      dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
+      this.dataGridView.RowHeadersDefaultCellStyle = dataGridViewCellStyle1;
+      this.dataGridView.Size = new System.Drawing.Size(554, 485);
+      this.dataGridView.TabIndex = 3;
+      this.dataGridView.CellValidating += new System.Windows.Forms.DataGridViewCellValidatingEventHandler(this.dataGridView_CellValidating);
+      // 
+      // contextMenuStrip
+      // 
+      this.contextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+            this.scaleValuesToolStripMenuItem,
+            this.scaleValuesmanuallyToolStripMenuItem,
+            this.showScalingToolStripMenuItem,
+            this.originalValuesToolStripMenuItem});
+      this.contextMenuStrip.Name = "contextMenuStrip";
+      this.contextMenuStrip.Size = new System.Drawing.Size(187, 92);
+      // 
+      // scaleValuesToolStripMenuItem
+      // 
+      this.scaleValuesToolStripMenuItem.Name = "scaleValuesToolStripMenuItem";
+      this.scaleValuesToolStripMenuItem.Size = new System.Drawing.Size(186, 22);
+      this.scaleValuesToolStripMenuItem.Text = "Scale values [0..1]";
+      this.scaleValuesToolStripMenuItem.Click += new System.EventHandler(this.scaleValuesToolStripMenuItem_Click);
+      // 
+      // scaleValuesmanuallyToolStripMenuItem
+      // 
+      this.scaleValuesmanuallyToolStripMenuItem.Name = "scaleValuesmanuallyToolStripMenuItem";
+      this.scaleValuesmanuallyToolStripMenuItem.Size = new System.Drawing.Size(186, 22);
+      this.scaleValuesmanuallyToolStripMenuItem.Text = "Scale values (manually)";
+      this.scaleValuesmanuallyToolStripMenuItem.Click += new System.EventHandler(this.scaleValuesmanuallyToolStripMenuItem_Click);
+      // 
+      // showScalingToolStripMenuItem
+      // 
+      this.showScalingToolStripMenuItem.Name = "showScalingToolStripMenuItem";
+      this.showScalingToolStripMenuItem.Size = new System.Drawing.Size(186, 22);
+      this.showScalingToolStripMenuItem.Text = "Show scaling...";
+      this.showScalingToolStripMenuItem.Click += new System.EventHandler(this.showScalingToolStripMenuItem_Click);
+      // 
+      // originalValuesToolStripMenuItem
+      // 
+      this.originalValuesToolStripMenuItem.Name = "originalValuesToolStripMenuItem";
+      this.originalValuesToolStripMenuItem.Size = new System.Drawing.Size(186, 22);
+      this.originalValuesToolStripMenuItem.Text = "Unscale values";
+      this.originalValuesToolStripMenuItem.Click += new System.EventHandler(this.originalValuesToolStripMenuItem_Click);
+      // 
+      // rowsLabel
+      // 
+      this.rowsLabel.AutoSize = true;
+      this.rowsLabel.Location = new System.Drawing.Point(3, 32);
+      this.rowsLabel.Name = "rowsLabel";
+      this.rowsLabel.Size = new System.Drawing.Size(37, 13);
+      this.rowsLabel.TabIndex = 4;
+      this.rowsLabel.Text = "Rows:";
+      // 
+      // columnsLabel
+      // 
+      this.columnsLabel.AutoSize = true;
+      this.columnsLabel.Location = new System.Drawing.Point(161, 32);
+      this.columnsLabel.Name = "columnsLabel";
+      this.columnsLabel.Size = new System.Drawing.Size(50, 13);
+      this.columnsLabel.TabIndex = 5;
+      this.columnsLabel.Text = "Columns:";
+      // 
+      // nameLabel
+      // 
+      this.nameLabel.AutoSize = true;
+      this.nameLabel.Location = new System.Drawing.Point(3, 6);
+      this.nameLabel.Name = "nameLabel";
+      this.nameLabel.Size = new System.Drawing.Size(41, 13);
+      this.nameLabel.TabIndex = 6;
+      this.nameLabel.Text = "Name: ";
+      // 
+      // nameTextBox
+      // 
+      this.nameTextBox.Location = new System.Drawing.Point(50, 3);
+      this.nameTextBox.Name = "nameTextBox";
+      this.nameTextBox.ReadOnly = true;
+      this.nameTextBox.Size = new System.Drawing.Size(219, 20);
+      this.nameTextBox.TabIndex = 7;
+      // 
+      // DatasetView
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Controls.Add(this.nameTextBox);
+      this.Controls.Add(this.nameLabel);
+      this.Controls.Add(this.columnsLabel);
+      this.Controls.Add(this.rowsLabel);
+      this.Controls.Add(this.dataGridView);
+      this.Controls.Add(this.columnsTextBox);
+      this.Controls.Add(this.rowsTextBox);
+      this.Name = "DatasetView";
+      this.Size = new System.Drawing.Size(560, 543);
+      ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).EndInit();
+      this.contextMenuStrip.ResumeLayout(false);
+      this.ResumeLayout(false);
+      this.PerformLayout();
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.TextBox rowsTextBox;
+    private System.Windows.Forms.TextBox columnsTextBox;
+    private System.Windows.Forms.DataGridView dataGridView;
+    private System.Windows.Forms.Label rowsLabel;
+    private System.Windows.Forms.Label columnsLabel;
+    private System.Windows.Forms.Label nameLabel;
+    private System.Windows.Forms.TextBox nameTextBox;
+    private System.Windows.Forms.ContextMenuStrip contextMenuStrip;
+    private System.Windows.Forms.ToolStripMenuItem scaleValuesToolStripMenuItem;
+    private System.Windows.Forms.ToolStripMenuItem originalValuesToolStripMenuItem;
+    private System.Windows.Forms.ToolStripMenuItem scaleValuesmanuallyToolStripMenuItem;
+    private System.Windows.Forms.ToolStripMenuItem showScalingToolStripMenuItem;
+  }
+}
Index: trunk/sources/HeuristicLab.DataAnalysis/3.3/DatasetView.resx
===================================================================
--- trunk/sources/HeuristicLab.DataAnalysis/3.3/DatasetView.resx	(revision 1904)
+++ trunk/sources/HeuristicLab.DataAnalysis/3.3/DatasetView.resx	(revision 1904)
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <metadata name="contextMenuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 17</value>
+  </metadata>
+</root>
Index: trunk/sources/HeuristicLab.DataAnalysis/3.3/HeuristicLab.DataAnalysis-3.2.csproj
===================================================================
--- trunk/sources/HeuristicLab.DataAnalysis/3.3/HeuristicLab.DataAnalysis-3.2.csproj	(revision 1904)
+++ trunk/sources/HeuristicLab.DataAnalysis/3.3/HeuristicLab.DataAnalysis-3.2.csproj	(revision 1904)
@@ -0,0 +1,160 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{7DD3A97A-56E9-462F-90E2-A351FE7AF5C2}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HeuristicLab.DataAnalysis</RootNamespace>
+    <AssemblyName>HeuristicLab.DataAnalysis-3.2</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <SignAssembly>true</SignAssembly>
+    <AssemblyOriginatorKeyFile>HeuristicLab.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <DocumentationFile>bin\Release\HeuristicLab.DataAnalysis-3.2.XML</DocumentationFile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x86\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <OutputPath>bin\x86\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <DocumentationFile>bin\Release\HeuristicLab.DataAnalysis-3.2.XML</DocumentationFile>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x64\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
+    <OutputPath>bin\x64\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <DocumentationFile>bin\Release\HeuristicLab.DataAnalysis-3.2.XML</DocumentationFile>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="DataFormatException.cs" />
+    <Compile Include="Dataset.cs" />
+    <Compile Include="DatasetParser.cs" />
+    <Compile Include="DatasetShuffler.cs" />
+    <Compile Include="DatasetView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="DatasetView.designer.cs">
+      <DependentUpon>DatasetView.cs</DependentUpon>
+    </Compile>
+    <Compile Include="HeuristicLabDataAnalysisPlugin.cs" />
+    <Compile Include="IDatasetManipulator.cs" />
+    <Compile Include="ManualScalingControl.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="ManualScalingControl.Designer.cs">
+      <DependentUpon>ManualScalingControl.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Statistics.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\HeuristicLab.Core\3.2\HeuristicLab.Core-3.2.csproj">
+      <Project>{F43B59AB-2B8C-4570-BC1E-15592086517C}</Project>
+      <Name>HeuristicLab.Core-3.2</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Data\3.2\HeuristicLab.Data-3.2.csproj">
+      <Project>{F473D9AF-3F09-4296-9F28-3C65118DAFFA}</Project>
+      <Name>HeuristicLab.Data-3.2</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Operators\3.2\HeuristicLab.Operators-3.2.csproj">
+      <Project>{A9983BA2-B3B2-475E-8E2C-62050B71D1C5}</Project>
+      <Name>HeuristicLab.Operators-3.2</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.PluginInfrastructure\HeuristicLab.PluginInfrastructure.csproj">
+      <Project>{94186A6A-5176-4402-AE83-886557B53CCA}</Project>
+      <Name>HeuristicLab.PluginInfrastructure</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Random\3.2\HeuristicLab.Random-3.2.csproj">
+      <Project>{47019A74-F7F7-482E-83AA-D3F4F777E879}</Project>
+      <Name>HeuristicLab.Random-3.2</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="HeuristicLab.snk" />
+    <None Include="Properties\AssemblyInfo.frame" />
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="DatasetView.resx">
+      <DependentUpon>DatasetView.cs</DependentUpon>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+    <EmbeddedResource Include="ManualScalingControl.resx">
+      <DependentUpon>ManualScalingControl.cs</DependentUpon>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <PropertyGroup>
+    <PreBuildEvent>set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+set ProjectDir=$(ProjectDir)
+set SolutionDir=$(SolutionDir)
+set Outdir=$(Outdir)
+
+call PreBuildEvent.cmd</PreBuildEvent>
+  </PropertyGroup>
+</Project>
Index: trunk/sources/HeuristicLab.DataAnalysis/3.3/HeuristicLabDataAnalysisPlugin.cs
===================================================================
--- trunk/sources/HeuristicLab.DataAnalysis/3.3/HeuristicLabDataAnalysisPlugin.cs	(revision 1904)
+++ trunk/sources/HeuristicLab.DataAnalysis/3.3/HeuristicLabDataAnalysisPlugin.cs	(revision 1904)
@@ -0,0 +1,34 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2008 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.Text;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.DataAnalysis {
+  [ClassInfo(Name = "HeuristicLab.DataAnalysis-3.2")]
+  [PluginFile(Filename = "HeuristicLab.DataAnalysis-3.2.dll", Filetype = PluginFileType.Assembly)]
+  [Dependency(Dependency = "HeuristicLab.Core-3.2")]
+  [Dependency(Dependency = "HeuristicLab.Data-3.2")]
+  public class HeuristicLabDataAnalysisPlugin : PluginBase {
+  }
+}
Index: trunk/sources/HeuristicLab.DataAnalysis/3.3/IDatasetManipulator.cs
===================================================================
--- trunk/sources/HeuristicLab.DataAnalysis/3.3/IDatasetManipulator.cs	(revision 1904)
+++ trunk/sources/HeuristicLab.DataAnalysis/3.3/IDatasetManipulator.cs	(revision 1904)
@@ -0,0 +1,32 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2008 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;
+
+namespace HeuristicLab.DataAnalysis {
+  interface IDatasetManipulator {
+    string Action { get; }
+    void Execute(Dataset dataset);
+  }
+}
Index: trunk/sources/HeuristicLab.DataAnalysis/3.3/ManualScalingControl.Designer.cs
===================================================================
--- trunk/sources/HeuristicLab.DataAnalysis/3.3/ManualScalingControl.Designer.cs	(revision 1904)
+++ trunk/sources/HeuristicLab.DataAnalysis/3.3/ManualScalingControl.Designer.cs	(revision 1904)
@@ -0,0 +1,88 @@
+﻿namespace HeuristicLab.DataAnalysis {
+  partial class ManualScalingControl {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if(disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Component Designer generated code
+
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      this.dataGridView = new System.Windows.Forms.DataGridView();
+      this.okButton = new System.Windows.Forms.Button();
+      this.cancelButton = new System.Windows.Forms.Button();
+      ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).BeginInit();
+      this.SuspendLayout();
+      // 
+      // dataGridView
+      // 
+      this.dataGridView.AllowUserToAddRows = false;
+      this.dataGridView.AllowUserToDeleteRows = false;
+      this.dataGridView.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.dataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
+      this.dataGridView.Location = new System.Drawing.Point(12, 12);
+      this.dataGridView.Name = "dataGridView";
+      this.dataGridView.ReadOnly = true;
+      this.dataGridView.Size = new System.Drawing.Size(268, 213);
+      this.dataGridView.TabIndex = 0;
+      this.dataGridView.CellValueChanged += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView_CellValueChanged);
+      this.dataGridView.KeyDown += new System.Windows.Forms.KeyEventHandler(this.dataGridView_KeyDown);
+      // 
+      // okButton
+      // 
+      this.okButton.Location = new System.Drawing.Point(12, 231);
+      this.okButton.Name = "okButton";
+      this.okButton.Size = new System.Drawing.Size(75, 23);
+      this.okButton.TabIndex = 1;
+      this.okButton.Text = "okButton";
+      this.okButton.UseVisualStyleBackColor = true;
+      this.okButton.Click += new System.EventHandler(this.button_Click);
+      // 
+      // cancelButton
+      // 
+      this.cancelButton.Location = new System.Drawing.Point(93, 231);
+      this.cancelButton.Name = "cancelButton";
+      this.cancelButton.Size = new System.Drawing.Size(75, 23);
+      this.cancelButton.TabIndex = 2;
+      this.cancelButton.Text = "cancelButton";
+      this.cancelButton.UseVisualStyleBackColor = true;
+      this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
+      // 
+      // ManualScalingControl
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.ClientSize = new System.Drawing.Size(292, 266);
+      this.Controls.Add(this.cancelButton);
+      this.Controls.Add(this.okButton);
+      this.Controls.Add(this.dataGridView);
+      this.Name = "ManualScalingControl";
+      ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).EndInit();
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.DataGridView dataGridView;
+    private System.Windows.Forms.Button okButton;
+    private System.Windows.Forms.Button cancelButton;
+  }
+}
Index: trunk/sources/HeuristicLab.DataAnalysis/3.3/ManualScalingControl.cs
===================================================================
--- trunk/sources/HeuristicLab.DataAnalysis/3.3/ManualScalingControl.cs	(revision 1904)
+++ trunk/sources/HeuristicLab.DataAnalysis/3.3/ManualScalingControl.cs	(revision 1904)
@@ -0,0 +1,115 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2008 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.Data;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+using HeuristicLab.PluginInfrastructure;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.DataAnalysis {
+  public partial class ManualScalingControl : Form {
+    public ManualScalingControl(bool editingAllowed) {
+      InitializeComponent();
+      dataGridView.ReadOnly = !editingAllowed;
+      okButton.Text = editingAllowed ? "Scale" : "Close";
+      cancelButton.Visible = editingAllowed;
+      cancelButton.Text = "Cancel";
+
+      // format all cells with the round-trip formatter to make sure that exported and imported values have
+      // the same numeric value
+      dataGridView.DefaultCellStyle.Format = "r";
+    }
+
+    private double[,] data;
+    public double[,] Data {
+      get {
+        return data;
+      }
+      set {
+        data = value;
+        UpdateControls();
+      }
+    }
+
+    protected void UpdateControls() {
+      Refresh();
+      dataGridView.ColumnCount = data.GetLength(0);
+      dataGridView.RowCount = data.GetLength(1);
+      for(int i = 0; i < dataGridView.RowCount; i++) {
+        for(int j = 0; j < dataGridView.ColumnCount; j++) {
+          dataGridView[j,i].Value = data[j, i];
+        }
+      }
+      dataGridView.Columns[0].HeaderText = "Factor";
+      dataGridView.Columns[1].HeaderText = "Offset";
+    }
+
+    private void button_Click(object sender, EventArgs e) {
+      DialogResult = DialogResult.OK;
+    }
+
+    private void cancelButton_Click(object sender, EventArgs e) {
+      DialogResult = DialogResult.Cancel;
+    }
+
+    // stolen from the internets
+    private void dataGridView_KeyDown(object sender, KeyEventArgs e) {
+      if(e.Control && e.KeyCode == Keys.C) {
+        DataObject d = dataGridView.GetClipboardContent();
+        Clipboard.SetDataObject(d);
+        e.Handled = true;
+      } else if(e.Control && e.KeyCode == Keys.V) {
+        string s = Clipboard.GetText();
+        string[] lines = s.Split(new char[] {'\n', '\r'},StringSplitOptions.RemoveEmptyEntries);
+        int row = dataGridView.CurrentCell.RowIndex;
+        int col = dataGridView.CurrentCell.ColumnIndex;
+        foreach(string line in lines) {
+          if(row < dataGridView.RowCount && line.Length > 0) {
+            string[] cells = line.Split(new char[] {'\t',' ',';'},StringSplitOptions.RemoveEmptyEntries);
+            for(int i = 0; i < cells.Length; i++) {
+              if(col + i < this.dataGridView.ColumnCount) {
+                dataGridView[col + i, row].Value = double.Parse(cells[i]);
+              } else {
+                break;
+              }
+            }
+            row++;
+          } else {
+            break;
+          }
+        }
+        e.Handled = true;
+      }
+    }
+
+    private void dataGridView_CellValueChanged(object sender, DataGridViewCellEventArgs e) {
+      if(e.RowIndex >= 0 && e.ColumnIndex >= 0) {
+        data[e.ColumnIndex, e.RowIndex] = (double)dataGridView[e.ColumnIndex, e.RowIndex].Value;
+      }
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.DataAnalysis/3.3/ManualScalingControl.resx
===================================================================
--- trunk/sources/HeuristicLab.DataAnalysis/3.3/ManualScalingControl.resx	(revision 1904)
+++ trunk/sources/HeuristicLab.DataAnalysis/3.3/ManualScalingControl.resx	(revision 1904)
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
Index: trunk/sources/HeuristicLab.DataAnalysis/3.3/Properties/AssemblyInfo.frame
===================================================================
--- trunk/sources/HeuristicLab.DataAnalysis/3.3/Properties/AssemblyInfo.frame	(revision 1904)
+++ trunk/sources/HeuristicLab.DataAnalysis/3.3/Properties/AssemblyInfo.frame	(revision 1904)
@@ -0,0 +1,59 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2008 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.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using HeuristicLab.PluginInfrastructure;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("HeuristicLab.DataAnalysis")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("HeuristicLab")]
+[assembly: AssemblyCopyright("(c) 2002-2008 HEAL")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("6db21047-d1dc-4b21-9064-45c4d114ff9f")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("3.2.0.$WCREV$")]
+[assembly: AssemblyFileVersion("3.2.0.$WCREV$")]
+[assembly: AssemblyBuildDate("$WCNOW$")]
Index: trunk/sources/HeuristicLab.DataAnalysis/3.3/Statistics.cs
===================================================================
--- trunk/sources/HeuristicLab.DataAnalysis/3.3/Statistics.cs	(revision 1904)
+++ trunk/sources/HeuristicLab.DataAnalysis/3.3/Statistics.cs	(revision 1904)
@@ -0,0 +1,245 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2008 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.Text;
+
+namespace HeuristicLab.DataAnalysis {
+  public class Statistics {
+
+    /// <summary>
+    /// Minimum returns the smalles entry of values.
+    /// Throws and exception if values is empty.
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="values"></param>
+    /// <returns></returns>
+    public static T Minimum<T>(IEnumerable<T> values) where T : struct, IComparable, IComparable<T> {
+      IEnumerator<T> enumerator = values.GetEnumerator();
+
+      // this will throw an exception if the values collection is empty
+      enumerator.MoveNext();
+      T minimum = enumerator.Current;
+
+      while (enumerator.MoveNext()) {
+        T current = enumerator.Current;
+        if (current.CompareTo(minimum) < 0) {
+          minimum = current;
+        }
+      }
+
+      return minimum;
+    }
+
+    /// <summary>
+    /// Maximum returns the largest entry of values.
+    /// Throws an exception if values is empty.
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="values"></param>
+    /// <returns></returns>
+    public static T Maximum<T>(IEnumerable<T> values) where T : struct, IComparable, IComparable<T> {
+      IEnumerator<T> enumerator = values.GetEnumerator();
+
+      // this will throw an exception if the values collection is empty
+      enumerator.MoveNext();
+      T maximum = enumerator.Current;
+
+      while (enumerator.MoveNext()) {
+        T current = enumerator.Current;
+        if (current.CompareTo(maximum) > 0) {
+          maximum = current;
+        }
+      }
+
+      return maximum;
+    }
+
+    /// <summary>
+    /// Range calculates the difference between the larges and smallest entry of values.
+    /// </summary>
+    /// <param name="values"></param>
+    /// <returns></returns>
+    public static double Range(double[] values) {
+      return Range(values, 0, values.Length);
+    }
+
+    /// <summary>
+    /// Range calculates the difference between the larges and smallest entry of values.
+    /// </summary>
+    public static double Range(List<double> values) {
+      return Range(values.ToArray(), 0, values.Count);
+    }
+
+    /// <summary>
+    /// Range calculates the difference between the largest and smallest entry of values between start and end.
+    /// </summary>
+    /// <param name="values">collection of values</param>
+    /// <param name="start">start index (inclusive)</param>
+    /// <param name="end">end index (exclusive)</param>
+    /// <returns></returns>
+    public static double Range(double[] values, int start, int end) {
+      if (start < 0 || start > values.Length || end < 0 || end > values.Length || start > end) {
+        throw new InvalidOperationException();
+      }
+
+      double minimum = double.PositiveInfinity;
+      double maximum = double.NegativeInfinity;
+      for (int i = start; i < end; i++) {
+        if (!double.IsNaN(values[i])) {
+          if (values[i] > maximum) {
+            maximum = values[i];
+          }
+          if (values[i] < minimum) {
+            minimum = values[i];
+          }
+        }
+      }
+      return (maximum - minimum);
+    }
+
+    /// <summary>
+    /// calculates the sum of all values.
+    /// </summary>
+    /// <param name="values"></param>
+    /// <returns></returns>
+    public static double Sum(double[] values) {
+      int n = values.Length;
+      double sum = 0.0;
+      for (int i = 0; i < n; i++) {
+        if (double.IsNaN(values[i])) {
+          throw new NotFiniteNumberException();
+        } else {
+          sum += values[i];
+        }
+      }
+      return sum;
+    }
+
+    /// <summary>
+    /// Calculates the mean of all values.
+    /// </summary>
+    /// <param name="values"></param>
+    /// <returns></returns>
+    public static double Mean(List<double> values) {
+      return Mean(values.ToArray(), 0, values.Count);
+    }
+
+    // Calculates the mean of all values.
+    public static double Mean(double[] values) {
+      return Mean(values, 0, values.Length);
+    }
+
+    /// <summary>
+    /// Calculates the mean of the values between start and end.
+    /// </summary>
+    /// <param name="values"></param>
+    /// <param name="start">start index (inclusive)</param>
+    /// <param name="end">end index(exclusive)</param>
+    /// <returns></returns>
+    public static double Mean(double[] values, int start, int end) {
+      if (values.Length == 0) throw new InvalidOperationException();
+      double sum = 0.0;
+      int n = 0;
+      for (int i = start; i < end; i++) {
+        if (!double.IsNaN(values[i])) {
+          sum += values[i];
+          n++;
+        }
+      }
+      if (n == 0) throw new InvalidOperationException();
+      return sum / n;
+    }
+
+    /// <summary>
+    /// Calculates the median of the values.
+    /// </summary>
+    /// <param name="values"></param>
+    /// <returns></returns>
+    public static double Median(double[] values) {
+      if (values.Length == 0) throw new InvalidOperationException();
+      int n = values.Length;
+      if (n == 0)
+        return 0;
+
+      double[] sortedValues = new double[n];
+
+      Array.Copy(values, sortedValues, n);
+      Array.Sort(sortedValues);
+
+      // return the middle element (if n is uneven) or the average of the two middle elements if n is even.
+      if (n % 2 == 1) {
+        return sortedValues[n / 2];
+      } else {
+        return (sortedValues[n / 2] + sortedValues[n / 2 + 1]) / 2.0;
+      }
+    }
+
+
+    /// <summary>
+    /// Calculates the standard deviation of values.
+    /// </summary>
+    /// <param name="values"></param>
+    /// <returns></returns>
+    public static double StandardDeviation(double[] values) {
+      return Math.Sqrt(Variance(values));
+    }
+
+    /// <summary>
+    /// Calculates the variance of values.
+    /// </summary>
+    /// <param name="values"></param>
+    /// <returns></returns>
+    public static double Variance(double[] values) {
+      return Variance(values, 0, values.Length);
+    }
+
+
+    /// <summary>
+    /// Calculates the variance of the entries of values between start and end.
+    /// </summary>
+    /// <param name="values"></param>
+    /// <param name="start">start index (inclusive)</param>
+    /// <param name="end">end index (exclusive)</param>
+    /// <returns></returns>
+    public static double Variance(double[] values, int start, int end) {
+      if (end - start == 1)
+        return 0.0;
+
+      double mean = Mean(values, start, end);
+      double squaredErrorsSum = 0.0;
+
+      int n = 0;
+      for (int i = start; i < end; i++) {
+        if (!double.IsNaN(values[i])) {
+          double d = values[i] - mean;
+          squaredErrorsSum += d * d;
+          n++;
+        }
+      }
+      if (n < 2) {
+        throw new InvalidOperationException();
+      }
+      return squaredErrorsSum / (n - 1);
+    }
+  }
+}
