Index: addons/HeuristicLab.Problems.BioBoost/Build.cmd
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/Build.cmd	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/Build.cmd	(revision 15711)
@@ -0,0 +1,104 @@
+@ECHO OFF
+
+SET CLEANBEFOREBUILD=
+
+SET SELECTED=
+SET CONFIGURATION=
+SET PLATFORM=
+
+IF "%~1"=="" GOTO :prompt_solution
+
+SET SELECTED=%1
+IF NOT EXIST %SELECTED% (
+  ECHO Solution file %SELECTED% could not be found.
+  GOTO :end
+)
+ECHO Building solution %SELECTED% ...
+GOTO :config_selection
+
+:prompt_solution
+SET /A COUNT=0
+FOR /F "tokens=*" %%A IN ('dir /B *.sln') DO (
+  CALL :forloopbody "%%A"
+)
+
+IF "%COUNT%"=="1" (
+  SET SELECTED=%SOLUTIONS.1%
+  ECHO Building %SOLUTIONS.1% as it is the only solution that was found ...
+  GOTO :config_selection
+)
+
+ECHO Found the following solutions:
+FOR /F "tokens=2* delims=.=" %%A IN ('SET SOLUTIONS.') DO ECHO %%A = %%B
+ECHO.
+SET /P SOLUTIONINDEX=Which solution to build? Type the number: 
+
+SET SELECTED=""
+FOR /F "tokens=2* delims=.=" %%A IN ('SET SOLUTIONS.') DO (
+  IF "%%A"=="%SOLUTIONINDEX%" SET SELECTED=%%B
+)
+
+IF %SELECTED%=="" GOTO :eof
+
+:config_selection
+IF "%~2"==""  GOTO :prompt_config
+
+SET CONFIGURATION=%~2
+ECHO Building configuration %CONFIGURATION% ...
+GOTO :platform_selection
+
+:prompt_config
+SET /P CONFIGURATION=Which configuration to build [Release]: 
+IF "%CONFIGURATION%"=="" SET CONFIGURATION=Release
+
+:platform_selection
+IF "%~3"=="" GOTO :prompt_platform
+  
+SET PLATFORM=%~3
+ECHO Building platform %PLATFORM% ...
+GOTO :clean
+
+:prompt_platform
+SET /P PLATFORM=Which platform to build [Any CPU]: 
+IF "%PLATFORM%"=="" SET PLATFORM=Any CPU
+
+:clean
+IF "%~4"=="" GOTO :prompt_clean
+
+SET CLEANBEFOREBUILD=%~4
+GOTO :main
+
+:prompt_clean
+SET /P CLEANBEFOREBUILD=Would you like to clean before building [n]: 
+IF "%CLEANBEFOREBUILD%"=="" SET CLEANBEFOREBUILD=n
+
+:main
+REM First find the path to the msbuild.exe by performing a registry query
+FOR /F "tokens=1,3 delims=	 " %%A IN ('REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\4.0"') DO (
+  IF "%%A"=="MSBuildToolsPath" SET MSBUILDPATH=%%B)
+
+REM Then execute msbuild to clean and build the solution
+REM Disable that msbuild creates a cache file of the solution
+SET MSBuildUseNoSolutionCache=1
+REM Run msbuild to clean and then build
+IF "%CLEANBEFOREBUILD%" NEQ "n" (
+  ECHO Cleaning ...
+  %MSBUILDPATH%msbuild.exe %SELECTED% /target:Clean /p:Configuration="%CONFIGURATION%",Platform="%PLATFORM%" /m:2 /nologo /verbosity:q /clp:ErrorsOnly
+)
+ECHO Building ...
+%MSBUILDPATH%msbuild.exe %SELECTED% /target:Build /p:Configuration="%CONFIGURATION%",Platform="%PLATFORM%" /m:2 /nologo /verbosity:q /clp:ErrorsOnly
+
+ECHO.
+ECHO DONE.
+
+:end
+
+PAUSE
+
+GOTO :eof
+
+REM This workaround is necessary so that COUNT gets reevaluated
+:forloopbody
+SET /A COUNT+=1
+SET SOLUTIONS.%COUNT%=%1
+GOTO :eof
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.BioBoost.sln
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.BioBoost.sln	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.BioBoost.sln	(revision 15711)
@@ -0,0 +1,48 @@
+﻿
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5E839856-8502-40BC-AA71-09AA821EC070}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Problems.BioBoost-3.3", "HeuristicLab.Problems.BioBoost\3.3\HeuristicLab.Problems.BioBoost-3.3.csproj", "{61D4AF50-8A40-44B9-9CD0-413F65D2235C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Problems.BioBoost.Views-3.3", "HeuristicLab.Problems.BioBoost.Views\3.3\HeuristicLab.Problems.BioBoost.Views-3.3.csproj", "{473AB0CD-0B71-471D-968C-A543B197E134}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|Any CPU = Release|Any CPU
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{61D4AF50-8A40-44B9-9CD0-413F65D2235C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{61D4AF50-8A40-44B9-9CD0-413F65D2235C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{61D4AF50-8A40-44B9-9CD0-413F65D2235C}.Debug|x64.ActiveCfg = Debug|x64
+		{61D4AF50-8A40-44B9-9CD0-413F65D2235C}.Debug|x64.Build.0 = Debug|x64
+		{61D4AF50-8A40-44B9-9CD0-413F65D2235C}.Debug|x86.ActiveCfg = Debug|x86
+		{61D4AF50-8A40-44B9-9CD0-413F65D2235C}.Debug|x86.Build.0 = Debug|x86
+		{61D4AF50-8A40-44B9-9CD0-413F65D2235C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{61D4AF50-8A40-44B9-9CD0-413F65D2235C}.Release|Any CPU.Build.0 = Release|Any CPU
+		{61D4AF50-8A40-44B9-9CD0-413F65D2235C}.Release|x64.ActiveCfg = Release|x64
+		{61D4AF50-8A40-44B9-9CD0-413F65D2235C}.Release|x64.Build.0 = Release|x64
+		{61D4AF50-8A40-44B9-9CD0-413F65D2235C}.Release|x86.ActiveCfg = Release|x86
+		{61D4AF50-8A40-44B9-9CD0-413F65D2235C}.Release|x86.Build.0 = Release|x86
+		{473AB0CD-0B71-471D-968C-A543B197E134}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{473AB0CD-0B71-471D-968C-A543B197E134}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{473AB0CD-0B71-471D-968C-A543B197E134}.Debug|x64.ActiveCfg = Debug|x64
+		{473AB0CD-0B71-471D-968C-A543B197E134}.Debug|x64.Build.0 = Debug|x64
+		{473AB0CD-0B71-471D-968C-A543B197E134}.Debug|x86.ActiveCfg = Debug|x86
+		{473AB0CD-0B71-471D-968C-A543B197E134}.Debug|x86.Build.0 = Debug|x86
+		{473AB0CD-0B71-471D-968C-A543B197E134}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{473AB0CD-0B71-471D-968C-A543B197E134}.Release|Any CPU.Build.0 = Release|Any CPU
+		{473AB0CD-0B71-471D-968C-A543B197E134}.Release|x64.ActiveCfg = Release|x64
+		{473AB0CD-0B71-471D-968C-A543B197E134}.Release|x64.Build.0 = Release|x64
+		{473AB0CD-0B71-471D-968C-A543B197E134}.Release|x86.ActiveCfg = Release|x86
+		{473AB0CD-0B71-471D-968C-A543B197E134}.Release|x86.Build.0 = Release|x86
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostCompoundSolutionEditor.Designer.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostCompoundSolutionEditor.Designer.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostCompoundSolutionEditor.Designer.cs	(revision 15711)
@@ -0,0 +1,297 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.BioBoost.Views {
+  partial class BioBoostCompoundSolutionEditor {
+    /// <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() {
+      System.Windows.Forms.Label vectorLayersLabel;
+      System.Windows.Forms.Label valueLayersLabel;
+      this.mapBox = new SharpMap.Forms.MapBox();
+      this.transportLayersListBox = new System.Windows.Forms.ListBox();
+      this.utilizationLayersListBox = new System.Windows.Forms.ListBox();
+      this.regionNameLabel = new System.Windows.Forms.Label();
+      this.regionDescriptionLabel = new System.Windows.Forms.Label();
+      this.qualityLabel = new System.Windows.Forms.Label();
+      this.feedstockCostsLabel = new System.Windows.Forms.Label();
+      this.transportCostsLabel = new System.Windows.Forms.Label();
+      this.optimizeTransportsButton = new System.Windows.Forms.Button();
+      this.optimizeUtilizationsButton = new System.Windows.Forms.Button();
+      this.statusStrip = new System.Windows.Forms.StatusStrip();
+      this.toolStripStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
+      this.costPerFuelLabel = new System.Windows.Forms.Label();
+      this.transportInfoLabel = new System.Windows.Forms.Label();
+      vectorLayersLabel = new System.Windows.Forms.Label();
+      valueLayersLabel = new System.Windows.Forms.Label();
+      this.statusStrip.SuspendLayout();
+      this.SuspendLayout();
+      // 
+      // vectorLayersLabel
+      // 
+      vectorLayersLabel.AutoSize = true;
+      vectorLayersLabel.Location = new System.Drawing.Point(3, 86);
+      vectorLayersLabel.Margin = new System.Windows.Forms.Padding(3);
+      vectorLayersLabel.Name = "vectorLayersLabel";
+      vectorLayersLabel.Size = new System.Drawing.Size(72, 13);
+      vectorLayersLabel.TabIndex = 9;
+      vectorLayersLabel.Text = "Vector Layers";
+      // 
+      // valueLayersLabel
+      // 
+      valueLayersLabel.AutoSize = true;
+      valueLayersLabel.Location = new System.Drawing.Point(3, 216);
+      valueLayersLabel.Name = "valueLayersLabel";
+      valueLayersLabel.Size = new System.Drawing.Size(68, 13);
+      valueLayersLabel.TabIndex = 10;
+      valueLayersLabel.Text = "Value Layers";
+      // 
+      // mapBox
+      // 
+      this.mapBox.ActiveTool = SharpMap.Forms.MapBox.Tools.Pan;
+      this.mapBox.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.mapBox.Cursor = System.Windows.Forms.Cursors.Hand;
+      this.mapBox.FineZoomFactor = 10D;
+      this.mapBox.Location = new System.Drawing.Point(189, 31);
+      this.mapBox.MapQueryMode = SharpMap.Forms.MapBox.MapQueryType.VisibleLayers;
+      this.mapBox.Name = "mapBox";
+      this.mapBox.PanOnClick = false;
+      this.mapBox.PreviewMode = SharpMap.Forms.MapBox.PreviewModes.Fast;
+      this.mapBox.QueryGrowFactor = 5F;
+      this.mapBox.QueryLayerIndex = 0;
+      this.mapBox.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(210)))), ((int)(((byte)(244)))), ((int)(((byte)(244)))), ((int)(((byte)(244)))));
+      this.mapBox.SelectionForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(244)))), ((int)(((byte)(244)))), ((int)(((byte)(244)))));
+      this.mapBox.ShowProgressUpdate = true;
+      this.mapBox.Size = new System.Drawing.Size(652, 396);
+      this.mapBox.TabIndex = 0;
+      this.mapBox.TakeFocusOnHover = true;
+      this.mapBox.Text = "mapBox";
+      this.mapBox.WheelZoomMagnitude = -2D;
+      this.mapBox.MouseMove += new SharpMap.Forms.MapBox.MouseEventHandler(this.mapBox_MouseMove);
+      this.mapBox.MouseDown += new SharpMap.Forms.MapBox.MouseEventHandler(this.mapBox_MouseDown);
+      this.mapBox.MouseUp += new SharpMap.Forms.MapBox.MouseEventHandler(this.mapBox_MouseUp);
+      // 
+      // transportLayersListBox
+      // 
+      this.transportLayersListBox.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed;
+      this.transportLayersListBox.FormattingEnabled = true;
+      this.transportLayersListBox.HorizontalScrollbar = true;
+      this.transportLayersListBox.Location = new System.Drawing.Point(6, 105);
+      this.transportLayersListBox.Name = "transportLayersListBox";
+      this.transportLayersListBox.Size = new System.Drawing.Size(172, 108);
+      this.transportLayersListBox.TabIndex = 1;
+      this.transportLayersListBox.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.vectorLayerNamesListBox_DrawItem);
+      this.transportLayersListBox.SelectedIndexChanged += new System.EventHandler(this.vectorLayerNamesListBox_SelectedIndexChanged);
+      // 
+      // utilizationLayersListBox
+      // 
+      this.utilizationLayersListBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+            | System.Windows.Forms.AnchorStyles.Left)));
+      this.utilizationLayersListBox.FormattingEnabled = true;
+      this.utilizationLayersListBox.HorizontalScrollbar = true;
+      this.utilizationLayersListBox.Items.AddRange(new object[] {
+            "StrawPotentials",
+            "StrawUtilizations",
+            "StrawConverterCapacities"});
+      this.utilizationLayersListBox.Location = new System.Drawing.Point(6, 232);
+      this.utilizationLayersListBox.Name = "utilizationLayersListBox";
+      this.utilizationLayersListBox.Size = new System.Drawing.Size(172, 69);
+      this.utilizationLayersListBox.TabIndex = 0;
+      this.utilizationLayersListBox.SelectedIndexChanged += new System.EventHandler(this.valueLayerNamesListBox_SelectedIndexChanged);
+      // 
+      // regionNameLabel
+      // 
+      this.regionNameLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+      this.regionNameLabel.Location = new System.Drawing.Point(3, 323);
+      this.regionNameLabel.MaximumSize = new System.Drawing.Size(500, 13);
+      this.regionNameLabel.Name = "regionNameLabel";
+      this.regionNameLabel.Size = new System.Drawing.Size(175, 12);
+      this.regionNameLabel.TabIndex = 8;
+      this.regionNameLabel.Text = "AT111";
+      this.regionNameLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+      // 
+      // regionDescriptionLabel
+      // 
+      this.regionDescriptionLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+      this.regionDescriptionLabel.Location = new System.Drawing.Point(3, 307);
+      this.regionDescriptionLabel.Margin = new System.Windows.Forms.Padding(3);
+      this.regionDescriptionLabel.MaximumSize = new System.Drawing.Size(500, 13);
+      this.regionDescriptionLabel.Name = "regionDescriptionLabel";
+      this.regionDescriptionLabel.Size = new System.Drawing.Size(175, 13);
+      this.regionDescriptionLabel.TabIndex = 7;
+      this.regionDescriptionLabel.Text = "Vienna";
+      this.regionDescriptionLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+      // 
+      // qualityLabel
+      // 
+      this.qualityLabel.AutoSize = true;
+      this.qualityLabel.Location = new System.Drawing.Point(3, 3);
+      this.qualityLabel.Margin = new System.Windows.Forms.Padding(3);
+      this.qualityLabel.Name = "qualityLabel";
+      this.qualityLabel.Size = new System.Drawing.Size(83, 13);
+      this.qualityLabel.TabIndex = 11;
+      this.qualityLabel.Text = "Solution Quality:";
+      // 
+      // feedstockCostsLabel
+      // 
+      this.feedstockCostsLabel.AutoSize = true;
+      this.feedstockCostsLabel.Location = new System.Drawing.Point(3, 22);
+      this.feedstockCostsLabel.Margin = new System.Windows.Forms.Padding(3);
+      this.feedstockCostsLabel.Name = "feedstockCostsLabel";
+      this.feedstockCostsLabel.Size = new System.Drawing.Size(128, 13);
+      this.feedstockCostsLabel.TabIndex = 12;
+      this.feedstockCostsLabel.Text = "Feedstock Acq. [Mio€/a]:";
+      // 
+      // transportCostsLabel
+      // 
+      this.transportCostsLabel.AutoSize = true;
+      this.transportCostsLabel.Location = new System.Drawing.Point(3, 41);
+      this.transportCostsLabel.Margin = new System.Windows.Forms.Padding(3);
+      this.transportCostsLabel.Name = "transportCostsLabel";
+      this.transportCostsLabel.Size = new System.Drawing.Size(98, 13);
+      this.transportCostsLabel.TabIndex = 13;
+      this.transportCostsLabel.Text = "Transport [Mio€/a]:";
+      // 
+      // optimizeTransportsButton
+      // 
+      this.optimizeTransportsButton.Location = new System.Drawing.Point(189, 3);
+      this.optimizeTransportsButton.Name = "optimizeTransportsButton";
+      this.optimizeTransportsButton.Size = new System.Drawing.Size(120, 23);
+      this.optimizeTransportsButton.TabIndex = 14;
+      this.optimizeTransportsButton.Text = "Optimize Transports";
+      this.optimizeTransportsButton.UseVisualStyleBackColor = true;
+      this.optimizeTransportsButton.Click += new System.EventHandler(this.optimizeTransportsButton_Click);
+      // 
+      // optimizeUtilizationsButton
+      // 
+      this.optimizeUtilizationsButton.Location = new System.Drawing.Point(315, 3);
+      this.optimizeUtilizationsButton.Name = "optimizeUtilizationsButton";
+      this.optimizeUtilizationsButton.Size = new System.Drawing.Size(120, 23);
+      this.optimizeUtilizationsButton.TabIndex = 15;
+      this.optimizeUtilizationsButton.Text = "Optimize Utilizations";
+      this.optimizeUtilizationsButton.UseVisualStyleBackColor = true;
+      this.optimizeUtilizationsButton.Click += new System.EventHandler(this.optimizeUtilizationsButton_Click);
+      // 
+      // statusStrip
+      // 
+      this.statusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+            this.toolStripStatusLabel});
+      this.statusStrip.Location = new System.Drawing.Point(0, 430);
+      this.statusStrip.Name = "statusStrip";
+      this.statusStrip.Size = new System.Drawing.Size(844, 22);
+      this.statusStrip.TabIndex = 16;
+      this.statusStrip.Text = "statusStrip";
+      // 
+      // toolStripStatusLabel
+      // 
+      this.toolStripStatusLabel.Name = "toolStripStatusLabel";
+      this.toolStripStatusLabel.Size = new System.Drawing.Size(28, 17);
+      this.toolStripStatusLabel.Text = "Info";
+      // 
+      // costPerFuelLabel
+      // 
+      this.costPerFuelLabel.AutoSize = true;
+      this.costPerFuelLabel.Location = new System.Drawing.Point(3, 60);
+      this.costPerFuelLabel.Margin = new System.Windows.Forms.Padding(3);
+      this.costPerFuelLabel.Name = "costPerFuelLabel";
+      this.costPerFuelLabel.Size = new System.Drawing.Size(130, 13);
+      this.costPerFuelLabel.TabIndex = 17;
+      this.costPerFuelLabel.Text = "Transport Fuel Costs [€/t]:";
+      // 
+      // transportInfoLabel
+      // 
+      this.transportInfoLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+      this.transportInfoLabel.Location = new System.Drawing.Point(3, 335);
+      this.transportInfoLabel.Name = "transportInfoLabel";
+      this.transportInfoLabel.Size = new System.Drawing.Size(175, 92);
+      this.transportInfoLabel.TabIndex = 18;
+      this.transportInfoLabel.Text = "Transport";
+      // 
+      // BioBoostCompoundSolutionEditor
+      // 
+      this.AllowDrop = true;
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Controls.Add(this.transportInfoLabel);
+      this.Controls.Add(this.costPerFuelLabel);
+      this.Controls.Add(this.statusStrip);
+      this.Controls.Add(this.optimizeUtilizationsButton);
+      this.Controls.Add(this.optimizeTransportsButton);
+      this.Controls.Add(this.transportCostsLabel);
+      this.Controls.Add(this.feedstockCostsLabel);
+      this.Controls.Add(this.qualityLabel);
+      this.Controls.Add(this.regionDescriptionLabel);
+      this.Controls.Add(this.regionNameLabel);
+      this.Controls.Add(this.utilizationLayersListBox);
+      this.Controls.Add(this.transportLayersListBox);
+      this.Controls.Add(this.mapBox);
+      this.Controls.Add(vectorLayersLabel);
+      this.Controls.Add(valueLayersLabel);
+      this.Name = "BioBoostCompoundSolutionEditor";
+      this.Size = new System.Drawing.Size(844, 452);
+      this.statusStrip.ResumeLayout(false);
+      this.statusStrip.PerformLayout();
+      this.ResumeLayout(false);
+      this.PerformLayout();
+
+    }
+
+    #endregion
+
+    private SharpMap.Forms.MapBox mapBox;
+    private System.Windows.Forms.ListBox transportLayersListBox;
+    private System.Windows.Forms.ListBox utilizationLayersListBox;
+    private System.Windows.Forms.Label regionNameLabel;
+    private System.Windows.Forms.Label regionDescriptionLabel;
+    private System.Windows.Forms.Label qualityLabel;
+    private System.Windows.Forms.Label feedstockCostsLabel;
+    private System.Windows.Forms.Label transportCostsLabel;
+    private System.Windows.Forms.Button optimizeTransportsButton;
+    private System.Windows.Forms.Button optimizeUtilizationsButton;
+    private System.Windows.Forms.StatusStrip statusStrip;
+    private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel;
+    private System.Windows.Forms.Label costPerFuelLabel;
+    private System.Windows.Forms.Label transportInfoLabel;
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostCompoundSolutionEditor.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostCompoundSolutionEditor.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostCompoundSolutionEditor.cs	(revision 15711)
@@ -0,0 +1,803 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using GeoAPI.Geometries;
+using HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.BioBoost.Representation;
+using HeuristicLab.BioBoost.Utils;
+using HeuristicLab.BioBoost.Views.MapViews;
+using HeuristicLab.Core.Views;
+using HeuristicLab.MainForm;
+using HeuristicLab.PluginInfrastructure;
+using NetTopologySuite.Geometries;
+using SharpMap.Data;
+using SharpMap.Forms;
+using SharpMap.Layers;
+using SharpMap.Rendering.Decoration;
+using SharpMap.Rendering.Decoration.ScaleBar;
+using Point = System.Drawing.Point;
+
+namespace HeuristicLab.BioBoost.Views {
+
+  [Content(typeof(BioBoostCompoundSolution))]
+  public partial class BioBoostCompoundSolutionEditor : ItemView {
+
+    private readonly GradientLegend utilizationLegend;
+
+    private SharpMap.Rendering.Thematics.ColorBlend vectorColorBlend =
+      new SharpMap.Rendering.Thematics.ColorBlend(new[] {
+        Color.FromArgb(0, 0, 255),
+        Color.FromArgb(128, 0, 128),
+        Color.FromArgb(255, 0, 0),
+      }, new[] { 0f, .5f, 1f });
+
+    public const string AllRegionsName = "All";
+
+    public new BioBoostCompoundSolution Content {
+      get { return (BioBoostCompoundSolution)base.Content; }
+      set { base.Content = value; }
+    }
+
+    public BioBoostCompoundSolutionEditor() {
+      InitializeComponent();
+
+      mapBox.Map.Decorations.Add(new ScaleBar {
+        Anchor = MapDecorationAnchor.RightBottom,
+        BarColor1 = Color.White,
+        BarColor2 = Color.Black,
+        BarStyle = ScaleBarStyle.Meridian,
+        MapUnit = (int)Unit.Degree,
+        BarUnit = (int)Unit.Kilometer,
+      });
+
+      utilizationLegend = new GradientLegend();
+      mapBox.Map.Decorations.Add(utilizationLegend);
+      mapBox.Map.Decorations.Add(new NorthArrow());
+      mapBox.ActiveTool = MapBox.Tools.None;
+    }
+
+
+
+    protected override void SetEnabledStateOfControls() {
+      base.SetEnabledStateOfControls();
+      ReadOnly = Locked || Content == null;
+      mapBox.Enabled = !Locked && Content != null;
+      transportLayersListBox.Enabled = !Locked && Content != null;
+      utilizationLayersListBox.Enabled = !Locked && Content != null;
+    }
+
+    #region content events
+    protected override void OnContentChanged() {
+      if (InvokeRequired) {
+        Invoke((Action)OnContentChanged);
+      } else {
+        base.OnContentChanged();
+        if (Content == null) {
+          Clear();
+        } else {
+          Update();
+        }
+      }
+    }
+    protected override void DeregisterContentEvents() {
+      Content.SolutionChanged -= SolutionChanged;
+      base.DeregisterContentEvents();
+    }
+
+    protected override void RegisterContentEvents() {
+      base.RegisterContentEvents();
+      Content.SolutionChanged += SolutionChanged;
+    }
+
+    private void SolutionChanged(object sender, EventArgs e) {
+      if (InvokeRequired) {
+        Invoke(new EventHandler<EventArgs>(SolutionChanged), sender, e);
+      } else {
+        Update();
+      }
+    }
+    #endregion
+
+
+    #region Main Logic
+    private void Clear() {
+      qualityLabel.Text = string.Empty;
+      feedstockCostsLabel.Text = string.Empty;
+      transportCostsLabel.Text = string.Empty;
+      utilizationLayersListBox.Items.Clear();
+      transportLayersListBox.Items.Clear();
+      mapBox.Map.Layers.Clear(); // only two layers are active at any time (representing the layers selected in the list boxes on the left)
+    }
+
+    private void Update() {
+      // store currently selected items
+      var selectedValueLayerName = GetSelectedLayer(utilizationLayersListBox);
+      var selectedVectorLayerName = GetSelectedLayer(transportLayersListBox);
+
+      // clear everything
+      Clear();
+      FillQualityInformation();
+      FillValueLayersListBox();
+      FillVectorLayersListBox();
+
+      // restore selection if possible
+      // when we couldn't restore the value or vector layer then there has been a larger change (unexpected) and we need to reset the zoom level
+      // this also makes sure that the zoom level is set correctly when the solution is initially displayed
+      if (!TrySetSelectedLayer(utilizationLayersListBox, selectedValueLayerName) |
+          !TrySetSelectedLayer(transportLayersListBox, selectedVectorLayerName)) {
+        ResetZoom();
+      }
+      mapBox.Refresh();
+    }
+
+    private void FillQualityInformation() {
+      qualityLabel.Text = string.Format("Solution quality: {0:F4}", Content.Quality);
+      feedstockCostsLabel.Text = string.Format("Feedstock [Mio€/a]: {0:N1}", Content.TotalFeedstockCosts / 1E6);
+      transportCostsLabel.Text = string.Format("Transport [Mio€/a]: {0:N1}", Content.TotalTransportCosts / 1E6);
+      costPerFuelLabel.Text = string.Format("Transport Fuel Costs [€/t]: {0:N1}", Content.TotalCosts / Content.TotalTransportFuelAmount);
+    }
+
+
+    private void FillValueLayersListBox() {
+      // we only add items for layers that we are allowed to change (layers that correspond to a vector in the representation)
+      // add utilizations for all feedstock
+      utilizationLayersListBox.BeginUpdate();
+      foreach (var pair in Content.UtilizationVectors) {
+        var newItem = new ListBoxItem<double[]> {
+          Color = Color.White,
+          Text = pair.Item1,
+          Value = pair.Item2
+        };
+        utilizationLayersListBox.Items.Add(newItem);
+      }
+      utilizationLayersListBox.EndUpdate();
+    }
+
+    private void FillVectorLayersListBox() {
+      // we only add items for vectors that we are allowed to change
+      // add transport vector layers for all products
+      transportLayersListBox.BeginUpdate();
+      int i = 0;
+      int n = Content.TransportVectors.Count();
+      foreach (var pair in Content.TransportVectors) {
+        var newItem = new ListBoxItem<int[]> {
+          Color = vectorColorBlend.GetColor(1f * i++ / (float)n),
+          Text = pair.Item1,
+          Value = pair.Item2
+        };
+        transportLayersListBox.Items.Add(newItem);
+      }
+      transportLayersListBox.EndUpdate();
+    }
+
+    private void UpdateMapLayers() {
+      mapBox.Map.Layers.Clear();
+      AddSelectedValueLayer(); // values first ...
+      AddSelectedVectorLayer(); // ... then vectors (because they need to be drawn last)
+      AddWorstTransportsVectorLayer();
+      mapBox.Refresh();
+    }
+
+    private void AddWorstTransportsVectorLayer() {
+      var geom = Content.Geometry;
+      var locs = Content.LocationNames;
+      var selectedProduct = GetSelectedLayer(transportLayersListBox);
+      if (selectedProduct == string.Empty) return;
+      int[] worstTransports = new int[locs.Length];
+      for (int i = 0; i < worstTransports.Length; i++) {
+        worstTransports[i] = -1;
+      }
+      foreach (var transport in CalcNonDominatedTransports()) {
+        if (transport.Product != selectedProduct) continue;
+        worstTransports[transport.SrcRegionIdx] = transport.DestRegionIdx;
+      }
+
+      var allTransports = Content.Transports.Where(t => t.Product == selectedProduct).ToArray();
+
+      // for all regions find the matching transport (if there is one)
+      var transportAmounts = locs
+        .Select(loc => allTransports.FirstOrDefault(t => t.SrcRegion == loc))
+        .Select(trans => trans == null ? 0.0 : trans.Amount)
+        .ToArray();
+
+      var generator = new LazyVectorLayerGenerator(geom, locs, worstTransports, transportAmounts, Color.Red, "Worst Transports");
+
+      mapBox.Map.Layers.Add(generator.Layer);
+    }
+
+
+    private void AddSelectedVectorLayer() {
+      var selectedVectorLayerItem = transportLayersListBox.SelectedItem as ListBoxItem<int[]>;
+      if (selectedVectorLayerItem == null) return;
+
+      var selectedProduct = GetSelectedLayer(transportLayersListBox);
+
+      var geom = Content.Geometry;
+      var locs = Content.LocationNames;
+
+      var allTranports = Content.Transports.Where(t => t.Product == selectedProduct).ToArray();
+
+      // foreach location find the transport amounts (if there is any)
+      var amounts = locs
+        .Select(loc => allTranports.FirstOrDefault(trans => trans.SrcRegion == loc))
+        .Select(trans => trans == null ? 0.0 : trans.Amount)
+        .ToArray();
+
+      var generator = new LazyVectorLayerGenerator(geom, locs, selectedVectorLayerItem.Value, amounts, selectedVectorLayerItem.Color, "Transports");
+
+      mapBox.Map.Layers.Add(generator.Layer);
+    }
+
+    private void AddSelectedValueLayer() {
+      var selectedValueLayerItem = utilizationLayersListBox.SelectedItem as ListBoxItem<double[]>;
+      if (selectedValueLayerItem == null) return;
+
+      var geom = Content.Geometry;
+      var locs = Content.LocationNames;
+
+      var generator = new LazyValueLayerGenerator(geom, locs, selectedValueLayerItem.Value, "Utilizations");
+
+      mapBox.Map.Layers.Add(generator.Layer);
+    }
+
+
+    // clicking on the map changes the underlying solution and causes a reevaluation
+    // this is called by the mouse-up event handler
+    private async void DispatchMouseUp(string startRegion, string endRegion, Tuple<string, string> arrow, Point mousePos) {
+      // some operations on the content might fail ... show an error dialog in this case
+      try {
+        if (arrow != null && startRegion == endRegion) {
+          // an vector was clicked => remove it
+          Content.SetTransport(GetSelectedLayer(transportLayersListBox), arrow.Item1, arrow.Item1);
+          // remove the vector
+        } else if (startRegion != string.Empty && endRegion == startRegion &&
+                   Util.Distance(startPos, mousePos) < 4) {
+          // no vector but
+          // region was clicked (no dragging) => update utilization
+          var currentUtil = Content.GetUtilization(GetSelectedLayer(utilizationLayersListBox), endRegion);
+          var newUtil = await ShowTrackBar(new Point(mousePos.X - 10, mousePos.Y - 10), currentUtil);
+          Content.SetUtilization(GetSelectedLayer(utilizationLayersListBox), endRegion, newUtil);
+        } else if (startRegion != string.Empty && endRegion != string.Empty) {
+          // we dragged from one region to another (possibly the same region
+          Content.SetTransport(GetSelectedLayer(transportLayersListBox), startRegion, endRegion);
+        }
+      } catch (SystemException e) {
+        var dialog = new ErrorDialog(e);
+        dialog.ShowDialog(this);
+      }
+    }
+
+    public void OptimizeTransports() {
+      // FullLocalSearchForTransports();
+      // NearestPlantLocalSearchForTransports();
+      PruneLongAndSmallTransports();
+    }
+
+    private IEnumerable<BioBoostCompoundSolution.TransportInfo> CalcNonDominatedTransports() {
+      var transports = Content.Transports.ToArray();
+      var transportDistances = transports.Select(t => t.Distance).ToArray();
+      var transportAmounts = transports.Select(t => t.Amount).ToArray();
+
+      for (int i = 0; i < transports.Length; i++) {
+        if (!IsDominated(i, transportDistances, transportAmounts)) {
+          yield return transports[i];
+        }
+      }
+    }
+
+    private void PruneLongAndSmallTransports() {
+
+      var nonDominatedTransports = CalcNonDominatedTransports().ToArray();
+
+      var oldQ = Content.Quality;
+      var curQ = Content.Quality;
+      var curContent = (BioBoostCompoundSolution)Content.Clone();
+      foreach (var transport in nonDominatedTransports) {
+        curContent.SetTransport(transport.Product, transport.SrcRegionIdx, transport.SrcRegionIdx);
+      }
+      curQ = curContent.Quality;
+
+      SetStatusInfo(string.Format("Deleted {0} transports. Total quality improvement: {1:F4}", nonDominatedTransports.Length,
+        curQ - Content.Quality));
+      Content.UpdateTo(curContent);
+    }
+
+    private bool IsDominated(int idx, double[] transportDistances, double[] transportAmounts) {
+      // check if there is any other transport that has a larger distance and a smaller amount
+      var dominatingIdx =
+        Enumerable.Range(0, transportDistances.Length)
+        .Where((otherIdx) => idx != otherIdx)
+        .Where((otherIdx) => transportDistances[otherIdx] > transportDistances[idx])
+        .Where((otherIdx) => transportAmounts[otherIdx] < transportAmounts[idx]);
+      return (dominatingIdx.Any());
+    }
+
+    /*
+    private void NearestPlantLocalSearchForTransports() {
+      // for each transport check if we can reroute it to a nearer plant (with minor loss in quality 1%)
+      const double maxRelativeQualityChange = -0.001;
+      var oldQ = Content.Quality;
+      var curQ = Content.Quality;
+      var curContent = (BioBoostCompoundSolution)Content.Clone();
+      // TODO: assumes that there is only one distance matrix and all products are transported using this matrix!!
+      Debug.Assert(Content.ProblemDataReference.Parameters.Count(p => p.Name.EndsWith("DistanceMatrix")) == 1);
+      var distanceMatrix = (DistanceMatrix)Content.ProblemDataReference.Parameters.First(p => p.Name.EndsWith("DistanceMatrix")).ActualValue;
+
+      // for each product a list of possible targets (possible targets stay fixed in optimization)
+      var curTransportTargets = curContent.TransportVectors
+        .Select(kvp => new KeyValuePair<string, int[]>(kvp.Item1, kvp.Item2.Distinct().Where(i => i >= 0).OrderBy(t => t).ToArray()))
+        .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
+
+      // for each product and for each region a list of the max 5 nearest plants
+      var nearestPlantIdx = new Dictionary<string, int[][]>();
+      foreach (var product in curTransportTargets.Keys) {
+        nearestPlantIdx.Add(product, new int[curContent.LocationNames.Length][]);
+        var nIdx = nearestPlantIdx[product];
+        for (int src = 0; src < nIdx.Length; src++) {
+          var plantsByDistance =
+            curTransportTargets[product].OrderBy(possibleTarget => distanceMatrix[src, possibleTarget]);
+          var nPlants = Math.Min(plantsByDistance.Count(), 3);
+          nIdx[src] = plantsByDistance.Take(nPlants).ToArray();
+        }
+      }
+
+      // generate possible changes
+      // either change the transport to the nearest existing plant ...
+      // ... or if the transport is within the same region then to the second nearest plant (reduces plants)
+      var changes = new List<Tuple<string, int, int>>(); // product x source x dest
+      foreach (var kvp in curContent.TransportVectors) {
+        var prod = kvp.Item1;
+        var curDest = kvp.Item2;
+        for (int src = 0; src < curDest.Length; src++) {
+          var dest = curDest[src];
+          if (dest == -1)
+            continue; // don't allow transports if the current transport target is -1 
+          foreach (var alternativeDest in nearestPlantIdx[prod][src]) {
+            if (alternativeDest != dest)
+              changes.Add(Tuple.Create(prod, src, alternativeDest));
+          }
+        }
+      }
+
+      var improvements = new List<double>();
+      // evalute changes (full evaluation)
+      for (int i = 0; i < changes.Count; i++) {
+        // apply each change in turn to a clone of the solution and check the change in quality
+        var change = changes[i];
+        var tmpContent = (BioBoostCompoundSolution)curContent.Clone();
+        tmpContent.SetTransport(change.Item1, change.Item2, change.Item3); // product, src, dest
+        improvements.Add(tmpContent.Quality - curQ); // if quality after change is worse than current quality improvement is negative
+      }
+
+      var sortedChanges =
+        changes.Zip(improvements, (change, improvement) => new { change, improvement })
+        .OrderByDescending(p => p.improvement) // positive improvements first
+        .ToArray();
+
+      int changeCount = 0;
+      int changeIdx = 0;
+
+      bool changed = true; // has there been a change in this iteration
+      // while there is a total deterioation not worse than -1%
+      var totalChange = 0.0;
+      while (changeIdx < sortedChanges.Length && changed && totalChange > (oldQ * maxRelativeQualityChange)) {
+        changed = false;
+        var change = sortedChanges[changeIdx].change;
+        var improvement = sortedChanges[changeIdx].improvement;
+        // and each step is not worse than -1%
+        if (improvement > curQ * maxRelativeQualityChange) {
+          changeCount++;
+          totalChange += improvement;
+          curContent.SetTransport(change.Item1, change.Item2, change.Item3); // product, src, dest
+          curQ = curContent.Quality; // update current quality
+          changed = true;
+        }
+        changeIdx++;
+      }
+
+      Content.UpdateTo(curContent);
+      SetStatusInfo(string.Format("Changed {0} transports. Total quality improvement: {1:F4}", changeCount,
+        Content.Quality - oldQ));
+    }
+    */
+
+    /*
+    private void FullLocalSearchForTransports() {
+      // for each transport check if we can reroute the transport to any other location (which already is a transport target for this product type)
+      // local search using best improvement
+      double oldQ;
+      var curQ = Content.Quality;
+      var curContent = (BioBoostCompoundSolution)Content.Clone();
+
+      // for each product a list of possible targets (possible targets stay fixed in optimization)
+      var curTransportTargets = curContent.TransportVectors
+        .Select(kvp => new KeyValuePair<string, int[]>(kvp.Item1, kvp.Item2.Distinct().OrderBy(t => t).ToArray()))
+        .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
+
+      int changeCount = 0;
+      do {
+        // store current quality (to check if we found an improvement)
+        oldQ = curQ;
+
+        // generate possible changes
+        var changes = new List<Tuple<string, int, int>>(); // product x source x dest
+        foreach (var kvp in curContent.TransportVectors) {
+          var prod = kvp.Item1;
+          var curDest = kvp.Item2;
+          foreach (var alternativeDest in curTransportTargets[prod]) {
+            if (alternativeDest == -1) continue; // don't allow transport to new locations (without plants)
+            for (int src = 0; src < curDest.Length; src++) {
+              var dest = curDest[src];
+              if (dest == -1) continue; // don't allow transports if the current transport target is -1 (TODO: check with erik)
+
+              if (dest != alternativeDest) {
+                changes.Add(Tuple.Create(prod, src, alternativeDest));
+              }
+            }
+          }
+        }
+
+        // evalute changes (full evaluation)
+        var bestImprovement = double.NegativeInfinity;
+        var bestChangeIdx = -1;
+        for (int i = 0; i < changes.Count; i++) {
+          // apply each change in turn to a clone of the solution and check the change in quality
+          var change = changes[i];
+          var tmpContent = (BioBoostCompoundSolution)curContent.Clone();
+          tmpContent.SetTransport(change.Item1, change.Item2, change.Item3); // product, src, dest
+          var improvement = tmpContent.Quality - curQ;
+          if (improvement > bestImprovement) {
+            bestImprovement = improvement;
+            bestChangeIdx = i;
+          }
+        }
+        if (bestImprovement > 0) {
+          changeCount++;
+          var bestChange = changes[bestChangeIdx];
+          curContent.SetTransport(bestChange.Item1, bestChange.Item2, bestChange.Item3); // product, src, dest
+          curQ = curContent.Quality; // update current quality
+        }
+
+        // apply best change
+      } while (oldQ < curQ);
+
+      SetStatusInfo(string.Format("Changed {0} transports. Total quality improvement: {1:F4}", changeCount,
+        curQ - Content.Quality));
+      Content.UpdateTo(curContent);
+    }*/
+
+
+    public void OptimizeUtilizations() {
+      double oldQ;
+      var curQ = Content.Quality;
+      var curContent = (BioBoostCompoundSolution)Content.Clone();
+      int changeCount = 0;
+      do {
+        oldQ = curQ;
+
+        // for each product and region check if the quality increases if we set the utilization to zero
+        // local search using first improvement
+        var changes = new List<Tuple<string, int, double>>(); // product x region x utilization
+        foreach (var pair in curContent.UtilizationVectors) {
+          var prod = pair.Item1;
+          var util = pair.Item2;
+          for (int regIdx = 0; regIdx < util.Length; regIdx++) {
+            if (util[regIdx] > 0) {
+              changes.Add(Tuple.Create(prod, regIdx, 0.0));
+            }
+          }
+        }
+
+        var bestImprovement = double.NegativeInfinity;
+        var bestChange = changes.First();
+        foreach (var change in changes) {
+          var tmpContent = (BioBoostCompoundSolution)curContent.Clone();
+          tmpContent.SetUtilization(change.Item1, change.Item2, change.Item3);
+          var newQ = tmpContent.Quality;
+          var improvement = newQ - curQ; // positive improvements (new quality is higher than current quality
+          if (improvement > bestImprovement) {
+            bestImprovement = improvement;
+            bestChange = change;
+          }
+        }
+
+        // apply if we found a possible improvement
+        if (bestImprovement > 0) {
+          curContent.SetUtilization(bestChange.Item1, bestChange.Item2, bestChange.Item3);
+          curQ = curContent.Quality;
+          changeCount++;
+        }
+      } while (oldQ < curQ);
+
+      SetStatusInfo(string.Format("Changed {0} utilizations. Total quality improvement: {1:F4}", changeCount,
+        curQ - Content.Quality));
+      Content.UpdateTo(curContent);
+    }
+
+    private void SetStatusInfo(string message) {
+      if (InvokeRequired) {
+        Invoke((Action<string>)SetStatusInfo, message);
+      } else {
+        toolStripStatusLabel.Text = message;
+      }
+    }
+
+    private void UpdateTransportInfo(Tuple<string, string> vector) {
+      transportInfoLabel.Text = string.Empty; // clear
+      if (vector != null) {
+        var transportProduct = GetSelectedLayer(transportLayersListBox);
+        var transportInfo =
+          Content.Transports.FirstOrDefault(
+            info => info.Product == transportProduct && info.SrcRegion == vector.Item1 && info.DestRegion == vector.Item2);
+        if (transportInfo != null) {
+
+          var sb = new StringBuilder();
+          sb.AppendFormat("{0} -> {1}", transportInfo.SrcRegion, transportInfo.DestRegion).AppendLine();
+          sb.AppendFormat("{0} (Mode: {1})", transportInfo.Product, transportInfo.Mode).AppendLine();
+          sb.AppendFormat("{0:N0} kt km", transportInfo.Distance * transportInfo.Amount / 1000.0).AppendLine();
+          sb.AppendFormat("{0:N1} kt {1:N0} km", transportInfo.Amount / 1000.0, transportInfo.Distance);
+          transportInfoLabel.Text = sb.ToString();
+        }
+      }
+    }
+    #endregion
+
+
+
+    #region Event Handlers (child controls)
+    private void vectorLayerNamesListBox_SelectedIndexChanged(object sender, EventArgs e) {
+      UpdateMapLayers();
+    }
+
+    private void valueLayerNamesListBox_SelectedIndexChanged(object sender, EventArgs e) {
+      UpdateMapLayers();
+    }
+
+    private void optimizeTransportsButton_Click(object sender, EventArgs e) {
+      using (BackgroundWorker bg = new BackgroundWorker()) {
+        MainFormManager.GetMainForm<MainForm.WindowsForms.MainForm>().AddOperationProgressToView(this, "Optimizing Transports...");
+        bg.DoWork += (o, a) => OptimizeTransports();
+        bg.RunWorkerCompleted += (o, a) => MainFormManager.GetMainForm<MainForm.WindowsForms.MainForm>().RemoveOperationProgressFromView(this);
+        bg.RunWorkerAsync();
+      }
+    }
+
+    private void optimizeUtilizationsButton_Click(object sender, EventArgs e) {
+      using (BackgroundWorker bg = new BackgroundWorker()) {
+        MainFormManager.GetMainForm<MainForm.WindowsForms.MainForm>().AddOperationProgressToView(this, "Optimizing Utilizations...");
+        bg.DoWork += (o, a) => OptimizeUtilizations();
+        bg.RunWorkerCompleted += (o, a) => MainFormManager.GetMainForm<MainForm.WindowsForms.MainForm>().RemoveOperationProgressFromView(this);
+        bg.RunWorkerAsync();
+      }
+    }
+    #endregion
+
+    #region mouse events
+    // TODO: it should be possible to allow panning and drawing arrows at the same time by implementing a CustomTool
+    private void mapBox_MouseMove(Coordinate worldPos, MouseEventArgs imagePos) {
+      var nuts_id = GetRegionAtWorldPos(worldPos);
+      var nuts_name = GetRegionDescription(nuts_id);
+      regionNameLabel.Text = nuts_id;
+      regionDescriptionLabel.Text = nuts_name;
+      mapBox.Cursor = String.IsNullOrEmpty(nuts_id) ? Cursors.Default : Cursors.Hand;
+      var arrow = GetArrowAtWorldPos(worldPos);
+      UpdateTransportInfo(arrow);
+    }
+
+    private Point startPos = new Point(0, 0);
+    private Coordinate startWorldPos;
+    private void mapBox_MouseDown(Coordinate worldPos, MouseEventArgs mouseEventArgs) {
+      if (mouseEventArgs.Button == MouseButtons.Left) {
+        startPos = mouseEventArgs.Location;
+        startWorldPos = worldPos;
+      }
+    }
+
+    private void mapBox_MouseUp(Coordinate endWorldPos, MouseEventArgs mousePos) {
+      if (mousePos.Button == MouseButtons.Left) {
+        var arrow = GetArrowAtWorldPos(startWorldPos);
+
+        var startRegion = GetRegionAtWorldPos(startWorldPos);
+        var endRegion = GetRegionAtWorldPos(endWorldPos);
+
+        DispatchMouseUp(startRegion, endRegion, arrow, mousePos.Location);
+      }
+    }
+
+    // custom drawing method for vector list box (for coloring of layers)
+    private void vectorLayerNamesListBox_DrawItem(object sender, DrawItemEventArgs e) {
+      var item = transportLayersListBox.Items[e.Index];
+      var listBoxItem = item as ListBoxItem<int[]>;
+      var backColor = listBoxItem.Color;
+      var foreColor = Color.White;
+
+      using (var backBrush = new SolidBrush(backColor)) {
+        e.Graphics.FillRectangle(backBrush, e.Bounds);
+      }
+      using (var foreBrush = new SolidBrush(foreColor)) {
+        e.Graphics.DrawString(
+          listBoxItem.Text,
+          transportLayersListBox.Font, foreBrush, e.Bounds);
+      }
+    }
+    #endregion
+
+    #region drag-and-drop of problem data
+
+    private bool dropAllowed = false;
+    protected override void OnDragDrop(DragEventArgs e) {
+      if (e.Effect != DragDropEffects.None) {
+        var problemData = (BioBoostProblemData)e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
+        Content.ProblemDataReference = (BioBoostProblemData)problemData.Clone();
+      }
+    }
+
+    protected override void OnDragEnter(DragEventArgs e) {
+      var problemData = (BioBoostProblemData)e.Data.GetData(HeuristicLab.Common.Constants.DragDropDataFormat);
+      dropAllowed = !ReadOnly && !Locked && problemData != null;
+    }
+
+    protected override void OnDragOver(DragEventArgs e) {
+      e.Effect = dropAllowed ?
+        DragDropEffects.Copy :
+        DragDropEffects.None;
+    }
+
+    #endregion
+
+
+    #region Auxiliar Methods
+    private Task<double> ShowTrackBar(Point location, double value) {
+
+      var wh = new AutoResetEvent(false);
+      var tb = new TrackBar {
+        TickStyle = TickStyle.None,
+        Minimum = 0,
+        Maximum = 100,
+        Value = (int)Math.Round(value * 100),
+        Location = location
+      };
+      var label = new Label();
+      label.Location = new Point(location.X, location.Y - label.Height);
+      label.Text = string.Format("Utilization: {0:F2}", value);
+      label.Width = tb.Width;
+
+      mapBox.Controls.Add(tb);
+      mapBox.Controls.Add(label);
+
+      tb.Focus();
+      tb.ValueChanged += (sender, args) => {
+        value = tb.Value / 100.0;
+        label.Text = string.Format("Utilization: {0:F2}", value);
+      };
+      tb.LostFocus += (sender, args) => {
+        mapBox.Controls.Remove(tb);
+        mapBox.Controls.Remove(label);
+        wh.Set();
+      };
+
+
+      return Task.Run(() => {
+        wh.WaitOne();
+        wh.Dispose();
+        return value;
+      });
+    }
+
+    // returns the NUTS_ID of the region if it has been hit
+    private string GetRegionAtWorldPos(Coordinate loc) {
+      var ds = new FeatureDataSet();
+      var layer = mapBox.Map.Layers.OfType<VectorLayer>().SingleOrDefault(l => l.LayerName == "Utilizations");
+      if (layer == null) return string.Empty;
+
+      layer.ExecuteIntersectionQuery(new NetTopologySuite.Geometries.Point(loc), ds);
+      return (from FeatureDataRow row in ds.Tables[0]
+              select row["NUTS_ID"] as string).FirstOrDefault() ?? string.Empty; // default is string.Empty
+    }
+
+    // returns the source and target NUTS_ID (Tuple(src, trgt)) for an vector if it has been hit
+    private Tuple<string, string> GetArrowAtWorldPos(Coordinate loc) {
+      var ds = new FeatureDataSet();
+      var layer = mapBox.Map.Layers.OfType<VectorLayer>().SingleOrDefault(l => l.LayerName == "Transports");
+      if (layer == null) return null;
+
+      var rect = new Coordinate[5];
+      var delta = mapBox.Map.PixelWidth * 2; // for bounding box arount the click point
+      rect[0] = new Coordinate(loc.X - delta, loc.Y - delta);
+      rect[1] = new Coordinate(loc.X + delta, loc.Y - delta);
+      rect[3] = new Coordinate(loc.X + delta, loc.Y + delta);
+      rect[2] = new Coordinate(loc.X - delta, loc.Y + delta);
+      rect[4] = new Coordinate(loc.X - delta, loc.Y - delta);
+      layer.ExecuteIntersectionQuery(new NetTopologySuite.Geometries.Polygon(new LinearRing(rect)), ds);
+
+      var arrow = (from FeatureDataRow row in ds.Tables[0]
+                   select Tuple.Create((string)row["NUTS_ID_SRC"], (string)row["NUTS_ID_DEST"])
+        ).FirstOrDefault();
+      return arrow;
+    }
+
+
+    private string GetRegionDescription(string regionName) {
+      if (regionName != null && Content.Geometry.Features.Columns.Contains("name")) {
+        var row = Content.Geometry.Features.Rows.Cast<FeatureDataRow>().FirstOrDefault(r => (string)r["NUTS_ID"] == regionName);
+        if (row != null)
+          return row["name"].ToString();
+      }
+      return string.Empty;
+    }
+
+
+    private void ResetZoom() {
+      if (mapBox.Map.Layers.Count > 0)
+        mapBox.Map.ZoomToExtents();
+      // mapBox.ActiveTool = MapBox.Tools.DrawLine;
+      mapBox.Refresh();
+    }
+
+
+    private string GetSelectedLayer(ListBox listBox) {
+      return
+      listBox.SelectedItem == null ?
+        string.Empty
+        : listBox.SelectedItem.ToString();
+    }
+
+
+    private bool TrySetSelectedLayer(ListBox listBox, string text) {
+      bool success = false;
+      if (string.IsNullOrEmpty(text)) {
+        listBox.SelectedIndex = 0;
+      } else {
+        int selectedIndex = 0;
+        for (int i = 0; i < listBox.Items.Count; i++) {
+          if (listBox.Items[i].ToString() == text) {
+            selectedIndex = i;
+            success = true;
+            break;
+          }
+        }
+        listBox.SelectedIndex = selectedIndex;
+      }
+      return success;
+    }
+    #endregion
+
+    // only necessary for drawing of vector layer elements with color
+    private class ListBoxItem<T> {
+      public Color Color { get; set; }
+      public string Text { get; set; }
+      public T Value { get; set; }
+
+      public override string ToString() {
+        return Text;
+      }
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostCompoundSolutionEditor.resx
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostCompoundSolutionEditor.resx	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostCompoundSolutionEditor.resx	(revision 15711)
@@ -0,0 +1,129 @@
+﻿<?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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <metadata name="vectorLayersLabel.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>False</value>
+  </metadata>
+  <metadata name="valueLayersLabel.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>False</value>
+  </metadata>
+  <metadata name="statusStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 17</value>
+  </metadata>
+</root>
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostCompoundSolutionView.Designer.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostCompoundSolutionView.Designer.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostCompoundSolutionView.Designer.cs	(revision 15711)
@@ -0,0 +1,459 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.BioBoost.Views {
+  partial class BioBoostCompoundSolutionView {
+    /// <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)) {
+        runningUpdateMap = false;
+        runningUpdateCosts = false;
+        updateMap.Set();
+        updateCosts.Set();
+        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() {
+      System.Windows.Forms.Label valueLayersLabel;
+      System.Windows.Forms.Label vectorLayersLabel;
+      System.Windows.Forms.TreeNode treeNode1 = new System.Windows.Forms.TreeNode("AT111");
+      System.Windows.Forms.TreeNode treeNode2 = new System.Windows.Forms.TreeNode("AT112");
+      System.Windows.Forms.TreeNode treeNode3 = new System.Windows.Forms.TreeNode("AT", new System.Windows.Forms.TreeNode[] {
+            treeNode1,
+            treeNode2});
+      System.Windows.Forms.TreeNode treeNode4 = new System.Windows.Forms.TreeNode("BE112");
+      System.Windows.Forms.TreeNode treeNode5 = new System.Windows.Forms.TreeNode("BE", new System.Windows.Forms.TreeNode[] {
+            treeNode4});
+      System.Windows.Forms.TreeNode treeNode6 = new System.Windows.Forms.TreeNode("All Regions", new System.Windows.Forms.TreeNode[] {
+            treeNode3,
+            treeNode5});
+      this.mapBox = new SharpMap.Forms.MapBox();
+      this.tabControl1 = new System.Windows.Forms.TabControl();
+      this.tabPage1 = new System.Windows.Forms.TabPage();
+      this.splitContainer1 = new System.Windows.Forms.SplitContainer();
+      this.valueLayerValueLabel = new System.Windows.Forms.Label();
+      this.valueLayerNamesListBox = new System.Windows.Forms.ListBox();
+      this.vectorLayerNamesListBox = new System.Windows.Forms.ListBox();
+      this.regionDescriptionLabel = new System.Windows.Forms.Label();
+      this.regionNameLabel = new System.Windows.Forms.Label();
+      this.splitContainer2 = new System.Windows.Forms.SplitContainer();
+      this.regionDetailView = new HeuristicLab.BioBoost.Views.BioBoostRegionDetailView();
+      this.saveMapImageButton = new System.Windows.Forms.Button();
+      this.tabPage2 = new System.Windows.Forms.TabPage();
+      this.bioBoostSolutionCostsView1 = new HeuristicLab.BioBoost.Views.BioBoostSolutionCostsView();
+      this.regionsTreeView = new System.Windows.Forms.TreeView();
+      this.tabPage3 = new System.Windows.Forms.TabPage();
+      this.openSolutionEditorButton = new System.Windows.Forms.Button();
+      this.saveFileDialog = new System.Windows.Forms.SaveFileDialog();
+      this.tabPage4 = new System.Windows.Forms.TabPage();
+      this.summaryView = new HeuristicLab.BioBoost.Views.BioBoostSummaryView();
+      valueLayersLabel = new System.Windows.Forms.Label();
+      vectorLayersLabel = new System.Windows.Forms.Label();
+      this.tabControl1.SuspendLayout();
+      this.tabPage1.SuspendLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
+      this.splitContainer1.Panel1.SuspendLayout();
+      this.splitContainer1.Panel2.SuspendLayout();
+      this.splitContainer1.SuspendLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).BeginInit();
+      this.splitContainer2.Panel1.SuspendLayout();
+      this.splitContainer2.Panel2.SuspendLayout();
+      this.splitContainer2.SuspendLayout();
+      this.tabPage2.SuspendLayout();
+      this.tabPage3.SuspendLayout();
+      this.tabPage4.SuspendLayout();
+      this.SuspendLayout();
+      // 
+      // valueLayersLabel
+      // 
+      valueLayersLabel.AutoSize = true;
+      valueLayersLabel.Location = new System.Drawing.Point(2, 145);
+      valueLayersLabel.Name = "valueLayersLabel";
+      valueLayersLabel.Size = new System.Drawing.Size(68, 13);
+      valueLayersLabel.TabIndex = 27;
+      valueLayersLabel.Text = "Value Layers";
+      // 
+      // vectorLayersLabel
+      // 
+      vectorLayersLabel.AutoSize = true;
+      vectorLayersLabel.Location = new System.Drawing.Point(6, 5);
+      vectorLayersLabel.Name = "vectorLayersLabel";
+      vectorLayersLabel.Size = new System.Drawing.Size(72, 13);
+      vectorLayersLabel.TabIndex = 26;
+      vectorLayersLabel.Text = "Vector Layers";
+      // 
+      // mapBox
+      // 
+      this.mapBox.ActiveTool = SharpMap.Forms.MapBox.Tools.Pan;
+      this.mapBox.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.mapBox.Cursor = System.Windows.Forms.Cursors.Hand;
+      this.mapBox.FineZoomFactor = 10D;
+      this.mapBox.Location = new System.Drawing.Point(3, 0);
+      this.mapBox.MapQueryMode = SharpMap.Forms.MapBox.MapQueryType.VisibleLayers;
+      this.mapBox.Name = "mapBox";
+      this.mapBox.PanOnClick = false;
+      this.mapBox.PreviewMode = SharpMap.Forms.MapBox.PreviewModes.Fast;
+      this.mapBox.QueryGrowFactor = 5F;
+      this.mapBox.QueryLayerIndex = 0;
+      this.mapBox.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(210)))), ((int)(((byte)(244)))), ((int)(((byte)(244)))), ((int)(((byte)(244)))));
+      this.mapBox.SelectionForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(244)))), ((int)(((byte)(244)))), ((int)(((byte)(244)))));
+      this.mapBox.ShowProgressUpdate = true;
+      this.mapBox.Size = new System.Drawing.Size(561, 635);
+      this.mapBox.TabIndex = 0;
+      this.mapBox.TakeFocusOnHover = true;
+      this.mapBox.Text = "mapBox";
+      this.mapBox.WheelZoomMagnitude = -2D;
+      this.mapBox.MouseMove += new SharpMap.Forms.MapBox.MouseEventHandler(this.mapBox_MouseMove);
+      this.mapBox.MouseDown += new SharpMap.Forms.MapBox.MouseEventHandler(this.mapBox_MouseDown);
+      this.mapBox.MouseUp += new SharpMap.Forms.MapBox.MouseEventHandler(this.mapBox_MouseUp);
+      // 
+      // tabControl1
+      // 
+      this.tabControl1.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.tabControl1.Controls.Add(this.tabPage1);
+      this.tabControl1.Controls.Add(this.tabPage2);
+      this.tabControl1.Controls.Add(this.tabPage3);
+      this.tabControl1.Controls.Add(this.tabPage4);
+      this.tabControl1.Location = new System.Drawing.Point(0, 0);
+      this.tabControl1.Name = "tabControl1";
+      this.tabControl1.SelectedIndex = 0;
+      this.tabControl1.Size = new System.Drawing.Size(1114, 682);
+      this.tabControl1.TabIndex = 2;
+      this.tabControl1.Selected += new System.Windows.Forms.TabControlEventHandler(this.tabControl1_Selected);
+      // 
+      // tabPage1
+      // 
+      this.tabPage1.Controls.Add(this.splitContainer1);
+      this.tabPage1.Location = new System.Drawing.Point(4, 22);
+      this.tabPage1.Name = "tabPage1";
+      this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
+      this.tabPage1.Size = new System.Drawing.Size(1106, 656);
+      this.tabPage1.TabIndex = 0;
+      this.tabPage1.Text = "Map";
+      this.tabPage1.UseVisualStyleBackColor = true;
+      // 
+      // splitContainer1
+      // 
+      this.splitContainer1.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.splitContainer1.Location = new System.Drawing.Point(6, 6);
+      this.splitContainer1.Name = "splitContainer1";
+      // 
+      // splitContainer1.Panel1
+      // 
+      this.splitContainer1.Panel1.Controls.Add(this.valueLayerValueLabel);
+      this.splitContainer1.Panel1.Controls.Add(this.valueLayerNamesListBox);
+      this.splitContainer1.Panel1.Controls.Add(this.vectorLayerNamesListBox);
+      this.splitContainer1.Panel1.Controls.Add(this.regionDescriptionLabel);
+      this.splitContainer1.Panel1.Controls.Add(this.regionNameLabel);
+      this.splitContainer1.Panel1.Controls.Add(valueLayersLabel);
+      this.splitContainer1.Panel1.Controls.Add(vectorLayersLabel);
+      // 
+      // splitContainer1.Panel2
+      // 
+      this.splitContainer1.Panel2.Controls.Add(this.splitContainer2);
+      this.splitContainer1.Size = new System.Drawing.Size(1094, 644);
+      this.splitContainer1.SplitterDistance = 214;
+      this.splitContainer1.TabIndex = 14;
+      // 
+      // valueLayerValueLabel
+      // 
+      this.valueLayerValueLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.valueLayerValueLabel.Location = new System.Drawing.Point(3, 620);
+      this.valueLayerValueLabel.Margin = new System.Windows.Forms.Padding(3);
+      this.valueLayerValueLabel.MaximumSize = new System.Drawing.Size(500, 13);
+      this.valueLayerValueLabel.Name = "valueLayerValueLabel";
+      this.valueLayerValueLabel.Size = new System.Drawing.Size(207, 13);
+      this.valueLayerValueLabel.TabIndex = 28;
+      this.valueLayerValueLabel.Text = "0 €/a";
+      this.valueLayerValueLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+      // 
+      // valueLayerNamesListBox
+      // 
+      this.valueLayerNamesListBox.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.valueLayerNamesListBox.FormattingEnabled = true;
+      this.valueLayerNamesListBox.HorizontalScrollbar = true;
+      this.valueLayerNamesListBox.Items.AddRange(new object[] {
+            "StrawPotentials",
+            "StrawUtilizations",
+            "StrawConverterCapacities"});
+      this.valueLayerNamesListBox.Location = new System.Drawing.Point(3, 161);
+      this.valueLayerNamesListBox.Name = "valueLayerNamesListBox";
+      this.valueLayerNamesListBox.Size = new System.Drawing.Size(208, 420);
+      this.valueLayerNamesListBox.TabIndex = 22;
+      this.valueLayerNamesListBox.SelectedIndexChanged += new System.EventHandler(this.valueLayerNamesListBox_SelectedIndexChanged);
+      // 
+      // vectorLayerNamesListBox
+      // 
+      this.vectorLayerNamesListBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.vectorLayerNamesListBox.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed;
+      this.vectorLayerNamesListBox.FormattingEnabled = true;
+      this.vectorLayerNamesListBox.HorizontalScrollbar = true;
+      this.vectorLayerNamesListBox.Location = new System.Drawing.Point(3, 21);
+      this.vectorLayerNamesListBox.Name = "vectorLayerNamesListBox";
+      this.vectorLayerNamesListBox.SelectionMode = System.Windows.Forms.SelectionMode.MultiSimple;
+      this.vectorLayerNamesListBox.Size = new System.Drawing.Size(208, 121);
+      this.vectorLayerNamesListBox.TabIndex = 23;
+      this.vectorLayerNamesListBox.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.vectorLayerNamesListBox_DrawItem);
+      this.vectorLayerNamesListBox.SelectedIndexChanged += new System.EventHandler(this.vectorLayerNamesListBox_SelectedIndexChanged);
+      // 
+      // regionDescriptionLabel
+      // 
+      this.regionDescriptionLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.regionDescriptionLabel.Location = new System.Drawing.Point(3, 601);
+      this.regionDescriptionLabel.Margin = new System.Windows.Forms.Padding(3);
+      this.regionDescriptionLabel.MaximumSize = new System.Drawing.Size(500, 13);
+      this.regionDescriptionLabel.Name = "regionDescriptionLabel";
+      this.regionDescriptionLabel.Size = new System.Drawing.Size(207, 13);
+      this.regionDescriptionLabel.TabIndex = 24;
+      this.regionDescriptionLabel.Text = "Vienna";
+      this.regionDescriptionLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+      // 
+      // regionNameLabel
+      // 
+      this.regionNameLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.regionNameLabel.Location = new System.Drawing.Point(3, 585);
+      this.regionNameLabel.MaximumSize = new System.Drawing.Size(500, 13);
+      this.regionNameLabel.Name = "regionNameLabel";
+      this.regionNameLabel.Size = new System.Drawing.Size(207, 13);
+      this.regionNameLabel.TabIndex = 25;
+      this.regionNameLabel.Text = "AT111";
+      this.regionNameLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+      // 
+      // splitContainer2
+      // 
+      this.splitContainer2.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.splitContainer2.Location = new System.Drawing.Point(3, 3);
+      this.splitContainer2.Name = "splitContainer2";
+      // 
+      // splitContainer2.Panel1
+      // 
+      this.splitContainer2.Panel1.Controls.Add(this.mapBox);
+      // 
+      // splitContainer2.Panel2
+      // 
+      this.splitContainer2.Panel2.Controls.Add(this.regionDetailView);
+      this.splitContainer2.Panel2.Controls.Add(this.saveMapImageButton);
+      this.splitContainer2.Size = new System.Drawing.Size(870, 638);
+      this.splitContainer2.SplitterDistance = 567;
+      this.splitContainer2.TabIndex = 14;
+      // 
+      // regionDetailView
+      // 
+      this.regionDetailView.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.regionDetailView.Caption = "View";
+      this.regionDetailView.Content = null;
+      this.regionDetailView.Location = new System.Drawing.Point(3, 7);
+      this.regionDetailView.Name = "regionDetailView";
+      this.regionDetailView.ReadOnly = false;
+      this.regionDetailView.Size = new System.Drawing.Size(293, 599);
+      this.regionDetailView.TabIndex = 13;
+      this.regionDetailView.RegionLabelClicked += new System.EventHandler(this.solutionDetailView_RegionLabelClicked);
+      // 
+      // saveMapImageButton
+      // 
+      this.saveMapImageButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+      this.saveMapImageButton.Location = new System.Drawing.Point(129, 612);
+      this.saveMapImageButton.Name = "saveMapImageButton";
+      this.saveMapImageButton.Size = new System.Drawing.Size(167, 23);
+      this.saveMapImageButton.TabIndex = 12;
+      this.saveMapImageButton.Text = "Save Map Image ...";
+      this.saveMapImageButton.UseVisualStyleBackColor = true;
+      this.saveMapImageButton.Click += new System.EventHandler(this.saveMapImageButton_Click);
+      // 
+      // tabPage2
+      // 
+      this.tabPage2.Controls.Add(this.bioBoostSolutionCostsView1);
+      this.tabPage2.Controls.Add(this.regionsTreeView);
+      this.tabPage2.Location = new System.Drawing.Point(4, 22);
+      this.tabPage2.Name = "tabPage2";
+      this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
+      this.tabPage2.Size = new System.Drawing.Size(1106, 656);
+      this.tabPage2.TabIndex = 1;
+      this.tabPage2.Text = "Costs";
+      this.tabPage2.UseVisualStyleBackColor = true;
+      // 
+      // bioBoostSolutionCostsView1
+      // 
+      this.bioBoostSolutionCostsView1.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.bioBoostSolutionCostsView1.Caption = "View";
+      this.bioBoostSolutionCostsView1.Content = null;
+      this.bioBoostSolutionCostsView1.Location = new System.Drawing.Point(174, 6);
+      this.bioBoostSolutionCostsView1.Name = "bioBoostSolutionCostsView1";
+      this.bioBoostSolutionCostsView1.ReadOnly = false;
+      this.bioBoostSolutionCostsView1.Size = new System.Drawing.Size(926, 644);
+      this.bioBoostSolutionCostsView1.TabIndex = 0;
+      // 
+      // regionsTreeView
+      // 
+      this.regionsTreeView.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+            | System.Windows.Forms.AnchorStyles.Left)));
+      this.regionsTreeView.Location = new System.Drawing.Point(3, 6);
+      this.regionsTreeView.Name = "regionsTreeView";
+      treeNode1.Name = "AT111";
+      treeNode1.Text = "AT111";
+      treeNode2.Name = "AT112";
+      treeNode2.Text = "AT112";
+      treeNode3.Name = "AT";
+      treeNode3.Text = "AT";
+      treeNode4.Name = "BE112";
+      treeNode4.Text = "BE112";
+      treeNode5.Name = "BE";
+      treeNode5.Text = "BE";
+      treeNode6.Name = "All Regions";
+      treeNode6.Text = "All Regions";
+      this.regionsTreeView.Nodes.AddRange(new System.Windows.Forms.TreeNode[] {
+            treeNode6});
+      this.regionsTreeView.Size = new System.Drawing.Size(165, 647);
+      this.regionsTreeView.TabIndex = 0;
+      this.regionsTreeView.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.regionsTreeView_AfterSelect);
+      // 
+      // tabPage3
+      // 
+      this.tabPage3.Controls.Add(this.openSolutionEditorButton);
+      this.tabPage3.Location = new System.Drawing.Point(4, 22);
+      this.tabPage3.Name = "tabPage3";
+      this.tabPage3.Padding = new System.Windows.Forms.Padding(3);
+      this.tabPage3.Size = new System.Drawing.Size(1106, 656);
+      this.tabPage3.TabIndex = 2;
+      this.tabPage3.Text = "Edit / Optimize Solution";
+      this.tabPage3.UseVisualStyleBackColor = true;
+      // 
+      // openSolutionEditorButton
+      // 
+      this.openSolutionEditorButton.Location = new System.Drawing.Point(6, 6);
+      this.openSolutionEditorButton.Name = "openSolutionEditorButton";
+      this.openSolutionEditorButton.Size = new System.Drawing.Size(113, 23);
+      this.openSolutionEditorButton.TabIndex = 0;
+      this.openSolutionEditorButton.Text = "Open Editor View";
+      this.openSolutionEditorButton.UseVisualStyleBackColor = true;
+      this.openSolutionEditorButton.Click += new System.EventHandler(this.openSolutionEditorButton_Click);
+      // 
+      // saveFileDialog
+      // 
+      this.saveFileDialog.DefaultExt = "png";
+      this.saveFileDialog.Filter = "PNG files|*.png|All files|*.*";
+      this.saveFileDialog.RestoreDirectory = true;
+      // 
+      // tabPage4
+      // 
+      this.tabPage4.Controls.Add(this.summaryView);
+      this.tabPage4.Location = new System.Drawing.Point(4, 22);
+      this.tabPage4.Name = "tabPage4";
+      this.tabPage4.Size = new System.Drawing.Size(1106, 656);
+      this.tabPage4.TabIndex = 3;
+      this.tabPage4.Text = "Summary";
+      this.tabPage4.UseVisualStyleBackColor = true;
+      // 
+      // summaryView
+      // 
+      this.summaryView.Caption = "View";
+      this.summaryView.Content = null;
+      this.summaryView.Dock = System.Windows.Forms.DockStyle.Fill;
+      this.summaryView.Location = new System.Drawing.Point(0, 0);
+      this.summaryView.Name = "summaryView";
+      this.summaryView.ReadOnly = false;
+      this.summaryView.Size = new System.Drawing.Size(1106, 656);
+      this.summaryView.TabIndex = 0;
+      // 
+      // BioBoostCompoundSolutionView
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Controls.Add(this.tabControl1);
+      this.Name = "BioBoostCompoundSolutionView";
+      this.Size = new System.Drawing.Size(1114, 682);
+      this.tabControl1.ResumeLayout(false);
+      this.tabPage1.ResumeLayout(false);
+      this.splitContainer1.Panel1.ResumeLayout(false);
+      this.splitContainer1.Panel1.PerformLayout();
+      this.splitContainer1.Panel2.ResumeLayout(false);
+      ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
+      this.splitContainer1.ResumeLayout(false);
+      this.splitContainer2.Panel1.ResumeLayout(false);
+      this.splitContainer2.Panel2.ResumeLayout(false);
+      ((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).EndInit();
+      this.splitContainer2.ResumeLayout(false);
+      this.tabPage2.ResumeLayout(false);
+      this.tabPage3.ResumeLayout(false);
+      this.tabPage4.ResumeLayout(false);
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+    private SharpMap.Forms.MapBox mapBox;
+    private System.Windows.Forms.TabControl tabControl1;
+    private System.Windows.Forms.TabPage tabPage1;
+    private System.Windows.Forms.TabPage tabPage2;
+    private System.Windows.Forms.TreeView regionsTreeView;
+    private BioBoostSolutionCostsView bioBoostSolutionCostsView1;
+    private System.Windows.Forms.TabPage tabPage3;
+    private System.Windows.Forms.Button openSolutionEditorButton;
+    private System.Windows.Forms.Button saveMapImageButton;
+    private System.Windows.Forms.SaveFileDialog saveFileDialog;
+    private BioBoostRegionDetailView regionDetailView;
+    private System.Windows.Forms.SplitContainer splitContainer1;
+    private System.Windows.Forms.Label valueLayerValueLabel;
+    private System.Windows.Forms.ListBox valueLayerNamesListBox;
+    private System.Windows.Forms.ListBox vectorLayerNamesListBox;
+    private System.Windows.Forms.Label regionDescriptionLabel;
+    private System.Windows.Forms.Label regionNameLabel;
+    private System.Windows.Forms.SplitContainer splitContainer2;
+    private System.Windows.Forms.TabPage tabPage4;
+    private BioBoostSummaryView summaryView;
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostCompoundSolutionView.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostCompoundSolutionView.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostCompoundSolutionView.cs	(revision 15711)
@@ -0,0 +1,657 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Globalization;
+using GeoAPI.Geometries;
+using HeuristicLab.BioBoost.Representation;
+using HeuristicLab.BioBoost.Utils;
+using HeuristicLab.BioBoost.Views.MapViews;
+using HeuristicLab.Common;
+using HeuristicLab.Core.Views;
+using HeuristicLab.MainForm;
+using HeuristicLab.MainForm.WindowsForms;
+using SharpMap.Data;
+using SharpMap.Forms;
+using SharpMap.Layers;
+using SharpMap.Rendering.Decoration;
+using SharpMap.Rendering.Decoration.ScaleBar;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Linq;
+using System.Threading;
+using System.Windows.Forms;
+using HeuristicLab.BioBoost.Evaluators;
+using HeuristicLab.PluginInfrastructure;
+using Point = System.Drawing.Point;
+
+namespace HeuristicLab.BioBoost.Views {
+
+  [Content(typeof(BioBoostCompoundSolution), IsDefaultView = true)]
+  public partial class BioBoostCompoundSolutionView : ItemView {
+
+    private readonly Dictionary<String, ILazyLayerGenerator> layerCache;
+    private readonly GradientLegend legend;
+    private readonly Disclaimer disclaimer;
+    private Thread mapUpdateThread;
+    private Thread costsUpdateThread;
+    private ManualResetEventSlim updateMap;
+    private ManualResetEventSlim updateCosts;
+
+    private SharpMap.Rendering.Thematics.ColorBlend vectorColorBlend =
+      new SharpMap.Rendering.Thematics.ColorBlend(new[] {
+        Color.FromArgb(0, 0, 255),
+        Color.FromArgb(128, 0, 128),
+        Color.FromArgb(255, 0, 0),
+      }, new[] { 0f, .5f, 1f });
+    private string currentRegion;
+    public const string AllRegionsName = "All";
+
+    public new BioBoostCompoundSolution Content {
+      get { return (BioBoostCompoundSolution)base.Content; }
+      set { base.Content = value; }
+    }
+
+    public BioBoostCompoundSolutionView() {
+      InitializeComponent();
+      layerCache = new Dictionary<string, ILazyLayerGenerator>();
+      mapBox.Map.Decorations.Add(new ScaleBar {
+        Anchor = MapDecorationAnchor.RightBottom,
+        BarColor1 = Color.White,
+        BarColor2 = Color.Black,
+        BarStyle = ScaleBarStyle.Meridian,
+        MapUnit = (int)Unit.Degree,
+        BarUnit = (int)Unit.Kilometer,
+      });
+      disclaimer = new Disclaimer {
+        Anchor = MapDecorationAnchor.RightTop,
+        Text = "ForestryResidues Utilization",
+        Enabled = true,
+        BackgroundColor = Color.FromArgb(128, 255, 255, 255),
+        ForeColor = Color.Black,
+        BorderColor = Color.Transparent,
+        Font = new Font(FontFamily.GenericSansSerif, 10, FontStyle.Regular)
+      };
+      legend = new GradientLegend {Size = new Size(300, 20)};
+      mapBox.Map.Decorations.Add(legend);
+      mapBox.Map.Decorations.Add(new NorthArrow());
+      mapBox.Map.Decorations.Add(disclaimer);
+        
+      updateMap = new ManualResetEventSlim(true);
+      mapUpdateThread = new Thread(UpdateMap);
+      mapUpdateThread.Start();
+      updateCosts = new ManualResetEventSlim(true);
+      costsUpdateThread = new Thread(UpdateCosts);
+      costsUpdateThread.Start();
+      currentRegion = AllRegionsName;
+    }
+
+
+    protected override void DeregisterContentEvents() {
+      Content.SolutionChanged -= SolutionChanged;
+      base.DeregisterContentEvents();
+    }
+
+    protected override void RegisterContentEvents() {
+      base.RegisterContentEvents();
+      Content.SolutionChanged += SolutionChanged;
+    }
+
+    #region Event Handlers (Content)
+
+    private void SolutionChanged(object sender, EventArgs e) {
+      if (InvokeRequired) {
+        Invoke(new EventHandler<EventArgs>(SolutionChanged), sender, e);
+      } else {
+        UpgradeSolution();
+        InitializeLayers();
+        DiscoverLayerNames();
+        summaryView.Content = new RegionDetailData {RegionName = null, Solution = Content};
+        ShowSelectedLayers(false);
+        ShowCosts();
+      }
+    }
+    #endregion
+
+    protected override void OnContentChanged() {
+      base.OnContentChanged();
+      if (Content == null) {
+        ClearAllLayerNames();
+        ClearCostsSummary();
+      } else {
+        UpgradeSolution();
+        InitializeLayers();
+        DiscoverLayerNames();
+        summaryView.Content = new RegionDetailData {RegionName = null, Solution = Content};
+        ShowSelectedLayers(true);
+        ShowCosts();
+      }
+    }
+
+    private bool upgradeInProgress = false;
+    private void UpgradeSolution() {
+      if (Content != null && !upgradeInProgress) {
+        upgradeInProgress = true;
+        Content.UpdateTo(new BioBoostCompoundSolution(
+          AggregateEvaluator.Evaluate(Content.ProblemDataReference, Content.DoubleValues, Content.IntValues),
+          Content.ProblemDataReference));
+        upgradeInProgress = false;
+      }
+    }
+
+    #region Main Logic
+    private void ResetZoom() {
+      if (mapBox.Map.Layers.Count > 0)
+        mapBox.Map.ZoomToExtents();
+      mapBox.ActiveTool = MapBox.Tools.Pan;
+      mapBox.Refresh();
+    }
+
+    private void DiscoverLayerNames() {
+      DiscoverValueLayers();
+      DiscoverVectorLayers();
+    }
+
+    private class ListBoxItem {
+      public Color Color;
+      public String Text;
+    }
+
+    private void DiscoverVectorLayers() {
+      var layerNames = vectorLayerNamesListBox.Items.Cast<ListBoxItem>().Select(l => l.Text).ToList();
+      if (layerNames.SequenceEqual(Content.IntValues.Keys)) return;
+      vectorLayerNamesListBox.BeginUpdate();
+      vectorLayerNamesListBox.Items.Clear();
+      int i = 0, n = Math.Max(1, Content.IntValues.Count - 1);
+      foreach (var values in Content.IntValues) {
+        var newItem = new ListBoxItem {
+          Color = vectorColorBlend.GetColor(1f * i++ / n),
+          Text = values.Key
+        };
+        vectorLayerNamesListBox.Items.Add(newItem);
+        if (layerNames.Any(name => name == values.Key) || layerNames.Count == 0)
+          vectorLayerNamesListBox.SelectedItems.Add(newItem);
+      }
+      vectorLayerNamesListBox.EndUpdate();
+    }
+
+    private void DiscoverValueLayers() {
+      var layerNames = AddRelativePotentials(Content.DoubleValues.Keys).ToList();
+      layerNames.Sort();
+      if (valueLayerNamesListBox.Items.Cast<string>().SequenceEqual(layerNames))
+        return;
+      valueLayerNamesListBox.BeginUpdate();
+      var selectedValueLayerName = (string)valueLayerNamesListBox.SelectedItem;
+      var firstFinalProduct = Content.ProblemDataReference.FinalProducts.FirstOrDefault();
+      if (selectedValueLayerName == null && firstFinalProduct != null)
+        selectedValueLayerName = LayerDescriptor.RelativeCostAtSource.NameWithPrefix(firstFinalProduct.Value);
+      valueLayerNamesListBox.Items.Clear();
+      foreach (var name in layerNames) {
+        var i = valueLayerNamesListBox.Items.Add(name);
+        if (name == selectedValueLayerName)
+          valueLayerNamesListBox.SelectedIndex = i;
+      }
+      if (valueLayerNamesListBox.SelectedIndex == -1)
+        valueLayerNamesListBox.SelectedIndex = 0;
+      valueLayerNamesListBox.EndUpdate();
+    }
+
+    private IEnumerable<string> AddRelativePotentials(IEnumerable<string> names) {
+      foreach (var name in names) {
+        if (LayerDescriptor.PotentialsFromProblemData.IsSuffixOf(name)) {
+          var formattedName = name.Replace(LayerDescriptor.PotentialsFromProblemData.FullName, " Potentials");
+          yield return formattedName;
+          yield return formattedName + " Relative";
+        } else {
+          yield return name;
+        }
+      }
+    }
+
+    private void ClearAllLayerNames() {
+      valueLayerNamesListBox.Items.Clear();
+      vectorLayerNamesListBox.Items.Clear();
+    }
+
+    private void ShowSelectedLayers(bool resetZoom) {
+      lock (updateMap) {
+        if (pendingUpdate != null) {
+          pendingUpdate.ResetZoom |= resetZoom;
+        } else {
+          pendingUpdate = new BackgroundArguments { ResetZoom = resetZoom };
+        }
+        updateMap.Set();
+      }
+    }
+
+    private void ShowCosts() {
+      updateCosts.Set();
+    }
+
+    private sealed class BackgroundArguments {
+      public bool ResetZoom;
+      public LazyValueLayerGenerator ValueLayerGenerator;
+      public List<LazyVectorLayerGenerator> VectorLayerGenerators;
+      public ILayer ValueLayer;
+      public List<ILayer> TransportLayers;
+    }
+
+    private BackgroundArguments pendingUpdate;
+    private bool runningUpdateMap = true;
+    private bool runningUpdateCosts = true;
+
+    private void UpdateMap() {
+      while (runningUpdateMap) {
+        BackgroundArguments currentUpdate = null;
+        // wait for a signal to update the map
+        while (!updateMap.Wait(2000)) {
+          if (!runningUpdateMap) return; // stop thread if requested
+        }
+        lock (updateMap) {
+          updateMap.Reset();
+          currentUpdate = pendingUpdate;
+          pendingUpdate = null;
+        }
+
+        // only do something if the map-tab is active
+        if (currentUpdate != null) {
+          DoShowSelectedLayers(currentUpdate);
+        }
+        Thread.Sleep(500);
+      }
+    }
+
+    private void UpdateCosts() {
+      while (runningUpdateCosts) {
+        // wait for signal to update the costs
+        while (!updateCosts.Wait(2000)) {
+          if (!runningUpdateCosts) return; // stop the thread if requested
+        }
+        updateCosts.Reset();
+
+        ClearCostsSummary();
+        PopulateRegionTree();
+        PopulateCostsSummary();
+
+        Thread.Sleep(500);
+      }
+    }
+
+    private void DoShowSelectedLayers(BackgroundArguments args) {
+      if (InvokeRequired) {
+        try {
+          var result = BeginInvoke(new Action<BackgroundArguments>(DoShowSelectedLayers), args);
+          result.AsyncWaitHandle.WaitOne();
+          EndInvoke(result);
+        } catch (ObjectDisposedException) { }
+      } else {
+        // only do something if the map-tab is active
+        if (tabControl1.SelectedTab != tabPage1) return;
+
+        GetConfigFromUI(args);
+        var generator = args.ValueLayerGenerator;
+        if (generator == null) return;
+        args.ValueLayer = generator.Layer; // this might take a while
+        args.TransportLayers = new List<ILayer>();
+        foreach (var g in args.VectorLayerGenerators) {
+          args.TransportLayers.Add(g.Layer); // TODO: cycle colors of vectors
+        }
+        UpdateUI(args);
+      }
+    }
+
+    private void GetConfigFromUI(BackgroundArguments args) {
+      var valueLayerName = (string)valueLayerNamesListBox.SelectedItem;
+      var vectorLayerNames = vectorLayerNamesListBox.SelectedItems.Cast<ListBoxItem>().Select(i => i.Text);
+      if (String.IsNullOrEmpty(valueLayerName)) return;
+      var generator = layerCache[valueLayerName] as LazyValueLayerGenerator;
+      if (generator == null) return;
+      args.ValueLayerGenerator = generator;
+      args.VectorLayerGenerators =
+        vectorLayerNames.Select(n => layerCache[n] as LazyVectorLayerGenerator).Where(g => g != null).ToList();
+
+    }
+
+    private void UpdateUI(BackgroundArguments args) {
+      if (IsDisposed || Disposing) return;
+      try {
+        var currentZoom = mapBox.Map.Zoom;
+        var currentCenter = mapBox.Map.Center;
+        mapBox.Map.Layers.Clear();
+        mapBox.Map.Layers.Add(args.ValueLayer);
+        foreach (var tl in args.TransportLayers)
+          mapBox.Map.Layers.Add(tl);
+        legend.MinValue = args.ValueLayerGenerator.ActualMinValue;
+        legend.MaxValue = args.ValueLayerGenerator.ActualMaxValue;
+        legend.Unit = args.ValueLayerGenerator.Unit;
+        legend.ColorBlend = new ColorBlend {
+          Colors = args.ValueLayerGenerator.ColorBlend.Colors,
+          Positions = args.ValueLayerGenerator.ColorBlend.Positions,
+        };
+        disclaimer.Text = args.ValueLayer.LayerName;
+        if (args.ResetZoom) {
+          ResetZoom();
+        } else {
+          mapBox.ActiveTool = MapBox.Tools.Pan;
+          mapBox.Map.Zoom = currentZoom;
+          mapBox.Map.Center = currentCenter;
+          mapBox.Refresh();
+        }
+      } catch (Exception x) {
+        MessageBox.Show(this, "Could not update UI, please try again:\n" + x);
+      }
+    }
+
+    private void InitializeLayers() {
+      lock (updateMap) {
+        layerCache.Clear();
+        var geom = Content.Geometry;
+        var locs = Content.LocationNames;
+        foreach (var kvp in Content.DoubleValues) {
+          var generator = new LazyValueLayerGenerator(geom, locs, kvp.Value, kvp.Key);
+          var name = kvp.Key;
+          if (kvp.Value.Min() > 0) generator.MinValue = 0;
+          if (kvp.Value.Max() < 0) generator.MaxValue = 0;
+          var layer = LayerDescriptor.GetLayer(name);
+          if (layer == LayerDescriptor.Utilizations || layer == LayerDescriptor.UtilizationsEffective) {
+            generator.MaxValue = 1;
+          } else if (layer == Representation.LayerDescriptor.PotentialsFromProblemData) {
+            generator.Unit = "t/a";
+            name = name.Replace(LayerDescriptor.PotentialsFromProblemData.FullName, " Potentials");
+            layerCache.Add(name + " Relative", new LazyValueLayerGenerator(geom, locs, kvp.Value, name + " Relative") {
+              MinValue = 0,
+              RealtiveToSize = true,
+              Unit = "t/ha/a"
+            });
+          } else {
+            if (layer != null)
+              generator.Unit = layer.Unit;
+          }
+          layerCache.Add(name, generator);
+        }
+        int i = 0, n = Math.Max(1, Content.IntValues.Count - 1);
+        foreach (var kvp in Content.IntValues) {
+          var name = kvp.Key;
+          var targets = kvp.Value;
+          var amounts = BioBoostCompoundSolution.FindAmountsTransportedFromSource(Content.DoubleValues, name);
+          if (amounts != null) {
+            for (int j = 0; j < amounts.Length; j++) {
+              if (amounts[j] <= 0) {
+                targets[j] = -1;
+              }
+            }
+          }
+          layerCache.Add(
+            name,
+            new LazyVectorLayerGenerator(geom, locs, targets,  amounts, vectorColorBlend.GetColor(1.0f * i / n), name) {
+              LineOffset = i * 2
+            });
+          i++;
+        }
+      }
+    }
+
+    private void ClearCostsSummary() {
+      if (InvokeRequired) {
+        try {
+          var result = BeginInvoke(new Action(ClearCostsSummary));
+          result.AsyncWaitHandle.WaitOne();
+          EndInvoke(result);
+        } catch (ObjectDisposedException) { }
+      } else {
+        if (IsDisposed || Disposing) return;
+        bioBoostSolutionCostsView1.Content = null;
+      }
+    }
+
+    private void PopulateCostsSummary() {
+      if (InvokeRequired) {
+        try {
+          var result = BeginInvoke(new Action(PopulateCostsSummary));
+          result.AsyncWaitHandle.WaitOne();
+          EndInvoke(result);
+        } catch (ObjectDisposedException) { }
+      } else {
+        if (IsDisposed || Disposing) return;
+        // only do something if the costs-tab is active
+        if (tabControl1.SelectedTab != tabPage2) return;
+
+        regionsTreeView.SelectedNode = regionsTreeView.Nodes.Find(currentRegion, true).FirstOrDefault();
+        regionsTreeView.Focus();
+        if (IsDisposed) return;
+        bioBoostSolutionCostsView1.Content = new RegionDetailData {
+          RegionName = currentRegion,
+          Solution = Content,
+        };
+      }
+    }
+
+    private void PopulateRegionTree() {
+      if (InvokeRequired) {
+        try {
+          var result = BeginInvoke(new Action(PopulateRegionTree));
+          result.AsyncWaitHandle.WaitOne();
+          EndInvoke(result);
+        } catch (ObjectDisposedException) { }
+      } else {
+        if (IsDisposed || Disposing) return;
+        regionsTreeView.Nodes.Clear();
+        if (Content == null) return;
+        regionsTreeView.Nodes.Add(AllRegionsName, AllRegionsName);
+        var allRegionsNodes = regionsTreeView.Nodes[AllRegionsName].Nodes;
+        foreach (var location in Content.LocationNames) {
+          var country = location.Substring(0, 2);
+          if (!allRegionsNodes.ContainsKey(country)) {
+            allRegionsNodes.Add(country, country);
+          }
+          allRegionsNodes[country].Nodes.Add(location, location);
+        }
+        regionsTreeView.HideSelection = false;
+        regionsTreeView.Nodes[AllRegionsName].Expand();
+      }
+    }
+
+    #endregion
+
+    public void SetFocus(string regionName) {
+      var row = Content.Geometry.Features.Rows.Cast<FeatureDataRow>().FirstOrDefault(r => (string)r["NUTS_ID"] == regionName);
+      if (row == null) return;
+      var coords = row.Geometry.Envelope.Buffer(1).Coordinates;
+      var env = new Envelope(coords.Min(c => c.X), coords.Max(c => c.X),
+                   coords.Min(c => c.Y), coords.Max(c => c.Y));
+      mapBox.Map.ZoomToBox(env);
+      mapBox.Refresh();
+    }
+
+    protected override void SetEnabledStateOfControls() {
+      base.SetEnabledStateOfControls();
+      vectorLayerNamesListBox.Enabled = Content != null;
+      valueLayerNamesListBox.Enabled = Content != null;
+      openSolutionEditorButton.Enabled = Content != null && !Locked;
+    }
+
+    #region Auxiliary Methods
+    private string GetRegionAtWorldPos(Coordinate loc) {
+      var ds = new FeatureDataSet();
+      Content.Geometry.ExecuteIntersectionQuery(new NetTopologySuite.Geometries.Point(loc), ds);
+      return (from FeatureDataRow row in ds.Tables[0]
+              select row["NUTS_ID"] as string).FirstOrDefault();
+    }
+
+    private string GetRegionDescription(string regionName) {
+      if (regionName != null && Content.Geometry.Features.Columns.Contains("name")) {
+        var row = Content.Geometry.Features.Rows.Cast<FeatureDataRow>().FirstOrDefault(r => (string)r["NUTS_ID"] == regionName);
+        if (row != null)
+          return row["name"].ToString();
+      }
+      return "";
+    }
+
+    private string GetCurrentValueLayerValue(string regionName) {
+      if (regionName == null) return "";
+      var layerName = valueLayerNamesListBox.SelectedItem as string;
+      if (layerName == null) return "";
+      var generator = layerCache[layerName] as LazyValueLayerGenerator;
+      if (generator == null) return "";
+      var mapping = generator.Mapping;
+      if (mapping == null) return "";
+      double value;
+      if (!mapping.TryGetValue(regionName, out value)) return "";
+      var v = Math.Abs(value);
+      //var format = v > 1000 ? "F0" : v > 100 ? "F1" : v > 10 ? "F2" : value < 0.01 ? "G" : "F3";
+      var format = v > 1000 ? "F0" : v > 100 ? "F1" : v > 10 ? "F2" : value < 0.01 ? "G" : "F3";
+      var info = (NumberFormatInfo)NumberFormatInfo.InvariantInfo.Clone();
+      info.NumberGroupSeparator = " ";
+      return string.Format("{0} {1}", value.ToString(format, info), generator.Unit);
+    }
+
+    #endregion
+
+    #region Event Handlers (child controls)
+    private void vectorLayerNamesListBox_SelectedIndexChanged(object sender, EventArgs e) {
+      ShowSelectedLayers(false);
+      vectorLayerNamesListBox.Invalidate();
+    }
+
+    private void valueLayerNamesListBox_SelectedIndexChanged(object sender, EventArgs e) {
+      ShowSelectedLayers(false);
+    }
+
+    private void mapBox_MouseMove(Coordinate worldPos, MouseEventArgs imagePos) {
+      var nuts_id = GetRegionAtWorldPos(worldPos);
+      var nuts_name = GetRegionDescription(nuts_id);
+      regionNameLabel.Text = nuts_id;
+      regionDescriptionLabel.Text = nuts_name;
+      valueLayerValueLabel.Text = GetCurrentValueLayerValue(nuts_id);
+      mapBox.Cursor = String.IsNullOrEmpty(nuts_id) ? Cursors.Default : Cursors.Hand;
+    }
+
+    private Point startPos = new Point(0, 0);
+    private void mapBox_MouseDown(Coordinate worldPos, MouseEventArgs imagePos) {
+      if (imagePos.Button == MouseButtons.Left) {
+        startPos = imagePos.Location;
+      }
+    }
+
+    private void mapBox_MouseUp(Coordinate worldPos, MouseEventArgs imagePos) {
+      if (imagePos.Button == MouseButtons.Left
+          && Util.Distance(imagePos.Location, startPos) < 4) {
+        currentRegion = GetRegionAtWorldPos(worldPos);
+        if (!String.IsNullOrEmpty(currentRegion)) {
+          regionDetailView.Content = new RegionDetailData {
+            RegionName = currentRegion,
+            Solution = Content,
+          };
+        }
+      }
+    }
+
+    private void solutionDetailView_RegionLabelClicked(object sender, EventArgs e) {
+      if (regionDetailView.Content != null)
+        SetFocus(regionDetailView.Content.RegionName);
+    }
+
+    private void vectorLayerNamesListBox_DrawItem(object sender, DrawItemEventArgs e) {
+      var item = vectorLayerNamesListBox.Items[e.Index];
+      var listBoxItem = item as ListBoxItem;
+      var foreColor = Color.Black;
+      if (listBoxItem != null) {
+        foreColor = listBoxItem.Color;
+      }
+      var backColor = vectorLayerNamesListBox.BackColor;
+      if (vectorLayerNamesListBox.SelectedItems.Contains(item)) {
+        backColor = foreColor;
+        foreColor = Color.White;
+      }
+      using (var backBrush = new SolidBrush(backColor)) {
+        e.Graphics.FillRectangle(backBrush, e.Bounds);
+      }
+      using (var foreBrush = new SolidBrush(foreColor)) {
+        e.Graphics.DrawString(
+          listBoxItem != null ? listBoxItem.Text : item.ToString(),
+          vectorLayerNamesListBox.Font, foreBrush, e.Bounds);
+      }
+    }
+    #endregion
+
+    private void tabControl1_Selected(object sender, TabControlEventArgs e) {
+      switch (e.TabPageIndex) {
+        case 0:
+          ShowSelectedLayers(false); // prepare for the map update
+          updateMap.Set(); // signal that the map should be updated once
+          break;
+        case 1:
+          updateCosts.Set(); // signal that the costs should be updated once
+          break;
+      }
+    }
+
+    private void regionsTreeView_AfterSelect(object sender, TreeViewEventArgs e) {
+      var labeltext = e.Node.Text.Split(' ');
+      if (labeltext.Length > 0)
+        currentRegion = labeltext[0];
+      if (e.Node.GetNodeCount(true) == 0) {
+        regionDetailView.Content = new RegionDetailData {
+          RegionName = currentRegion,
+          Solution = Content,
+        };
+      }
+
+      ClearCostsSummary();
+      PopulateCostsSummary();
+    }
+
+    private void openSolutionEditorButton_Click(object sender, EventArgs e) {
+      // clone solution and also clone problem-data separately (solution does not clone problem data itself)
+      var cloner = new Cloner();
+      var clonedSolution = cloner.Clone(Content);
+      var clonedProblemData = cloner.Clone(Content.ProblemDataReference);
+      clonedSolution.ProblemDataReference = clonedProblemData;
+
+      // create and open editor view for content
+      var vh = new ViewHost();
+      vh.Content = clonedSolution;
+      vh.ViewType = typeof (BioBoostCompoundSolutionEditor);
+      vh.Show();
+    }
+
+    public void SaveMapViewToPNG(string filename) {
+      var bitmap = new Bitmap(mapBox.Width, mapBox.Height);
+      mapBox.DrawToBitmap(bitmap, new Rectangle(0, 0, mapBox.Width, mapBox.Height));
+      bitmap.Save(filename);
+    }
+
+    private void saveMapImageButton_Click(object sender, EventArgs e) {
+      if (saveFileDialog.ShowDialog() == DialogResult.OK) {
+        try {
+          Enabled = false;
+          SaveMapViewToPNG(saveFileDialog.FileName);
+        } catch (Exception x) {
+          ErrorHandling.ShowErrorDialog(this, x);
+        } finally {
+          Enabled = true;
+        }
+      }
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostCompoundSolutionView.resx
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostCompoundSolutionView.resx	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostCompoundSolutionView.resx	(revision 15711)
@@ -0,0 +1,129 @@
+﻿<?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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <metadata name="valueLayersLabel.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>False</value>
+  </metadata>
+  <metadata name="vectorLayersLabel.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>False</value>
+  </metadata>
+  <metadata name="saveFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 17</value>
+  </metadata>
+</root>
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostParetoSetView.Designer.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostParetoSetView.Designer.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostParetoSetView.Designer.cs	(revision 15711)
@@ -0,0 +1,96 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.BioBoost.Views {
+  partial class BioBoostParetoSetView {
+    /// <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() {
+      System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
+      System.Windows.Forms.DataVisualization.Charting.Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series();
+      System.Windows.Forms.DataVisualization.Charting.DataPoint dataPoint1 = new System.Windows.Forms.DataVisualization.Charting.DataPoint(-0.1D, 10000D);
+      this.paretoSetChart = new System.Windows.Forms.DataVisualization.Charting.Chart();
+      ((System.ComponentModel.ISupportInitialize)(this.paretoSetChart)).BeginInit();
+      this.SuspendLayout();
+      // 
+      // paretoSetChart
+      // 
+      this.paretoSetChart.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)));
+      chartArea1.AxisX.IntervalAutoMode = System.Windows.Forms.DataVisualization.Charting.IntervalAutoMode.VariableCount;
+      chartArea1.AxisX.IntervalType = System.Windows.Forms.DataVisualization.Charting.DateTimeIntervalType.Number;
+      chartArea1.AxisY.IntervalAutoMode = System.Windows.Forms.DataVisualization.Charting.IntervalAutoMode.VariableCount;
+      chartArea1.AxisY.IntervalType = System.Windows.Forms.DataVisualization.Charting.DateTimeIntervalType.Number;
+      chartArea1.AxisY2.IntervalType = System.Windows.Forms.DataVisualization.Charting.DateTimeIntervalType.Number;
+      chartArea1.Name = "ChartArea1";
+      this.paretoSetChart.ChartAreas.Add(chartArea1);
+      this.paretoSetChart.Location = new System.Drawing.Point(3, 3);
+      this.paretoSetChart.Name = "paretoSetChart";
+      series1.ChartArea = "ChartArea1";
+      series1.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.FastPoint;
+      series1.Name = "Series1";
+      series1.Points.Add(dataPoint1);
+      series1.ToolTip = "#VALX, #VAL";
+      series1.XValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double;
+      series1.YValueType = System.Windows.Forms.DataVisualization.Charting.ChartValueType.Double;
+      this.paretoSetChart.Series.Add(series1);
+      this.paretoSetChart.Size = new System.Drawing.Size(576, 353);
+      this.paretoSetChart.TabIndex = 0;
+      this.paretoSetChart.Text = "paretoSetChart";
+      this.paretoSetChart.DoubleClick += new System.EventHandler(this.paretoSetChart_DoubleClick);
+      this.paretoSetChart.MouseDown += new System.Windows.Forms.MouseEventHandler(this.paretoSetChart_MouseDown);
+      // 
+      // BioBoostParetoSetView
+      // 
+      this.Controls.Add(this.paretoSetChart);
+      this.Name = "BioBoostParetoSetView";
+      this.Size = new System.Drawing.Size(582, 359);
+      ((System.ComponentModel.ISupportInitialize)(this.paretoSetChart)).EndInit();
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.DataVisualization.Charting.Chart paretoSetChart;
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostParetoSetView.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostParetoSetView.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostParetoSetView.cs	(revision 15711)
@@ -0,0 +1,129 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Windows.Forms;
+using System.Windows.Forms.DataVisualization.Charting;
+using HeuristicLab.BioBoost.Representation;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Core.Views;
+using HeuristicLab.MainForm;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.BioBoost.Views {
+
+  [Content(typeof (ItemCollection<BioBoostCompoundSolution>), false)]
+  public partial class BioBoostParetoSetView : ItemView {
+
+    private Point mouseDownPos;
+
+    public new ItemCollection<BioBoostCompoundSolution> Content {
+      get { return (ItemCollection<BioBoostCompoundSolution>)base.Content; }
+      set { base.Content = value; }
+    }
+
+    public BioBoostParetoSetView() {
+      InitializeComponent();
+    }
+
+    protected override void RegisterContentEvents() {
+      base.RegisterContentEvents();
+      Content.ItemsAdded += UpdateChart;
+      Content.ItemsRemoved += UpdateChart;
+      Content.CollectionReset += UpdateChart;
+    }
+
+    protected override void DeregisterContentEvents() {
+      base.DeregisterContentEvents();
+      Content.CollectionReset -= UpdateChart;
+      Content.ItemsRemoved -= UpdateChart;
+      Content.CollectionReset -= UpdateChart;
+    }
+
+    protected override void OnContentChanged() {
+      base.OnContentChanged();
+      UpdateChart(this, EventArgs.Empty);
+    }
+
+    protected virtual void UpdateChart(object sender, EventArgs args) {
+      if (InvokeRequired) {
+        Invoke(new EventHandler(UpdateChart), sender, args);
+      } else {
+        try {
+          if (paretoSetChart.IsDisposed) return;
+          var points = paretoSetChart.Series[0].Points;
+          if (Content == null) {
+            points.Clear();
+            return;
+          }
+          var newPoints = Content.Where(solution => solution.Qualities.Length >= 2).Select(s => new { x = s.Qualities[0], y = s.Qualities[1], solution = s}).ToList();
+          if (newPoints.Count > 0) {
+            var chartArea = paretoSetChart.ChartAreas[0];
+            AdaptAxis(chartArea.AxisX, newPoints.Select(p => p.x), 1);
+            AdaptAxis(chartArea.AxisY, newPoints.Select(p => p.y), 1);
+            paretoSetChart.BeginInit();
+            points.Clear();
+            foreach (var point in newPoints) {
+              points.Add(new DataPoint(point.x, point.y) {
+                Tag = point.solution,
+              });
+            }
+            paretoSetChart.EndInit();
+          }
+        } catch (Exception x) {
+          ErrorHandling.ShowErrorDialog(x);
+        }
+      }
+    }
+
+    private void AdaptAxis(Axis axis, IEnumerable<double> values, int precision = 0, double overshot = 0.5, double margin = 0.25) {
+      var newMax = values.Max();
+      var newMin = values.Min();
+      var range = newMax - newMin;
+      newMax = newMax + range*margin;
+      newMin = newMin - range*margin;
+      if (range == 0) return;
+      var oldRange = axis.Maximum - axis.Minimum;
+      if (range*3 < oldRange) {
+        axis.Maximum = Math.Round(newMax+range*overshot, precision);
+        axis.Minimum = Math.Round(newMin-range*overshot , precision);
+      } else {
+        if (newMax > axis.Maximum) axis.Maximum = Math.Round(newMax+range*overshot, precision);
+        if (newMin < axis.Minimum) axis.Minimum = Math.Round(newMin-range*overshot, precision);
+      }
+    }
+
+    private void paretoSetChart_MouseDown(object sender, MouseEventArgs e) { mouseDownPos = e.Location; }
+    private void paretoSetChart_DoubleClick(object sender, EventArgs e) {
+      var pos = mouseDownPos;
+      var result = paretoSetChart.HitTest(pos.X, pos.Y, ChartElementType.DataPoint);
+      var point = result.Object as DataPoint;
+      if (point != null && point.Tag is IContent)
+        MainFormManager.MainForm.ShowContent((IContent)point.Tag);
+    }
+
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostParetoSetView.resx
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostParetoSetView.resx	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostParetoSetView.resx	(revision 15711)
@@ -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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostProblemDataView.Designer.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostProblemDataView.Designer.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostProblemDataView.Designer.cs	(revision 15711)
@@ -0,0 +1,298 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.BioBoost.Views {
+  partial class BioBoostProblemDataView {
+    /// <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.tabControl = new System.Windows.Forms.TabControl();
+      this.dataPage = new System.Windows.Forms.TabPage();
+      this.splitRegionFactorsImportButton = new System.Windows.Forms.Button();
+      this.filterButton = new System.Windows.Forms.Button();
+      this.importDescriptorsButton = new System.Windows.Forms.Button();
+      this.checkButton = new System.Windows.Forms.Button();
+      this.importNeighborsButton = new System.Windows.Forms.Button();
+      this.loadShapeFileButton = new System.Windows.Forms.Button();
+      this.importDistancesButton = new System.Windows.Forms.Button();
+      this.importFeedstockButton = new System.Windows.Forms.Button();
+      this.parameterCollectionView = new HeuristicLab.Core.Views.ParameterCollectionView();
+      this.mapPage = new System.Windows.Forms.TabPage();
+      this.mapBox = new SharpMap.Forms.MapBox();
+      this.openFileDialog = new System.Windows.Forms.OpenFileDialog();
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit();
+      this.tabControl.SuspendLayout();
+      this.dataPage.SuspendLayout();
+      this.mapPage.SuspendLayout();
+      this.SuspendLayout();
+      // 
+      // nameTextBox
+      // 
+      this.errorProvider.SetIconAlignment(this.nameTextBox, System.Windows.Forms.ErrorIconAlignment.MiddleLeft);
+      this.errorProvider.SetIconPadding(this.nameTextBox, 2);
+      this.nameTextBox.Size = new System.Drawing.Size(604, 20);
+      // 
+      // infoLabel
+      // 
+      this.infoLabel.Location = new System.Drawing.Point(669, 3);
+      // 
+      // tabControl
+      // 
+      this.tabControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+            | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.tabControl.Controls.Add(this.dataPage);
+      this.tabControl.Controls.Add(this.mapPage);
+      this.tabControl.Location = new System.Drawing.Point(3, 26);
+      this.tabControl.Name = "tabControl";
+      this.tabControl.SelectedIndex = 0;
+      this.tabControl.Size = new System.Drawing.Size(682, 423);
+      this.tabControl.TabIndex = 3;
+      // 
+      // dataPage
+      // 
+      this.dataPage.Controls.Add(this.splitRegionFactorsImportButton);
+      this.dataPage.Controls.Add(this.filterButton);
+      this.dataPage.Controls.Add(this.importDescriptorsButton);
+      this.dataPage.Controls.Add(this.checkButton);
+      this.dataPage.Controls.Add(this.importNeighborsButton);
+      this.dataPage.Controls.Add(this.loadShapeFileButton);
+      this.dataPage.Controls.Add(this.importDistancesButton);
+      this.dataPage.Controls.Add(this.importFeedstockButton);
+      this.dataPage.Controls.Add(this.parameterCollectionView);
+      this.dataPage.Location = new System.Drawing.Point(4, 22);
+      this.dataPage.Name = "dataPage";
+      this.dataPage.Padding = new System.Windows.Forms.Padding(3);
+      this.dataPage.Size = new System.Drawing.Size(674, 397);
+      this.dataPage.TabIndex = 0;
+      this.dataPage.Text = "Data";
+      this.dataPage.UseVisualStyleBackColor = true;
+      // 
+      // splitRegionFactorsImportButton
+      // 
+      this.splitRegionFactorsImportButton.BackgroundImage = global::HeuristicLab.Problems.BioBoost.Views.Properties.Resources.Farm_Fresh_arrow_divide;
+      this.splitRegionFactorsImportButton.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom;
+      this.splitRegionFactorsImportButton.Location = new System.Drawing.Point(166, 7);
+      this.splitRegionFactorsImportButton.Name = "splitRegionFactorsImportButton";
+      this.splitRegionFactorsImportButton.Size = new System.Drawing.Size(26, 26);
+      this.splitRegionFactorsImportButton.TabIndex = 10;
+      this.toolTip.SetToolTip(this.splitRegionFactorsImportButton, "import descriptors");
+      this.splitRegionFactorsImportButton.UseVisualStyleBackColor = true;
+      this.splitRegionFactorsImportButton.Click += new System.EventHandler(this.splitRegionFactorsImportButton_Click);
+      // 
+      // filterButton
+      // 
+      this.filterButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+      this.filterButton.Location = new System.Drawing.Point(563, 7);
+      this.filterButton.Name = "filterButton";
+      this.filterButton.Size = new System.Drawing.Size(51, 23);
+      this.filterButton.TabIndex = 9;
+      this.filterButton.Text = "Filter...";
+      this.filterButton.UseVisualStyleBackColor = true;
+      this.filterButton.Click += new System.EventHandler(this.filterButton_Click);
+      // 
+      // importDescriptorsButton
+      // 
+      this.importDescriptorsButton.BackgroundImage = global::HeuristicLab.Problems.BioBoost.Views.Properties.Resources.FoamingBeakerCartoon;
+      this.importDescriptorsButton.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom;
+      this.importDescriptorsButton.Location = new System.Drawing.Point(134, 6);
+      this.importDescriptorsButton.Name = "importDescriptorsButton";
+      this.importDescriptorsButton.Size = new System.Drawing.Size(26, 26);
+      this.importDescriptorsButton.TabIndex = 8;
+      this.toolTip.SetToolTip(this.importDescriptorsButton, "import descriptors");
+      this.importDescriptorsButton.UseVisualStyleBackColor = true;
+      this.importDescriptorsButton.Click += new System.EventHandler(this.importConversionsButton_Click);
+      // 
+      // checkButton
+      // 
+      this.checkButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+      this.checkButton.Location = new System.Drawing.Point(620, 7);
+      this.checkButton.Name = "checkButton";
+      this.checkButton.Size = new System.Drawing.Size(48, 23);
+      this.checkButton.TabIndex = 7;
+      this.checkButton.Text = "Check";
+      this.checkButton.UseVisualStyleBackColor = true;
+      this.checkButton.Click += new System.EventHandler(this.checkButton_Click);
+      // 
+      // importNeighborsButton
+      // 
+      this.importNeighborsButton.BackgroundImage = global::HeuristicLab.Problems.BioBoost.Views.Properties.Resources.neighbors;
+      this.importNeighborsButton.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom;
+      this.importNeighborsButton.Location = new System.Drawing.Point(102, 6);
+      this.importNeighborsButton.Name = "importNeighborsButton";
+      this.importNeighborsButton.Size = new System.Drawing.Size(26, 26);
+      this.importNeighborsButton.TabIndex = 6;
+      this.toolTip.SetToolTip(this.importNeighborsButton, "Import Neighbors");
+      this.importNeighborsButton.UseVisualStyleBackColor = true;
+      this.importNeighborsButton.Click += new System.EventHandler(this.importNeighborsButton_Click);
+      // 
+      // loadShapeFileButton
+      // 
+      this.loadShapeFileButton.BackgroundImage = global::HeuristicLab.Problems.BioBoost.Views.Properties.Resources.ShapefileIcon;
+      this.loadShapeFileButton.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom;
+      this.loadShapeFileButton.Location = new System.Drawing.Point(6, 6);
+      this.loadShapeFileButton.Name = "loadShapeFileButton";
+      this.loadShapeFileButton.Size = new System.Drawing.Size(26, 26);
+      this.loadShapeFileButton.TabIndex = 4;
+      this.toolTip.SetToolTip(this.loadShapeFileButton, "Load Shapefile");
+      this.loadShapeFileButton.UseVisualStyleBackColor = true;
+      this.loadShapeFileButton.Click += new System.EventHandler(this.loadShapeFileButton_Click);
+      // 
+      // importDistancesButton
+      // 
+      this.importDistancesButton.BackgroundImage = global::HeuristicLab.Problems.BioBoost.Views.Properties.Resources.Transport;
+      this.importDistancesButton.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom;
+      this.importDistancesButton.Location = new System.Drawing.Point(70, 6);
+      this.importDistancesButton.Name = "importDistancesButton";
+      this.importDistancesButton.Size = new System.Drawing.Size(26, 26);
+      this.importDistancesButton.TabIndex = 2;
+      this.toolTip.SetToolTip(this.importDistancesButton, "Import Distance Matrix");
+      this.importDistancesButton.UseVisualStyleBackColor = true;
+      this.importDistancesButton.Click += new System.EventHandler(this.importDistancesButton_Click);
+      // 
+      // importFeedstockButton
+      // 
+      this.importFeedstockButton.BackgroundImage = global::HeuristicLab.Problems.BioBoost.Views.Properties.Resources.WheatStraw;
+      this.importFeedstockButton.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom;
+      this.importFeedstockButton.Location = new System.Drawing.Point(38, 6);
+      this.importFeedstockButton.Name = "importFeedstockButton";
+      this.importFeedstockButton.Size = new System.Drawing.Size(26, 26);
+      this.importFeedstockButton.TabIndex = 1;
+      this.toolTip.SetToolTip(this.importFeedstockButton, "Import Feedstock Potentials");
+      this.importFeedstockButton.UseVisualStyleBackColor = true;
+      this.importFeedstockButton.Click += new System.EventHandler(this.importFeedstockButton_Click);
+      // 
+      // parameterCollectionView
+      // 
+      this.parameterCollectionView.AllowEditingOfHiddenParameters = true;
+      this.parameterCollectionView.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.parameterCollectionView.Caption = "ParameterCollection View";
+      this.parameterCollectionView.Content = null;
+      this.parameterCollectionView.Location = new System.Drawing.Point(6, 38);
+      this.parameterCollectionView.Name = "parameterCollectionView";
+      this.parameterCollectionView.ReadOnly = false;
+      this.parameterCollectionView.ShowDetails = true;
+      this.parameterCollectionView.Size = new System.Drawing.Size(662, 353);
+      this.parameterCollectionView.TabIndex = 0;
+      // 
+      // mapPage
+      // 
+      this.mapPage.Controls.Add(this.mapBox);
+      this.mapPage.Location = new System.Drawing.Point(4, 22);
+      this.mapPage.Name = "mapPage";
+      this.mapPage.Padding = new System.Windows.Forms.Padding(3);
+      this.mapPage.Size = new System.Drawing.Size(674, 397);
+      this.mapPage.TabIndex = 1;
+      this.mapPage.Text = "Map";
+      this.mapPage.UseVisualStyleBackColor = true;
+      // 
+      // mapBox
+      // 
+      this.mapBox.ActiveTool = SharpMap.Forms.MapBox.Tools.Pan;
+      this.mapBox.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.mapBox.Cursor = System.Windows.Forms.Cursors.Hand;
+      this.mapBox.FineZoomFactor = 10D;
+      this.mapBox.Location = new System.Drawing.Point(6, 6);
+      this.mapBox.MapQueryMode = SharpMap.Forms.MapBox.MapQueryType.LayerByIndex;
+      this.mapBox.Name = "mapBox";
+      this.mapBox.PanOnClick = false;
+      this.mapBox.QueryGrowFactor = 5F;
+      this.mapBox.QueryLayerIndex = 0;
+      this.mapBox.SelectionBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(210)))), ((int)(((byte)(244)))), ((int)(((byte)(244)))), ((int)(((byte)(244)))));
+      this.mapBox.SelectionForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(244)))), ((int)(((byte)(244)))), ((int)(((byte)(244)))));
+      this.mapBox.ShowProgressUpdate = false;
+      this.mapBox.Size = new System.Drawing.Size(662, 385);
+      this.mapBox.TabIndex = 0;
+      this.mapBox.TabStop = false;
+      this.mapBox.TakeFocusOnHover = true;
+      this.mapBox.Text = "mapBox";
+      this.mapBox.WheelZoomMagnitude = -2D;
+      this.mapBox.MouseClick += new System.Windows.Forms.MouseEventHandler(this.mapBox_MouseClick);
+      // 
+      // openFileDialog
+      // 
+      this.openFileDialog.DefaultExt = "*.csv";
+      this.openFileDialog.Filter = "All Files|*.*";
+      this.openFileDialog.Title = "Import File";
+      // 
+      // BioBoostProblemDataView
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Controls.Add(this.tabControl);
+      this.Name = "BioBoostProblemDataView";
+      this.Size = new System.Drawing.Size(688, 452);
+      this.Controls.SetChildIndex(this.tabControl, 0);
+      this.Controls.SetChildIndex(this.infoLabel, 0);
+      this.Controls.SetChildIndex(this.nameTextBox, 0);
+      this.Controls.SetChildIndex(this.nameLabel, 0);
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).EndInit();
+      this.tabControl.ResumeLayout(false);
+      this.dataPage.ResumeLayout(false);
+      this.mapPage.ResumeLayout(false);
+      this.ResumeLayout(false);
+      this.PerformLayout();
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.TabControl tabControl;
+    private System.Windows.Forms.TabPage dataPage;
+    private System.Windows.Forms.TabPage mapPage;
+    private SharpMap.Forms.MapBox mapBox;
+    private Core.Views.ParameterCollectionView parameterCollectionView;
+    private System.Windows.Forms.Button importDistancesButton;
+    private System.Windows.Forms.Button importFeedstockButton;
+    private System.Windows.Forms.OpenFileDialog openFileDialog;
+    private System.Windows.Forms.Button loadShapeFileButton;
+    private System.Windows.Forms.Button importNeighborsButton;
+    private System.Windows.Forms.Button checkButton;
+    private System.Windows.Forms.Button importDescriptorsButton;
+    private System.Windows.Forms.Button filterButton;
+    private System.Windows.Forms.Button splitRegionFactorsImportButton;
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostProblemDataView.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostProblemDataView.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostProblemDataView.cs	(revision 15711)
@@ -0,0 +1,316 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 GeoAPI.Geometries;
+using HeuristicLab.BioBoost.Persistence;
+using HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.Core.Views;
+using HeuristicLab.MainForm;
+using HeuristicLab.Persistence.Default.Xml;
+using SharpMap.Data;
+using SharpMap.Data.Providers;
+using SharpMap.Forms;
+using SharpMap.Layers;
+using SharpMap.Rendering.Thematics;
+using SharpMap.Styles;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.IO;
+using System.Windows.Forms;
+using ColorBlend = SharpMap.Rendering.Thematics.ColorBlend;
+
+namespace HeuristicLab.BioBoost.Views {
+
+  [Content(typeof(BioBoostProblemData), IsDefaultView = true)]
+  public partial class BioBoostProblemDataView : NamedItemView {
+
+    public new BioBoostProblemData Content {
+      get { return (BioBoostProblemData)base.Content; }
+      set { base.Content = value; }
+    }
+
+    private VectorLayer regions;
+    private FilterDialog filterDialog;
+
+    public BioBoostProblemDataView() {
+      InitializeComponent();
+      filterDialog = new FilterDialog();
+    }
+
+    private GeometryFeatureProvider gfp2;
+    private void PrepareMap(object sender, DoWorkEventArgs e) {
+      var gfp = ShapeFileLoader.LoadShapeFile("C:\\Users\\P40031\\SkyDrive\\NUTS3\\NUTS3_regions_2010_WGS84.shp"); // TODO!
+      var ms = new MemoryStream();
+      XmlGenerator.Serialize(gfp, ms);
+      gfp2 = XmlParser.Deserialize<GeometryFeatureProvider>(new MemoryStream(ms.ToArray()));
+    }
+
+    private void ShowMap(object sender, RunWorkerCompletedEventArgs e) {
+      var outline = new Pen(Color.FromArgb(128, Color.White), 0.5f);
+      var small = new VectorStyle { Fill = Brushes.Blue, EnableOutline = true, Outline = outline };
+      var large = new VectorStyle { Fill = Brushes.Red, EnableOutline = true, Outline = outline };
+      regions = new VectorLayer("NUTS3 Regions") {
+        DataSource = gfp2,
+        Theme =
+          new GradientTheme("Shape_Area", 0, 5, small, large) { FillColorBlend = ColorBlend.Rainbow5 },
+      };
+
+      // add labels
+      var l = new LabelLayer("NUTS3 Labels") {
+        DataSource = gfp2,
+        LabelColumn = "NUTS_ID",
+        PriorityColumn = "Shape_Area",
+      };
+
+      // add geometries
+      var geometries = new Collection<IGeometry>();
+      GeoAPI.GeometryServiceProvider.Instance = new NetTopologySuite.NtsGeometryServices();
+      var f = GeoAPI.GeometryServiceProvider.Instance.CreateGeometryFactory(4326);
+      regions.DataSource.Open();
+      var rows = regions.DataSource.GetObjectIDsInView(regions.Envelope);
+      foreach (var row in rows) {
+        var source = regions.DataSource.GetFeature(row).Geometry.Centroid;
+        var ds = new FeatureDataSet();
+        regions.DataSource.ExecuteIntersectionQuery(source.Buffer(0.1), ds);
+        var neighbors = ds.Tables[0].Rows;
+        if (neighbors.Count > 0) {
+          var ls = f.CreateLineString(new[] {
+            source.Coordinate,
+            ((FeatureDataRow) neighbors[rng.Next(neighbors.Count)]).
+                                        Geometry.Centroid.
+                                        Coordinate,
+          });
+          geometries.Add(ls);
+        }
+      }
+      regions.DataSource.Close();
+      var v = new VectorLayer("Vectors") {
+        DataSource = new GeometryProvider(geometries),
+      };
+      v.Style.Line.SetLineCap(LineCap.NoAnchor, LineCap.ArrowAnchor, DashCap.Flat);
+
+      // add layers
+      mapBox.Map.Layers.Add(regions);
+      mapBox.Map.Layers.Add(l);
+      mapBox.Map.Layers.Add(v);
+
+      // configure map
+      mapBox.Map.ZoomToExtents();
+      mapBox.Refresh();
+      mapBox.ActiveTool = MapBox.Tools.Pan;
+      tabControl.SelectedTab = mapPage;
+    }
+
+    private readonly Dictionary<string, VectorStyle> styles = new Dictionary<string, VectorStyle>();
+    private readonly Random rng = new Random();
+    private VectorStyle GetRandomStyle(FeatureDataRow row) {
+      var name = row["NUTS_ID"].ToString();
+      VectorStyle style;
+      if (!styles.TryGetValue(name, out style)) {
+        style = new VectorStyle {
+          Fill = new SolidBrush(Color.FromArgb(rng.Next(256), rng.Next(256), rng.Next(256)))
+        };
+        styles[name] = style;
+      }
+      return style;
+    }
+
+    protected override void DeregisterContentEvents() {
+      base.DeregisterContentEvents();
+      Content.GeometryChanged -= GeometryChanged;
+    }
+
+    protected override void RegisterContentEvents() {
+      base.RegisterContentEvents();
+      Content.GeometryChanged += GeometryChanged;
+    }
+
+
+    #region Event Handlers (Content)
+    private void GeometryChanged(object sender, EventArgs eventArgs) {
+      if (InvokeRequired) {
+        Invoke(new EventHandler<EventArgs>(GeometryChanged), new object[] { sender, eventArgs });
+      } else {
+        UpdateMap();
+      }
+    }
+    #endregion
+
+    protected override void OnContentChanged() {
+      base.OnContentChanged();
+      if (Content == null) {
+        parameterCollectionView.Content = null;
+      } else {
+        parameterCollectionView.Content = Content.Parameters;
+      }
+      UpdateMap();
+    }
+
+    protected override void SetEnabledStateOfControls() {
+      base.SetEnabledStateOfControls();
+      parameterCollectionView.Enabled = Content != null;
+      loadShapeFileButton.Enabled = Content != null;
+      importFeedstockButton.Enabled = Content != null;
+      importDistancesButton.Enabled = Content != null;
+    }
+
+    private void UpdateMap() {
+      mapBox.Map.Layers.Clear();
+      mapBox.ShowProgressUpdate = false;
+      if (Content == null || Content.Geometry == null) return;
+      mapBox.ShowProgressUpdate = true;
+      var outline = new Pen(Color.FromArgb(128, Color.White), 0.5f);
+      var small = new VectorStyle { Fill = Brushes.Blue, EnableOutline = true, Outline = outline };
+      var large = new VectorStyle { Fill = Brushes.Red, EnableOutline = true, Outline = outline };
+      mapBox.Map.Layers.Add(new VectorLayer("Regions", Content.Geometry) {
+        //Theme = new GradientTheme("Shape_Area", 0, 5, small, large) {
+        //FillColorBlend = ColorBlend.Rainbow5,
+        //},
+      });
+      mapBox.Map.ZoomToExtents();
+      mapBox.Refresh();
+      mapBox.ActiveTool = MapBox.Tools.Pan;
+    }
+
+    #region Event Handlers (child controls)
+    private void mapBox_MouseClick(object sender, MouseEventArgs e) {
+      if (e.Button == MouseButtons.Right) {
+        var c = mapBox.Map.ImageToWorld(e.Location);
+        var f = GeoAPI.GeometryServiceProvider.Instance.CreateGeometryFactory(4326);
+        var ds = new FeatureDataSet();
+        regions.ExecuteIntersectionQuery(f.CreatePoint(c), ds);
+        if (ds.Tables[0].Rows.Count > 0) {
+          var text = ds.Tables[0].Rows[0]["NUTS_ID"].ToString();
+          toolTip.SetToolTip(mapBox, text);
+        }
+      }
+    }
+
+    private void importFeedstockButton_Click(object sender, EventArgs e) {
+      openFileDialog.Filter = "Comma Separted Value|*.csv|All Files|*.*";
+      if (openFileDialog.ShowDialog() == DialogResult.OK) {
+        try {
+          Enabled = false;
+          Content.LoadFeedstockPotentials(openFileDialog.FileName);
+        } catch (Exception x) {
+          PluginInfrastructure.ErrorHandling.ShowErrorDialog(this, x);
+        } finally {
+          Enabled = true;
+        }
+      }
+    }
+
+    private void loadShapeFileButton_Click(object sender, EventArgs e) {
+      openFileDialog.Filter = "ESRI Shape Files|*.shp|All Files|*.*";
+      if (openFileDialog.ShowDialog() == DialogResult.OK) {
+        try {
+          Enabled = false;
+          Content.LoadShapeFile(openFileDialog.FileName);
+          tabControl.SelectedTab = mapPage;
+        } catch (Exception x) {
+          PluginInfrastructure.ErrorHandling.ShowErrorDialog(this, x);
+        } finally {
+          Enabled = true;
+        }
+      }
+    }
+
+    private void importDistancesButton_Click(object sender, EventArgs e) {
+      openFileDialog.Filter = "Comma Serparted Value|*.csv|All Files|*.*";
+      if (openFileDialog.ShowDialog() == DialogResult.OK) {
+        try {
+          Enabled = false;
+          Content.LoadDistanceMatrix(openFileDialog.FileName);
+        } catch (Exception x) {
+          PluginInfrastructure.ErrorHandling.ShowErrorDialog(this, x);
+        } finally {
+          Enabled = true;
+        }
+      }
+    }
+
+    private void importNeighborsButton_Click(object sender, EventArgs e) {
+      openFileDialog.Filter = "Comma Separated Value|*.csv|All Files|*.*";
+      if (openFileDialog.ShowDialog() == DialogResult.OK) {
+        try {
+          Enabled = false;
+          Content.LoadNeighbors(openFileDialog.FileName);
+        } catch (Exception x) {
+          PluginInfrastructure.ErrorHandling.ShowErrorDialog(this, x);
+        } finally {
+          Enabled = true;
+        }
+      }
+    }
+
+    private void checkButton_Click(object sender, EventArgs e) {
+      var warnings = Content.CheckGeoData();
+      if (!string.IsNullOrEmpty(warnings))
+        MessageBox.Show(warnings, "Warnings", MessageBoxButtons.OK);
+    }
+
+    private void importConversionsButton_Click(object sender, EventArgs e) {
+      openFileDialog.Filter = "YAML Files|*.yaml|All Files|*.*";
+      if (openFileDialog.ShowDialog() == DialogResult.OK) {
+        try {
+          Enabled = false;
+          Content.LoadDescriptors(openFileDialog.FileName);
+        } catch (Exception x) {
+          PluginInfrastructure.ErrorHandling.ShowErrorDialog(this, x);
+        } finally {
+          Enabled = true;
+        }
+      }
+
+    }
+
+    private void splitRegionFactorsImportButton_Click(object sender, EventArgs e) {
+      openFileDialog.Filter = "CSV Files|*.csv|All Files|*.*";
+      if (openFileDialog.ShowDialog() == DialogResult.OK) {
+        try {
+          Enabled = false;
+          Content.LoadSplitRegionDistanceFactors(openFileDialog.FileName);
+        } catch (Exception x) {
+          PluginInfrastructure.ErrorHandling.ShowErrorDialog(this, x);
+        } finally {
+          Enabled = true;
+        }
+      }
+    }
+
+    private void filterButton_Click(object sender, EventArgs e) {
+      if (filterDialog.ShowDialog() == DialogResult.OK) {
+        if (filterDialog.Keep) {
+          Content.KeepRegions(filterDialog.Regex);
+        } else {
+          Content.RemoveRegions(filterDialog.Regex);
+        }
+      }
+    }
+
+    #endregion
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostProblemDataView.resx
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostProblemDataView.resx	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostProblemDataView.resx	(revision 15711)
@@ -0,0 +1,132 @@
+﻿<?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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <metadata name="errorProvider.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 17</value>
+  </metadata>
+  <metadata name="errorProvider.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 17</value>
+  </metadata>
+  <metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>140, 17</value>
+  </metadata>
+  <metadata name="openFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>230, 17</value>
+  </metadata>
+</root>
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostRegionDetailView.Designer.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostRegionDetailView.Designer.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostRegionDetailView.Designer.cs	(revision 15711)
@@ -0,0 +1,157 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.BioBoost.Views {
+  partial class BioBoostRegionDetailView {
+    /// <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() {
+      System.Windows.Forms.GroupBox plantsGroupBox;
+      this.dataGridView = new System.Windows.Forms.DataGridView();
+      this.NameColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
+      this.ValueColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
+      this.regionNameLabel = new System.Windows.Forms.LinkLabel();
+      this.regionDescriptionLabel = new System.Windows.Forms.Label();
+      plantsGroupBox = new System.Windows.Forms.GroupBox();
+      plantsGroupBox.SuspendLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).BeginInit();
+      this.SuspendLayout();
+      // 
+      // plantsGroupBox
+      // 
+      plantsGroupBox.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)));
+      plantsGroupBox.Controls.Add(this.dataGridView);
+      plantsGroupBox.Location = new System.Drawing.Point(3, 30);
+      plantsGroupBox.Name = "plantsGroupBox";
+      plantsGroupBox.Size = new System.Drawing.Size(286, 536);
+      plantsGroupBox.TabIndex = 4;
+      plantsGroupBox.TabStop = false;
+      plantsGroupBox.Text = "Regional Values";
+      // 
+      // dataGridView
+      // 
+      this.dataGridView.AllowUserToAddRows = false;
+      this.dataGridView.AllowUserToDeleteRows = false;
+      this.dataGridView.AllowUserToOrderColumns = true;
+      this.dataGridView.AllowUserToResizeRows = 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.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
+            this.NameColumn,
+            this.ValueColumn});
+      this.dataGridView.Location = new System.Drawing.Point(7, 20);
+      this.dataGridView.Name = "dataGridView";
+      this.dataGridView.ReadOnly = true;
+      this.dataGridView.RowHeadersVisible = false;
+      this.dataGridView.RowHeadersWidthSizeMode = System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.DisableResizing;
+      this.dataGridView.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.CellSelect;
+      this.dataGridView.ShowEditingIcon = false;
+      this.dataGridView.Size = new System.Drawing.Size(273, 510);
+      this.dataGridView.TabIndex = 0;
+      // 
+      // NameColumn
+      // 
+      this.NameColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
+      this.NameColumn.HeaderText = "Name";
+      this.NameColumn.Name = "NameColumn";
+      this.NameColumn.ReadOnly = true;
+      this.NameColumn.Width = 60;
+      // 
+      // ValueColumn
+      // 
+      this.ValueColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
+      this.ValueColumn.HeaderText = "Value";
+      this.ValueColumn.Name = "ValueColumn";
+      this.ValueColumn.ReadOnly = true;
+      this.ValueColumn.Width = 59;
+      // 
+      // regionNameLabel
+      // 
+      this.regionNameLabel.ActiveLinkColor = System.Drawing.Color.Red;
+      this.regionNameLabel.Dock = System.Windows.Forms.DockStyle.Top;
+      this.regionNameLabel.Location = new System.Drawing.Point(0, 0);
+      this.regionNameLabel.Name = "regionNameLabel";
+      this.regionNameLabel.Size = new System.Drawing.Size(292, 14);
+      this.regionNameLabel.TabIndex = 0;
+      this.regionNameLabel.TabStop = true;
+      this.regionNameLabel.Text = "AT111";
+      this.regionNameLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+      this.regionNameLabel.Click += new System.EventHandler(this.regionNameLabel_Click);
+      // 
+      // regionDescriptionLabel
+      // 
+      this.regionDescriptionLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.regionDescriptionLabel.Location = new System.Drawing.Point(0, 14);
+      this.regionDescriptionLabel.MaximumSize = new System.Drawing.Size(500, 13);
+      this.regionDescriptionLabel.Name = "regionDescriptionLabel";
+      this.regionDescriptionLabel.Size = new System.Drawing.Size(292, 13);
+      this.regionDescriptionLabel.TabIndex = 8;
+      this.regionDescriptionLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+      // 
+      // BioBoostRegionDetailView
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Controls.Add(plantsGroupBox);
+      this.Controls.Add(this.regionDescriptionLabel);
+      this.Controls.Add(this.regionNameLabel);
+      this.Name = "BioBoostRegionDetailView";
+      this.Size = new System.Drawing.Size(292, 569);
+      plantsGroupBox.ResumeLayout(false);
+      ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).EndInit();
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.LinkLabel regionNameLabel;
+    private System.Windows.Forms.Label regionDescriptionLabel;
+    private System.Windows.Forms.DataGridView dataGridView;
+    private System.Windows.Forms.DataGridViewTextBoxColumn NameColumn;
+    private System.Windows.Forms.DataGridViewTextBoxColumn ValueColumn;
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostRegionDetailView.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostRegionDetailView.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostRegionDetailView.cs	(revision 15711)
@@ -0,0 +1,105 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.BioBoost.Representation;
+using HeuristicLab.Core.Views;
+using HeuristicLab.MainForm;
+using SharpMap.Data;
+using System;
+using System.ComponentModel;
+using System.Linq;
+
+namespace HeuristicLab.BioBoost.Views {
+
+  [Content(typeof(RegionDetailData), IsDefaultView = true)]
+  public partial class BioBoostRegionDetailView : ItemView {
+
+    public new RegionDetailData Content {
+      get { return (RegionDetailData)base.Content; }
+      set { base.Content = value; }
+    }
+
+    public BioBoostRegionDetailView() {
+      InitializeComponent();
+    }
+
+    protected override void DeregisterContentEvents() {
+      base.DeregisterContentEvents();
+    }
+
+    protected override void RegisterContentEvents() {
+      base.RegisterContentEvents();
+    }
+
+    protected override void SetEnabledStateOfControls() {
+      base.SetEnabledStateOfControls();
+      dataGridView.Enabled = Content != null;
+    }
+
+    protected override void OnContentChanged() {
+      base.OnContentChanged();
+      if (Content == null) {
+        Clear();
+      } else {
+        Clear();
+        Populate(Content.Solution, Content.RegionName);
+      }
+    }
+
+    public event EventHandler RegionLabelClicked;
+
+    protected void OnRegionLabelClicked() {
+      EventHandler h = RegionLabelClicked;
+      if (h != null)
+        h.Invoke(this, EventArgs.Empty);
+    }
+
+    private void Populate(BioBoostCompoundSolution solution, string regionName) {
+      regionNameLabel.Text = regionName; regionDescriptionLabel.Text = GetRegionDescription(regionName);
+      var locidx = solution.LocationNames.IndexOfFirst(s => s == regionName);
+      if (locidx < 0) return;
+      dataGridView.Rows.Clear();
+      foreach (var array in solution.DoubleValues) {
+        dataGridView.Rows.Add(array.Key, array.Value[locidx]);
+      }
+      dataGridView.Sort(NameColumn, ListSortDirection.Ascending);
+    }
+
+    private void Clear() {
+      regionNameLabel.Text = "";
+      regionDescriptionLabel.Text = "";
+      dataGridView.Rows.Clear();
+    }
+
+    private string GetRegionDescription(string regionName) {
+      if (regionName != null && Content.Solution.Geometry.Features.Columns.Contains("name")) {
+        var row = Content.Solution.Geometry.Features.Rows.Cast<FeatureDataRow>().FirstOrDefault(r => (string)r["NUTS_ID"] == regionName);
+        if (row != null)
+          return row["name"].ToString();
+      }
+      return "";
+    }
+
+    private void regionNameLabel_Click(object sender, EventArgs e) {
+      OnRegionLabelClicked();
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostRegionDetailView.resx
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostRegionDetailView.resx	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostRegionDetailView.resx	(revision 15711)
@@ -0,0 +1,129 @@
+﻿<?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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <metadata name="plantsGroupBox.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>False</value>
+  </metadata>
+  <metadata name="NameColumn.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
+  <metadata name="ValueColumn.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
+</root>
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionCostsView.Designer.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionCostsView.Designer.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionCostsView.Designer.cs	(revision 15711)
@@ -0,0 +1,158 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.BioBoost.Views {
+  partial class BioBoostSolutionCostsView {
+    /// <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.costsGroupBox = new System.Windows.Forms.GroupBox();
+      this.costsTextBox1 = new System.Windows.Forms.TextBox();
+      this.costsTextBox1Label = new System.Windows.Forms.Label();
+      this.costsDataGridView = new System.Windows.Forms.DataGridView();
+      this.costsColumn1 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+      this.costsColumn2 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+      this.costsGroupBox.SuspendLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.costsDataGridView)).BeginInit();
+      this.SuspendLayout();
+      // 
+      // costsGroupBox
+      // 
+      this.costsGroupBox.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.costsGroupBox.Controls.Add(this.costsTextBox1);
+      this.costsGroupBox.Controls.Add(this.costsTextBox1Label);
+      this.costsGroupBox.Controls.Add(this.costsDataGridView);
+      this.costsGroupBox.Location = new System.Drawing.Point(0, 0);
+      this.costsGroupBox.Name = "costsGroupBox";
+      this.costsGroupBox.Size = new System.Drawing.Size(349, 417);
+      this.costsGroupBox.TabIndex = 3;
+      this.costsGroupBox.TabStop = false;
+      this.costsGroupBox.Text = "Costs Summary";
+      // 
+      // costsTextBox1
+      // 
+      this.costsTextBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+      this.costsTextBox1.BackColor = System.Drawing.SystemColors.Window;
+      this.costsTextBox1.BorderStyle = System.Windows.Forms.BorderStyle.None;
+      this.costsTextBox1.Font = new System.Drawing.Font("Lucida Console", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+      this.costsTextBox1.Location = new System.Drawing.Point(209, 399);
+      this.costsTextBox1.Name = "costsTextBox1";
+      this.costsTextBox1.ReadOnly = true;
+      this.costsTextBox1.Size = new System.Drawing.Size(134, 11);
+      this.costsTextBox1.TabIndex = 4;
+      this.costsTextBox1.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
+      // 
+      // costsTextBox1Label
+      // 
+      this.costsTextBox1Label.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+      this.costsTextBox1Label.AutoSize = true;
+      this.costsTextBox1Label.Location = new System.Drawing.Point(120, 397);
+      this.costsTextBox1Label.Name = "costsTextBox1Label";
+      this.costsTextBox1Label.Size = new System.Drawing.Size(89, 13);
+      this.costsTextBox1Label.TabIndex = 3;
+      this.costsTextBox1Label.Text = "Total Costs (€/a):";
+      // 
+      // costsDataGridView
+      // 
+      this.costsDataGridView.AllowUserToAddRows = false;
+      this.costsDataGridView.AllowUserToDeleteRows = false;
+      this.costsDataGridView.AllowUserToResizeRows = false;
+      this.costsDataGridView.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.costsDataGridView.BackgroundColor = System.Drawing.SystemColors.Window;
+      this.costsDataGridView.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
+      this.costsDataGridView.CellBorderStyle = System.Windows.Forms.DataGridViewCellBorderStyle.None;
+      this.costsDataGridView.ColumnHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.None;
+      this.costsDataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
+      this.costsDataGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
+            this.costsColumn1,
+            this.costsColumn2});
+      this.costsDataGridView.Location = new System.Drawing.Point(6, 19);
+      this.costsDataGridView.Name = "costsDataGridView";
+      this.costsDataGridView.ReadOnly = true;
+      this.costsDataGridView.RowHeadersVisible = false;
+      this.costsDataGridView.RowTemplate.Height = 16;
+      this.costsDataGridView.Size = new System.Drawing.Size(337, 374);
+      this.costsDataGridView.TabIndex = 0;
+      // 
+      // costsColumn1
+      // 
+      this.costsColumn1.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
+      this.costsColumn1.HeaderText = "Item";
+      this.costsColumn1.Name = "costsColumn1";
+      this.costsColumn1.ReadOnly = true;
+      // 
+      // costsColumn2
+      // 
+      this.costsColumn2.HeaderText = "€/a";
+      this.costsColumn2.MinimumWidth = 50;
+      this.costsColumn2.Name = "costsColumn2";
+      this.costsColumn2.ReadOnly = true;
+      this.costsColumn2.Width = 120;
+      // 
+      // BioBoostSolutionCostsView
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Controls.Add(this.costsGroupBox);
+      this.Name = "BioBoostSolutionCostsView";
+      this.Size = new System.Drawing.Size(349, 417);
+      this.costsGroupBox.ResumeLayout(false);
+      this.costsGroupBox.PerformLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.costsDataGridView)).EndInit();
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.GroupBox costsGroupBox;
+    private System.Windows.Forms.DataGridView costsDataGridView;
+    private System.Windows.Forms.DataGridViewTextBoxColumn costsColumn1;
+    private System.Windows.Forms.DataGridViewTextBoxColumn costsColumn2;
+    private System.Windows.Forms.TextBox costsTextBox1;
+    private System.Windows.Forms.Label costsTextBox1Label;
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionCostsView.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionCostsView.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionCostsView.cs	(revision 15711)
@@ -0,0 +1,196 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.BioBoost.Representation;
+using HeuristicLab.Core.Views;
+using HeuristicLab.Data;
+using HeuristicLab.MainForm;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace HeuristicLab.BioBoost.Views {
+
+  [Content(typeof(RegionDetailData), IsDefaultView = false)]
+  public partial class BioBoostSolutionCostsView : ItemView {
+
+    public new RegionDetailData Content {
+      get { return (RegionDetailData)base.Content; }
+      set { base.Content = value; }
+    }
+    
+    public BioBoostSolutionCostsView() {
+      InitializeComponent();
+    }
+
+    protected override void OnContentChanged() {
+      base.OnContentChanged();
+      if (Content == null) {
+        Clear();
+      } else {
+        Clear();
+        Populate(Content.Solution, Content.RegionName);
+      }
+    }
+
+    private Dictionary<string, double> costs;
+    private Dictionary<String, double> values; 
+    private Dictionary<string, List<string>> strings;
+
+    private void AddCost(string name, double value) {
+      // ReSharper disable once CompareOfFloatsByEqualityOperator
+      if (value == 0) return;
+      double oldValue = 0;
+      costs.TryGetValue(name, out oldValue);
+      costs[name] = oldValue + value;
+    }
+
+    private void AddSummableValue(string name, double value) {
+      // ReSharper disable once CompareOfFloatsByEqualityOperator
+      if (value == 0) return;
+      double oldValue = 0;
+      values.TryGetValue(name, out oldValue);
+      values[name] = oldValue + value;
+    }
+
+    private void AddString(string name, string value) {
+      if (string.IsNullOrEmpty(value) || value == "0") return;
+      List<String> oldValues;
+      if (!strings.TryGetValue(name, out oldValues)) {
+        oldValues = new List<string>();
+        strings[name] = oldValues;
+      }
+      if (oldValues.Count < 2) {
+        oldValues.Add(value);
+      }
+    }
+    
+
+    private void AddSupplierCosts(string name, DoubleArray values, List<int> supplierIndices) {
+      if (values == null) return;
+      double sum = 0;
+      foreach (var supplierIdx in supplierIndices) {
+        sum += values[supplierIdx];
+      }
+      AddCost(name + " Sum", sum);
+      if (supplierIndices.Count > 1)
+        AddString(name + " Avg", (sum/supplierIndices.Count).ToString(CultureInfo.InvariantCulture));
+    }
+
+    private void AddSupplierValues(string name, DoubleArray values, List<int> supplierIndices) {
+      if (values == null) return;
+      double sum = 0;
+      foreach (var supplierIdx in supplierIndices) {
+        sum += values[supplierIdx];
+      }
+      AddSummableValue(name + " Sum", sum);
+      if (supplierIndices.Count > 1)
+        AddString(name + " Avg", (sum/supplierIndices.Count).ToString(CultureInfo.InvariantCulture));
+    }
+
+
+    private void Populate(BioBoostCompoundSolution solution, string regionName) {
+      costsColumn2.DefaultCellStyle.Font = new Font("Lucida Console", 7);
+      costsColumn2.DefaultCellStyle.Format = "N0";
+      costsColumn2.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
+
+      costs = new Dictionary<string, double>();
+      values = new Dictionary<string, double>();
+      strings = new Dictionary<string, List<string>>();
+      foreach (var locationName in solution.LocationNames) {
+        if (regionName == BioBoostCompoundSolutionView.AllRegionsName || locationName.StartsWith(regionName))
+          AddRegion(solution, locationName);
+      }
+
+      var totalCost = 0d;
+      foreach (var cost in costs) {
+        costsDataGridView.Rows.Add(cost.Key, cost.Value);
+        totalCost += cost.Value;
+      }
+
+      foreach (var value in values) {
+        costsDataGridView.Rows.Add(value.Key, value.Value);
+      }
+
+      foreach (var value in strings) {
+        if (value.Value.Count == 1) {
+          double doubleValue;
+          if (Double.TryParse(value.Value[0], NumberStyles.Float, CultureInfo.InvariantCulture, out doubleValue)) {
+            costsDataGridView.Rows.Add(value.Key, doubleValue);
+          } else {
+          costsDataGridView.Rows.Add(value.Key, value.Value[0]);
+          }
+        } else {
+          //costsDataGridView.Rows.Add(value.Key, string.Join(",", value.Value));
+        }
+      }
+
+      /* var total = 0d;
+      foreach (var kvp in solution.DoubleValues) {
+        var name = kvp.Key;
+        if (name.EndsWith(BioBoostProblem.CostsName) || name.EndsWith(BioBoostProblem.CostName)) {
+          var sum = 0d;
+          for (int i = 0; i < kvp.Value.Length; i++) {
+            if (solution.LocationNames[i].StartsWith(regionName) || regionName.Equals(BioBoostCompoundSolutionView.AllRegionsName)) {
+              sum += kvp.Value[i];
+            }
+          }
+          if (name.EndsWith(BioBoostProblem.CostName)) {
+            name = name.Replace(BioBoostProblem.CostName, string.Empty);
+          } else {
+            name = name.Replace(BioBoostProblem.CostsName, string.Empty);
+          }
+          costsDataGridView.Rows.Add(name, sum);
+          total += sum;
+        }
+      } */
+      costsTextBox1.Text = totalCost.ToString("N0");
+    }
+
+    private void AddRegion(BioBoostCompoundSolution solution, string regionName) {
+      var supplierCollector = new SupplierCollector(solution, regionName);
+      foreach (var product in supplierCollector.Products) {
+        AddSummableValue(LayerDescriptor.ConverterCapacities.NameWithPrefix(product.Name), product.ConverterCapacity);
+        AddSummableValue(LayerDescriptor.StorageCapacities.NameWithPrefix(product.Name), product.StorageCapacity);
+        AddCost(LayerDescriptor.ConversionCosts.NameWithPrefix(product.Name), product.ConversionCost);
+        AddCost(LayerDescriptor.StorageCost.NameWithPrefix(product.Name), product.StorageCost);
+        AddCost(LayerDescriptor.ConversionPlantConstructionCost.NameWithPrefix(product.Name), product.ConversionPlantConstructionCost);
+        AddCost(LayerDescriptor.ConversionPlantOperationCost.NameWithPrefix(product.Name), product.ConversionPlantOperationCost);
+        AddString(LayerDescriptor.TransportTargets.NameWithPrefix(product.Name), product.TargetName);
+        AddSupplierValues(LayerDescriptor.AmountsTransportedFromSource.NameWithPrefix(product.Name), product.TransportedAmounts, product.SuppliersIndices);
+        AddSupplierValues(LayerDescriptor.TransportDistance.NameWithPrefix(product.Name), product.TransportDistances, product.SuppliersIndices);
+        AddSupplierValues(LayerDescriptor.Tkm.NameWithPrefix(product.Name), product.Tkm, product.SuppliersIndices);
+        AddSupplierValues(LayerDescriptor.RelativeCostAtSource.NameWithPrefix(product.Name), product.RelativeProductionCosts, product.SuppliersIndices); // TODO: really?
+        AddSupplierCosts(LayerDescriptor.TotalCostsAtSource.NameWithPrefix(product.Name), product.AcquisitionCosts, product.SuppliersIndices);
+        AddSupplierCosts(LayerDescriptor.DischargeCosts.NameWithPrefix(product.Name), product.DischargeCosts, product.SuppliersIndices);
+        AddSupplierCosts(LayerDescriptor.TransportCosts.NameWithPrefix(product.Name), product.TransportCosts, product.SuppliersIndices);
+        AddSupplierCosts(LayerDescriptor.HandlingCosts.NameWithPrefix(product.Name), product.HandlingCosts, product.SuppliersIndices);
+      }
+    }
+
+    private void Clear() {
+      costsDataGridView.Rows.Clear();
+      costsTextBox1.Text = string.Empty;
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionCostsView.resx
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionCostsView.resx	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionCostsView.resx	(revision 15711)
@@ -0,0 +1,126 @@
+﻿<?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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <metadata name="costsColumn1.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
+  <metadata name="costsColumn2.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
+</root>
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionDetailView.Designer.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionDetailView.Designer.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionDetailView.Designer.cs	(revision 15711)
@@ -0,0 +1,145 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.BioBoost.Views {
+  partial class BioBoostSolutionDetailView {
+    /// <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() {
+      System.Windows.Forms.GroupBox plantsGroupBox;
+      System.Windows.Forms.TreeNode treeNode1 = new System.Windows.Forms.TreeNode("AT111 (100t/a)");
+      System.Windows.Forms.TreeNode treeNode2 = new System.Windows.Forms.TreeNode("AT112 (200t/a)");
+      System.Windows.Forms.TreeNode treeNode3 = new System.Windows.Forms.TreeNode("FP (1000t/a)", new System.Windows.Forms.TreeNode[] {
+            treeNode1,
+            treeNode2});
+      System.Windows.Forms.TreeNode treeNode4 = new System.Windows.Forms.TreeNode("HTC");
+      System.Windows.Forms.TreeNode treeNode5 = new System.Windows.Forms.TreeNode("CP");
+      this.plantsTreeView = new System.Windows.Forms.TreeView();
+      this.regionNameLabel = new System.Windows.Forms.LinkLabel();
+      this.regionDescriptionLabel = new System.Windows.Forms.Label();
+      plantsGroupBox = new System.Windows.Forms.GroupBox();
+      plantsGroupBox.SuspendLayout();
+      this.SuspendLayout();
+      // 
+      // plantsGroupBox
+      // 
+      plantsGroupBox.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)));
+      plantsGroupBox.Controls.Add(this.plantsTreeView);
+      plantsGroupBox.Location = new System.Drawing.Point(3, 30);
+      plantsGroupBox.Name = "plantsGroupBox";
+      plantsGroupBox.Size = new System.Drawing.Size(286, 536);
+      plantsGroupBox.TabIndex = 4;
+      plantsGroupBox.TabStop = false;
+      plantsGroupBox.Text = "Plant Configurations";
+      // 
+      // plantsTreeView
+      // 
+      this.plantsTreeView.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.plantsTreeView.Font = new System.Drawing.Font("Lucida Console", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+      this.plantsTreeView.HotTracking = true;
+      this.plantsTreeView.Location = new System.Drawing.Point(7, 20);
+      this.plantsTreeView.Name = "plantsTreeView";
+      treeNode1.Name = "Node3";
+      treeNode1.Text = "AT111 (100t/a)";
+      treeNode2.Name = "AT112";
+      treeNode2.Text = "AT112 (200t/a)";
+      treeNode3.Name = "FP";
+      treeNode3.Text = "FP (1000t/a)";
+      treeNode4.Name = "HTC";
+      treeNode4.Text = "HTC";
+      treeNode5.Name = "CP";
+      treeNode5.Text = "CP";
+      this.plantsTreeView.Nodes.AddRange(new System.Windows.Forms.TreeNode[] {
+            treeNode3,
+            treeNode4,
+            treeNode5});
+      this.plantsTreeView.Size = new System.Drawing.Size(273, 510);
+      this.plantsTreeView.TabIndex = 0;
+      this.plantsTreeView.NodeMouseClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(this.plantsTreeView_NodeMouseDoubleClick);
+      // 
+      // regionNameLabel
+      // 
+      this.regionNameLabel.ActiveLinkColor = System.Drawing.Color.Red;
+      this.regionNameLabel.Dock = System.Windows.Forms.DockStyle.Top;
+      this.regionNameLabel.Location = new System.Drawing.Point(0, 0);
+      this.regionNameLabel.Name = "regionNameLabel";
+      this.regionNameLabel.Size = new System.Drawing.Size(292, 14);
+      this.regionNameLabel.TabIndex = 0;
+      this.regionNameLabel.TabStop = true;
+      this.regionNameLabel.Text = "AT111";
+      this.regionNameLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+      this.regionNameLabel.Click += new System.EventHandler(this.regionNameLabel_Click);
+      // 
+      // regionDescriptionLabel
+      // 
+      this.regionDescriptionLabel.Dock = System.Windows.Forms.DockStyle.Top;
+      this.regionDescriptionLabel.Location = new System.Drawing.Point(0, 14);
+      this.regionDescriptionLabel.MaximumSize = new System.Drawing.Size(500, 13);
+      this.regionDescriptionLabel.Name = "regionDescriptionLabel";
+      this.regionDescriptionLabel.Size = new System.Drawing.Size(292, 13);
+      this.regionDescriptionLabel.TabIndex = 8;
+      this.regionDescriptionLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+      // 
+      // BioBoostSolutionDetailView
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Controls.Add(plantsGroupBox);
+      this.Controls.Add(this.regionDescriptionLabel);
+      this.Controls.Add(this.regionNameLabel);
+      this.Name = "BioBoostSolutionDetailView";
+      this.Size = new System.Drawing.Size(292, 569);
+      plantsGroupBox.ResumeLayout(false);
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.TreeView plantsTreeView;
+    private System.Windows.Forms.LinkLabel regionNameLabel;
+    private System.Windows.Forms.Label regionDescriptionLabel;
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionDetailView.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionDetailView.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionDetailView.cs	(revision 15711)
@@ -0,0 +1,152 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Globalization;
+using HeuristicLab.BioBoost.Representation;
+using HeuristicLab.Core.Views;
+using HeuristicLab.MainForm;
+using SharpMap.Data;
+using System;
+using System.Linq;
+using System.Windows.Forms;
+using System.Windows.Forms.DataVisualization.Charting;
+
+namespace HeuristicLab.BioBoost.Views {
+
+  [Content(typeof(RegionDetailData), IsDefaultView = false)]
+  public partial class BioBoostSolutionDetailView : ItemView {
+
+    public new RegionDetailData Content {
+      get { return (RegionDetailData)base.Content; }
+      set { base.Content = value; }
+    }
+
+    public BioBoostSolutionDetailView() {
+      InitializeComponent();
+    }
+
+    protected override void DeregisterContentEvents() {
+      base.DeregisterContentEvents();
+    }
+
+    protected override void RegisterContentEvents() {
+      base.RegisterContentEvents();
+    }
+
+    protected override void SetEnabledStateOfControls() {
+      base.SetEnabledStateOfControls();
+      plantsTreeView.Enabled = Content != null;
+    }
+
+    protected override void OnContentChanged() {
+      base.OnContentChanged();
+      if (Content == null) {
+        Clear();
+      } else {
+        Clear();
+        Populate(Content.Solution, Content.RegionName);
+      }
+    }
+
+    public event EventHandler RegionLabelClicked;
+
+    protected void OnRegionLabelClicked() {
+      EventHandler h = RegionLabelClicked;
+      if (h != null)
+        h.Invoke(this, EventArgs.Empty);
+    }
+
+    private void Populate(BioBoostCompoundSolution solution, string regionName) {
+      regionNameLabel.Text = regionName; regionDescriptionLabel.Text = GetRegionDescription(regionName);
+      var locidx = solution.LocationNames.IndexOfFirst(s => s == regionName);
+      if (locidx < 0) return;
+      var supplierCollector = new SupplierCollector(solution, regionName);
+      foreach (var feedstock in supplierCollector.Feedstocks)
+        AddFeedstock(feedstock);
+      foreach (var product in supplierCollector.Products)
+        AddPlant(product);
+    }
+
+    private void Clear() {
+      regionNameLabel.Text = "";
+      regionDescriptionLabel.Text = "";
+      plantsTreeView.Nodes.Clear();
+    }
+
+    private void AddFeedstock(SupplierCollector.ProductInfo product) {
+      var potentialSeries = new Series(product.Name);
+      potentialSeries.Points.Add(product.Potential);
+      potentialSeries.ChartType = SeriesChartType.StackedBar100;
+    }
+
+    private void AddPlant(SupplierCollector.ProductInfo product) {
+      var totalAmount = product.Suppliers.Values.Sum();
+      if (totalAmount > 0) {
+        plantsTreeView.Nodes.Add(string.Format("{0} {1,11:### ### ###} t/a", product.Name, totalAmount));
+        foreach (var s in product.Suppliers)
+          AddSupplier(product.Name, s.Key, s.Value);
+      }
+    }
+
+    private void AddSupplier(string type, string sourceName, double feedstockAmount) {
+      foreach (TreeNode node in plantsTreeView.Nodes) {
+        if (node.Text.StartsWith(type)) {
+          node.Nodes.Add(string.Format(CultureInfo.InvariantCulture, "{0} {1,9:# ### ###} t/a", sourceName, feedstockAmount));
+          if (plantsTreeView.Nodes.Count == 1)
+            node.Expand();
+          else
+            plantsTreeView.CollapseAll();
+          break;
+        }
+      }
+    }
+
+    private string GetRegionDescription(string regionName) {
+      if (regionName != null && Content.Solution.Geometry.Features.Columns.Contains("name")) {
+        var row = Content.Solution.Geometry.Features.Rows.Cast<FeatureDataRow>().FirstOrDefault(r => (string)r["NUTS_ID"] == regionName);
+        if (row != null)
+          return row["name"].ToString();
+      }
+      return "";
+    }
+
+    private void plantsTreeView_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e) {
+      if (e.Node.Parent != null) { // child node clicked
+        var labeltext = e.Node.Text.Split(' ');
+        if (labeltext.Length > 0)
+          TrySwitchToRegion(labeltext[0]);
+      }
+    }
+
+    private void TrySwitchToRegion(string regionName) {
+      if (Content.Solution.LocationNames.Contains(regionName)) {
+        Content = new RegionDetailData {
+          Solution = Content.Solution,
+          RegionName = regionName
+        };
+      }
+    }
+
+    private void regionNameLabel_Click(object sender, EventArgs e) {
+      OnRegionLabelClicked();
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionDetailView.resx
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionDetailView.resx	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionDetailView.resx	(revision 15711)
@@ -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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <metadata name="plantsGroupBox.GenerateMember" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>False</value>
+  </metadata>
+</root>
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionHistoryView.Designer.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionHistoryView.Designer.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionHistoryView.Designer.cs	(revision 15711)
@@ -0,0 +1,53 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.BioBoost.Views {
+  partial class BioBoostSolutionHistoryView {
+    /// <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() {
+      components = new System.ComponentModel.Container();
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+    }
+
+    #endregion
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionHistoryView.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionHistoryView.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSolutionHistoryView.cs	(revision 15711)
@@ -0,0 +1,61 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Text.RegularExpressions;
+using System.Windows.Forms;
+using HeuristicLab.BioBoost.Representation;
+using HeuristicLab.Core;
+using HeuristicLab.Core.Views;
+using HeuristicLab.MainForm;
+
+namespace HeuristicLab.BioBoost.Views {
+
+  [Content(typeof (ItemCollection<BioBoostCompoundSolution>), false)]
+  public partial class BioBoostSolutionHistoryView : MovieView<BioBoostCompoundSolution> {
+
+    private string firstFileName;
+    private readonly SaveFileDialog saveFileDialog = new SaveFileDialog();
+
+    public BioBoostSolutionHistoryView() {
+      InitializeComponent();
+    }
+
+    protected override void playButton_Click(object sender, EventArgs e) {
+      if (saveFileDialog.ShowDialog() == DialogResult.OK) {
+        firstFileName = saveFileDialog.FileName;
+      }
+      base.playButton_Click(sender, e);
+    }
+
+    private static readonly Regex FILENAME_REGEX = new Regex(@"(.*)(-\d+)?(\.png)?", RegexOptions.IgnoreCase);
+
+    protected override void trackBar_ValueChanged(object sender, EventArgs e) {
+      base.trackBar_ValueChanged(sender, e);
+      var solution = viewHost.Content as BioBoostCompoundSolution;
+      var view = viewHost.ActiveView as BioBoostCompoundSolutionView;
+      if (view != null && solution != null) {
+        var filename = firstFileName.Replace(".png", string.Format("-{0:000000}.png", trackBar.Value));
+        view.SaveMapViewToPNG(filename);
+      }
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSummaryView.Designer.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSummaryView.Designer.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSummaryView.Designer.cs	(revision 15711)
@@ -0,0 +1,176 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.BioBoost.Views {
+  partial class BioBoostSummaryView {
+    /// <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.splitContainer1 = new System.Windows.Forms.SplitContainer();
+      this.treeView = new System.Windows.Forms.TreeView();
+      this.gridView = new System.Windows.Forms.DataGridView();
+      this.NameColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
+      this.ValueColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
+      this.valueLabel = new System.Windows.Forms.Label();
+      this.regionLabel = new System.Windows.Forms.Label();
+      ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
+      this.splitContainer1.Panel1.SuspendLayout();
+      this.splitContainer1.Panel2.SuspendLayout();
+      this.splitContainer1.SuspendLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.gridView)).BeginInit();
+      this.SuspendLayout();
+      // 
+      // splitContainer1
+      // 
+      this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
+      this.splitContainer1.Location = new System.Drawing.Point(0, 0);
+      this.splitContainer1.Name = "splitContainer1";
+      // 
+      // splitContainer1.Panel1
+      // 
+      this.splitContainer1.Panel1.Controls.Add(this.valueLabel);
+      this.splitContainer1.Panel1.Controls.Add(this.treeView);
+      // 
+      // splitContainer1.Panel2
+      // 
+      this.splitContainer1.Panel2.Controls.Add(this.regionLabel);
+      this.splitContainer1.Panel2.Controls.Add(this.gridView);
+      this.splitContainer1.Size = new System.Drawing.Size(1041, 624);
+      this.splitContainer1.SplitterDistance = 421;
+      this.splitContainer1.TabIndex = 0;
+      // 
+      // treeView
+      // 
+      this.treeView.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.treeView.Location = new System.Drawing.Point(0, 21);
+      this.treeView.Name = "treeView";
+      this.treeView.Size = new System.Drawing.Size(419, 603);
+      this.treeView.TabIndex = 0;
+      this.treeView.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeView_AfterSelect);
+      // 
+      // gridView
+      // 
+      this.gridView.AllowUserToAddRows = false;
+      this.gridView.AllowUserToDeleteRows = false;
+      this.gridView.AllowUserToResizeRows = false;
+      this.gridView.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.gridView.AutoSizeColumnsMode = System.Windows.Forms.DataGridViewAutoSizeColumnsMode.AllCells;
+      this.gridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
+      this.gridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
+            this.NameColumn,
+            this.ValueColumn});
+      this.gridView.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically;
+      this.gridView.Location = new System.Drawing.Point(0, 21);
+      this.gridView.Name = "gridView";
+      this.gridView.ReadOnly = true;
+      this.gridView.RowHeadersVisible = false;
+      this.gridView.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
+      this.gridView.Size = new System.Drawing.Size(616, 603);
+      this.gridView.TabIndex = 0;
+      this.gridView.CurrentCellChanged += new System.EventHandler(this.gridView_CurrentCellChanged);
+      // 
+      // NameColumn
+      // 
+      this.NameColumn.HeaderText = "Name";
+      this.NameColumn.Name = "NameColumn";
+      this.NameColumn.ReadOnly = true;
+      this.NameColumn.Width = 60;
+      // 
+      // ValueColumn
+      // 
+      this.ValueColumn.HeaderText = "Value";
+      this.ValueColumn.Name = "ValueColumn";
+      this.ValueColumn.ReadOnly = true;
+      this.ValueColumn.Width = 59;
+      // 
+      // valueLabel
+      // 
+      this.valueLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.valueLabel.Location = new System.Drawing.Point(3, 0);
+      this.valueLabel.Name = "valueLabel";
+      this.valueLabel.Size = new System.Drawing.Size(416, 18);
+      this.valueLabel.TabIndex = 1;
+      this.valueLabel.Text = "no value layer selected";
+      this.valueLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+      // 
+      // regionLabel
+      // 
+      this.regionLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.regionLabel.Location = new System.Drawing.Point(3, 0);
+      this.regionLabel.Name = "regionLabel";
+      this.regionLabel.Size = new System.Drawing.Size(610, 18);
+      this.regionLabel.TabIndex = 2;
+      this.regionLabel.Text = "no region selected";
+      this.regionLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+      // 
+      // BioBoostSummaryView
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Controls.Add(this.splitContainer1);
+      this.Name = "BioBoostSummaryView";
+      this.Size = new System.Drawing.Size(1041, 624);
+      this.splitContainer1.Panel1.ResumeLayout(false);
+      this.splitContainer1.Panel2.ResumeLayout(false);
+      ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
+      this.splitContainer1.ResumeLayout(false);
+      ((System.ComponentModel.ISupportInitialize)(this.gridView)).EndInit();
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.SplitContainer splitContainer1;
+    private System.Windows.Forms.TreeView treeView;
+    private System.Windows.Forms.DataGridView gridView;
+    private System.Windows.Forms.DataGridViewTextBoxColumn NameColumn;
+    private System.Windows.Forms.DataGridViewTextBoxColumn ValueColumn;
+    private System.Windows.Forms.Label valueLabel;
+    private System.Windows.Forms.Label regionLabel;
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSummaryView.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSummaryView.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSummaryView.cs	(revision 15711)
@@ -0,0 +1,194 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.ComponentModel;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+using HeuristicLab.Core.Views;
+using HeuristicLab.Data;
+using HeuristicLab.MainForm;
+
+namespace HeuristicLab.BioBoost.Views {
+
+  [Content(typeof(RegionDetailData), IsDefaultView = false)]
+  public partial class BioBoostSummaryView : ItemView {
+
+    public new RegionDetailData Content {
+      get { return (RegionDetailData)base.Content; }
+      set { base.Content = value; }
+    }
+
+    public BioBoostSummaryView() {
+      InitializeComponent();
+    }
+
+    protected override void OnContentChanged() {
+      base.OnContentChanged();
+      if (Content == null) {
+        Clear();
+      } else {
+        Clear();
+        Populate();
+      }
+    }
+
+    protected void Clear() {
+      treeView.Nodes.Clear();
+      gridView.Rows.Clear();
+      regionLabel.Text = "no region selected";
+      valueLabel.Text = "no value selected";
+    }
+
+    protected void Populate() {
+      foreach (var targets in Content.Solution.TransportTargets) {
+        var node = treeView.Nodes.Add(targets.Key);
+        node.Tag = node.Text;
+        for (int i = 0; i < targets.Value.Length; i++) {
+          if (targets.Value[i] != null && targets.Value[i].Count > 0) {
+            var innerNode = node.Nodes.Add(Content.Solution.LocationNames[i]);
+            innerNode.Tag = innerNode.Text;
+            foreach (var suppliers in targets.Value[i]) {
+              var supplierNode = innerNode.Nodes.Add(Content.Solution.LocationNames[suppliers.Value]);
+              supplierNode.Tag = supplierNode.Text;
+            }
+          }
+        }
+      }
+      valueLabel.Text = "no value selected";
+      regionLabel.Text = Content.RegionName ?? "no region selected";
+    }
+
+    private void treeView_AfterSelect(object sender, TreeViewEventArgs e) {
+      gridView.Rows.Clear();
+      if (treeView.SelectedNode != null) {
+        var i = GetLocationIndex((string)treeView.SelectedNode.Tag);
+        if (i >= 0) {
+          PopulateGridView(i);
+        }
+      }
+    }
+
+    private int GetLocationIndex(string regionName) {
+      return Content.Solution.LocationNames.IndexOfFirst(x => x == regionName);
+    }
+
+    private double? GetValue(string regionName, string valueName) {
+      if (valueName == null) return null;
+      var i = GetLocationIndex(regionName);
+      if (i < 0) return 0;
+      DoubleArray doubles;
+      IntArray ints;
+      if (Content.Solution.DoubleValues.TryGetValue(valueName, out doubles)) {
+        return doubles[i];
+      } else if (Content.Solution.IntValues.TryGetValue(valueName, out ints)) {
+        return ints[i];
+      }
+      return null;
+    }
+
+    private void PopulateGridView(int index) {
+      regionLabel.Text = Content.Solution.LocationNames[index];
+      foreach (var kvp in Content.Solution.DoubleValues.Where(kvp => kvp.Value[index] != 0)) {
+        gridView.Rows.Add(kvp.Key, kvp.Value[index]);
+      }
+      foreach (var kvp in Content.Solution.IntValues.Where(kvp => kvp.Value[index] != 0)) {
+        gridView.Rows.Add(kvp.Key, kvp.Value[index]);
+      }
+      foreach (var kvp in Content.Solution.StringValues.Where(kvp => !string.IsNullOrWhiteSpace(kvp.Value[index]))) {
+        gridView.Rows.Add(kvp.Key, kvp.Value[index]);
+      }
+      foreach (var kvp in from kvp
+                            in Content.Solution.TransportTargets
+                          where kvp.Value[index] != null
+                          let s = string.Join(", ", kvp.Value[index])
+                          where !string.IsNullOrWhiteSpace(s) select kvp) {
+        gridView.Rows.Add(kvp.Key, string.Join(", ", kvp.Value[index]));
+      }
+      gridView.Sort(NameColumn, ListSortDirection.Ascending);
+    }
+
+    private void gridView_CurrentCellChanged(object sender, EventArgs e) {
+      string valueName = null;
+      if (gridView.SelectedRows.Count > 0) {
+        valueName = (string) gridView.SelectedRows[0].Cells[0].Value;
+      }
+      foreach (TreeNode rootNodes in treeView.Nodes) {
+        UpdateAggregatedValues(rootNodes, valueName);
+      }
+    }
+
+    private static string F(double value, int significantDigits = 6) {
+      int msd = (int)Math.Ceiling(Math.Log10(value));
+      int decimals = 6 - msd;
+      if (decimals <= 0) {
+        return value.ToString("### ### ### ### ### ### ### ### ### ### ### ### ###", CultureInfo.InvariantCulture);
+      } else if (decimals > significantDigits) {
+        return value.ToString("g2");
+      } else {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < msd; i+=3) {
+          if (sb.Length > 0) sb.Append(" ");
+          sb.Append("###");
+        }
+        sb.Append(".");
+        for (int i = 0; i < decimals; i += 3) {
+          if (sb[sb.Length-1] != '.') sb.Append(" ");
+          sb.Append("###");
+        }
+        return value.ToString(sb.ToString(), CultureInfo.InvariantCulture);
+      }
+    }
+
+    private double UpdateAggregatedValues(TreeNode node, string valueName) {
+      valueLabel.Text = valueName;
+      if (node.Nodes.Count == 0) {
+        var value = GetValue((string) node.Tag, valueName);
+        if (value.HasValue) {
+          node.Text = string.Format("{0} ({1})", node.Tag, F(value.Value));
+          return value.Value;
+        }
+        return 0;
+      }
+      double sum = 0;
+      int count = 0;
+      foreach (TreeNode subnode in node.Nodes) {
+        var subvalue = UpdateAggregatedValues(subnode, valueName);
+        sum += subvalue;
+        count++;
+      }
+      if (sum != 0) {
+        node.Text = string.Format("{0}   ({1} total,   {2} avg,    {3} count)", node.Tag, F(sum), F(sum/count), F(count));
+      } else {
+        var value = GetValue((string) node.Tag, valueName);
+        if (value.HasValue) {
+          node.Text = string.Format("{0} ({1})", node.Tag, F(value.Value));
+          return value.Value;
+        }
+        node.Text = (string) node.Tag;
+      }
+      return sum;
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSummaryView.resx
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSummaryView.resx	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/BioBoostSummaryView.resx	(revision 15711)
@@ -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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/EnumerableExtentions.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/EnumerableExtentions.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/EnumerableExtentions.cs	(revision 15711)
@@ -0,0 +1,41 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.BioBoost.Views {
+  public static class EnumerableExtentions {
+    /// <summary>
+    /// Returns the index of the first element in source matched by predicate.
+    /// </summary>
+    public static int IndexOfFirst<T>(this IEnumerable<T> source, Func<T, bool> predicate) {
+      int i = 0;
+      foreach (T item in source) {
+        if (predicate(item)) {
+          return i;
+        }
+        i++;
+      }
+      return -1;
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/FilterDialog.Designer.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/FilterDialog.Designer.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/FilterDialog.Designer.cs	(revision 15711)
@@ -0,0 +1,160 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.BioBoost.Views {
+  partial class FilterDialog {
+    /// <summary>
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary>
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Windows Form Designer generated code
+
+    /// <summary>
+    /// Required method for Designer support - do not modify
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      this.components = new System.ComponentModel.Container();
+      System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FilterDialog));
+      this.label1 = new System.Windows.Forms.Label();
+      this.textBox1 = new System.Windows.Forms.TextBox();
+      this.keepOption = new System.Windows.Forms.RadioButton();
+      this.removeOption = new System.Windows.Forms.RadioButton();
+      this.okButton = new System.Windows.Forms.Button();
+      this.cancelButton = new System.Windows.Forms.Button();
+      this.errorProvider1 = new System.Windows.Forms.ErrorProvider(this.components);
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider1)).BeginInit();
+      this.SuspendLayout();
+      // 
+      // label1
+      // 
+      this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.label1.Location = new System.Drawing.Point(13, 13);
+      this.label1.Name = "label1";
+      this.label1.Size = new System.Drawing.Size(445, 48);
+      this.label1.TabIndex = 0;
+      this.label1.Text = resources.GetString("label1.Text");
+      // 
+      // textBox1
+      // 
+      this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.textBox1.Location = new System.Drawing.Point(12, 89);
+      this.textBox1.Name = "textBox1";
+      this.textBox1.Size = new System.Drawing.Size(446, 20);
+      this.textBox1.TabIndex = 1;
+      this.textBox1.Text = "^(FR|BE|NL|LU)";
+      this.textBox1.Validating += new System.ComponentModel.CancelEventHandler(this.textBox1_Validating);
+      this.textBox1.Validated += new System.EventHandler(this.textBox1_Validated);
+      // 
+      // keepOption
+      // 
+      this.keepOption.AutoSize = true;
+      this.keepOption.Checked = true;
+      this.keepOption.Location = new System.Drawing.Point(12, 118);
+      this.keepOption.Name = "keepOption";
+      this.keepOption.Size = new System.Drawing.Size(49, 17);
+      this.keepOption.TabIndex = 2;
+      this.keepOption.TabStop = true;
+      this.keepOption.Text = "&keep";
+      this.keepOption.UseVisualStyleBackColor = true;
+      this.keepOption.CheckedChanged += new System.EventHandler(this.keepOption_CheckedChanged);
+      // 
+      // removeOption
+      // 
+      this.removeOption.AutoSize = true;
+      this.removeOption.Location = new System.Drawing.Point(67, 118);
+      this.removeOption.Name = "removeOption";
+      this.removeOption.Size = new System.Drawing.Size(60, 17);
+      this.removeOption.TabIndex = 3;
+      this.removeOption.Text = "&remove";
+      this.removeOption.UseVisualStyleBackColor = true;
+      this.removeOption.CheckedChanged += new System.EventHandler(this.keepOption_CheckedChanged);
+      // 
+      // okButton
+      // 
+      this.okButton.Location = new System.Drawing.Point(383, 115);
+      this.okButton.Name = "okButton";
+      this.okButton.Size = new System.Drawing.Size(75, 23);
+      this.okButton.TabIndex = 5;
+      this.okButton.Text = "&OK";
+      this.okButton.UseVisualStyleBackColor = true;
+      this.okButton.Click += new System.EventHandler(this.okButton_Click);
+      // 
+      // cancelButton
+      // 
+      this.cancelButton.Location = new System.Drawing.Point(302, 115);
+      this.cancelButton.Name = "cancelButton";
+      this.cancelButton.Size = new System.Drawing.Size(75, 23);
+      this.cancelButton.TabIndex = 4;
+      this.cancelButton.Text = "&Cancel";
+      this.cancelButton.UseVisualStyleBackColor = true;
+      this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
+      // 
+      // errorProvider1
+      // 
+      this.errorProvider1.ContainerControl = this;
+      // 
+      // FilterDialog
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.ClientSize = new System.Drawing.Size(470, 148);
+      this.ControlBox = false;
+      this.Controls.Add(this.cancelButton);
+      this.Controls.Add(this.okButton);
+      this.Controls.Add(this.removeOption);
+      this.Controls.Add(this.keepOption);
+      this.Controls.Add(this.textBox1);
+      this.Controls.Add(this.label1);
+      this.Name = "FilterDialog";
+      this.Text = "Filter Regions";
+      this.TopMost = true;
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider1)).EndInit();
+      this.ResumeLayout(false);
+      this.PerformLayout();
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.Label label1;
+    private System.Windows.Forms.TextBox textBox1;
+    private System.Windows.Forms.RadioButton keepOption;
+    private System.Windows.Forms.RadioButton removeOption;
+    private System.Windows.Forms.Button okButton;
+    private System.Windows.Forms.Button cancelButton;
+    private System.Windows.Forms.ErrorProvider errorProvider1;
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/FilterDialog.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/FilterDialog.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/FilterDialog.cs	(revision 15711)
@@ -0,0 +1,81 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.ComponentModel;
+using System.Text.RegularExpressions;
+using System.Windows.Forms;
+
+namespace HeuristicLab.BioBoost.Views {
+  public partial class FilterDialog : Form {
+
+    public Regex Regex { get; private set; }
+    public bool Keep { get; private set; }
+
+    public FilterDialog() {
+      InitializeComponent();
+      Keep = true;
+    }
+
+    protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
+      if (keyData == Keys.Enter) {
+        DialogResult = DialogResult.OK;
+        Close();
+        return true;
+      } else if (keyData == Keys.Escape) {
+        DialogResult = DialogResult.Cancel;
+        Close();
+        return true;
+      }
+      return base.ProcessCmdKey(ref msg, keyData);
+    }
+
+    private void textBox1_Validating(object sender, CancelEventArgs e) {
+      try {
+        Regex = new Regex(textBox1.Text, RegexOptions.IgnoreCase|RegexOptions.IgnorePatternWhitespace);
+      } catch (ArgumentException x) {
+        textBox1.Select(0, textBox1.Text.Length);
+        e.Cancel = true;
+        errorProvider1.SetError(textBox1, "not a valid regular expression.");
+      }
+    }
+
+    private void textBox1_Validated(object sender, EventArgs e) {
+      errorProvider1.SetError(textBox1, "");
+    }
+
+    private void cancelButton_Click(object sender, EventArgs e) {
+      DialogResult = DialogResult.Cancel;
+      Close();
+    }
+
+    private void okButton_Click(object sender, EventArgs e) {
+      DialogResult = DialogResult.OK;
+      Close();
+    }
+
+    private void keepOption_CheckedChanged(object sender, EventArgs e) {
+      Keep = keepOption.Checked;
+    }
+
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/FilterDialog.resx
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/FilterDialog.resx	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/FilterDialog.resx	(revision 15711)
@@ -0,0 +1,127 @@
+﻿<?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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="label1.Text" xml:space="preserve">
+    <value>Filter data according to region names. You can specify a regular expression for either the region names to keep, or the region names to remove.
+For example: '^(FR|BE|NL|LU)' selects France, Belgium, the Netherlands and Luxemburg.</value>
+  </data>
+  <metadata name="errorProvider1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 17</value>
+  </metadata>
+</root>
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/GeometryExtensions.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/GeometryExtensions.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/GeometryExtensions.cs	(revision 15711)
@@ -0,0 +1,38 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 GeoAPI.Geometries;
+using System.Collections.Generic;
+
+namespace HeuristicLab.BioBoost.Views {
+  public static class GeometryExtensions {
+    public static IGeometry[] ToArray(this IGeometry geom) {
+      var results = new IGeometry[geom.NumGeometries];
+      for (int i=0; i<results.Length; i++)
+        results[i] = geom.GetGeometryN(i);
+      return results;
+    }
+    public static IEnumerable<IGeometry> GetGeometries(this IGeometry geom) {
+      for (int i = 0; i<geom.NumGeometries; i++)
+        yield return geom.GetGeometryN(i);
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/HeuristicLab.Problems.BioBoost.Views-3.3.csproj
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/HeuristicLab.Problems.BioBoost.Views-3.3.csproj	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/HeuristicLab.Problems.BioBoost.Views-3.3.csproj	(revision 15711)
@@ -0,0 +1,404 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{473AB0CD-0B71-471D-968C-A543B197E134}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HeuristicLab.Problems.BioBoost.Views</RootNamespace>
+    <AssemblyName>HeuristicLab.Problems.BioBoost.Views-3.3</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <TargetFrameworkProfile />
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <CodeAnalysisLogFile>bin\Debug\HeuristicLab.BioBoost.Views.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+    <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+    <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+    <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+    <CodeAnalysisIgnoreBuiltInRuleSets>true</CodeAnalysisIgnoreBuiltInRuleSets>
+    <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+    <CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <CodeAnalysisLogFile>bin\Release\HeuristicLab.BioBoost.Views.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+    <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+    <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+    <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+    <CodeAnalysisIgnoreBuiltInRuleSets>true</CodeAnalysisIgnoreBuiltInRuleSets>
+    <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+    <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <CodeAnalysisLogFile>bin\Debug\HeuristicLab.BioBoost.Views.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+    <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+    <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+    <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+    <CodeAnalysisIgnoreBuiltInRuleSets>true</CodeAnalysisIgnoreBuiltInRuleSets>
+    <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+    <CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <CodeAnalysisLogFile>bin\Release\HeuristicLab.BioBoost.Views.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+    <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+    <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+    <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+    <CodeAnalysisIgnoreBuiltInRuleSets>true</CodeAnalysisIgnoreBuiltInRuleSets>
+    <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+    <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SignAssembly>false</SignAssembly>
+  </PropertyGroup>
+  <PropertyGroup>
+    <AssemblyOriginatorKeyFile>HeuristicLab.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="BruTile, Version=0.7.4.4, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\BruTile.0.7.4.4\lib\net40\BruTile.dll</HintPath>
+    </Reference>
+    <Reference Include="BruTile.Desktop, Version=0.7.4.4, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\BruTile.0.7.4.4\lib\net40\BruTile.Desktop.dll</HintPath>
+    </Reference>
+    <Reference Include="BruTile.MbTiles, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\BruTile.0.7.4.4\lib\net40\BruTile.MbTiles.dll</HintPath>
+    </Reference>
+    <Reference Include="BruTile.Serialization, Version=0.7.4.4, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\BruTile.0.7.4.4\lib\net40\BruTile.Serialization.dll</HintPath>
+    </Reference>
+    <Reference Include="Common.Logging, Version=2.0.0.0, Culture=neutral, PublicKeyToken=af08829b84f0328e, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\Common.Logging.2.0.0\lib\2.0\Common.Logging.dll</HintPath>
+    </Reference>
+    <Reference Include="GeoAPI, Version=1.7.2.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\GeoAPI.1.7.2\lib\net403-client\GeoAPI.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Collections-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=x86">
+      <SpecificVersion>False</SpecificVersion>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Common-3.3">
+      <HintPath>C:\Program Files\HeuristicLab 3.3\HeuristicLab.Common-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Core-3.3">
+      <HintPath>C:\Program Files\HeuristicLab 3.3\HeuristicLab.Core-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Core.Views-3.3">
+      <HintPath>C:\Program Files\HeuristicLab 3.3\HeuristicLab.Core.Views-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Data-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Encodings.IntegerVectorEncoding-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>C:\Program Files\HeuristicLab 3.3\HeuristicLab.Encodings.IntegerVectorEncoding-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.MainForm-3.3">
+      <HintPath>C:\Program Files\HeuristicLab 3.3\HeuristicLab.MainForm-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.MainForm.WindowsForms-3.3">
+      <HintPath>C:\Program Files\HeuristicLab 3.3\HeuristicLab.MainForm.WindowsForms-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Operators-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>C:\Program Files\HeuristicLab 3.3\HeuristicLab.Operators-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Optimization-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>C:\Program Files\HeuristicLab 3.3\HeuristicLab.Optimization-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Optimizer-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\..\..\..\..\Program Files\HeuristicLab 3.3\HeuristicLab.Optimizer-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Parameters-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=x86">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>C:\Program Files\HeuristicLab 3.3\HeuristicLab.Parameters-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Persistence-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=x86">
+      <SpecificVersion>False</SpecificVersion>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.PluginInfrastructure-3.3">
+      <HintPath>C:\Program Files\HeuristicLab 3.3\HeuristicLab.PluginInfrastructure-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="NetTopologySuite, Version=1.13.2.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\NetTopologySuite.1.13.2\lib\net403-client\NetTopologySuite.dll</HintPath>
+    </Reference>
+    <Reference Include="NetTopologySuite.IO.GeoTools, Version=1.13.2.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\NetTopologySuite.IO.1.13.2\lib\net403-client\NetTopologySuite.IO.GeoTools.dll</HintPath>
+    </Reference>
+    <Reference Include="NetTopologySuite.IO.MsSqlSpatial, Version=1.13.2.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\NetTopologySuite.IO.1.13.2\lib\net403-client\NetTopologySuite.IO.MsSqlSpatial.dll</HintPath>
+    </Reference>
+    <Reference Include="NetTopologySuite.IO.PostGis, Version=1.13.2.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\NetTopologySuite.IO.1.13.2\lib\net403-client\NetTopologySuite.IO.PostGis.dll</HintPath>
+    </Reference>
+    <Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="PowerCollections, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\NetTopologySuite.1.13.2\lib\net403-client\PowerCollections.dll</HintPath>
+    </Reference>
+    <Reference Include="ProjNet, Version=1.3.0.3, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\ProjNET4GeoAPI.1.3.0.3\lib\net403-client\ProjNet.dll</HintPath>
+    </Reference>
+    <Reference Include="SharpMap, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\SharpMap.1.1.0\lib\net40-client\SharpMap.dll</HintPath>
+    </Reference>
+    <Reference Include="SharpMap.UI">
+      <HintPath>..\..\packages\SharpMap.UI.1.1.0\lib\net40-client\SharpMap.UI.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Data.SQLite, Version=1.0.86.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\System.Data.SQLite.MSIL.1.0.86.0\lib\net45\System.Data.SQLite.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Data.SQLite.Linq, Version=1.0.86.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\System.Data.SQLite.MSIL.1.0.86.0\lib\net45\System.Data.SQLite.Linq.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Windows.Forms.DataVisualization" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="BioBoostProblemDataView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="BioBoostProblemDataView.Designer.cs">
+      <DependentUpon>BioBoostProblemDataView.cs</DependentUpon>
+    </Compile>
+    <Compile Include="BioBoostSolutionCostsView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="BioBoostSolutionCostsView.Designer.cs">
+      <DependentUpon>BioBoostSolutionCostsView.cs</DependentUpon>
+    </Compile>
+    <Compile Include="BioBoostRegionDetailView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="BioBoostRegionDetailView.Designer.cs">
+      <DependentUpon>BioBoostRegionDetailView.cs</DependentUpon>
+    </Compile>
+    <Compile Include="BioBoostSolutionDetailView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="BioBoostSolutionDetailView.Designer.cs">
+      <DependentUpon>BioBoostSolutionDetailView.cs</DependentUpon>
+    </Compile>
+    <Compile Include="BioBoostCompoundSolutionEditor.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="BioBoostCompoundSolutionEditor.Designer.cs">
+      <DependentUpon>BioBoostCompoundSolutionEditor.cs</DependentUpon>
+    </Compile>
+    <Compile Include="BioBoostParetoSetView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="BioBoostParetoSetView.Designer.cs">
+      <DependentUpon>BioBoostParetoSetView.cs</DependentUpon>
+    </Compile>
+    <Compile Include="BioBoostSolutionHistoryView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="BioBoostSolutionHistoryView.Designer.cs">
+      <DependentUpon>BioBoostSolutionHistoryView.cs</DependentUpon>
+    </Compile>
+    <Compile Include="BioBoostSummaryView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="BioBoostSummaryView.Designer.cs">
+      <DependentUpon>BioBoostSummaryView.cs</DependentUpon>
+    </Compile>
+    <Compile Include="EnumerableExtentions.cs" />
+    <Compile Include="FilterDialog.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="FilterDialog.Designer.cs">
+      <DependentUpon>FilterDialog.cs</DependentUpon>
+    </Compile>
+    <Compile Include="GeometryExtensions.cs" />
+    <Compile Include="BioBoostCompoundSolutionView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="BioBoostCompoundSolutionView.Designer.cs">
+      <DependentUpon>BioBoostCompoundSolutionView.cs</DependentUpon>
+    </Compile>
+    <Compile Include="MapViews\GradientLegend.cs" />
+    <Compile Include="MapViews\ILazyLayerGenerator.cs" />
+    <Compile Include="MapViews\LazyVectorLayerGenerator.cs" />
+    <Compile Include="MapViews\LazyValueLayerGenerator.cs" />
+    <Compile Include="MenuItems\CreateBioBoostExperimentMenuItem.cs" />
+    <Compile Include="MenuItems\ExportSolutionMenuItem.cs" />
+    <Compile Include="Plugin.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Properties\Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>Resources.resx</DependentUpon>
+    </Compile>
+    <Compile Include="RegionDetailData.cs" />
+    <Compile Include="SupplierCollector.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="HeuristicLab.snk" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+    <None Include="Resources\WheatStraw.png" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Resources\Transport.png" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Resources\Coins.png" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Resources\ShapefileIcon.png" />
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="BioBoostParetoSetView.resx">
+      <DependentUpon>BioBoostParetoSetView.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="BioBoostProblemDataView.resx">
+      <DependentUpon>BioBoostProblemDataView.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="BioBoostCompoundSolutionView.resx">
+      <DependentUpon>BioBoostCompoundSolutionView.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="BioBoostSolutionCostsView.resx">
+      <DependentUpon>BioBoostSolutionCostsView.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="BioBoostRegionDetailView.resx">
+      <DependentUpon>BioBoostRegionDetailView.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="BioBoostSolutionDetailView.resx">
+      <DependentUpon>BioBoostSolutionDetailView.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="BioBoostCompoundSolutionEditor.resx">
+      <DependentUpon>BioBoostCompoundSolutionEditor.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="BioBoostSummaryView.resx">
+      <DependentUpon>BioBoostSummaryView.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="FilterDialog.resx">
+      <DependentUpon>FilterDialog.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Properties\Resources.resx">
+      <Generator>PublicResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+    </EmbeddedResource>
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="Resources\Farm-Fresh_arrow_divide.png" />
+    <Content Include="Resources\FeedstockCost.png" />
+    <Content Include="Resources\FoamingBeakerCartoon.png" />
+    <Content Include="Resources\neighbors.png" />
+    <Content Include="Resources\straw_bag.png" />
+    <Content Include="Resources\TransportAndStorageCost.png" />
+    <Content Include="Resources\TransportCost.png" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\HeuristicLab.Problems.BioBoost\3.3\HeuristicLab.Problems.BioBoost-3.3.csproj">
+      <Project>{61d4af50-8a40-44b9-9cd0-413f65d2235c}</Project>
+      <Name>HeuristicLab.Problems.BioBoost-3.3</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <PropertyGroup>
+    <PreBuildEvent>set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+set ProjectDir=$(ProjectDir)
+set SolutionDir=$(SolutionDir)
+set Outdir=$(Outdir)
+
+call PreBuildEvent.cmd
+</PreBuildEvent>
+  </PropertyGroup>
+  <!-- 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>
+  -->
+</Project>
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/MapViews/GradientLegend.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/MapViews/GradientLegend.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/MapViews/GradientLegend.cs	(revision 15711)
@@ -0,0 +1,101 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Drawing.Drawing2D;
+using SharpMap;
+using SharpMap.Rendering.Decoration;
+using System;
+using System.Drawing;
+
+using System.Globalization;
+
+
+namespace HeuristicLab.BioBoost.Views.MapViews {
+  public class GradientLegend : MapDecoration {
+    public Size Size { get; set; }
+    public double MinValue { get; set; }
+    public double MaxValue { get; set; }
+    public ColorBlend ColorBlend { get; set; }
+    public Point Offset { get; set; }
+    public Font Font { get; set; }
+    public String Unit { get; set; }
+
+    public GradientLegend() {
+      Size = new Size(150, 20);
+      Anchor = MapDecorationAnchor.LeftBottom;
+      MinValue = 0;
+      MaxValue = 1;
+      Offset = new Point(10, 10);
+      // color blend does not match the gradient legend exactly
+      /*
+       ColorBlend  = new ColorBlend {
+      Colors = new[] {
+        Color.FromArgb(0, 0, 127),
+        Color.FromArgb(0, 0, 255),
+        Color.FromArgb(0, 255, 255),
+        Color.FromArgb(0, 255, 0),
+        Color.FromArgb(127, 255, 0),
+        Color.FromArgb(255, 255, 0),
+        Color.FromArgb(255, 127, 0),
+        Color.FromArgb(255, 0, 0),
+        Color.FromArgb(127, 0, 0)},
+      Positions = new[] { 0.0f, 0.125f, 0.25f, 0.375f, 0.5f, 0.625f, 0.75f, 0.875f, 1f }
+       };
+       */
+      // GradientLegend uses ColorBlend from System.Drawing and we need to convert it to a SharpMap colorblend here
+      ColorBlend = new ColorBlend() {
+        Colors = LazyValueLayerGenerator.DefaultColorBlend.Colors,
+        Positions = LazyValueLayerGenerator.DefaultColorBlend.Positions
+      };
+      Font = (Font)SystemFonts.DefaultFont.Clone();
+    }
+
+    protected override Size InternalSize(Graphics g, Map map) {
+      return new Size(Size.Width + Offset.X + 4, Size.Height + Offset.Y + 3);
+    }
+
+    protected override void OnRender(Graphics g, Map map) {
+      var pos = new PointF(g.ClipBounds.Left + Offset.X, g.ClipBounds.Bottom - Offset.Y - Size.Height);
+      var brush = new System.Drawing.Drawing2D.LinearGradientBrush(pos, new PointF(pos.X + Size.Width, pos.Y), Color.Black, Color.Black) {
+        InterpolationColors = ColorBlend
+      };
+      g.FillRectangle(new SolidBrush(Color.FromArgb(127, 255, 255, 255)),
+        pos.X - 1, pos.Y - 1, Size.Width + 3, Size.Height + 2);
+      var minStr = MinValue.ToString(CultureInfo.InvariantCulture);
+      var maxStr = MaxValue.ToString("G4", CultureInfo.InvariantCulture);
+      if (!String.IsNullOrEmpty(Unit)) maxStr += " " + Unit;
+      var minDim = g.MeasureString(minStr, Font);
+      var maxDim = g.MeasureString(maxStr, Font);
+      var textHeight = Math.Min(minDim.Height, maxDim.Height);
+      g.FillRectangle(brush, pos.X, pos.Y + textHeight, Size.Width, Size.Height - textHeight - 2);
+      g.DrawString(minStr, Font, Brushes.Black, pos.X, pos.Y);
+      g.DrawString(maxStr, Font, Brushes.Black, pos.X + Size.Width - maxDim.Width - 2, pos.Y);
+      g.DrawLine(Pens.Black, pos.X, pos.Y, pos.X, pos.Y + Size.Height);
+      g.DrawLine(Pens.Black, pos.X + Size.Width, pos.Y, pos.X + Size.Width, pos.Y + Size.Height);
+
+      g.DrawLine(Pens.Black, pos.X + Size.Width / 4, pos.Y + textHeight, pos.X + Size.Width / 4, pos.Y + Size.Height);
+      g.DrawLine(Pens.Black, pos.X + Size.Width / 2, pos.Y + textHeight / 2, pos.X + Size.Width / 2, pos.Y + Size.Height);
+      g.DrawLine(Pens.Black, pos.X + Size.Width / 4 * 3, pos.Y + textHeight, pos.X + Size.Width / 4 * 3, pos.Y + Size.Height);
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/MapViews/ILazyLayerGenerator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/MapViews/ILazyLayerGenerator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/MapViews/ILazyLayerGenerator.cs	(revision 15711)
@@ -0,0 +1,29 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 SharpMap.Layers;
+
+namespace HeuristicLab.BioBoost.Views.MapViews {
+  public interface ILazyLayerGenerator {
+    ILayer Layer { get;  }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/MapViews/LazyValueLayerGenerator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/MapViews/LazyValueLayerGenerator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/MapViews/LazyValueLayerGenerator.cs	(revision 15711)
@@ -0,0 +1,151 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 GeoAPI.CoordinateSystems;
+using GeoAPI.Geometries;
+using NetTopologySuite.CoordinateSystems.Transformations;
+using NetTopologySuite.Geometries;
+using ProjNet.CoordinateSystems;
+using ProjNet.CoordinateSystems.Transformations;
+using SharpMap.Data;
+using SharpMap.Data.Providers;
+using SharpMap.Layers;
+using SharpMap.Rendering.Thematics;
+using SharpMap.Styles;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Linq;
+using ColorBlend = SharpMap.Rendering.Thematics.ColorBlend;
+
+namespace HeuristicLab.BioBoost.Views.MapViews {
+  public class LazyValueLayerGenerator : ILazyLayerGenerator {
+    public static ColorBlend DefaultColorBlend = new ColorBlend(new[] {
+        Color.FromArgb(0, 128, 255),
+        Color.FromArgb(0, 255, 255),
+        Color.FromArgb(0, 255, 0),
+        Color.FromArgb(128, 255, 0),
+        Color.FromArgb(255, 255, 0),
+        Color.FromArgb(255, 128, 0),
+      }, new[] { 0f, 1f / 5, 2f / 5, 3f / 5, 4f / 5, 1f });
+
+
+    private GeometryFeatureProvider geom;
+    private IEnumerable<string> locationNames;
+    private IEnumerable<double> values;
+    private ILayer layer;
+    public ColorBlend ColorBlend { get; set; }
+    public double? MinValue { get; set; }
+    public double? MaxValue { get; set; }
+    public double ActualMinValue { get; private set; }
+    public double ActualMaxValue { get; private set; }
+    public String LayerName { get; set; }
+    public bool RealtiveToSize { get; set; }
+    public string Unit { get; set; }
+    public Dictionary<string, double> Mapping; 
+
+    public LazyValueLayerGenerator(GeometryFeatureProvider geom, IEnumerable<string> locationNames, IEnumerable<double> values, String layerName) {
+      this.geom = geom;
+      this.locationNames = locationNames;
+      this.values = values;
+      this.LayerName = layerName;
+      this.RealtiveToSize = false;
+      this.ColorBlend = DefaultColorBlend;
+    }
+
+    public ILayer Layer {
+      get {
+        if (layer == null) BuildLayer();
+        return layer;
+      }
+    }
+
+    private void BuildLayer() {
+      string[] locationNames = this.locationNames.ToArray();
+      double[] values = this.values.ToArray();
+      this.locationNames = null;
+      this.values = null;
+      Mapping = locationNames
+        .Zip(values, (location, value) => new { location, value })
+        .ToDictionary(p => p.location, p => p.value);
+      if (RealtiveToSize) {
+        foreach (FeatureDataRow row in geom.Features.Rows) {
+          var nutsId = (string)row["NUTS_ID"];
+          double value;
+          if (Mapping.TryGetValue(nutsId, out value)) {
+            Mapping[nutsId] = value / GetAreaInHa(row.Geometry);
+          }
+        }
+      }
+      MinValue = MinValue ?? Mapping.Values.Min();
+      MaxValue = MaxValue ?? Mapping.Values.Max();
+      ActualMinValue = Math.Min(MinValue.Value, MaxValue.Value);
+      ActualMaxValue = Math.Max(MinValue.Value, MaxValue.Value);
+      var range = ActualMaxValue - ActualMinValue;
+      if (range == 0) range = 1;
+      layer = new VectorLayer(LayerName, geom) {
+        SmoothingMode = SmoothingMode.HighQuality,
+        Theme = new CustomTheme(row => {
+          var col = Color.LightGray;
+          double value;
+          if (row != null && Mapping.TryGetValue((string)row["NUTS_ID"], out value)) {
+            if (value != 0)
+              col = ColorBlend.GetColor((float)((value - ActualMinValue) / range));
+          }
+          return new VectorStyle {
+            Fill = new SolidBrush(col),
+            EnableOutline = true,
+            Outline = new Pen(Color.Black, 1f),
+          };
+        })
+      };
+
+    }
+
+    private static readonly CoordinateTransformationFactory transformFactory = new CoordinateTransformationFactory();
+    private static readonly CoordinateSystemFactory factory = new CoordinateSystemFactory();
+    private static double GetAreaInHa(IGeometry geom) {
+      geom = (IGeometry)geom.Clone();
+      var centroid = geom.Centroid;
+      var parameters = new List<ProjectionParameter> {
+        new ProjectionParameter("latitude_of_origin", centroid.Y),
+        new ProjectionParameter("central_meridian", centroid.X),
+        new ProjectionParameter("standard_parallel_1", 30),
+        new ProjectionParameter("standard_parallel_2", 75),
+        new ProjectionParameter("false_easting", 0),
+        new ProjectionParameter("false_northing", 0)
+      };
+      var projection = factory.CreateProjection("Albers", "albers_conic_equal_area", parameters);
+      var cartesian = factory.CreateProjectedCoordinateSystem(
+        "local albers",
+        GeographicCoordinateSystem.WGS84,
+        projection,
+        LinearUnit.Metre,
+        new AxisInfo("East", AxisOrientationEnum.East),
+        new AxisInfo("North", AxisOrientationEnum.North));
+      var transform = transformFactory.CreateFromCoordinateSystems(GeographicCoordinateSystem.WGS84, cartesian);
+      var transformed = GeometryTransform.TransformGeometry(GeometryFactory.Default, geom, transform.MathTransform);
+      return transformed.Area / 10000;
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/MapViews/LazyVectorLayerGenerator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/MapViews/LazyVectorLayerGenerator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/MapViews/LazyVectorLayerGenerator.cs	(revision 15711)
@@ -0,0 +1,126 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 GeoAPI.Geometries;
+using NetTopologySuite.Geometries;
+using SharpMap.Data;
+using SharpMap.Data.Providers;
+using SharpMap.Layers;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Drawing2D;
+using System.Linq;
+
+namespace HeuristicLab.BioBoost.Views.MapViews {
+  public class LazyVectorLayerGenerator : ILazyLayerGenerator {
+
+    private GeometryFeatureProvider geom;
+    private IEnumerable<string> locationNames;
+    private IEnumerable<int> transportTargets;
+    private IEnumerable<double> transportAmounts;
+    private ILayer layer;
+    public String LayerName { get; set; }
+    public Color VectorColor { get; set; }
+    public int LineOffset { get; set; }
+
+    public LazyVectorLayerGenerator(GeometryFeatureProvider geom,
+      IEnumerable<string> locationNames,
+      IEnumerable<int> transportTargets,
+      IEnumerable<double> transportAmounts,
+      Color vectorColor,
+      String layerName) {
+      this.geom = geom;
+      if (locationNames == null) throw new ArgumentNullException("locationNames");
+      if (transportTargets == null) throw new ArgumentNullException("transportTargets");
+      this.locationNames = locationNames;
+      this.transportTargets = transportTargets;
+      this.transportAmounts = transportAmounts;
+      this.VectorColor = vectorColor;
+      this.LayerName = layerName;
+    }
+
+    public ILayer Layer {
+      get {
+        if (layer == null) BuildLayer();
+        return layer;
+      }
+    }
+
+    private void BuildLayer() {
+      string[] locationNames = this.locationNames.ToArray();
+      int[] transportTargets = this.transportTargets.ToArray();
+      double[] transportAmounts = this.transportAmounts == null ? null : this.transportAmounts.ToArray();
+      this.locationNames = null;
+      this.transportTargets = null;
+      var nameIndex = locationNames.Select((loc, idx) => new { loc, idx }).ToDictionary(p => p.loc, p => p.idx);
+      var centroids = new Coordinate[locationNames.Length];
+      foreach (FeatureDataRow row in geom.Features) {
+        int idx;
+        if (nameIndex.TryGetValue((string)row["NUTS_ID"], out idx)) {
+          var centroid = row.Geometry.Centroid;
+          try {
+            if (!centroid.Within(row.Geometry)) centroid = row.Geometry.InteriorPoint;
+          } catch (Exception x) { }
+          centroids[idx] = centroid.Coordinate;
+        }
+      }
+      var dataTable = new FeatureDataTable();
+      dataTable.Columns.Add("NUTS_ID_SRC");
+      dataTable.Columns.Add("NUTS_ID_DEST");
+
+      // var transports = new Collection<IGeometry>();
+      // GeoAPI.GeometryServiceProvider.Instance = new NetTopologySuite.NtsGeometryServices();
+      // var f = GeoAPI.GeometryServiceProvider.Instance.CreateGeometryFactory(4326);
+      for (int i = 0; i < locationNames.Length; i++) {
+        if (transportAmounts != null && transportAmounts[i] <= 0) continue;
+        IGeometry g = null;
+        var j = transportTargets[i];
+        var source = centroids[i];
+        if (source == null) continue;
+        if (i == j)
+          g = new NetTopologySuite.Geometries.Point(source);
+        if (j == -1) continue;
+        var target = j < centroids.Length && j >= 0 ? centroids[j] : null;
+        if (target != null)
+          g = new LineString(new[] { source, target });
+
+        var row = dataTable.NewRow();
+        row.Geometry = g;
+        row["NUTS_ID_SRC"] = locationNames[i];
+        row["NUTS_ID_DEST"] = locationNames[j];
+        dataTable.AddRow(row);
+      }
+
+      var geometryProv = new GeometryFeatureProvider(dataTable);
+      var vectorLayer = new VectorLayer(LayerName, geometryProv);
+      vectorLayer.SmoothingMode = SmoothingMode.HighQuality;
+      vectorLayer.Style.Line.SetLineCap(LineCap.NoAnchor, LineCap.ArrowAnchor, DashCap.Flat);
+      vectorLayer.Style.Line.CustomEndCap = new AdjustableArrowCap(3, 5);
+      vectorLayer.Style.Line.Color = VectorColor;
+      vectorLayer.Style.Line.Width = 1;
+      vectorLayer.Style.LineOffset = LineOffset;
+      vectorLayer.Style.PointColor = new SolidBrush(VectorColor);
+      vectorLayer.Style.PointSize = 2;
+      this.layer = vectorLayer;
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/MenuItems/CreateBioBoostExperimentMenuItem.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/MenuItems/CreateBioBoostExperimentMenuItem.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/MenuItems/CreateBioBoostExperimentMenuItem.cs	(revision 15711)
@@ -0,0 +1,247 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.MainForm;
+using HeuristicLab.Optimization;
+using HeuristicLab.Optimizer;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.RegularExpressions;
+using HeuristicLab.BioBoost.Data;
+using HeuristicLab.BioBoost.Evaluators;
+using HeuristicLab.BioBoost.Operators.Mutation;
+using HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.BioBoost.Utils;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Parameters;
+using MenuItem = HeuristicLab.MainForm.WindowsForms.MenuItem;
+
+
+namespace HeuristicLab.BioBoost.Views {
+  internal sealed class CreateBioBoostExperimentMenuItem : MenuItem, IOptimizerUserInterfaceItemProvider {
+    public override string Name {
+      get { return "Create BioBoost Experiment"; }
+    }
+
+    public override IEnumerable<string> Structure {
+      get { return new string[] { "&Edit" }; }
+    }
+
+    public override int Position {
+      get { return 1450; }
+    }
+
+    protected override void OnToolStripItemSet(EventArgs e) {
+      ToolStripItem.Enabled = false;
+    }
+
+    protected override void OnActiveViewChanged(object sender, EventArgs e) {
+      IContentView activeView = MainFormManager.MainForm.ActiveView as IContentView;
+      if (activeView == null) {
+        ToolStripItem.Enabled = false;
+        return;
+      }
+
+      var content = activeView.Content;
+      var algorithm = content as IAlgorithm;
+
+      ToolStripItem.Enabled = algorithm != null && algorithm.Problem is BioBoostProblem;
+    }
+
+    private enum Pathway { FP, CP, HTC };
+    private enum Region { BI, SK, BS, SE, SW, C, S, EU };
+    private enum Price { Cheap, Medium, Expensive };
+    private enum Implementation { Narrow, Normal, Broad };
+
+    private int nValues(Type t) { return Enum.GetValues(t).Length; }
+
+    public override void Execute() {
+      IContentView activeView = (IContentView)MainFormManager.MainForm.ActiveView;
+      var mainForm = ((MainForm.WindowsForms.MainForm) MainFormManager.MainForm);
+      var progress = mainForm.AddOperationProgressToContent(activeView.Content, "Generating Algorithm Configurations");
+      int n = nValues(typeof (Pathway))*nValues(typeof (Region))*nValues(typeof (Price))* nValues(typeof (Implementation));
+      int count = 0;
+      progress.Start();
+      progress.ProgressValue = 1.0*count/n;
+      var alg = activeView.Content as IAlgorithm;
+
+      Action<IContentView> action = view => {
+        var optimizers = new List<IOptimizer>();
+        foreach (Region r in Enum.GetValues(typeof (Region))) {
+          var x = new Experiment("BioBoost final experiment " + r);
+          foreach (Pathway pw in Enum.GetValues(typeof (Pathway))) {
+            foreach (Price p in Enum.GetValues(typeof (Price))) {
+              foreach (Implementation i in Enum.GetValues(typeof (Implementation))) {
+                x.Optimizers.Add(CreateConfiguration(alg, pw, r, p, i, true));
+                progress.ProgressValue = 1.0*(++count)/n;
+                //x.Optimizers.Add(CreateConfiguration(alg, pw, r, p, i, false));
+                //progress.Start(string.Format("{0}/{1}", count, n));
+              }
+            }
+          }
+          var br = new BatchRun("BioBoost final batch run " + r);
+          br.Repetitions = 3;
+          br.Optimizer = x;
+          optimizers.Add(br);
+        }
+        progress.Finish();
+        foreach (var opt in optimizers)
+          MainFormManager.MainForm.ShowContent(opt);
+      };
+
+
+      action.BeginInvoke(activeView, delegate(IAsyncResult result) {
+        try {
+          action.EndInvoke(result);
+        } catch (SystemException e) {
+          var dialog = new PluginInfrastructure.ErrorDialog(e);
+          dialog.ShowDialog();
+        }
+        mainForm.RemoveOperationProgressFromContent(activeView.Content);
+      }, null);
+
+    }
+
+    private static IAlgorithm CreateConfiguration(IAlgorithm alg, Pathway pw, Region r, Price p, Implementation i, bool limitedDistanceInit) {
+      alg = (IAlgorithm) alg.Clone();
+      var problem = alg.Problem as BioBoostProblem;
+      var problemData = problem.ProblemData;
+
+      switch (r) {
+        case Region.BI: problemData.KeepRegions(new Regex("^(UK|IE)")); break; // BI (British Islands)
+        case Region.SK: problemData.KeepRegions(new Regex("^(SE|FI)")); break; // SK (Scandinavia)
+        case Region.BS: problemData.KeepRegions(new Regex("^(EE|LV|LT)")); break; // BS (Baltic States)
+        case Region.SE: problemData.KeepRegions(new Regex("^(BG|RO|EL|MK)")); break; // SE (South East Europe)
+        case Region.SW: problemData.KeepRegions(new Regex("^(ES|PT|FR|NL|BE|LU)")); break; //SW (South West Europe)
+        case Region.C: problemData.KeepRegions(new Regex("^(DE|DK|PL|CZ|SK)")); break; // C (Central Europe)
+        case Region.S: problemData.KeepRegions(new Regex("^(AT|SI|HU|IT|HR)")); break; // S (South Central)
+        case Region.EU: /* don't remove anything */ break;
+      }
+
+      string feedstock = null;
+      string carrier = null;
+      string finalProduct = null;
+      switch (pw) {
+        case Pathway.FP: feedstock = "Straw"; carrier = "Biosyncrude"; finalProduct = "TransportFuel"; break;
+        case Pathway.CP: feedstock = "ForestryResidues"; carrier = "Biooil"; finalProduct = "TransportFuel"; break;
+        case Pathway.HTC: feedstock = "MunicipalWaste"; carrier = "Biocoal"; finalProduct = "ElectricityOut"; break;
+      }
+      SetPathway(problemData, feedstock, carrier, finalProduct);
+
+      switch (p) {
+        case Price.Cheap: ScaleFeedstockPrice(problemData, feedstock, 0.75); break;
+        case Price.Medium: ScaleFeedstockPrice(problemData, feedstock, 1); break;
+        case Price.Expensive:  ScaleFeedstockPrice(problemData, feedstock, 1.5); break;
+      }
+
+      double alpha = 1;
+      bool plantKiller = false;
+      switch (i) {
+        case Implementation.Narrow: alpha = 1; plantKiller = true; break;
+        case Implementation.Normal: alpha = 1; plantKiller = false; break;
+        case Implementation.Broad: alpha = 0.5; plantKiller = false; break;
+      }
+      ((MonolithicEvaluator) problem.Evaluator).AlphaParameter.Value = new DoubleValue(alpha);
+      var mutationOperators = ((MultiMutator) NavigateItem(alg, "Mutator")).Operators;
+      mutationOperators.SetItemCheckedState(mutationOperators.First(op => op.Name == "PlantKiller"), plantKiller);
+
+      if (limitedDistanceInit) {
+        Choose( (ConstrainedValueParameter<IIntegerVectorCreator>) NavigateParameter(problem, "SolutionCreator", "IntegerVectorCreator"), "LimitedDistanceTransportTargetCreator");
+        Set((IParameterizedItem) NavigateItem(problem, "SolutionCreator", "IntegerVectorCreator"), "TournamentSize", 20);
+      } else {
+        Choose((ConstrainedValueParameter<IIntegerVectorCreator>) NavigateParameter(problem, "SolutionCreator", "IntegerVectorCreator"), "UniformRandomIntegerVectorCreator");
+      }
+
+      // adjust generations
+      int n = problem.NRegions;
+      Set(alg, "MaximumGenerations", n*n);
+
+      alg.Name = string.Format("BioBoost 11a final {0} {1} {2} {3} {4} {5}Gen", pw, r, p, i, limitedDistanceInit ? "LimitedDistanceInit" : "", n*n);
+      return alg;
+    }
+
+    private static void ScaleFeedstockPrice(BioBoostProblemData problemData, string feedstockName, double scale) {
+      Scale((Product) NavigateItem(problemData, "DataItems", "Product: " + feedstockName), "Price", scale);
+      Scale((Product) NavigateItem(problemData, "DataItems", "Product: " + feedstockName), "MaxPrice", scale);
+    }
+
+    private static void SetPathway(BioBoostProblemData problemData, string feedstock, string carrier, string finalProduct) {
+      CheckOnly(problemData, "Utilizations", feedstock);
+      CheckOnly(problemData, "TransportTargets", feedstock, carrier);
+      CheckOnly(problemData, "FinalProducts", finalProduct);
+      var potentials = problemData.FeedstockPotentials.Select(p => p.Name).ToHashSet();
+      foreach (var p in potentials) {
+        if (p != feedstock + "Potentials") {
+          problemData.FeedstockPotentials.Remove(p);
+        }
+      }
+      foreach (var p in problemData.Products) {
+        if (potentials.Contains(p.Label + "Potentials") && p.Label != feedstock)
+          problemData.DataItems.Remove(p);
+      }
+    }
+
+
+    private static void Set(IParameterizedItem item, string name, double value) { ((IValueParameter<DoubleValue>)item.Parameters[name]).Value = new DoubleValue(value); }
+    private static void Set(IParameterizedItem item, string name, int value) { ((IValueParameter<IntValue>)item.Parameters[name]).Value = new IntValue(value); }
+
+    private static void Scale(IParameterizedItem item, string name, double scale) {
+      var value = ((IValueParameter<DoubleValue>) item.Parameters[name]).Value.Value;
+      ((IValueParameter<DoubleValue>)item.Parameters[name]).Value = new DoubleValue(value*scale);
+    }
+
+    private static void CheckOnly(IParameterizedItem item, string name, params string[] values) {
+      var valueSet = new HashSet<string>(values);
+      var parameters = ((ValueParameter<CheckedItemList<StringValue>>) item.Parameters[name]).Value;
+      foreach (var i in parameters) {
+        parameters.SetItemCheckedState(i, valueSet.Contains(i.Value));
+      }
+    }
+
+    private static IItem NavigateItem(IItem item, params string[] path) {
+      for (int i = 0; i < path.Length; i++) {
+        if (item is IParameterizedItem) {
+          item = ((IValueParameter) ((IParameterizedItem) item).Parameters[path[i]]).Value;
+        } else if (item is ItemCollection<DataItem>) {
+          item = ((ItemCollection<DataItem>) item).First(x => x.ToString() == path[i]);
+        }
+      }
+      return item;
+    }
+
+    private static IItem NavigateParameter(IItem item, params string[] path) {
+      for (int i = 0; i < path.Length; i++) {
+        item = ((IParameterizedItem) item).Parameters[path[i]];
+        if (i < path.Length-1)
+          item = ((IValueParameter) item).Value;
+      }
+      return item;
+    }
+
+    private static void Choose<T>(ConstrainedValueParameter<T> param, string valueName) where T : class, IItem {
+      param.Value = param.ValidValues.First(v => v.ItemName == valueName);
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/MenuItems/ExportSolutionMenuItem.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/MenuItems/ExportSolutionMenuItem.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/MenuItems/ExportSolutionMenuItem.cs	(revision 15711)
@@ -0,0 +1,197 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.BioBoost.Representation;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.MainForm;
+using HeuristicLab.Optimization;
+using HeuristicLab.Optimizer;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+using MenuItem = HeuristicLab.MainForm.WindowsForms.MenuItem;
+
+
+namespace HeuristicLab.BioBoost.Views {
+  internal sealed class ExportSolutionMenuItem : MenuItem, IOptimizerUserInterfaceItemProvider {
+    public override string Name {
+      get { return "Export CSV"; }
+    }
+
+    public override IEnumerable<string> Structure {
+      get { return new string[] { "&File" }; }
+    }
+
+    public override int Position {
+      get { return 1450; }
+    }
+
+    protected override void OnToolStripItemSet(EventArgs e) {
+      ToolStripItem.Enabled = false;
+    }
+
+    protected override void OnActiveViewChanged(object sender, EventArgs e) {
+      IContentView activeView = MainFormManager.MainForm.ActiveView as IContentView;
+      if (activeView == null) {
+        ToolStripItem.Enabled = false;
+        return;
+      }
+
+      var content = activeView.Content;
+      RunCollection runCollection = content as RunCollection;
+      var optimizer = content as IOptimizer;
+      if (runCollection == null && optimizer != null) {
+        runCollection = ((IOptimizer)content).Runs;
+      }
+
+      var alg = content as IAlgorithm;
+      var solution = content as BioBoostCompoundSolution;
+
+      ToolStripItem.Enabled =
+        // at least on run with a result || or the alg is paused and results contains a bioboost solution
+        (runCollection != null && runCollection.Any(run => run.Results.Any(p => p.Value is BioBoostCompoundSolution))) ||
+        (alg != null && alg.ExecutionState == ExecutionState.Paused && alg.Results.Any(r => r.Value is BioBoostCompoundSolution)) ||
+        (solution != null)
+        ;
+    }
+
+    public override void Execute() {
+      var folderBrowserDialog = new FolderBrowserDialog();
+      folderBrowserDialog.Description = "Select the export directory.";
+      folderBrowserDialog.RootFolder = Environment.SpecialFolder.Desktop;
+      if (folderBrowserDialog.ShowDialog() == DialogResult.OK) {
+        var folderName = folderBrowserDialog.SelectedPath;
+        IContentView activeView = (IContentView)MainFormManager.MainForm.ActiveView;
+        var mainForm = (MainForm.WindowsForms.MainForm)MainFormManager.MainForm;
+        mainForm.AddOperationProgressToContent(activeView.Content, "Export solutions.");
+
+        Action<IContentView> action = (view) => {
+          var i = 0;
+          // export the solutions of all runs
+          foreach (var run in view.Content.GetObjectGraphObjects(excludeStaticMembers: true).OfType<Run>()) {
+            var solution =
+              run.GetObjectGraphObjects(excludeStaticMembers: true).OfType<BioBoostCompoundSolution>().FirstOrDefault();
+            if (solution == null) continue;
+            ExportSolution(folderName, i++, run.Name, solution);
+          }
+          // export the solutions in the results of the paused algorithm
+          var alg = view.Content as IAlgorithm;
+          if (alg != null && alg.ExecutionState == ExecutionState.Paused) {
+            foreach (var solution in alg.Results.Select(r => r.Value).OfType<BioBoostCompoundSolution>()) {
+              ExportSolution(folderName, i++, alg.Name, solution);
+            }
+          }
+
+          // export the solution itself
+          var bioBoostSolution = view.Content as BioBoostCompoundSolution;
+          if (bioBoostSolution != null)
+            ExportSolution(folderName, i++, bioBoostSolution.Name, bioBoostSolution);
+        };
+
+        action.BeginInvoke(activeView, delegate(IAsyncResult result) {
+          try {
+            action.EndInvoke(result);
+          } catch (SystemException e) {
+            var dialog = new HeuristicLab.PluginInfrastructure.ErrorDialog(e);
+            dialog.ShowDialog();
+          }
+          mainForm.RemoveOperationProgressFromContent(activeView.Content);
+        }, null);
+      }
+    }
+
+    private void ExportSolution(string folderName, int i, string name, BioBoostCompoundSolution solution) {
+      var csv = CreateCsvSolution(solution);
+      var filename = string.Format("{0}-{1}.csv", i, name);
+      // remove invalid characters
+      foreach (var ch in Path.GetInvalidFileNameChars()) {
+        filename = filename.Replace(ch, '_');
+
+      }
+      var path = Path.Combine(folderName, filename);
+      if (path.Length >= 248) throw new PathTooLongException("The path is longer than 248 characters. Try to save your files in a different folder");
+      if (filename.Length >= 260) throw new PathTooLongException("The filename is longer than 260 characters. Please change the name of runs to something shorter.");
+      File.WriteAllText(path, csv);
+    }
+
+    private string CreateCsvSolution(BioBoostCompoundSolution content) {
+      content.EvaluateAndUpdateAllResults();
+      var sb = new StringBuilder();
+      // header
+      sb.Append("NUTS_ID").Append(",");
+      sb.Append(string.Join(",", content.IntValues.Select(x => string.Format("\"{0}\"", x.Key)))).Append(",");
+      sb.Append(string.Join(",", content.IntValues.Select(x => string.Format("\"{0}-Region\"", x.Key)))).Append(",");
+      sb.Append(string.Join(",", content.DoubleValues.Select(x => string.Format("\"{0}\"", x.Key)))).Append(",");
+      sb.Append(string.Join(",", content.StringValues.Select(x => string.Format("\"{0}\"", x.Key))));
+      sb.Append(Environment.NewLine);
+      // rows
+      for (int i = 0; i < content.LocationNames.Length; i++) {
+        sb.Append(content.LocationNames[i]);
+        foreach (var kvp in content.IntValues) { sb.Append(",").Append(kvp.Value[i].ToString("D", CultureInfo.InvariantCulture)); }
+        foreach (var kvp in content.IntValues) { sb.Append(",").Append(kvp.Value[i] < 0 ? "" : content.LocationNames[kvp.Value[i]]); }
+        foreach (var kvp in content.DoubleValues) { sb.Append(",").Append(kvp.Value[i].ToString("G", CultureInfo.InvariantCulture)); }
+        foreach (var kvp in content.StringValues) { sb.Append(",").Append(kvp.Value[i]); }
+        sb.Append(Environment.NewLine);
+      }
+
+      return sb.ToString();
+    }
+
+    /*
+    private string CreateJsonSolution(BioBoostCompoundSolution content) {
+      var builder = new StringBuilder();
+      builder.Append("{ \"type\": \"FeatureCollection\", \n\"features\": [");
+      for (int i = 0; i < content.LocationNames.Length; i++) {
+        if (i > 0) builder.Append(",");
+        builder.Append("\n{ \"type\": \"Feature\", \"properties\": { \"NUTS_ID\": \"");
+        builder.Append(content.LocationNames[i]);
+        builder.Append("\"");
+        foreach (var kvp in content.IntValues) {
+          var target = content.LocationNames[i];
+          if (kvp.Value[i] >= 0) {
+            target = content.LocationNames[kvp.Value[i]];
+          }
+          builder.Append(",\n                                     \"");
+          builder.Append(kvp.Key);
+          builder.Append("\": \"");
+          builder.Append(target);
+          builder.Append("\"");
+        }
+        foreach (var kvp in content.DoubleValues) {
+          builder.Append(",\n                                     \"");
+          builder.Append(kvp.Key);
+          builder.Append("\": ");
+          builder.Append(kvp.Value[i].ToString("R", CultureInfo.InvariantCulture));
+        }
+        builder.Append("} }");
+      }
+      builder.Append("\n]\n}");
+
+      return builder.ToString();
+    }
+    */
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/Plugin.cs.frame
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/Plugin.cs.frame	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/Plugin.cs.frame	(revision 15711)
@@ -0,0 +1,37 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.BioBoost.Views {
+  [Plugin("HeuristicLab.Problems.BioBoost.Views", "HeuristicLab views plugin for FP7 project BioBoost", "3.3.12.$WCREV$")]
+  [PluginFile("HeuristicLab.Problems.BioBoost.Views-3.3.dll", PluginFileType.Assembly)]
+  [PluginDependency("HeuristicLab.Problems.BioBoost", "3.3")]
+  [PluginDependency("HeuristicLab.Collections", "3.3")]
+  [PluginDependency("HeuristicLab.Common", "3.3")]
+  [PluginDependency("HeuristicLab.Core", "3.3")]
+  [PluginDependency("HeuristicLab.Core.Views", "3.3")]
+  [PluginDependency("HeuristicLab.MainForm", "3.3")]
+  [PluginDependency("HeuristicLab.MainForm.WindowsForms", "3.3")]
+  [PluginDependency("HeuristicLab.Optimization", "3.3")]
+  [PluginDependency("HeuristicLab.Persistence", "3.3")]
+  public class Plugin : PluginBase {}
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/Properties/AssemblyInfo.cs.frame
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/Properties/AssemblyInfo.cs.frame	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/Properties/AssemblyInfo.cs.frame	(revision 15711)
@@ -0,0 +1,56 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.InteropServices;
+
+// 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.Problems.BioBoost.Views")]
+[assembly: AssemblyDescription("Views for the HeuristicLab BioBoost Plugin")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("HeuristicLab")]
+[assembly: AssemblyCopyright("(c) 2002-2015 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("c307fa4b-9c9e-4c13-812d-3213d24fc712")]
+
+// 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.3.0.0")]
+[assembly: AssemblyFileVersion("3.3.12.$WCREV$")]
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/Properties/Resources.Designer.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/Properties/Resources.Designer.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/Properties/Resources.Designer.cs	(revision 15711)
@@ -0,0 +1,173 @@
+﻿//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.42000
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace HeuristicLab.Problems.BioBoost.Views.Properties {
+    using System;
+    
+    
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    public class Resources {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources() {
+        }
+        
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        public static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("HeuristicLab.Problems.BioBoost.Views.Properties.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        public static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
+        public static System.Drawing.Bitmap Coins {
+            get {
+                object obj = ResourceManager.GetObject("Coins", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
+        public static System.Drawing.Bitmap Farm_Fresh_arrow_divide {
+            get {
+                object obj = ResourceManager.GetObject("Farm_Fresh_arrow_divide", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
+        public static System.Drawing.Bitmap FeedstockCost {
+            get {
+                object obj = ResourceManager.GetObject("FeedstockCost", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
+        public static System.Drawing.Bitmap FoamingBeakerCartoon {
+            get {
+                object obj = ResourceManager.GetObject("FoamingBeakerCartoon", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
+        public static System.Drawing.Bitmap neighbors {
+            get {
+                object obj = ResourceManager.GetObject("neighbors", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
+        public static System.Drawing.Bitmap ShapefileIcon {
+            get {
+                object obj = ResourceManager.GetObject("ShapefileIcon", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
+        public static System.Drawing.Bitmap straw_bag {
+            get {
+                object obj = ResourceManager.GetObject("straw_bag", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
+        public static System.Drawing.Bitmap Transport {
+            get {
+                object obj = ResourceManager.GetObject("Transport", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
+        public static System.Drawing.Bitmap TransportAndStorageCost {
+            get {
+                object obj = ResourceManager.GetObject("TransportAndStorageCost", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
+        public static System.Drawing.Bitmap TransportCost {
+            get {
+                object obj = ResourceManager.GetObject("TransportCost", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
+        public static System.Drawing.Bitmap WheatStraw {
+            get {
+                object obj = ResourceManager.GetObject("WheatStraw", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+    }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/Properties/Resources.resx
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/Properties/Resources.resx	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/Properties/Resources.resx	(revision 15711)
@@ -0,0 +1,154 @@
+﻿<?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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+  <data name="Coins" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\resources\coins.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="FeedstockCost" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\resources\feedstockcost.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="ShapefileIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\resources\shapefileicon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="straw_bag" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\resources\straw_bag.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="Transport" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\resources\transport.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="TransportCost" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\resources\transportcost.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="WheatStraw" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\resources\wheatstraw.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="TransportAndStorageCost" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\resources\transportandstoragecost.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="FoamingBeakerCartoon" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\resources\foamingbeakercartoon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="neighbors" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\resources\neighbors.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="Farm_Fresh_arrow_divide" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\resources\farm-fresh_arrow_divide.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+</root>
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/RegionDetailData.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/RegionDetailData.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/RegionDetailData.cs	(revision 15711)
@@ -0,0 +1,69 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.BioBoost.Representation;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System;
+
+namespace HeuristicLab.BioBoost.Views {
+
+  [StorableClass]
+  public class RegionDetailData : ParameterizedNamedItem {
+
+    public override bool CanChangeName { get { return false; } }
+
+    #region Parameters
+    public ValueParameter<BioBoostCompoundSolution> SolutionParameter {
+      get { return (ValueParameter<BioBoostCompoundSolution>) Parameters["Solution"]; }
+    }
+    public ValueParameter<StringValue> RegionNameParameter {
+      get { return (ValueParameter<StringValue>) Parameters["RegionName"]; }
+    }
+    #endregion
+
+    #region Parameter Values
+    public BioBoostCompoundSolution Solution {
+      get { return SolutionParameter.Value; }
+      set { SolutionParameter.Value = value;  }
+    }
+    public String RegionName {
+      get { return RegionNameParameter.Value.Value; }
+      set { RegionNameParameter.Value.Value = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected RegionDetailData(bool isDeserializing) : base(isDeserializing) {}
+    protected RegionDetailData(RegionDetailData orig, Cloner cloner) : base(orig, cloner) {}
+    public RegionDetailData() {
+      Parameters.Add(new ValueParameter<BioBoostCompoundSolution>("Solution", "The solution from which the detail should be obtained."));
+      Parameters.Add(new ValueParameter<StringValue>("RegionName", "The name of the region for which details show be displayed."));
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RegionDetailData(this, cloner);
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/SupplierCollector.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/SupplierCollector.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/SupplierCollector.cs	(revision 15711)
@@ -0,0 +1,171 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Diagnostics;
+using System.Text.RegularExpressions;
+using HeuristicLab.BioBoost.Representation;
+using HeuristicLab.Data;
+
+namespace HeuristicLab.BioBoost.Views {
+
+
+  public class SupplierCollector {
+
+    public class ProductInfo {
+      public string Name;
+      public double Potential;
+      public double Utilization;
+      public double ConverterCapacity;
+      public double StorageCapacity;
+      public double ConversionCost;
+      public double StorageCost;
+      public double ConversionPlantConstructionCost;
+      public double ConversionPlantOperationCost;
+      public string TargetName;
+      public IntArray TransportTargts;
+      public DoubleArray TransportedAmounts;
+      public DoubleArray Utilizations;
+      public DoubleArray Potentials;
+      public DoubleArray AcquisitionCosts;
+      public DoubleArray DischargeCosts;
+      public DoubleArray TransportCosts;
+      public DoubleArray HandlingCosts;
+      public DoubleArray RelativeProductionCosts;
+      public DoubleArray TransportDistances;
+      public DoubleArray Tkm;
+      public StringArray TransportModes;
+      public Dictionary<string, double> Suppliers;
+      public List<int> SuppliersIndices;
+    }
+
+    public List<ProductInfo> Feedstocks { get; private set; }
+    public List<ProductInfo> Products { get; private set; }
+
+    public SupplierCollector(BioBoostCompoundSolution solution, string regionName) {
+      Feedstocks = new List<ProductInfo>();
+      Products = new List<ProductInfo>();
+      var locidx = solution.LocationNames.IndexOfFirst(s => s == regionName);
+      if (locidx < 0) return;
+      var products = new Dictionary<string, ProductInfo>();
+      foreach (var kvp in solution.DoubleValues) {
+        AddProductInfo(
+          products, kvp.Key, LayerDescriptor.PotentialsFromProblemData.FullName,
+          pi => {
+            pi.Potential = kvp.Value[locidx];
+            pi.Potentials = kvp.Value;
+          });
+        AddProductInfo(
+          products, kvp.Key, LayerDescriptor.Utilizations.FullName,
+          pi => {
+            pi.Utilization = kvp.Value[locidx];
+            pi.Utilizations = kvp.Value;
+          });
+        AddProductInfo(products, kvp.Key, LayerDescriptor.AmountsTransportedFromSource.FullName, pi => { pi.TransportedAmounts = kvp.Value; });
+        AddProductInfo(products, kvp.Key, LayerDescriptor.TotalCostsAtSource.FullName, pi => { pi.AcquisitionCosts = kvp.Value; });
+        AddProductInfo(products, kvp.Key, LayerDescriptor.DischargeCosts.FullName, pi => { pi.DischargeCosts = kvp.Value; });
+        //AddProductInfo(products, kvp.Key, LayerDescriptor.TotalCostsAtSource.FullName, pi => { pi.Costs = kvp.Value; });
+        //AddProductInfo(products, kvp.Key, LayerDescriptor.TotalCostsAtTarget.FullName, pi => { pi.Costs = kvp.Value; });
+        //AddProductInfo(products, kvp.Key, LayerDescriptor.Costs.FullName, pi => { pi.Costs = kvp.Value; });
+        //AddProductInfo(products, kvp.Key, LayerDescriptor.AmountsAtSource.FullName + LayerDescriptor.Costs.FullName, pi => { pi.Costs = Add(pi.Costs, kvp.Value); });
+        //AddProductInfo(products, kvp.Key, LayerDescriptor.AmountsAtTarget.FullName + LayerDescriptor.Costs.FullName, pi => { pi.Costs = Add(pi.Costs, kvp.Value); });
+        AddProductInfo(products, kvp.Key, LayerDescriptor.TransportCosts.FullName, pi => { pi.TransportCosts = kvp.Value; });
+        AddProductInfo(products, kvp.Key, LayerDescriptor.HandlingCosts.FullName, pi => { pi.HandlingCosts = kvp.Value; });
+        AddProductInfo(products, kvp.Key, LayerDescriptor.RelativeCostAtSource.FullName, pi => { pi.RelativeProductionCosts = kvp.Value; });
+        AddProductInfo(products, kvp.Key, LayerDescriptor.TransportDistance.FullName, pi => { pi.TransportDistances = kvp.Value; });
+        AddProductInfo(products, kvp.Key, LayerDescriptor.Tkm.FullName, pi => { pi.Tkm = kvp.Value; });
+        AddProductInfo(products, kvp.Key, LayerDescriptor.ConverterCapacities.FullName, pi => { pi.ConverterCapacity = kvp.Value[locidx]; });
+        AddProductInfo(products, kvp.Key, LayerDescriptor.StorageCapacities.FullName, pi => { pi.StorageCapacity = kvp.Value[locidx]; });
+        AddProductInfo(products, kvp.Key, LayerDescriptor.ConversionCosts.FullName, pi => { pi.ConversionCost = kvp.Value[locidx]; });
+        AddProductInfo(products, kvp.Key, LayerDescriptor.StorageCost.FullName, pi => { pi.StorageCost = kvp.Value[locidx]; });
+        AddProductInfo(products, kvp.Key, LayerDescriptor.ConversionPlantConstructionCost.FullName, pi => { pi.ConversionPlantConstructionCost = kvp.Value[locidx]; });
+        AddProductInfo(products, kvp.Key, LayerDescriptor.ConversionPlantOperationCost.FullName, pi => { pi.ConversionPlantOperationCost = kvp.Value[locidx]; });
+      }
+      foreach (var kvp in solution.IntValues) {
+        AddProductInfo(
+          products, kvp.Key, LayerDescriptor.TransportTargets.FullName,
+          pi => {
+            var target = kvp.Value[locidx];
+            pi.TargetName = target >= 0 ? solution.LocationNames[target] : "<none>";
+            pi.TransportTargts = kvp.Value;
+          });
+      }
+      if (solution.StringValues == null) {
+        foreach (var kvp in solution.StringValues) {
+          AddProductInfo(
+            products, kvp.Key, LayerDescriptor.TransportModes.FullName, pi => { pi.TransportModes = kvp.Value; });
+        }
+      }
+      foreach (var product in products.Values) {
+        product.Suppliers = new Dictionary<string, double>();
+        product.SuppliersIndices = new List<int>();
+        Products.Add(product);
+        if (product.Potentials != null) Feedstocks.Add(product);
+        if (product.TransportTargts == null) {
+          product.Suppliers.Add(solution.LocationNames[locidx], 0);
+          product.SuppliersIndices.Add(locidx);
+        } else {
+          for (int i = 0; i < product.TransportTargts.Length; i++) {
+            if (product.TransportTargts[i] != locidx) continue;
+            var amount = 1d;
+            if (product.TransportedAmounts != null) {
+              amount = product.TransportedAmounts[i];
+            } else if (product.Potentials != null && product.Utilizations != null) {
+              amount = product.Potentials[i]*product.Utilizations[i];
+            }
+            if (amount > 0) {
+              product.SuppliersIndices.Add(i);
+              product.Suppliers.Add(solution.LocationNames[i], amount);
+            }
+          }
+        }
+      }
+    }
+
+    private static readonly Regex nameSplitter = new Regex(@"([^ ]+)( .*)");
+
+    private void AddProductInfo(Dictionary<string, ProductInfo> dict, string name, string suffix, Action<ProductInfo> setter) {
+      var match = nameSplitter.Match(name);
+      if (!match.Success) return;
+      if (!match.Groups[2].Success || match.Groups[2].Value != suffix) return;
+      var productName = match.Groups[1].Value;
+      ProductInfo info;
+      if (!dict.TryGetValue(productName, out info)) {
+        info = new ProductInfo { Name = productName };
+        dict.Add(productName, info);
+      }
+      setter(info);
+    }
+
+    private static DoubleArray Add(DoubleArray a, DoubleArray b) {
+      if (a == null) return b;
+      if (b == null) return a;
+      Debug.Assert(a.Length == b.Length);
+      var result = new DoubleArray(a.Length);
+      for (int i = 0; i < a.Length; i++) {
+        result[i] = a[i] + b[i];
+      }
+      return result;
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/packages.config
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/packages.config	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost.Views/3.3/packages.config	(revision 15711)
@@ -0,0 +1,13 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="BruTile" version="0.7.4.4" targetFramework="net45" />
+  <package id="Common.Logging" version="2.0.0" targetFramework="net45" />
+  <package id="GeoAPI" version="1.7.2" targetFramework="net45" />
+  <package id="NetTopologySuite" version="1.13.2" targetFramework="net45" />
+  <package id="NetTopologySuite.IO" version="1.13.2" targetFramework="net45" />
+  <package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />
+  <package id="ProjNET4GeoAPI" version="1.3.0.3" targetFramework="net45" />
+  <package id="SharpMap" version="1.1.0" targetFramework="net45" />
+  <package id="SharpMap.UI" version="1.1.0" targetFramework="net45" />
+  <package id="System.Data.SQLite.MSIL" version="1.0.86.0" targetFramework="net45" />
+</packages>
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Analysis/BestBioBoostSolutionAnalyzer.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Analysis/BestBioBoostSolutionAnalyzer.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Analysis/BestBioBoostSolutionAnalyzer.cs	(revision 15711)
@@ -0,0 +1,161 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.BioBoost.Representation;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System.Linq;
+
+namespace HeuristicLab.BioBoost.Analysis {
+
+  [Item("BestBioBoostSolutionAnalyzer", "An operator for analyzing the best bioboost solution.")]
+  [StorableClass]
+  public class BestBioBoostSolutionAnalyzer : SingleSuccessorOperator, IAnalyzer {
+
+    public bool EnabledByDefault { get { return true; } }
+
+    #region Parameters
+    public LookupParameter<BoolValue> MaximizationParameter {
+      get { return (LookupParameter<BoolValue>) Parameters["Maximization"]; }
+    }
+    public ScopeTreeLookupParameter<DoubleValue> TotalCostParameter {
+      get { return (ScopeTreeLookupParameter<DoubleValue>) Parameters["TotalCost"]; }
+    } 
+    public LookupParameter<BioBoostProblemData> ProblemDataParameter {
+      get { return (LookupParameter<BioBoostProblemData>) Parameters["ProblemData"]; }
+    }
+    public LookupParameter<BioBoostCompoundSolution> BestSolutionParameter {
+      get { return (LookupParameter<BioBoostCompoundSolution>) Parameters["BestSolution"]; }
+    }
+    public ValueLookupParameter<ResultCollection> ResultsParameter {
+      get { return (ValueLookupParameter<ResultCollection>)Parameters["Results"]; }
+    }
+    public LookupParameter<DoubleValue> BestKnownQualityParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["BestKnownQuality"]; }
+    }
+    public LookupParameter<DoubleValue> BestQualityParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["BestQuality"]; }
+    }
+    public LookupParameter<BioBoostCompoundSolution> BestKnownSolutionParameter {
+      get { return (LookupParameter<BioBoostCompoundSolution>)Parameters["BestKnownSolution"]; }
+    }
+    public LookupParameter<ItemCollection<BioBoostCompoundSolution>> SolutionHistoryParameter {
+      get { return (LookupParameter<ItemCollection<BioBoostCompoundSolution>>)Parameters["SolutionHistory"]; }
+    }
+    public ValueLookupParameter<BoolValue> TrackHistoryParameter {
+      get { return (ValueLookupParameter<BoolValue>) Parameters["TrackHistory"]; }
+    }
+    #endregion
+
+    #region Parameter Values
+    public bool Maximization {
+      get { return MaximizationParameter.ActualValue.Value;  }
+    }
+    public BioBoostProblemData ProblemData {
+      get { return ProblemDataParameter.ActualValue; }
+    }
+    public BioBoostCompoundSolution BestSolution {
+      get { return BestSolutionParameter.ActualValue; }
+      set { BestSolutionParameter.ActualValue = value; }
+    }
+    private bool TrackHistory { get { return TrackHistoryParameter.ActualValue.Value;  } }
+    #endregion
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected BestBioBoostSolutionAnalyzer(bool isDeserializing) : base(isDeserializing) {}
+    protected BestBioBoostSolutionAnalyzer(BestBioBoostSolutionAnalyzer orig, Cloner cloner) : base(orig, cloner) {}
+    public BestBioBoostSolutionAnalyzer() {
+      Parameters.Add(new LookupParameter<BoolValue>("Maximization", "Whether this is a maximization problem."));
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("TotalCost", "The total cost of the whole scenario."));
+      Parameters.Add(new LookupParameter<BioBoostProblemData>("ProblemData", "The collection of problem data."));
+      Parameters.Add(new LookupParameter<BioBoostCompoundSolution>("BestSolution", "Aggregation of solution components."));
+      Parameters.Add(new ValueLookupParameter<ResultCollection>("Results", "The result collection where the best solution should be stored."));
+      Parameters.Add(new LookupParameter<DoubleValue>("BestKnownQuality", "The quality of the best known solution of this instance."));
+      Parameters.Add(new LookupParameter<DoubleValue>("BestQuality", "The quality of the best solution of this run."));
+      Parameters.Add(new LookupParameter<BioBoostCompoundSolution>("BestKnownSolution", "The best known solution of this instance."));
+      Parameters.Add(new LookupParameter<ItemCollection<BioBoostCompoundSolution>>("SolutionHistory", "The history of best solutions over time."));
+      Parameters.Add(new ValueLookupParameter<BoolValue>("TrackHistory", "True if all best solutions (over time) should be recorded in SolutionHistory", new BoolValue(false)));
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new BestBioBoostSolutionAnalyzer(this, cloner);
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    public void AfterDeserialization() {
+      if (!Parameters.ContainsKey("Maximization"))
+        Parameters.Add(new LookupParameter<BoolValue>("Maximization", "Whether this is a maximization problem."));
+      if (!Parameters.ContainsKey("SolutionHistory"))
+        Parameters.Add(new LookupParameter<ItemCollection<BioBoostCompoundSolution>>("SolutionHistory", "The history of best solutions over time."));
+      if (!Parameters.ContainsKey("TrackHistory"))
+        Parameters.Add(new ValueLookupParameter<BoolValue>("TrackHistory", "True if all best solutions (over time) should be recorded in SolutionHistory", new BoolValue(false)));
+      if (!Parameters.ContainsKey("BestQuality"))
+        Parameters.Add(new LookupParameter<DoubleValue>("BestQuality", "The quality of the best solution of this run."));
+    }
+    #endregion
+
+    IEnumerable<IScope> GetSubScopes(IScope scope, int depth) {
+      if (depth == 1)
+        return scope.SubScopes;
+      return scope.SubScopes.Select(s => GetSubScopes(s, depth - 1)).Aggregate((l1, l2) => l1.Concat(l2));
+    }
+
+    public override IOperation Apply() {
+      var costs = TotalCostParameter.ActualValue.Select((cost, idx) => new {cost.Value, idx}).OrderBy(p => p.Value);
+      var best = Maximization ? costs.Last() : costs.First();
+      var bestScope = TotalCostParameter.Depth == 0 ? ExecutionContext.Scope : GetSubScopes(ExecutionContext.Scope, TotalCostParameter.Depth).ToList()[best.idx];
+      var newBestSolution = new BioBoostCompoundSolution(bestScope, ProblemData);
+      if (BestSolution == null) {
+        BestSolution = newBestSolution;
+        ResultsParameter.ActualValue.Add(new Result("BestSolution", BestSolution));
+      } else {
+        BestSolution.UpdateTo(newBestSolution);
+      }
+      if (BestKnownQualityParameter.ActualValue == null ||
+          Maximization && best.Value > BestKnownQualityParameter.ActualValue.Value ||
+          !Maximization && best.Value < BestKnownQualityParameter.ActualValue.Value) {
+        BestKnownQualityParameter.ActualValue = new DoubleValue(best.Value);
+        BestKnownSolutionParameter.ActualValue = BestSolution;
+      }
+      if (TrackHistory &&
+          (BestQualityParameter.ActualValue == null ||
+           Maximization && best.Value > BestQualityParameter.ActualValue.Value ||
+           !Maximization && best.Value < BestQualityParameter.ActualValue.Value)) {
+        IResult solutionHistoryResult = null;
+        if (!ResultsParameter.ActualValue.TryGetValue("SolutionHistory", out solutionHistoryResult)) {
+          solutionHistoryResult = new Result("SolutionHistory", new ItemCollection<BioBoostCompoundSolution>());
+          ResultsParameter.ActualValue.Add(solutionHistoryResult);
+        }
+        ((ItemCollection<BioBoostCompoundSolution>) solutionHistoryResult.Value).Add(
+          (BioBoostCompoundSolution) newBestSolution.SlimClone());
+      }
+      return base.Apply();
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Analysis/MultiObjejctiveBioBoostSolutionAnalyzer.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Analysis/MultiObjejctiveBioBoostSolutionAnalyzer.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Analysis/MultiObjejctiveBioBoostSolutionAnalyzer.cs	(revision 15711)
@@ -0,0 +1,149 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Diagnostics;
+using HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.BioBoost.Representation;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System.Linq;
+using HeuristicLab.BioBoost.Utils;
+
+namespace HeuristicLab.BioBoost.Analysis {
+
+  [Item("MultiObjectiveBioBoostSolutionAnalyzer", "An operator for analyzing the set of best bioboost solutions (multi objective).")]
+  [StorableClass]
+  public class MultiObjectiveBioBoostSolutionAnalyzer : SingleSuccessorOperator, IAnalyzer {
+
+    public bool EnabledByDefault { get { return true; } }
+
+    #region Parameters
+    public LookupParameter<BoolArray> MaximizationParameter {
+      get { return (LookupParameter<BoolArray>) Parameters["Maximization"]; }
+    }
+    public ScopeTreeLookupParameter<DoubleArray> QualitiesParameter {
+      get { return (ScopeTreeLookupParameter<DoubleArray>) Parameters["QualityCriteria"]; }
+    } 
+    public LookupParameter<BioBoostProblemData> ProblemDataParameter {
+      get { return (LookupParameter<BioBoostProblemData>) Parameters["ProblemData"]; }
+    }
+    public LookupParameter<ItemCollection<BioBoostCompoundSolution>> BestSolutionsParameter {
+      get { return (LookupParameter<ItemCollection<BioBoostCompoundSolution>>) Parameters["BestSolutions"]; }
+    }
+    public ValueLookupParameter<ResultCollection> ResultsParameter {
+      get { return (ValueLookupParameter<ResultCollection>)Parameters["Results"]; }
+    }
+    /*public LookupParameter<DoubleValue> BestKnownQualityParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["BestKnownQuality"]; }
+    }
+    public LookupParameter<BioBoostCompoundSolution> BestKnownSolutionParameter {
+      get { return (LookupParameter<BioBoostCompoundSolution>)Parameters["BestKnownSolution"]; }
+    } */
+    /* public LookupParameter<ItemCollection<BioBoostCompoundSolution>> SolutionHistoryParameter {
+      get { return (LookupParameter<ItemCollection<BioBoostCompoundSolution>>)Parameters["SolutionHistory"]; }
+    } 
+    public ValueLookupParameter<BoolValue> TrackHistoryParameter {
+      get { return (ValueLookupParameter<BoolValue>) Parameters["TrackHistory"]; }
+    } */
+    #endregion
+
+    #region Parameter Values
+    public BoolArray Maximization {
+      get { return MaximizationParameter.ActualValue;  }
+    }
+    public BioBoostProblemData ProblemData {
+      get { return ProblemDataParameter.ActualValue; }
+    }
+    public ItemCollection<BioBoostCompoundSolution> BestSolutions {
+      get { return BestSolutionsParameter.ActualValue; }
+      set { BestSolutionsParameter.ActualValue = value; }
+    }
+    // private bool TrackHistory { get { return TrackHistoryParameter.ActualValue.Value;  } }
+    #endregion
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected MultiObjectiveBioBoostSolutionAnalyzer(bool isDeserializing) : base(isDeserializing) {}
+    protected MultiObjectiveBioBoostSolutionAnalyzer(MultiObjectiveBioBoostSolutionAnalyzer orig, Cloner cloner) : base(orig, cloner) {}
+    public MultiObjectiveBioBoostSolutionAnalyzer() {
+      Parameters.Add(new LookupParameter<BoolArray>("Maximization", "Whether this is a maximization problem."));
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleArray>("QualityCriteria", "The list of quality criteria."));
+      Parameters.Add(new LookupParameter<BioBoostProblemData>("ProblemData", "The collection of problem data."));
+      Parameters.Add(new LookupParameter<ItemCollection<BioBoostCompoundSolution>>("BestSolutions", "Pareto set of best solutions.."));
+      Parameters.Add(new ValueLookupParameter<ResultCollection>("Results", "The result collection where the best solution should be stored."));
+      /* Parameters.Add(new LookupParameter<DoubleValue>("BestKnownQuality", "The quality of the best known solution of this instance."));
+      Parameters.Add(new LookupParameter<BioBoostCompoundSolution>("BestKnownSolution", "The best known solution of this instance."));
+      Parameters.Add(new LookupParameter<ItemCollection<BioBoostCompoundSolution>>("SolutionHistory", "The history of best solutions over time."));
+      Parameters.Add(new ValueLookupParameter<BoolValue>("TrackHistory", "True if all best solutions (over time) should be recorded in SolutionHistory", new BoolValue(false))); */
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MultiObjectiveBioBoostSolutionAnalyzer(this, cloner);
+    }
+    #endregion
+
+    public override IOperation Apply() {
+      var qualities = QualitiesParameter.ActualValue.Select((q, i) => new {q, i}).ToList();
+      var maximization = Maximization;
+      var bestQualities =
+        qualities.Where(q1 => qualities.All(q2 => q1.i == q2.i || !IsDominating(q2.q, q1.q, maximization)))
+        .GroupBy(q => q.q, q => q, Enumerable.SequenceEqual).Select(g => g.First());
+      IResult bestSolutionsResult = null;
+      ItemCollection<BioBoostCompoundSolution> bestSolutions = null;
+      if (!ResultsParameter.ActualValue.TryGetValue("BestSolutions", out bestSolutionsResult)) {
+        bestSolutions = new ItemCollection<BioBoostCompoundSolution>();
+        ResultsParameter.ActualValue.Add(new Result("BestSolutions", bestSolutions));
+      } else {
+        bestSolutions = bestSolutionsResult.Value as ItemCollection<BioBoostCompoundSolution>;
+        if (bestSolutions != null) {
+          bestSolutions.Clear();
+        }
+      }
+      if (bestSolutions == null)
+        throw new InvalidOperationException("BestSolutions in Results has wrong type and cannot be updated.");
+      var solutions = bestQualities
+        .OrderByDescending(q => q.q[0])
+        .Select(q => new BioBoostCompoundSolution(ExecutionContext.Scope.SubScopes[q.i], ProblemData) {
+                       Name = string.Format("[{0}]", string.Join(", ", q.q))})
+        .ToList();
+      bestSolutions.AddRange(solutions);
+      return base.Apply();
+    }
+
+    private static bool IsDominating(DoubleArray a, DoubleArray b, BoolArray maximization) {
+      Debug.Assert(a.Length == b.Length);
+      for (int i = 0; i < a.Length; i++) {
+        if (maximization[i]) {
+          if (a[i] <= b[i]) return false;
+        } else {
+          if (a[i] >= b[i]) return false;
+        }
+      }
+      return true;
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Analysis/MultiOperatorUsageAnalyzer.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Analysis/MultiOperatorUsageAnalyzer.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Analysis/MultiOperatorUsageAnalyzer.cs	(revision 15711)
@@ -0,0 +1,110 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Analysis;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System.Linq;
+
+namespace HeuristicLab.BioBoost.Analysis {
+
+  [Item("MultiOperatorUsageAnalyzer", "An operator for analyzing utilization of different choices of a multi manipulation operatoutilization of different choices of a multi manipulation operator.")]
+  [StorableClass]
+  public class MultiOperatorUsageAnalyzer : SingleSuccessorOperator, IAnalyzer {
+
+    public bool EnabledByDefault { get { return false; } }
+
+    #region Parameters
+    public ScopeTreeLookupParameter<StringValue> SelectedOperatorParameter {
+      get { return (ScopeTreeLookupParameter<StringValue>) Parameters["SelectedOperator"]; }
+    } 
+    public ValueLookupParameter<ResultCollection> ResultsParameter {
+      get { return (ValueLookupParameter<ResultCollection>)Parameters["Results"]; }
+    }
+    #endregion
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected MultiOperatorUsageAnalyzer(bool isDeserializing) : base(isDeserializing) {}
+    protected MultiOperatorUsageAnalyzer(MultiOperatorUsageAnalyzer orig, Cloner cloner) : base(orig, cloner) {}
+    public MultiOperatorUsageAnalyzer() {
+      Parameters.Add(new ScopeTreeLookupParameter<StringValue>("SelectedOperator", "The selected operators in a population."));
+      Parameters.Add(new ValueLookupParameter<ResultCollection>("Results", "The result collection where the best solution should be stored."));
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MultiOperatorUsageAnalyzer(this, cloner);
+    }
+    #endregion
+
+    public override IOperation Apply() {
+      var operators = SelectedOperatorParameter.ActualValue;
+      var table = GetOrCreateTable(SelectedOperatorParameter.ActualName + "Usages");
+      AddValues(table, operators);
+      var avgTable = GetOrCreateTable(SelectedOperatorParameter.ActualName + "Avg Usages");
+      foreach (var row in table.Rows) {
+        DataRow avgRow;
+        if (!avgTable.Rows.TryGetValue(row.Name, out avgRow)) {
+          avgRow = new DataRow(row.Name);
+          avgRow.Values.AddRange(Enumerable.Repeat(0d, row.Values.Count - 1));
+          avgTable.Rows.Add(avgRow);
+        }
+        avgRow.Values.Add(row.Values.Average());
+      }
+      return base.Apply();
+    }
+
+    private static void AddValues(DataTable table, ItemArray<StringValue> operators) {
+      var n = operators.Length;
+      var groups = operators
+        .GroupBy(v => v.Value)
+        .ToDictionary(g => g.Key, g => 1.0*g.Count()/n);
+      var len = table.Rows.Count == 0 ? 0 : table.Rows.Max(r => r.Values.Count);
+      foreach (var row in table.Rows) {
+        var probability = 0d;
+        if (groups.TryGetValue(row.Name, out probability))
+          groups.Remove(row.Name);
+        row.Values.Add(probability);
+      }
+      foreach (var newOp in groups) {
+        var row = new DataRow(newOp.Key);
+        row.Values.AddRange(Enumerable.Repeat(0d, len));
+        row.Values.Add(newOp.Value);
+        table.Rows.Add(row);
+      }
+    }
+
+    private DataTable GetOrCreateTable(string tableName) {
+      IResult result = null;
+      if (ResultsParameter.ActualValue.TryGetValue(tableName, out result)) {
+        return (DataTable)result.Value;
+      } else {
+        var table = new DataTable(tableName);
+        ResultsParameter.ActualValue.Add(new Result(tableName, table));
+        return table;
+      }
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/BioBoostProblem.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/BioBoostProblem.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/BioBoostProblem.cs	(revision 15711)
@@ -0,0 +1,153 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.BioBoost.Analysis;
+using HeuristicLab.BioBoost.Evaluators;
+using HeuristicLab.BioBoost.Operators.Crossover;
+using HeuristicLab.BioBoost.Operators.Mutation;
+using HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.BioBoost.SolutionCreation;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System;
+using HeuristicLab.BioBoost.Operators.Moves;
+
+namespace HeuristicLab.BioBoost {
+
+  public interface IBioBoostSimulationEvaluator : ISingleObjectiveEvaluator, IMultiObjectiveEvaluator {}
+
+  [Item("BioBoost Problem", "EU-wide aggregate biomass logistics simulation.")]
+  [Creatable("Problems")]
+  [StorableClass]
+  public class BioBoostProblem : SingleObjectiveHeuristicOptimizationProblem<AggregateEvaluator, BioBoostSolutionCreator>, IStorableContent {
+
+    #region IStorableContent Members
+    public string Filename { get; set; }
+    #endregion
+
+    #region Parameters
+    public ValueParameter<BioBoostProblemData> ProblemDataParameter {
+      get { return (ValueParameter<BioBoostProblemData>) Parameters["ProblemData"]; }
+    }
+    public ValueParameter<IntMatrix> RegionBoundsParameter {
+      get { return (ValueParameter<IntMatrix>) Parameters["RegionBounds"]; }
+    }
+    public ValueParameter<IntValue> NRegionsParameter {
+      get { return (ValueParameter<IntValue>) Parameters["NRegions"]; }
+    }
+    public ValueParameter<BoolValue> RemoveIntermediateResultsParameter {
+      get { return (ValueParameter<BoolValue>) Parameters["RemoveIntermediateResults"]; }
+    }
+    #endregion
+
+    #region Parameter Values
+    public BioBoostProblemData ProblemData {
+      get { return ProblemDataParameter.Value; }
+    }
+    public IntMatrix RegionBounds {
+      get { return RegionBoundsParameter.Value; }
+      set { RegionBoundsParameter.Value = value; }
+    }
+    public int NRegions {
+      get { return NRegionsParameter.Value.Value; }
+      set { NRegionsParameter.Value = new IntValue(value); }
+    }
+    public bool RemoveIntermediateResults {
+      get { return RemoveIntermediateResultsParameter.Value.Value; }
+    }
+    #endregion
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected BioBoostProblem(bool isDeserializing) : base(isDeserializing) {}
+    protected BioBoostProblem(BioBoostProblem orig, Cloner cloner) : base(orig, cloner) {
+      RegisterEvents();
+    }
+    public BioBoostProblem() {
+      Parameters.Add(new ValueParameter<BioBoostProblemData>("ProblemData", "Encapsulation of all data describing the problem instance."));
+      Parameters.Add(new ValueParameter<IntMatrix>("RegionBounds", "Bounds for valid region ids.", new IntMatrix(new int[,]{{0, 0}})));
+      Parameters.Add(new ValueParameter<IntValue>("NRegions", "Number of regions.", new IntValue(0)));
+      Parameters.Add(new ValueParameter<BoolValue>("RemoveIntermediateResults", "Whether to remove intermediate results created during evaluation.", new BoolValue(true)));
+      RegionBoundsParameter.Hidden = true;
+      Maximization.Value = true;
+      RegisterEvents();
+      Operators.Add(new CompoundCrossover());
+      Operators.Add(new MultiCrossover());
+      Operators.Add(new PlantBasedCrossover());
+      Operators.Add(new BoundaryToggleRealVectorMutator());
+      Operators.Add(new CompoundMutator());
+      Operators.Add(new EmptyMutator());
+      Operators.Add(new MultiMutator());
+      Operators.Add(new PlantKiller());
+      Operators.Add(new PlantMerger());
+      Operators.Add(new PlantMover());
+      Operators.Add(new PlantScalingMutator());
+      Operators.Add(new PlantSupplierEqualizer());
+      Operators.Add(new PlantSupplierRandomizer());
+      Operators.Add(new PlantSupplierToggler());
+      Operators.Add(new PlantSupplierUtilizationExchanger());
+      Operators.Add(new BestBioBoostSolutionAnalyzer());
+      Operators.Add(new MoveGeneratorAdapter());
+      Operators.Add(new MoveEvaluatorAdapter());
+      Operators.Add(new MoveMakerAdapter());
+      Evaluator = new MonolithicEvaluator();
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new BioBoostProblem(this, cloner);
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterEvents();
+    }
+    #endregion
+
+    #region events
+    private void RegisterEvents() {
+      NRegionsParameter.ToStringChanged += new EventHandler(NRegionsParameterChanged);
+      ProblemDataParameter.ValueChanged += UpdateEventRegistration;
+      UpdateEventRegistration(this, EventArgs.Empty);
+    }
+
+    private BioBoostProblemData registeredProblemData = null;
+
+    private void UpdateEventRegistration(object sender, EventArgs eventArgs) {
+      if (registeredProblemData == ProblemData) return;
+      if (registeredProblemData != null) {
+        registeredProblemData.LocationNamesParameter.ToStringChanged -= LocationNamesChanged;
+      }
+      ProblemData.LocationNamesParameter.ToStringChanged += LocationNamesChanged;
+      registeredProblemData = ProblemData;
+    }
+
+    private void LocationNamesChanged(object sender, EventArgs e) {
+      NRegions = ProblemData.LocationNames.Length;
+    }
+
+    private void NRegionsParameterChanged(object sender, EventArgs e) {
+      RegionBounds = new IntMatrix(new int[,] {{0, NRegions}});
+    }
+    #endregion
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Data/Conversion.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Data/Conversion.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Data/Conversion.cs	(revision 15711)
@@ -0,0 +1,235 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using YamlDotNet.RepresentationModel;
+
+namespace HeuristicLab.BioBoost.Data {
+  [StorableClass]
+  [Item("Conversion", "Describes a conversion process including storage.")]
+  public class Conversion : DataItem {
+
+    #region Parameters
+    public IValueParameter<StringValue> LabelParameter { get { return (IValueParameter<StringValue>)Parameters["Label"]; } }
+    public IValueParameter<StringValue> FeedstockParameter { get { return (IValueParameter<StringValue>)Parameters["Feedstock"]; } }
+    public IValueParameter<DoubleValue> CostParameter { get { return (IValueParameter<DoubleValue>)Parameters["Cost"]; } }
+    public IValueParameter<DoubleValue> DesignCapacityParameter { get { return (IValueParameter<DoubleValue>)Parameters["DesignCapacity"]; } }
+    public IValueParameter<DoubleValue> ConstructionParameter { get { return (IValueParameter<DoubleValue>)Parameters["Construction"]; } }
+    public IValueParameter<DoubleValue> MinConstructionParameter { get { return (IValueParameter<DoubleValue>)Parameters["MinConstruction"]; } }
+    public IValueParameter<DoubleValue> MaintenanceParameter { get { return (IValueParameter<DoubleValue>)Parameters["Maintenance"]; } }
+    public IValueParameter<DoubleValue> MinMaintenanceParameter { get { return (IValueParameter<DoubleValue>)Parameters["MinMaintenance"]; } }
+    public IValueParameter<DoubleValue> ConstructionScalingExponentParameter { get { return (IValueParameter<DoubleValue>)Parameters["ConstructionScalingExponent"]; } }
+    public IValueParameter<DoubleValue> MaintenanceScalingExponentParameter { get { return (IValueParameter<DoubleValue>)Parameters["MaintenanceScalingExponent"]; } }
+    public IValueParameter<DoubleValue> SafetyStockParameter { get { return (IValueParameter<DoubleValue>)Parameters["SafetyStock"]; } }
+    public IValueParameter<DoubleValue> DryMatterLossParameter { get { return (IValueParameter<DoubleValue>)Parameters["DryMatterLoss"]; } }
+    public IValueParameter<LogisticAction> StorageParameter { get { return (IValueParameter<LogisticAction>)Parameters["Storage"]; } }
+    public IValueParameter<DoubleValue> UtilizationFactorParameter { get { return (IValueParameter<DoubleValue>)Parameters["UtilizationFactor"]; } }
+    public IValueParameter<ValueParameterCollection> ProductsParameter { get { return (IValueParameter<ValueParameterCollection>)Parameters["Products"]; } }
+    public IValueParameter<ValueParameterCollection> ConstructionEmissionsParameter { get { return (IValueParameter<ValueParameterCollection>)Parameters["ConstructionEmissions"]; } }
+    public IValueParameter<ValueParameterCollection> AvailableCapacitiesParameter { get { return (IValueParameter<ValueParameterCollection>)Parameters["AvailableCapacities"]; } }
+    public IValueParameter<ValueParameterCollection> MaxCapacitiesParameter { get { return (IValueParameter<ValueParameterCollection>)Parameters["MaxCapacities"]; } }
+    public IValueParameter<DoubleValue> AvailableMaintenanceFactorParameter { get { return (IValueParameter<DoubleValue>)Parameters["AvailableMaintenanceFactor"]; } }
+    public IValueParameter<DoubleValue> MinCapacityParameter { get { return (IValueParameter<DoubleValue>) Parameters["MinCapacity"]; } }
+    public IValueParameter<StringValue> MainProductParameter { get { return (IValueParameter<StringValue>)Parameters["MainProduct"]; } }
+    public IValueParameter<DoubleValue> MainProductConversionRateParameter { get { return (IValueParameter<DoubleValue>)Parameters["MainProductConversionRate"]; } }
+    #endregion
+
+    #region Parameter Values
+    public string Label { get { return LabelParameter.Value.Value; } }
+    public string Feedstock { get { return FeedstockParameter.Value.Value; } }
+    public string MainProduct { get { return MainProductParameter.Value.Value; } set { MainProductParameter.Value.Value = value; }
+    }
+
+    public double Cost { get { return CostParameter.Value.Value; } set { CostParameter.Value.Value = value; } }
+
+    public double DesignCapacity { get { return DesignCapacityParameter.Value.Value; } }
+    public double Construction { get { return ConstructionParameter.Value.Value; } }
+    public double MinConstruction { get { return MinConstructionParameter.Value.Value; } }
+    public double Maintenance { get { return MaintenanceParameter.Value.Value; } }
+    public double MinMaintenance { get { return MinMaintenanceParameter.Value.Value; } }
+    public double ConstructionScalingExponent { get { return ConstructionScalingExponentParameter.Value.Value; } }
+    public double MaintenanceScalingExponent { get { return MaintenanceScalingExponentParameter.Value.Value; } }
+    public double SafetyStock { get { return SafetyStockParameter.Value.Value; } }
+    public double DryMatterLoss { get { return DryMatterLossParameter.Value.Value; } }
+    public double UtilizationFactor { get { return UtilizationFactorParameter.Value.Value; } }
+    public LogisticAction Storage { get { return StorageParameter.Value; } }
+    public ValueParameterCollection Products { get { return ProductsParameter.Value; } }
+    public ValueParameterCollection ConstructionEmissions { get { return ConstructionEmissionsParameter.Value; } }
+    public ValueParameterCollection MaxCapacities { get { return MaxCapacitiesParameter.Value; } }
+    public ValueParameterCollection AvailableCapacities { get { return AvailableCapacitiesParameter.Value; } }
+    public double AvailableMaintenanceFactor { get { return AvailableMaintenanceFactorParameter.Value.Value; } }
+    public double MainProductConversionRate {
+      get { return MainProductConversionRateParameter.Value.Value; }
+      set { MainProductConversionRateParameter.Value = new DoubleValue(value); }
+    }
+
+    public double MinCapacity {
+      get {
+        double minCapacity = MinCapacityParameter.Value.Value;
+        if (minCapacity == 0d)
+          minCapacity = MinCapacityParameter.Value.Value = GetInferredMinCapacity();
+        return minCapacity;
+      }
+    }
+
+    private double GetInferredMinCapacity() {
+      if (MinConstructionParameter.Value != null && // reconstruct from MinConstruction
+          ConstructionParameter.Value != null &&
+          DesignCapacityParameter.Value != null &&
+          ConstructionScalingExponentParameter.Value != null)
+        return Math.Pow(MinConstruction / Construction, 1 / ConstructionScalingExponent) * DesignCapacity;
+      if (MinMaintenanceParameter.Value != null && // reconstruct from MinMaintenance
+          MaintenanceParameter.Value != null &&
+          MaintenanceScalingExponentParameter.Value != null &&
+          DesignCapacityParameter.Value != null)
+        return Math.Pow(MinMaintenance / Maintenance, 1 / MaintenanceScalingExponent) * DesignCapacity;
+      throw new IndexOutOfRangeException("MinCapacity is not available and could be reconstructed from other parameters.");
+    }
+
+    #endregion
+
+    #region Construction & Cloning
+    public Conversion() {
+      Parameters.Add(new ValueParameter<StringValue>("Label", "The label/name of this conversion."));
+      Parameters.Add(new ValueParameter<StringValue>("Feedstock", "The product used as feedstock (@target)."));
+      Parameters.Add(new ValueParameter<DoubleValue>("Cost", "The conversion cost [EUR/t]."));
+      Parameters.Add(new ValueParameter<DoubleValue>("Construction", "The amortized construction costs [EUR/a]"));
+      Parameters.Add(new ValueParameter<DoubleValue>("Maintenance", "The amortized operation and maintenance costs [EUR/a]"));
+      Parameters.Add(new ValueParameter<DoubleValue>("DesignCapacity", "The yearly turnover of feedstock [t/a]."));
+      Parameters.Add(new ValueParameter<DoubleValue>("MinConstruction", "The minimum construction costs [EUR/a]"));
+      Parameters.Add(new ValueParameter<DoubleValue>("MinMaintenance", "The minimum maintenance costs [EUR/a]"));
+      Parameters.Add(new ValueParameter<DoubleValue>("ConstructionScalingExponent", "The exponent used for up- and downsising construction costs.", new DoubleValue(0.86)));
+      Parameters.Add(new ValueParameter<DoubleValue>("MaintenanceScalingExponent", "The exponent used for up- and downscaling maintenance costs.", new DoubleValue(0.91)));
+      Parameters.Add(new ValueParameter<DoubleValue>("SafetyStock", "The number of days feedstock needs to be stored on average."));
+      Parameters.Add(new ValueParameter<DoubleValue>("DryMatterLoss", "The percentage of feedstock that is lost due to shrinkage.", new DoubleValue(0.0)));
+      Parameters.Add(new ValueParameter<DoubleValue>("UtilizationFactor", "Assumed utilization of a plant.", new DoubleValue(0.7)));
+      Parameters.Add(new ValueParameter<LogisticAction>("Storage", "Description of storage cost components [EUR/t/a]"));
+      Parameters.Add(new ValueParameter<ValueParameterCollection>("Products", "The list and amounts of products created by the conversion."));
+      Parameters.Add(new ValueParameter<ValueParameterCollection>("ConstructionEmissions", "The set of amortized emissions and amounts [t/a]"));
+      Parameters.Add(new ValueParameter<ValueParameterCollection>("AvailableCapacities", "Dictionary of regions with their free capacities of this conversion type."));
+      Parameters.Add(new ValueParameter<ValueParameterCollection>("MaxCapacities", "Dictionary of regions (or 'Default') with their maximum allows capapcity for this conversion type."));
+      Parameters.Add(new ValueParameter<DoubleValue>("AvailableMaintenanceFactor", "Scaling factor for maintenance costs when using free capacities."));
+      Parameters.Add(new ValueParameter<DoubleValue>("MinCapacity", "Minimum capacity to be reasonably build."));
+      Parameters.Add(new ValueParameter<StringValue>("MainProduct", "The main output product created during this conversion process."));
+      Parameters.Add(new ValueParameter<DoubleValue>("MainProductConversionRate", "The conversion rate of the main output product. (This value is automatically calculated)"));
+      RegisterEventHandlers();
+    }
+
+    [StorableConstructor]
+    protected Conversion(bool isDeserializing) : base(isDeserializing) { }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (!Parameters.ContainsKey("AvailableCapacities"))
+        Parameters.Add(new ValueParameter<ValueParameterCollection>("AvailableCapacities", "Dictionary of regions with their free capacities of this conversion type."));
+      if (!Parameters.ContainsKey("MaxCapacities"))
+        Parameters.Add(new ValueParameter<ValueParameterCollection>("MaxCapacities", "Dictionary of regions (or 'Default') with their maximum allows capapcity for this conversion type."));
+      if (!Parameters.ContainsKey("AvailableMaintenanceFactor"))
+        Parameters.Add(new ValueParameter<DoubleValue>("AvailableMaintenanceFactor", "Scaling factor for maintenance costs when using free capacities."));
+      if (!Parameters.ContainsKey("DryMatterLoss"))
+        Parameters.Add(new ValueParameter<DoubleValue>("DryMatterLoss", "The percentage of feedstock that is lost due to shrinkage.", new DoubleValue(0.0)));
+      if (!Parameters.ContainsKey("MinCapacity"))
+        Parameters.Add(new ValueParameter<DoubleValue>("MinCapacity", "Minimum capacity to be reasonably build.", new DoubleValue(GetInferredMinCapacity())));
+      if (!Parameters.ContainsKey("MainProduct"))
+        Parameters.Add(new ValueParameter<StringValue>("MainProduct", "The main output product created during this conversion process."));
+      if (!Parameters.ContainsKey("MainProductConversionRate"))
+      Parameters.Add(new ValueParameter<DoubleValue>("MainProductConversionRate", "The conversion rate of the main output product. (This value is automatically calculated)"));
+      RegisterEventHandlers();
+    }
+
+    protected Conversion(Conversion orig, Cloner cloner)
+      : base(orig, cloner) {
+      RegisterEventHandlers();
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new Conversion(this, cloner);
+    }
+    #endregion
+
+    protected override void Parse(YamlMappingNode node) {
+      base.Parse(node);
+      MaybeDetermineMainProductConversionRate();
+    }
+
+    private void MaybeDetermineMainProductConversionRate() {
+      if (MainProductParameter.Value != null &&
+          (MainProductConversionRateParameter.Value == null || MainProductConversionRate == 0))
+        MainProductConversionRate = ((DoubleValue) Products[MainProduct].Value).Value;
+    }
+
+    public override void CollectParameterValues(System.Collections.Generic.IDictionary<string, IItem> values) {
+      var tmpDict = new Dictionary<string, IItem>();
+      base.CollectParameterValues(tmpDict);
+      foreach (var entry in tmpDict) {
+        if (entry.Key == "Label") continue;
+        if (entry.Key == "Feedstock") continue;
+        values.Add("Conversion " + Label + "." + Feedstock + "." + entry.Key, entry.Value);
+      }
+    }
+
+    private void RegisterEventHandlers() {
+      // when the HL value is changed
+      LabelParameter.ValueChanged += (sender, args) => {
+        UpdateName();
+        LabelParameter.Value.ValueChanged += (s, a) => { UpdateName(); };
+      };
+      // when the HL value's value is changed
+      LabelParameter.Value.ValueChanged += (sender, args) => { UpdateName(); };
+    }
+
+    private void UpdateName() {
+      this.Name = ItemName + ": " + Label;
+    }
+
+    public override bool IsEquivalentTo(DataItem other) {
+      var c = other as Conversion;
+      if (c == null) return false;
+      return c.Label == Label;
+    }
+
+    public void MaybeInferMainProduct(Dictionary<string, double> prices) {
+      if (MainProductParameter.Value != null) { return; }
+      string mainProductName = null;
+      double mainProductRevenue = 0;
+      foreach (var product in Products) {
+        double price = 0;
+        if (prices.TryGetValue(product.Name, out price) && product.Value is ValueParameter<DoubleValue>) {
+          var doubleValue = (IValueParameter<DoubleValue>)product;
+          var revenue = price*doubleValue.Value.Value;
+          if (mainProductName == null && revenue > 0 || revenue > mainProductRevenue) {
+            mainProductName = product.Name;
+            mainProductRevenue = revenue;
+          }
+        }
+      }
+      if (mainProductName != null) {
+        MainProduct = MainProduct;
+        MaybeDetermineMainProductConversionRate();
+      }
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Data/CostFactors.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Data/CostFactors.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Data/CostFactors.cs	(revision 15711)
@@ -0,0 +1,73 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.BioBoost.Data {
+
+  [StorableClass]
+  [Item("CostFactors", "Splits the cost into several differen areas which can are different for different regions.")]
+  public class CostFactors : DataItem {
+
+    #region Parameters
+    public IValueParameter<ValueParameterCollection> InvestmentParameter { get { return (IValueParameter<ValueParameterCollection>)Parameters["Investment"]; } }
+    public IValueParameter<ValueParameterCollection> LaborParameter { get { return (IValueParameter<ValueParameterCollection>)Parameters["Labor"]; } }
+    public IValueParameter<ValueParameterCollection> FuelParameter { get { return (IValueParameter<ValueParameterCollection>)Parameters["Fuel"]; } }
+    public IValueParameter<ValueParameterCollection> MaintenanceParameter { get { return (IValueParameter<ValueParameterCollection>)Parameters["Maintenance"]; } }
+    public IValueParameter<ValueParameterCollection> OtherParameter { get { return (IValueParameter<ValueParameterCollection>)Parameters["Other"]; } }
+    #endregion
+
+    #region Parameter Values
+    public ValueParameterCollection Investment { get { return InvestmentParameter.Value; } }
+    public ValueParameterCollection Labor { get { return LaborParameter.Value; } }
+    public ValueParameterCollection Fuel { get { return FuelParameter.Value; } }
+    public ValueParameterCollection Maintenance { get { return MaintenanceParameter.Value; } }
+    public ValueParameterCollection Other { get { return OtherParameter.Value; } }
+    #endregion
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected CostFactors(bool isDeserializing) : base(isDeserializing) { }
+
+    protected CostFactors(CostFactors orig, Cloner cloner) : base(orig, cloner) { }
+
+    public CostFactors() {
+      Parameters.Add(new ValueParameter<ValueParameterCollection>("Investment", "The cost factors for investment."));
+      Parameters.Add(new ValueParameter<ValueParameterCollection>("Labor", "The cost factors for labor."));
+      Parameters.Add(new ValueParameter<ValueParameterCollection>("Fuel", "The cost factors for fuel."));
+      Parameters.Add(new ValueParameter<ValueParameterCollection>("Maintenance", "The cost factors for maintenance."));
+      Parameters.Add(new ValueParameter<ValueParameterCollection>("Other", "The cost factors for other costs."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CostFactors(this, cloner);
+    }
+    #endregion
+
+
+    public override bool IsEquivalentTo(DataItem other) {
+      return true;
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Data/DataItem.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Data/DataItem.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Data/DataItem.cs	(revision 15711)
@@ -0,0 +1,191 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using YamlDotNet.RepresentationModel;
+
+namespace HeuristicLab.BioBoost.Data {
+
+  [StorableClass]
+  [Item("DataItem", "Generic Item for holding various pieces of information")]
+  public abstract class DataItem : ParameterizedNamedItem {
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected DataItem(bool isDeserializing) : base(isDeserializing) {}
+    protected DataItem(DataItem orig, Cloner cloner) : base(orig, cloner) {}
+    protected DataItem() {}
+    #endregion
+
+    public static IEnumerable<DataItem> ParseFile(string filename) {
+      using (var reader = File.OpenText(filename)) {
+        return ParseStream(reader);
+      }
+    }
+
+    public abstract bool IsEquivalentTo(DataItem other);
+
+    public static IEnumerable<DataItem> ParseStream(TextReader reader) {
+      var yaml = new YamlStream();
+      yaml.Load(reader);
+      if (yaml.Documents.Count == 0) return Enumerable.Empty<DataItem>();
+      var root = yaml.Documents[0].RootNode as YamlMappingNode;
+      if (root == null) return Enumerable.Empty<DataItem>();
+      return ParseItems(root);
+    }
+
+    private static IEnumerable<DataItem> ParseItems(YamlMappingNode root) {
+      foreach (var child in root.Children) {
+        var type = child.Key as YamlScalarNode;
+        var value = child.Value as YamlSequenceNode;
+        if (type == null || value == null) {
+          // ignore or error?
+        } else {
+          switch (((string) type).ToLowerInvariant()) {
+            case "products":
+              foreach (var item in ParseSequence<Product>(value))
+                yield return item;
+              break;
+            case "logistics":
+              foreach (var item in ParseSequence<Logistic>(value))
+                yield return item;
+              break;
+            case "conversions":
+              foreach (var item in ParseSequence<Conversion>(value))
+                yield return item;
+              break;
+            case "cost-factors":
+              foreach (var item in ParseSequence<CostFactors>(value))
+                yield return item;
+              break;
+          }
+        }
+      }
+    }
+
+    public static IEnumerable<T> ParseSequence<T>(YamlSequenceNode seq) where T : DataItem, new() {
+      foreach (var node in seq.Children) {
+        var mappingNode = node as YamlMappingNode;
+        if (mappingNode == null) continue;
+        var item = new T();
+        item.Parse(mappingNode);
+        yield return item;
+      }
+    }
+
+    protected virtual void Parse(YamlMappingNode node) {
+      foreach (var child in node) {
+        var parameterNode = child.Key as YamlScalarNode;
+        if (parameterNode == null) continue;
+        var parameterName = ConvertNameYAML2NET(parameterNode.ToString());
+        IParameter param;
+        if (Parameters.TryGetValue(parameterName, out param) && param is IValueParameter) {
+          SetParameter(param, child.Value);
+        }
+      }
+      // TODO: check that all parameters have been filled
+    }
+
+    private static void SetParameter(IParameter param, YamlNode node) {
+      if (node is YamlScalarNode) {
+        SetScalarParameter((IValueParameter) param, (YamlScalarNode) node);
+      } else if (node is YamlMappingNode) {
+        SetMappingParameter((IValueParameter) param, (YamlMappingNode) node);
+      } else {
+        // TODO: parse error/warning?
+      }
+    }
+
+    private static void SetScalarParameter(IValueParameter param, YamlScalarNode node) {
+      if (param.DataType == typeof(StringValue)) {
+        param.Value = new StringValue(node.ToString());
+      } else if (param.DataType == typeof(DoubleValue)) {
+        param.Value = new DoubleValue(Double.Parse(node.ToString(), CultureInfo.InvariantCulture));
+      } else {
+        // TODO: parse error/warning?
+      }
+    }
+
+    private static void SetMappingParameter(IValueParameter param, YamlMappingNode node) {
+      if (typeof (DataItem).IsAssignableFrom(param.DataType)) {
+        var constructorInfo = param.DataType.GetConstructor(Type.EmptyTypes);
+        if (constructorInfo != null) {
+          var item = (DataItem) constructorInfo.Invoke(new object[0]);
+          item.Parse(node);
+          param.Value = item;
+          return;
+        }
+      } else if (param.DataType.IsAssignableFrom(typeof(ValueParameterCollection))) {
+        var dict = new ValueParameterCollection();
+        foreach (var child in node.Children) {
+          var key = child.Key as YamlScalarNode;
+          if (key != null) {
+            var p = new ValueParameter<DoubleValue>(key.ToString());
+            SetParameter(p, child.Value);
+            dict.Add(p);
+          } else {
+            // TODO: parse error/warning?
+          }
+        }
+        param.Value = dict;
+      }
+      // TODO: parse error? warning?
+    }
+
+    public static IItem CreateItem(YamlNode node) {
+      var n = node as YamlScalarNode;
+      if (n == null) return null;
+      double d;
+      string s = n.ToString();
+      if (Double.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out d)) {
+        return new DoubleValue(d);
+      } else {
+        return new StringValue(s);
+      }
+    }
+
+    #region Auxiliary Methods
+    public static string ConvertNameYAML2NET(string s) {
+      var sb = new StringBuilder();
+      foreach (var word in s.Split('-')) {
+        sb.Append(CultureInfo.InvariantCulture.TextInfo.ToTitleCase(word.ToLower()));
+      }
+      return sb.ToString();
+    }
+
+    public static string ConvertNameNET2YAML(string s) {
+      return Regex.Replace(s, "([A-Z])", "-$1", RegexOptions.Compiled).Trim().ToLower();
+    }
+    #endregion
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Data/Logistic.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Data/Logistic.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Data/Logistic.cs	(revision 15711)
@@ -0,0 +1,135 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.BioBoost.Data {
+  [StorableClass]
+  [Item("Logistic", "Describes a logistic modality for a certain product.")]
+  public class Logistic : DataItem {
+
+    #region Parameters
+    public IValueParameter<StringValue> ModeParameter { get { return (IValueParameter<StringValue>)Parameters["Mode"]; } }
+    public IValueParameter<StringValue> ProductParameter { get { return (IValueParameter<StringValue>)Parameters["Product"]; } }
+    public IValueParameter<StringValue> DistancesParameter { get { return (IValueParameter<StringValue>)Parameters["Distances"]; } }
+    public IValueParameter<LogisticAction> TransportParameter { get { return (IValueParameter<LogisticAction>)Parameters["Transport"]; } }
+    public IValueParameter<LogisticAction> HandlingParameter { get { return (IValueParameter<LogisticAction>)Parameters["Handling"]; } }
+    public IValueParameter<DoubleValue> MinAmountParameter { get { return (IValueParameter<DoubleValue>)Parameters["MinAmount"]; } }
+    public IValueParameter<DoubleValue> MaxAmountParameter { get { return (IValueParameter<DoubleValue>)Parameters["MaxAmount"]; } }
+    public IValueParameter<DoubleValue> MaxDistanceParameter { get { return (IValueParameter<DoubleValue>)Parameters["MaxDistance"]; } }
+    public IValueParameter<DoubleValue> WaterContentParameter { get { return (IValueParameter<DoubleValue>)Parameters["WaterContent"]; } }
+    #endregion
+
+    #region Parameter Values
+    public string Mode { get { return ModeParameter.Value.Value; } }
+    public string Product { get { return ProductParameter.Value.Value; } }
+    public string Distances { get { return DistancesParameter.Value.Value; } }
+    public double MinAmount { get { return MinAmountParameter.Value.Value; } }
+    public double MaxAmount { get { return MaxAmountParameter.Value.Value; } }
+    public double MaxDistance { get { return MaxDistanceParameter.Value.Value; } }
+    public double WaterContent { get { return WaterContentParameter.Value.Value; } }
+    public LogisticAction Transport { get { return TransportParameter.Value; } }
+    public LogisticAction Handling { get { return HandlingParameter.Value; } }
+    #endregion
+
+    #region Construction & Cloning
+    public Logistic() {
+      Parameters.Add(new ValueParameter<StringValue>("Mode", "The logistic's mode."));
+      Parameters.Add(new ValueParameter<StringValue>("Product", "The logistic's transported product (from source to target)."));
+      Parameters.Add(new ValueParameter<StringValue>("Distances", "The distances matrix to be used."));
+      Parameters.Add(new ValueParameter<DoubleValue>("MinAmount", "The minimum amount per year to be transported (if any)", new DoubleValue(0)));
+      Parameters.Add(new ValueParameter<DoubleValue>("MaxAmount", "The maximum amount per year to be transported (if any)", new DoubleValue(Double.MaxValue)));
+      Parameters.Add(new ValueParameter<DoubleValue>("MaxDistance", "The maximum distance this logistic should cover", new DoubleValue(Double.MaxValue)));
+      Parameters.Add(new ValueParameter<DoubleValue>("WaterContent", "The amount of water considered in tranport/handling costs", new DoubleValue(0)));
+      Parameters.Add(new ValueParameter<LogisticAction>("Transport", "The single or compound transport cost per tkm."));
+      Parameters.Add(new ValueParameter<LogisticAction>("Handling", "The single or compound handling cost per t."));
+
+      RegisterEventHandlers();
+    }
+
+    [StorableConstructor]
+    protected Logistic(bool isDeserializing) : base(isDeserializing) { }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (!Parameters.ContainsKey("MinAmount"))
+        Parameters.Add(new ValueParameter<DoubleValue>("MinAmount", "The minimum amount per year to be transported (if any)", new DoubleValue(0)));
+      if (!Parameters.ContainsKey("MaxAmount"))
+        Parameters.Add(new ValueParameter<DoubleValue>("MaxAmount", "The maximum amount per year to be transported (if any)", new DoubleValue(Double.MaxValue)));
+      if (!Parameters.ContainsKey("MaxDistance"))
+        Parameters.Add(new ValueParameter<DoubleValue>("MaxDistance", "The maximum distance this logistic should cover", new DoubleValue(Double.MaxValue)));
+      if (!Parameters.ContainsKey("WaterContent"))
+        Parameters.Add(new ValueParameter<DoubleValue>("WaterContent", "The amount of water considered in tranport/handling costs", new DoubleValue(0)));
+      RegisterEventHandlers();
+    }
+
+    protected Logistic(Logistic orig, Cloner cloner)
+      : base(orig, cloner) {
+      RegisterEventHandlers();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new Logistic(this, cloner);
+    }
+    #endregion
+
+    public override void CollectParameterValues(System.Collections.Generic.IDictionary<string, IItem> values) {
+      var tmpDict = new Dictionary<string, IItem>();
+      base.CollectParameterValues(tmpDict);
+      foreach (var entry in tmpDict) {
+        if (entry.Key == "Mode") continue;
+        if (entry.Key == "Product") continue;
+        values.Add("Logistics " + Product + "." + Mode + "." + entry.Key, entry.Value);
+      }
+    }
+
+    private void RegisterEventHandlers() {
+      // when the HL value is changed
+      ModeParameter.ValueChanged += (sender, args) => {
+        UpdateName();
+        ModeParameter.Value.ValueChanged += (s, a) => { UpdateName(); };
+      };
+      ProductParameter.ValueChanged += (sender, args) => {
+        UpdateName();
+        ProductParameter.Value.ValueChanged += (s, a) => { UpdateName(); };
+      };
+      // when the HL value's value is changed
+      ModeParameter.Value.ValueChanged += (sender, args) => { UpdateName(); };
+      ProductParameter.Value.ValueChanged += (sender, args) => { UpdateName(); };
+    }
+
+    private void UpdateName() {
+      this.Name = ItemName + ": " + Product + " (" + Mode + ")";
+    }
+
+    public override bool IsEquivalentTo(DataItem other) {
+      var l = other as Logistic;
+      if (l == null) return false;
+      return l.Mode == Mode && l.Product == Product;
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Data/LogisticAction.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Data/LogisticAction.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Data/LogisticAction.cs	(revision 15711)
@@ -0,0 +1,80 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.BioBoost.Data {
+  [StorableClass]
+  [Item("LogisticAction", "Summarizes cost factors and emissions for a logistic action.")]
+  public class LogisticAction : DataItem {
+
+    #region Parameters
+    public IValueParameter<DoubleValue> InvestmentParameter { get { return (IValueParameter<DoubleValue>)Parameters["Investment"]; } }
+    public IValueParameter<DoubleValue> LaborParameter { get { return (IValueParameter<DoubleValue>)Parameters["Labor"]; } }
+    public IValueParameter<DoubleValue> FuelParameter { get { return (IValueParameter<DoubleValue>)Parameters["Fuel"]; } }
+    public IValueParameter<DoubleValue> MaintenanceParameter { get { return (IValueParameter<DoubleValue>)Parameters["Maintenance"]; } }
+    public IValueParameter<DoubleValue> OtherParameter { get { return (IValueParameter<DoubleValue>)Parameters["Other"]; } }
+    public IValueParameter<ValueParameterCollection> EmissionsParameter {
+      get { return (IValueParameter<ValueParameterCollection>)Parameters["Emissions"]; }
+    }
+    #endregion
+
+    #region Parameter Values
+    public double Investment { get { return InvestmentParameter.Value.Value; } }
+    public double Labor { get { return LaborParameter.Value.Value; } }
+    public double Fuel { get { return FuelParameter.Value.Value; } }
+    public double Maintenance { get { return MaintenanceParameter.Value.Value; } }
+    public double Other { get { return OtherParameter.Value.Value; } set { OtherParameter.Value = new DoubleValue(value); } }
+
+    public ValueParameterCollection Emissions { get { return EmissionsParameter.Value; } }
+    #endregion
+
+    #region Construction & Cloning
+
+    public LogisticAction() {
+      Parameters.Add(new ValueParameter<DoubleValue>("Investment", "The investment cost per unit."));
+      Parameters.Add(new ValueParameter<DoubleValue>("Labor", "The labor cost per unit."));
+      Parameters.Add(new ValueParameter<DoubleValue>("Fuel", "The fuelt cost per unit."));
+      Parameters.Add(new ValueParameter<DoubleValue>("Maintenance", "The maintenance cost per unit."));
+      Parameters.Add(new ValueParameter<DoubleValue>("Other", "other costs per unit."));
+      Parameters.Add(new ValueParameter<ValueParameterCollection>("Emissions", "The set of emission amounts per unit."));
+    }
+
+    [StorableConstructor]
+    protected LogisticAction(bool isDeserializing) : base(isDeserializing) { }
+
+    protected LogisticAction(LogisticAction orig, Cloner cloner) : base(orig, cloner) { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new LogisticAction(this, cloner);
+    }
+
+    #endregion
+
+    public override bool IsEquivalentTo(DataItem other) {
+      return false;
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Data/Product.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Data/Product.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Data/Product.cs	(revision 15711)
@@ -0,0 +1,146 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.BioBoost.Data {
+  [StorableClass]
+  [Item("Product", "Summarizes product information.")]
+  public class Product : DataItem {
+
+    #region Parameters
+    public IValueParameter<StringValue> LabelParameter { get { return (IValueParameter<StringValue>)Parameters["Label"]; } }
+    public IValueParameter<DoubleValue> PriceParameter { get { return (IValueParameter<DoubleValue>)Parameters["Price"]; } }
+    public IValueParameter<DoubleValue> PriceAtSourceParameter { get { return (IValueParameter<DoubleValue>)Parameters["PriceAtSource"]; } }
+    public IValueParameter<DoubleValue> PriceAtTargetParameter { get { return (IValueParameter<DoubleValue>)Parameters["PriceAtTarget"]; } }
+    public IValueParameter<DoubleValue> MaxPenaltyParameter { get { return (IValueParameter<DoubleValue>)Parameters["MaxPenalty"]; } }
+    public IValueParameter<DoubleValue> PercentageParameter { get { return (IValueParameter<DoubleValue>)Parameters["Percentage"]; } }
+    public IValueParameter<DoubleValue> MaxPriceParameter { get { return (IValueParameter<DoubleValue>)Parameters["MaxPrice"]; } }
+    public IValueParameter<ValueParameterCollection> PriceScalingParameter { get { return (IValueParameter<ValueParameterCollection>)Parameters["PriceScaling"]; } }
+    public IValueParameter<ValueParameterCollection> MaxPriceScalingParameter { get { return (IValueParameter<ValueParameterCollection>)Parameters["MaxPriceScaling"]; } }
+    #endregion
+
+    #region Parameter Values
+    public string Label { get { return LabelParameter.Value.Value; } }
+    public double Price { get { return PriceParameter.Value.Value; } }
+    public double PriceAtSource { get { return (PriceAtSourceParameter.Value ?? PriceParameter.Value).Value; } }
+    public double PriceAtTarget { get { return (PriceAtTargetParameter.Value ?? PriceParameter.Value).Value; } }
+    public double MaxPenalty { get { return MaxPenaltyParameter.Value.Value; } }
+    public double Percentage { get { return PercentageParameter.Value.Value; } }
+    public double MaxPrice { get { return MaxPriceParameter.Value.Value; } }
+    public ValueParameterCollection PriceScaling { get { return PriceScalingParameter.Value; } }
+    public ValueParameterCollection MaxPriceScaling { get { return MaxPriceScalingParameter.Value; } }
+    #endregion
+
+    #region Construction & Cloning
+    public Product() {
+      Parameters.Add(new ValueParameter<StringValue>("Label", "The label/name of this product."));
+      Parameters.Add(new ValueParameter<DoubleValue>("Price", "The product's price; can be negative to indicate disposal cost.", new DoubleValue(0)));
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("PriceAtSource", "The product's price at the source/production location."));
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("PriceAtTarget", "The product's price when delivered to the customer."));
+      Parameters.Add(new ValueParameter<DoubleValue>("MaxPenalty", "The maximum penalty factor that is then multiplied with the base price at maximum market saturation.", new DoubleValue(1)));
+      Parameters.Add(new ValueParameter<DoubleValue>("Percentage", "The percentage of the feedstock utilization where the price starts to increase.", new DoubleValue(0.5)));
+      Parameters.Add(new ValueParameter<DoubleValue>("MaxPrice", "The maximum product's price at 100 percent utilization.", new DoubleValue(0)));
+      Parameters.Add(new ValueParameter<ValueParameterCollection>("PriceScaling", "Regional scaling of base price", new ValueParameterCollection()));
+      Parameters.Add(new ValueParameter<ValueParameterCollection>("MaxPriceScaling", "Regional scaling of max price", new ValueParameterCollection()));
+      RegisterEventHandlers();
+    }
+
+    [StorableConstructor]
+    protected Product(bool isDeserializing) : base(isDeserializing) { }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterEventHandlers();
+      if (!Parameters.ContainsKey("PriceScaling"))
+        Parameters.Add(new ValueParameter<ValueParameterCollection>("PriceScaling", "Regional scaling of base price", new ValueParameterCollection()));
+      if (!Parameters.ContainsKey("MaxPriceScaling"))
+        Parameters.Add(new ValueParameter<ValueParameterCollection>("MaxPriceScaling", "Regional scaling of max price", new ValueParameterCollection()));
+    }
+
+    protected Product(Product orig, Cloner cloner)
+      : base(orig, cloner) {
+      RegisterEventHandlers();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new Product(this, cloner);
+    }
+    #endregion
+
+    public override void CollectParameterValues(System.Collections.Generic.IDictionary<string, IItem> values) {
+      var tmpDict = new Dictionary<string, IItem>();
+      base.CollectParameterValues(tmpDict);
+      foreach (var entry in tmpDict) {
+        if (entry.Key == "Label") continue;
+        values.Add("Product " + Label + "." + entry.Key, entry.Value);
+      }
+    }
+    private void RegisterEventHandlers() {
+      // when the HL value is changed
+      LabelParameter.ValueChanged += (sender, args) => {
+        UpdateName();
+        LabelParameter.Value.ValueChanged += (s, a) => { UpdateName(); };
+      };
+      // when the HL value's value is changed
+      LabelParameter.Value.ValueChanged += (sender, args) => { UpdateName(); };
+    }
+
+    private void UpdateName() {
+      this.Name = ItemName + ": " + Label;
+    }
+
+    public override bool IsEquivalentTo(DataItem other) {
+      var p = other as Product;
+      if (p == null) return false;
+      return p.Label == Label;
+    }
+
+    public double GetRegionalBasePrice(string regionName) {
+      IValueParameter priceParam = null;
+      IValueParameter<DoubleValue> price;
+      while (regionName.Length >= 2) {
+        if (PriceScaling.TryGetValue(regionName, out priceParam)) break;
+        regionName = regionName.Remove(regionName.Length - 1);
+      }
+      price = priceParam as IValueParameter<DoubleValue>;
+      if (price != null) return Price * price.Value.Value;
+      return Price;
+    }
+
+    public double GetRegionalMaxPrice(string regionName) {
+      IValueParameter maxPriceParam = null;
+      IValueParameter<DoubleValue> maxPrice;
+      while (regionName.Length >= 2) {
+        if (MaxPriceScaling.TryGetValue(regionName, out maxPriceParam)) break;
+        regionName = regionName.Remove(regionName.Length - 1);
+      }
+      maxPrice = maxPriceParam as IValueParameter<DoubleValue>;
+      if (maxPrice != null) return MaxPrice * maxPrice.Value.Value;
+      return MaxPrice;
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/AggregateEvaluator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/AggregateEvaluator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/AggregateEvaluator.cs	(revision 15711)
@@ -0,0 +1,180 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Threading;
+using HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System.Collections.Generic;
+
+namespace HeuristicLab.BioBoost.Evaluators {
+  [StorableClass]
+  public class AggregateEvaluator : AlgorithmOperator, IBioBoostSimulationEvaluator {
+
+    #region ISingleObjectiveEvaluator Members
+    public ILookupParameter<DoubleValue> QualityParameter { get { return TotalCostParameter; } }
+    #endregion
+
+    #region IMultiObjectEvaluator Members
+    public ILookupParameter<DoubleArray> QualitiesParameter { get { return (ILookupParameter<DoubleArray>) Parameters["QualityCriteria"]; } }
+    #endregion
+
+    #region Parameters
+    public ILookupParameter<ResultCollection> CostsParameter {
+      get { return (ILookupParameter<ResultCollection>)Parameters["Costs"]; }
+    }
+    public ILookupParameter<ResultCollection> IntermediateResultsParameter {
+      get { return (ILookupParameter<ResultCollection>)Parameters["IntermediateResults"]; }
+    }
+    public LookupParameter<BioBoostProblemData> ProblemDataParameter {
+      get { return (LookupParameter<BioBoostProblemData>)Parameters["ProblemData"]; }
+    }
+    public LookupParameter<DoubleValue> TotalCostParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["TotalCost"]; }
+    }
+    public LookupParameter<BoolValue> RemoveIntermediateResultsParameter {
+      get { return (LookupParameter<BoolValue>)Parameters["RemoveIntermediateResults"]; }
+    }
+    #endregion
+
+    #region Parameter Values
+    public ResultCollection Costs {
+      get { return CostsParameter.ActualValue; }
+    }
+    public ResultCollection IntermediateResults {
+      get { return IntermediateResultsParameter.ActualValue; }
+    }
+    public BioBoostProblemData ProblemData {
+      get { return ProblemDataParameter.ActualValue; }
+      set { ProblemDataParameter.ActualValue = value; }
+    }
+    public bool RemoveIntermediateResults {
+      get { return RemoveIntermediateResultsParameter.ActualValue.Value; }
+      set { RemoveIntermediateResultsParameter.ActualValue = new BoolValue(value); }
+    }
+    #endregion
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected AggregateEvaluator(bool isDeserializing) : base(isDeserializing) { }
+    protected AggregateEvaluator(AggregateEvaluator orig, Cloner cloner) : base(orig, cloner) { }
+    public AggregateEvaluator() {
+      Parameters.Add(new LookupParameter<ResultCollection>("Costs", "Collection of all costs"));
+      Parameters.Add(new LookupParameter<ResultCollection>("IntermediateResults", "Collection of all intermediate results."));
+      Parameters.Add(new LookupParameter<DoubleValue>("TotalCost", "Total cost of all aggregation steps."));
+      Parameters.Add(new LookupParameter<BioBoostProblemData>("ProblemData", "The encapsulated problem instance."));
+      Parameters.Add(new LookupParameter<BoolValue>("RemoveIntermediateResults", "Whether to remove intermediate results created during evaluation."));
+      Parameters.Add(new LookupParameter<DoubleArray>("QualityCriteria", "The list of quality criteria used for multi-objecjtive optimization."));
+      SetOperatorChain(new SingleSuccessorOperator[] {
+        new InitializationEvaluator(),
+        new FeedstockCostEvaluator(),
+        new LogisticCostEvaluator(),
+        new ConversionCostEvaluator(),
+        new LogisticCostEvaluator(),
+        new ConversionCostEvaluator(),
+        new SinkEvaluator(),
+        new ConcludingEvaluator()
+      });
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new AggregateEvaluator(this, cloner);
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    void AfterDeserialization() {
+      if (!Parameters.ContainsKey("QualityCriteria"))
+        Parameters.Add(new LookupParameter<DoubleArray>("QualityCriteria", "The list of quality criteria used for multi-objecjtive optimization."));
+    }
+    #endregion
+
+    protected void SetOperatorChain(IEnumerable<SingleSuccessorOperator> operators) {
+      OperatorGraph.InitialOperator = null;
+      OperatorGraph.Operators.Clear();
+      SingleSuccessorOperator lastOp = null;
+      foreach (var op in operators) {
+        if (lastOp == null) {
+          OperatorGraph.InitialOperator = op;
+        } else {
+          lastOp.Successor = op;
+        }
+        lastOp = op;
+      }
+    }
+
+    protected bool InitializeCostsAndIntermediateResults = true;
+    public override IOperation Apply() {
+      if (InitializeCostsAndIntermediateResults) {
+        CostsParameter.ActualValue = new ResultCollection();
+        IntermediateResultsParameter.ActualValue = new ResultCollection();
+      }
+      return base.Apply();
+    }
+
+    // evaluates a solution for a bioboost problem specified by the utlizations and transport targets 
+    // and returns the resulting scope after complete evaluation
+    // this is called by the BioBoostCompoundSolution to update all solution information after a change
+    public static Scope Evaluate(BioBoostProblemData problemData,
+      IEnumerable<KeyValuePair<string, DoubleArray>> utilizations,
+      IEnumerable<KeyValuePair<string, IntArray>> transportTargets) {
+      // prepare scope structure
+      // (necessary because InitializationEvaluator clears the solutionCandidateScope)
+      var problemScope = new Scope("Problem");
+      var solutionCandScope = new Scope("SolutionCandidate");
+      problemScope.SubScopes.Add(solutionCandScope);
+
+      // create variables for parameter values
+      problemScope.Variables.Add(new Variable("ProblemData", problemData));
+      problemScope.Variables.Add(new Variable("RemoveIntermediateResults", new BoolValue(true)));
+      foreach (var kvp in utilizations) {
+        solutionCandScope.Variables.Add(new Variable(kvp.Key, kvp.Value));
+      }
+      foreach (var kvp in transportTargets) {
+        solutionCandScope.Variables.Add(new Variable(kvp.Key, kvp.Value));
+      }
+
+      // effectively executes the operators like an engine
+      var eval = new AggregateEvaluator();
+      var context = new HeuristicLab.Core.ExecutionContext(null, eval, solutionCandScope);
+
+      // start engine to execute the operatorgraph within this algorithmoperator and wait until it's done
+      using (var wh = new AutoResetEvent(false)) {
+        var engine = new HeuristicLab.SequentialEngine.SequentialEngine();
+        engine.Stopped += (sender, args) => {
+          wh.Set();
+        };
+        engine.ExceptionOccurred += (sender, args) => {
+          wh.Set();
+        };
+
+        engine.Prepare(context);
+        engine.Start();
+        wh.WaitOne();
+      }
+      return solutionCandScope;
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/BioBoostEvaluator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/BioBoostEvaluator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/BioBoostEvaluator.cs	(revision 15711)
@@ -0,0 +1,96 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.BioBoost.Operators;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System;
+
+namespace HeuristicLab.BioBoost.Evaluators {
+
+  [StorableClass]
+  public abstract class BioBoostEvaluator : BioBoostOperator  {
+
+    #region Parameter
+    public ILookupParameter<ResultCollection> CostsParameter {
+      get { return (ILookupParameter<ResultCollection>) Parameters["Costs"]; }
+    }
+    public ILookupParameter<ResultCollection> IntermediateResultsParameter {
+      get { return (ILookupParameter<ResultCollection>) Parameters["IntermediateResults"]; }
+    }
+    #endregion
+
+    #region Parameter Values
+    public ResultCollection Costs {
+      get { return CostsParameter.ActualValue; }
+    }
+    public ResultCollection IntermediateResults {
+      get { return IntermediateResultsParameter.ActualValue; }
+    }
+    #endregion
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected BioBoostEvaluator(bool isDeserializing) : base(isDeserializing) {}
+    protected BioBoostEvaluator(BioBoostEvaluator original, Cloner cloner) : base(original, cloner) {}
+    protected BioBoostEvaluator() {
+      Parameters.Add(new LookupParameter<ResultCollection>("Costs", "Collection of all costs."));
+      Parameters.Add(new LookupParameter<ResultCollection>("Emissions", "Collection of all emissions."));
+      Parameters.Add(new LookupParameter<ResultCollection>("IntermediateResults", "Collection of all intermeditate results."));
+    }
+    #endregion
+
+    protected void PutInScope(string label, IItem value, bool isIntermediateVariable) {
+      var vars = ExecutionContext.Scope.Variables;
+      var var = new Variable(label, value);
+      if (vars.ContainsKey(label))
+        vars.Remove(label);
+      vars.Add(var);
+      if (isIntermediateVariable)
+        IntermediateResults.Add(new Result(var.Name, value.GetType()));
+    }
+
+    protected void AddInScope(string label, DoubleArray values, bool isIntermediateValue) {
+      var oldValues = GetFromScope<DoubleArray>(label);
+      if (oldValues != null) {
+        if (oldValues.Length != values.Length)
+          throw new ArgumentException("DoubleArray lentgh differs from new length, cannot add " + label);
+        for (int i = 0; i<oldValues.Length; i++)
+          oldValues[i] += values[i];
+      } else {
+        PutInScope(label, values, isIntermediateValue);
+      }
+    }
+
+    protected void AddCost(string label, double value) {
+      if (Equals(value, 0d)) return;
+      if (Costs.ContainsKey(label)) {
+        ((DoubleValue)Costs[label].Value).Value += value;
+      } else {
+        Costs.Add(new Result(label, new DoubleValue(value)));
+      }
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/ConcludingEvaluator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/ConcludingEvaluator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/ConcludingEvaluator.cs	(revision 15711)
@@ -0,0 +1,338 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.RegularExpressions;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System.Linq;
+using HeuristicLab.BioBoost.Representation;
+using HeuristicLab.BioBoost.Utils;
+
+namespace HeuristicLab.BioBoost.Evaluators {
+  [StorableClass]
+  public class ConcludingEvaluator : BioBoostEvaluator {
+
+    #region Parameter
+    public LookupParameter<DoubleValue> TotalCostParameter {
+      get { return (LookupParameter<DoubleValue>) Parameters["TotalCost"]; }
+    }
+    public LookupParameter<BoolValue> RemoveIntermediateResultsParameter {
+      get { return (LookupParameter<BoolValue>) Parameters["RemoveIntermediateResults"]; }
+    }
+    public ILookupParameter<DoubleArray> QualityCriteriaParameter {
+      get { return (ILookupParameter<DoubleArray>) Parameters["QualityCriteria"]; }
+    }
+    #endregion
+
+    #region Parameter Values
+    public double TotalCost {
+      get { return TotalCostParameter.ActualValue.Value; }
+      set { TotalCostParameter.ActualValue = new DoubleValue(value); }
+    }
+    public bool RemoveIntermediateResults {
+      get { return RemoveIntermediateResultsParameter.ActualValue.Value; }
+      set { RemoveIntermediateResultsParameter.ActualValue = new BoolValue(value); }
+    }
+    public DoubleArray QualityCriteria {
+      get { return QualityCriteriaParameter.ActualValue; }
+      set { QualityCriteriaParameter.ActualValue = value; }
+    }
+    #endregion
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected ConcludingEvaluator(bool isDeserializing) : base(isDeserializing) {}
+    public ConcludingEvaluator() {
+      Parameters.Add(new LookupParameter<BoolValue>("RemoveIntermediateResults", "Whether to remove intermediate results created during evaluation."));
+      Parameters.Add(new LookupParameter<DoubleValue>("TotalCost", "Overall cost of the whole scenario."));
+      Parameters.Add(new LookupParameter<DoubleArray>("QualityCriteria", "The list of qualities to consider."));
+    }
+    public ConcludingEvaluator(ConcludingEvaluator original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ConcludingEvaluator(this, cloner);
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    void AfterDeserialization() {
+      if (!Parameters.ContainsKey("QualityCriteria"))
+        Parameters.Add(new LookupParameter<DoubleArray>("QualityCriteria", "The list of qualities to consider."));
+    }
+    #endregion
+
+    private readonly Regex penaltyRegex = new Regex("[Pp]enalt(y|ies)$");
+
+    public override IOperation Apply() {
+      CreateAggregationLayers();
+      var expenses = 0d;
+      var revenues = 0d;
+      var penalties = 0d;
+      foreach (var cost in Costs) {
+        var value = cost.Value as DoubleValue;
+        if (value == null) continue;
+        if (penaltyRegex.IsMatch(cost.Name)) {
+          penalties += value.Value;
+        } else if (value.Value > 0) {
+          expenses += value.Value;
+        } else {
+          revenues -= value.Value;
+        }
+      }
+      var roi = Math.Abs(expenses) < 1 ? revenues : (revenues - expenses)/expenses;
+      TotalCost = roi - penalties;
+      var qualities = new List<double> {TotalCost};
+      if (RemoveIntermediateResults) {
+        foreach (var r in IntermediateResults) {
+          RemoveFromScope(r.Name);
+        }
+        RemoveFromScope(IntermediateResultsParameter.ActualName);
+        RemoveFromScope(CostsParameter.ActualName);
+      }
+      foreach (var p in ProblemData.Products) {
+        var amounts = GetFromScope<DoubleArray>(LayerDescriptor.AmountsAtSource.NameWithPrefix(p.Label));
+        if (amounts != null) {
+          qualities.Add(amounts.Sum());
+        }
+      }
+      QualityCriteria = new DoubleArray(qualities.ToArray());
+      return base.Apply();
+    }
+
+    private void CreateAggregationLayers() {
+      // for transport targets (straw, biosyncrude)
+      // aggregate sources (recursively)
+      // straw -> straw targets
+      // straw -> straw targets -> biosyncrude targets
+      // biosyncrude -> biosyncrude targets
+      var scope = ExecutionContext.Scope;
+
+      // straw sources, biosyncrude sources
+      var sources = scope.Variables
+        .Where(v => LayerDescriptor.Sources.IsSuffixOf(v.Name))
+        .Where(v => v.Value is ItemArray<ItemList<IntValue>>)
+        .ToDictionary(
+          v => LayerDescriptor.Sources.RemoveSuffixFrom(v.Name),
+          v => (ItemArray<ItemList<IntValue>>)v.Value);
+
+      // determine straw 1, biosyncrude 2 ???
+      // -> find utilizations
+      var feedstocks = scope.Variables
+        .Where(v => LayerDescriptor.Utilizations.IsSuffixOf(v.Name))
+        .Select(v => LayerDescriptor.Utilizations.RemoveSuffixFrom(v.Name))
+        .ToHashSet();
+      if (feedstocks.Count > 1) throw new InvalidOperationException("Currently only one feedstock is allowed.");
+      if (feedstocks.Count == 0) return; 
+      var feedstock = feedstocks.First();
+      var carriers = sources.Keys.Where(k => k != feedstock);
+      if (carriers.Count() > 1) throw new InvalidOperationException("Currently only one carrier is allowed");
+      var carrier = carriers.Count() == 0 ? null : carriers.First();
+
+      var feedstockSources = sources[feedstock];
+      var carrierSources = carrier == null ? null : sources[carrier];
+      var finalProductName = GetFinalProductName(carrier ?? feedstock);
+      if (finalProductName == null) finalProductName = "TransportFuel";
+
+
+      if (carrier == null) {
+        AnalyzeSingleEchelon(feedstock, finalProductName, feedstockSources);
+      } else {
+        AnalyzeBinaryEchelon(feedstock, carrier, finalProductName, feedstockSources, carrierSources);
+      }
+    }
+
+    private void AnalyzeBinaryEchelon(string feedstock, string carrier, string finalProductName, ItemArray<ItemList<IntValue>> feedstockSources, ItemArray<ItemList<IntValue>> carrierSources) {
+      var length = feedstockSources.Length;
+
+      var feedstockCosts = GetFromScope<DoubleArray>(LayerDescriptor.TotalCostsAtSource.NameWithPrefix(feedstock));
+      //var feedstockAmounts = GetFromScope<DoubleArray>(LayerDescriptor.AmountsTransportedFromSource.NameWithPrefix(feedstock));
+      var feedstockLogisticCosts = GetFromScope<DoubleArray>(LayerDescriptor.TotalLogisticCosts.NameWithPrefix(feedstock));
+      var carrierLogisticCosts = GetFromScope<DoubleArray>(LayerDescriptor.TotalLogisticCosts.NameWithPrefix(carrier));
+      var decentralConversionCosts = GetFromScope<DoubleArray>(LayerDescriptor.TotalAmortizedConversionCosts.NameWithPrefix(feedstock));
+      var finalProductAmounts = GetFromScope<DoubleArray>(LayerDescriptor.AmountsAtSource.NameWithPrefix(finalProductName));
+      var carrierProductAmounts = GetFromScope<DoubleArray>(LayerDescriptor.AmountsTransportedFromSource.NameWithPrefix(carrier));
+      var finalProductCosts = GetFromScope<DoubleArray>(LayerDescriptor.TotalCostsAtSource.NameWithPrefix(finalProductName));
+      var carrierProductCosts = GetFromScope<DoubleArray>(LayerDescriptor.TotalCostsAtSource.NameWithPrefix(carrier));
+      var centralConversionCosts = GetFromScope<DoubleArray>(LayerDescriptor.TotalAmortizedConversionCosts.NameWithPrefix(carrier));
+      var finalProductPrice = ProblemData.Products.FirstOrDefault(p => p.Label == finalProductName).PriceAtSource;
+      var carrierProductPrice = ProblemData.Products.FirstOrDefault(p => p.Label == carrier).PriceAtSource;
+
+      var centralPlantsFeedstockCosts = new DoubleArray(length);
+      var centralPlantsFeedstockCostsRelative = new DoubleArray(length);
+      var centralPlantsDecentralLogisticCosts = new DoubleArray(length);
+      var centralPlantsDecentralLogisticCostsRelative = new DoubleArray(length);
+      var centralPlantsDecentralConversionCosts = new DoubleArray(length);
+      var centralPlantsDecentralConversionCostsRelative = new DoubleArray(length);
+      var centralPlantsCentralLogisticCosts = new DoubleArray(length);
+      var centralPlantsCentralLogisticCostsRelative = new DoubleArray(length);
+      // var plantsCentralConversionCosts = new DoubleArray(length);  already there
+      var centralPlantsCentralConversionCostsRelative = new DoubleArray(length);
+      var centralPlantsRoiFollowed = new DoubleArray(length);
+      var centralPlantsRoiAggregated = new DoubleArray(length);
+
+      var decentralPlantsFeedstockCosts = new DoubleArray(length);
+      var decentralPlantsFeedstockCostsRelative = new DoubleArray(length);
+      var decentralPlantsDecentralLogisticCosts = new DoubleArray(length);
+      var decentralPlantsDecentralLogisticCostsRelative = new DoubleArray(length);
+      //var decentralPlantsDecentralConversionCosts = new DoubleArray(length);
+      var decentralPlantsDecentralConversionCostsRelative = new DoubleArray(length);
+      var decentralPlantsRoiFollowed = new DoubleArray(length);
+      var decentralPlantsRoiAggregated = new DoubleArray(length);
+
+      for (int i = 0; i < carrierSources.Length; i++) {
+        if (carrierSources[i] != null) { // central plant
+          var plantsFeedstockSources = carrierSources[i]
+            .Select(j => feedstockSources[j.Value].Select(s => s.Value))
+            .Aggregate((e1, e2) => e1.Concat(e2))
+            .ToHashSet();
+          var plantsCarrierSources = carrierSources[i].Select(j => j.Value).ToHashSet();
+          var finalProductAmount = finalProductAmounts[i];
+
+          centralPlantsFeedstockCosts[i] = feedstockCosts.FuncOverIndices(plantsFeedstockSources, Sum);
+          centralPlantsFeedstockCostsRelative[i] = centralPlantsFeedstockCosts[i]/finalProductAmount;
+
+          centralPlantsDecentralLogisticCosts[i] = feedstockLogisticCosts.FuncOverIndices(plantsFeedstockSources, Sum);
+          centralPlantsDecentralLogisticCostsRelative[i] = centralPlantsDecentralLogisticCosts[i]/finalProductAmount;
+
+          centralPlantsDecentralConversionCosts[i] = decentralConversionCosts.FuncOverIndices(plantsCarrierSources, Sum);
+          centralPlantsDecentralConversionCostsRelative[i] = centralPlantsDecentralConversionCosts[i]/finalProductAmount;
+
+          centralPlantsCentralLogisticCosts[i] = carrierLogisticCosts.FuncOverIndices(plantsCarrierSources, Sum);
+          centralPlantsCentralLogisticCostsRelative[i] = centralPlantsCentralLogisticCosts[i]/finalProductAmount;
+
+          centralPlantsCentralConversionCostsRelative[i] = centralConversionCosts[i]/finalProductAmount;
+
+          var revenue = finalProductAmounts[i]*finalProductPrice;
+          var profit = revenue - finalProductCosts[i];
+          centralPlantsRoiFollowed[i] = finalProductCosts[i] == 0 ? profit : profit/finalProductCosts[i];
+
+          var totalCost = centralPlantsFeedstockCosts[i] + centralPlantsDecentralLogisticCosts[i] +
+                          centralPlantsDecentralConversionCosts[i] +
+                          centralPlantsCentralLogisticCosts[i] +
+                          centralConversionCosts[i];
+          centralPlantsRoiAggregated[i] = (revenue - totalCost)/totalCost;
+        }
+        if (feedstockSources[i] != null) { // decentral plant
+          var plantsFeedstockSources = feedstockSources[i].Select(j => j.Value).ToHashSet();
+          var carrierProductAmount = carrierProductAmounts[i];
+
+          decentralPlantsFeedstockCosts[i] = feedstockCosts.FuncOverIndices(plantsFeedstockSources, Sum);
+          decentralPlantsFeedstockCostsRelative[i] = decentralPlantsFeedstockCosts[i]/carrierProductAmount;
+
+          decentralPlantsDecentralLogisticCosts[i] = feedstockLogisticCosts.FuncOverIndices(plantsFeedstockSources, Sum);
+          decentralPlantsDecentralLogisticCostsRelative[i] = decentralPlantsDecentralLogisticCosts[i]/carrierProductAmount;
+
+          decentralPlantsDecentralConversionCostsRelative[i] = decentralConversionCosts[i]/carrierProductAmount;
+
+          var revenue = carrierProductAmounts[i]*carrierProductPrice;
+          var profit = revenue - carrierProductCosts[i];
+          decentralPlantsRoiFollowed[i] = carrierProductCosts[i] == 0 ? profit : profit/carrierProductCosts[i];
+
+          var totalCost = decentralPlantsFeedstockCosts[i] + decentralPlantsDecentralLogisticCosts[i] + decentralConversionCosts[i];
+          decentralPlantsRoiAggregated[i] = (revenue - totalCost)/totalCost;
+        }
+      }
+
+      PutInScope(LayerDescriptor.FeedstockCosts.NameWithPrefix(finalProductName), centralPlantsFeedstockCosts, false);
+      PutInScope(LayerDescriptor.FeedstockCostsRelative.NameWithPrefix(finalProductName), centralPlantsFeedstockCostsRelative, false);
+      PutInScope(LayerDescriptor.DecentralLogisticCosts.NameWithPrefix(finalProductName), centralPlantsDecentralLogisticCosts, false);
+      PutInScope(LayerDescriptor.DecentralLogisticCostsRelative.NameWithPrefix(finalProductName), centralPlantsDecentralLogisticCostsRelative, false);
+      PutInScope(LayerDescriptor.DecentralConversionCosts.NameWithPrefix(finalProductName), centralPlantsDecentralConversionCosts, false);
+      PutInScope(LayerDescriptor.DecentralConversionCostsRelative.NameWithPrefix(finalProductName), centralPlantsDecentralConversionCostsRelative, false);
+      PutInScope(LayerDescriptor.CentralLogisticCosts.NameWithPrefix(finalProductName), centralPlantsCentralLogisticCosts, false);
+      PutInScope(LayerDescriptor.CentralLogisticCostsRelative.NameWithPrefix(finalProductName), centralPlantsCentralLogisticCostsRelative, false);
+      PutInScope(LayerDescriptor.CentralConversionCostsRelative.NameWithPrefix(finalProductName), centralPlantsCentralConversionCostsRelative, false);
+      PutInScope(LayerDescriptor.RoiFollowed.NameWithPrefix(finalProductName), centralPlantsRoiFollowed, false);
+      PutInScope(LayerDescriptor.RoiAggregated.NameWithPrefix(finalProductName), centralPlantsRoiAggregated, false);
+
+      PutInScope(LayerDescriptor.FeedstockCosts.NameWithPrefix(carrier), decentralPlantsFeedstockCosts, false);
+      PutInScope(LayerDescriptor.FeedstockCostsRelative.NameWithPrefix(carrier), decentralPlantsFeedstockCostsRelative, false);
+      PutInScope(LayerDescriptor.DecentralLogisticCosts.NameWithPrefix(carrier), decentralPlantsDecentralLogisticCosts, false);
+      PutInScope(LayerDescriptor.DecentralLogisticCostsRelative.NameWithPrefix(carrier), decentralPlantsDecentralLogisticCostsRelative, false);
+      PutInScope(LayerDescriptor.DecentralConversionCostsRelative.NameWithPrefix(carrier), decentralPlantsDecentralConversionCostsRelative, false);
+      PutInScope(LayerDescriptor.RoiFollowed.NameWithPrefix(carrier), decentralPlantsRoiFollowed, false);
+      PutInScope(LayerDescriptor.RoiAggregated.NameWithPrefix(carrier), decentralPlantsRoiAggregated, false);
+    }
+
+    private void AnalyzeSingleEchelon(string feedstock, string finalProductName, ItemArray<ItemList<IntValue>> feedstockSources) {
+      var length = feedstockSources.Length;
+
+      var feedstockCosts = GetFromScope<DoubleArray>(LayerDescriptor.TotalCostsAtSource.NameWithPrefix(feedstock));
+      var feedstockLogisticCosts = GetFromScope<DoubleArray>(LayerDescriptor.TotalLogisticCosts.NameWithPrefix(feedstock));
+      var centralConversionCosts = GetFromScope<DoubleArray>(LayerDescriptor.TotalAmortizedConversionCosts.NameWithPrefix(feedstock));
+      var finalProductAmounts = GetFromScope<DoubleArray>(LayerDescriptor.AmountsAtSource.NameWithPrefix(finalProductName));
+      var finalProductCosts = GetFromScope<DoubleArray>(LayerDescriptor.TotalCostsAtSource.NameWithPrefix(finalProductName));
+      var finalProductPrice = ProblemData.Products.FirstOrDefault(p => p.Label == finalProductName).PriceAtSource;
+
+      var centralPlantsFeedstockCosts = new DoubleArray(length);
+      var centralPlantsFeedstockCostsRelative = new DoubleArray(length);
+      var centralPlantsCentralLogisticCosts = new DoubleArray(length);
+      var centralPlantsCentralLogisticCostsRelative = new DoubleArray(length);
+      var centralPlantsCentralConversionCostsRelative = new DoubleArray(length);
+      var centralPlantsRoiFollowed = new DoubleArray(length);
+      var centralPlantsRoiAggregated = new DoubleArray(length);
+
+      for (int i = 0; i < feedstockSources.Length; i++) {
+        if (feedstockSources[i] != null) { 
+          var plantsFeedstockSources = feedstockSources[i].Select(j => j.Value).ToHashSet();
+          var finalProductAmount = finalProductAmounts[i];
+
+          centralPlantsFeedstockCosts[i] = feedstockCosts.FuncOverIndices(plantsFeedstockSources, Sum);
+          centralPlantsFeedstockCostsRelative[i] = centralPlantsFeedstockCosts[i]/finalProductAmount;
+
+          centralPlantsCentralLogisticCosts[i] = feedstockLogisticCosts.FuncOverIndices(plantsFeedstockSources, Sum);
+          centralPlantsCentralLogisticCostsRelative[i] = centralPlantsCentralLogisticCosts[i]/finalProductAmount;
+
+          centralPlantsCentralConversionCostsRelative[i] = centralConversionCosts[i]/finalProductAmount;
+
+          var revenue = finalProductAmounts[i]*finalProductPrice;
+          var profit = revenue - finalProductCosts[i];
+          centralPlantsRoiFollowed[i] = finalProductCosts[i] == 0 ? profit : profit/finalProductCosts[i];
+
+          var totalCost = centralPlantsFeedstockCosts[i] + centralPlantsCentralLogisticCosts[i] + centralConversionCosts[i];
+          centralPlantsRoiAggregated[i] = (revenue - totalCost)/totalCost;
+        }
+      }
+
+      PutInScope(LayerDescriptor.FeedstockCosts.NameWithPrefix(finalProductName), centralPlantsFeedstockCosts, false);
+      PutInScope(LayerDescriptor.FeedstockCostsRelative.NameWithPrefix(finalProductName), centralPlantsFeedstockCostsRelative, false);
+      PutInScope(LayerDescriptor.CentralLogisticCosts.NameWithPrefix(finalProductName), centralPlantsCentralLogisticCosts, false);
+      PutInScope(LayerDescriptor.CentralLogisticCostsRelative.NameWithPrefix(finalProductName), centralPlantsCentralLogisticCostsRelative, false);
+      PutInScope(LayerDescriptor.CentralConversionCostsRelative.NameWithPrefix(finalProductName), centralPlantsCentralConversionCostsRelative, false);
+      PutInScope(LayerDescriptor.RoiFollowed.NameWithPrefix(finalProductName), centralPlantsRoiFollowed, false);
+      PutInScope(LayerDescriptor.RoiAggregated.NameWithPrefix(finalProductName), centralPlantsRoiAggregated, false);
+
+    }
+
+    private static double Sum(IEnumerable<double> values) { return values.Sum(); }
+
+    private string GetFinalProductName(string feedstock) {
+      var productLinks = ProblemData.ProductLinks;
+      for (int i = 0; i < productLinks.Rows; i++) {
+        if (productLinks[i, 0] == feedstock)
+          return productLinks[i, 1];
+      }
+      return null;
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/ConversionCostEvaluator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/ConversionCostEvaluator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/ConversionCostEvaluator.cs	(revision 15711)
@@ -0,0 +1,269 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.BioBoost.Data;
+using HeuristicLab.BioBoost.Utils;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.BioBoost.Representation;
+
+namespace HeuristicLab.BioBoost.Evaluators {
+  [StorableClass]
+  [Item("ConversionCostEvaluator", "Simulates the conversion of all applicable conversion processes.")]
+  public class ConversionCostEvaluator : BioBoostEvaluator {
+
+    #region fields
+    private DoubleArray invest, maint, fuel, labor, other;
+    #endregion
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected ConversionCostEvaluator(bool isDeserializing) : base(isDeserializing) {}
+    protected ConversionCostEvaluator(ConversionCostEvaluator original, Cloner cloner) : base(original, cloner) { }
+    public ConversionCostEvaluator() { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ConversionCostEvaluator(this, cloner);
+    }
+    #endregion
+
+    public override IOperation Apply() {
+      var conversions = ProblemData.Conversions;
+      var products = new Dictionary<string, DoubleArray>();
+      var prices = ProblemData.Products.ToDictionary(p => p.Label, p => p.Price);
+      DoubleArray productCosts = new DoubleArray(0);
+      invest = ProblemData.InvestmentCostFactors;
+      maint = ProblemData.MaintenanceCostFactors;
+      fuel = ProblemData.FuelCostFactors;
+      labor = ProblemData.LaborCostFactors;
+      other = ProblemData.OtherCostFactors;
+      foreach (var feedstock in conversions.Select(c => c.Key)) {
+        var feedstockAmounts = GetFromScope<DoubleArray>(LayerDescriptor.AmountsAtTarget.NameWithPrefix(feedstock));
+        var feedstockCosts = GetFromScope<DoubleArray>(LayerDescriptor.TotalCostsAtTarget.NameWithPrefix(feedstock));
+        if (feedstockAmounts == null) continue;
+        var length = feedstockAmounts.Length;
+        var totalConversionCost = 0d;
+        var totalConstructionCost = 0d;
+        var totalOperationCost = 0d;
+        var totalStorageCost = 0d;
+        var totalScalingPenalty = 0d;
+        var totalExceedingCapacityPenalty = 0d;
+        var converterCapacities = new DoubleArray(length);
+        var maxCapacities = new DoubleArray(length);
+        var storageCapacities = new DoubleArray(length);
+        var chosenConversions = new List<Variant>(new Variant[length]);
+        if (productCosts.Length < length)
+          productCosts = new DoubleArray(length);
+        for (int i = 0; i < length; i++) {
+          var amount = feedstockAmounts[i];
+          maxCapacities[i] = conversions[feedstock].Max(c => GetMaxCapacity(c, ProblemData.LocationNames[i]));
+          if (amount <= 0) continue;
+          var chosenConversion = ChooseConversion(conversions[feedstock], amount, i);
+          if (chosenConversion != null) {
+            //feedstockAmounts[i] = 0;
+            totalConversionCost += chosenConversion.Cost;
+            totalConstructionCost += chosenConversion.ConstructionCost;
+            totalOperationCost += chosenConversion.OperationCost;
+            totalStorageCost += chosenConversion.StorageCost;
+            totalScalingPenalty += chosenConversion.ScalingPenalty;
+            totalExceedingCapacityPenalty += chosenConversion.ExceedingCapacityPenalty;
+            converterCapacities[i] = chosenConversion.Capacity;
+            storageCapacities[i] = chosenConversion.StorageCapacity;
+            AddProducts(products, chosenConversion.Conversion.Products, Math.Min(chosenConversion.Amount, chosenConversion.Capacity), i, length);
+            AddProducts(products, chosenConversion.Conversion.ConstructionEmissions, chosenConversion.Capacity/chosenConversion.Conversion.DesignCapacity, i, length);
+            chosenConversions[i] = chosenConversion;
+            feedstockCosts[i] += chosenConversion.StorageCost;
+            productCosts[i] += feedstockCosts[i] + chosenConversion.Cost + chosenConversion.ConstructionCost + chosenConversion.OperationCost; // still without side products
+          } else {
+            feedstockAmounts[i] = 0;
+          }
+        }
+        // TODO: 2. Runde?!?!?
+        //RemoveFromScope(LayerDescriptor.AmountsAtTarget.NameWithPrefix(feedstock));
+        RenameInScope(LayerDescriptor.AmountsAtTarget.NameWithPrefix(feedstock), LayerDescriptor.AmountsAtTargetConverted.NameWithPrefix(feedstock));
+        var conversionCosts = chosenConversions.Select(0, v => v.Cost).ToDoubleArray();
+        var constructionCosts = chosenConversions.Select(0, v => v.ConstructionCost).ToDoubleArray();
+        var operationCosts = chosenConversions.Select(0, v => v.OperationCost).ToDoubleArray();
+        PutInScope(LayerDescriptor.ConversionCosts.NameWithPrefix(feedstock), conversionCosts, false);
+        PutInScope(LayerDescriptor.ConversionPlantConstructionCost.NameWithPrefix(feedstock), constructionCosts, false);
+        PutInScope(LayerDescriptor.ConversionPlantOperationCost.NameWithPrefix(feedstock), operationCosts, false);
+        PutInScope(LayerDescriptor.RelativeConversionCosts.NameWithPrefix(feedstock), conversionCosts.Zip(feedstockAmounts, (c, a) => a == 0 ? 0 : c/a).ToDoubleArray(), false);
+        PutInScope(LayerDescriptor.RelativeConversionPlantConstructionCosts.NameWithPrefix(feedstock), constructionCosts.Zip(feedstockAmounts, (c, a) => a == 0 ? 0 : c/a).ToDoubleArray(), false);
+        PutInScope(LayerDescriptor.RelativeConversionPlantOperationCosts.NameWithPrefix(feedstock), operationCosts.Zip(feedstockAmounts, (c, a) => a == 0 ? 0 : c/a).ToDoubleArray(), false);
+        var storageCosts = chosenConversions.Select(0, v => v.StorageCost).ToDoubleArray();
+        PutInScope(LayerDescriptor.StorageCost.NameWithPrefix(feedstock), storageCosts, false);
+        PutInScope(LayerDescriptor.RelativeStorageCost.NameWithPrefix(feedstock), storageCosts.Zip(feedstockAmounts, (c, a) => a == 0 ? 0 : c/a).ToDoubleArray(), false);
+        var totalLogisticCost = GetFromScope<DoubleArray>(LayerDescriptor.TotalLogisticCosts.NameWithPrefix(feedstock));
+        totalLogisticCost = totalLogisticCost.Zip(storageCosts, (l, s) => l + s).ToDoubleArray();
+        PutInScope(LayerDescriptor.TotalLogisticCosts.NameWithPrefix(feedstock), totalLogisticCost, false);
+        PutInScope(LayerDescriptor.LogisticCostsPerTon.NameWithPrefix(feedstock), totalLogisticCost.Zip(feedstockAmounts, (c, a) => a == 0 ? 0 : c/a).ToDoubleArray(), false);
+        PutInScope(LayerDescriptor.MaxConversionCapacity.NameWithPrefix(feedstock), maxCapacities, false);
+        var scalingPenalties = chosenConversions.Select(0, v => v.ScalingPenalty).ToDoubleArray();
+        var exceedingCapacityPenalties = chosenConversions.Select(0, v => v.ExceedingCapacityPenalty).ToDoubleArray();
+        PutInScope(LayerDescriptor.ScalingPenalty.NameWithPrefix(feedstock), scalingPenalties, false);
+        PutInScope(LayerDescriptor.ExceedingCapacityPenalties.NameWithPrefix(feedstock), exceedingCapacityPenalties, false);
+        AddInScope(LayerDescriptor.TotalPenalty.Name, scalingPenalties.Zip(exceedingCapacityPenalties, (s, c) => s+c).ToDoubleArray(), false);
+        PutInScope(LayerDescriptor.TotalCostsAtTarget.NameWithPrefix(feedstock), feedstockCosts, false); // now including storage costs
+        PutInScope(LayerDescriptor.RelativeCostAtTarget.NameWithPrefix(feedstock), feedstockCosts.Zip(feedstockAmounts, (c,a) => a == 0 ? 0 : c/a).ToDoubleArray(), false);
+        var totalDirectConversionCost = chosenConversions.Select(0, c => c.Cost + c.Conversion.Products.TotalCost(prices, c.Conversion.MainProduct)*c.Amount) .ToDoubleArray();
+        PutInScope(LayerDescriptor.TotalDirectConversionCost.NameWithPrefix(feedstock), totalDirectConversionCost, false);
+        //var mainProductAmounts = chosenConversions.Select((c, i) => c != null ? 0 : products[c.Conversion.MainProduct][i]).ToArray();
+        PutInScope(LayerDescriptor.RelativeTotalDirectConversionCost.NameWithPrefix(feedstock), totalDirectConversionCost.Zip(feedstockAmounts, (c, a) => a == 0 ? 0 : c/a).ToDoubleArray(), false);
+        PutInScope(LayerDescriptor.ScalingFactors.NameWithPrefix(feedstock), chosenConversions.Select(0, v => v.ScalingFactor).ToDoubleArray(), false);
+        var totalAmortizedConversionCost = totalDirectConversionCost
+          // .Zip(storageCosts, (t, s) => t + s) -> included in logistic costs
+          .Zip(constructionCosts, (t, c) => t + c)
+          .Zip(operationCosts, (t, o) => t + o)
+          .ToDoubleArray();
+        PutInScope(LayerDescriptor.TotalAmortizedConversionCosts.NameWithPrefix(feedstock), totalAmortizedConversionCost, false); 
+        PutInScope(LayerDescriptor.RelativeTotalAmortizedConversionCosts.NameWithPrefix(feedstock), totalAmortizedConversionCost.Zip(feedstockAmounts, (c, a) => a == 0 ? 0 : c/a).ToDoubleArray(), false); 
+        AddCost(LayerDescriptor.ConversionCosts.NameWithPrefix(feedstock), totalConversionCost);
+        AddCost(LayerDescriptor.ConversionPlantConstructionCost.NameWithPrefix(feedstock), totalConstructionCost);
+        AddCost(LayerDescriptor.ConversionPlantOperationCost.NameWithPrefix(feedstock), totalOperationCost);
+        AddCost(LayerDescriptor.StorageCost.NameWithPrefix(feedstock), totalStorageCost);
+        AddCost(LayerDescriptor.ScalingPenalty.NameWithPrefix(feedstock), totalScalingPenalty);
+        AddCost(LayerDescriptor.ExceedingCapacityPenalties.NameWithPrefix(feedstock), totalExceedingCapacityPenalty);
+        AddInScope(LayerDescriptor.ConverterCapacities.NameWithPrefix(feedstock), converterCapacities, false);
+        AddInScope(LayerDescriptor.StorageCapacities.NameWithPrefix(feedstock), storageCapacities, false);
+        AddInScope(LayerDescriptor.LocalAddedValue.Name, chosenConversions.Select(0, v => v.Cost + v.ConstructionCost + v.OperationCost).ToDoubleArray(), false);
+        foreach (var p in products) {
+          if (p.Value.Max() <= 0 || (prices.ContainsKey(p.Key) && prices[p.Key] <= 0)) continue; // don't report "production cost" for demands and waste products
+          var costsAtSource = new DoubleArray(productCosts.Select((c,i) => c + (chosenConversions[i] == null ? 0 : chosenConversions[i].Conversion.Products.TotalCost(prices, p.Key)*chosenConversions[i].Amount)).ToArray());
+          AddInScope(LayerDescriptor.TotalCostsAtSource.NameWithPrefix(p.Key), costsAtSource, false);
+          costsAtSource = GetFromScope<DoubleArray>(LayerDescriptor.TotalCostsAtSource.NameWithPrefix(p.Key));
+          PutInScope(LayerDescriptor.RelativeCostAtSource.NameWithPrefix(p.Key), costsAtSource.Zip(p.Value, (c,a) => a == 0 ? 0 : c/a).ToDoubleArray(), false);
+        }
+      }
+      foreach (var p in products) {
+        AddInScope(LayerDescriptor.AmountsAtSource.NameWithPrefix(p.Key), p.Value, false);
+      }
+      return base.Apply();
+    }
+
+    private void AddProducts(Dictionary<string, DoubleArray> overallProducts, IEnumerable<IValueParameter> products, double amount, int i, int length) {
+      foreach (var e in products) {
+        DoubleArray values = null;
+        if (!overallProducts.TryGetValue(e.Name, out values)) {
+          overallProducts.Add(e.Name, values = new DoubleArray(length));
+        }
+        values[i] += ((DoubleValue)e.Value).Value*amount;
+      }
+    }
+
+    private class Variant : IComparable<Variant> {
+      public Conversion Conversion;
+      public double Cost;
+      public double ConstructionCost;
+      public double OperationCost;
+      public double Capacity;
+      public double StorageCost;
+      public double StorageCapacity;
+      public double Amount;
+      public double ScalingPenalty;
+      public double ExceedingCapacityPenalty;
+      public double ScalingFactor;
+
+      public int CompareTo(Variant other) {
+        return (int) (Cost - other.Cost);
+      }
+    }
+
+    private Variant ChooseConversion(IEnumerable<Conversion> conversions, double amount, int i) {
+      var variants = new List<Variant>();
+      foreach (var c in conversions) { // TODO: select best scaling variant?
+        if (amount <= 0) continue;
+        var actualAmount = amount * (1-c.DryMatterLoss);
+        var v = new Variant {Capacity = actualAmount/c.UtilizationFactor, Conversion = c};
+        var regionName = ProblemData.LocationNames[i];
+        double maxCapacity = GetMaxCapacity(c, regionName);
+        v.ExceedingCapacityPenalty = CapacityPenalty(v.Capacity, maxCapacity);
+        //if (maxCapacity <= 0) continue;
+        var availableCapacity = GetValue(c.AvailableCapacities, regionName, 0);
+        var newCapacity = Math.Max(0, v.Capacity - availableCapacity);
+        v.ScalingFactor = v.Capacity/c.DesignCapacity;
+        var minScale = c.MinCapacity/c.DesignCapacity;
+        var maxScale = maxCapacity/c.DesignCapacity;
+        v.ScalingPenalty = ScalingPenalty(v.ScalingFactor, minScale, maxScale);
+        v.ConstructionCost = ScaledCost(newCapacity/c.DesignCapacity, maxScale, c.Construction, c.ConstructionScalingExponent);
+        v.OperationCost = ScaledCost(v.ScalingFactor, maxScale, c.Maintenance, c.MaintenanceScalingExponent);
+        v.OperationCost = (newCapacity/v.Capacity)*v.OperationCost + ((v.Capacity - newCapacity)/v.Capacity)*v.OperationCost*c.AvailableMaintenanceFactor;
+        v.Cost = c.Cost*actualAmount;
+        v.Amount = actualAmount;
+        v.StorageCapacity = v.Capacity/365*c.SafetyStock;
+        v.StorageCost = GetLogisticActionCost(c.Storage, v.StorageCapacity, i);
+        variants.Add(v);
+      }
+      variants.Sort();
+      return variants.FirstOrDefault();
+    }
+
+    public static double GetMaxCapacity(Conversion c, string regionName) {
+      var maxCapacity = GetValue(c.MaxCapacities, regionName, -1);
+      if (maxCapacity < 0) maxCapacity = GetValue(c.MaxCapacities, "Default", -2);
+      return maxCapacity;
+    }
+
+    private double GetLogisticActionCost(LogisticAction a, double amount, int i) {
+      return
+        amount*a.Investment*invest[i] +
+        amount*a.Maintenance*maint[i] +
+        amount*a.Fuel*fuel[i] +
+        amount*a.Labor*labor[i] +
+        amount*a.Other*other[i];
+    }
+
+    private static double GetValue(ValueParameterCollection values, string name, double defaultValue) {
+      IValueParameter parameter;
+      if (values.TryGetValue(name, out parameter))
+        return ((DoubleValue) parameter.Value).Value;
+      return defaultValue;
+    }
+
+    public static double ScalingPenalty(double scale, double minScale, double maxScale) {
+      if (scale > maxScale)
+        return Util.Sqr(scale-maxScale);
+      if (scale < minScale)
+        return 4*(minScale - scale)*scale/Util.Sqr(minScale) * 2;
+      return 0;
+    }
+
+    public static double CapacityPenalty(double capacity, double maxCapacity) {
+      if (capacity > maxCapacity) {
+        if (maxCapacity == 0) {
+          return Math.Pow(capacity, 2);
+        } else {
+          return Math.Pow((capacity - maxCapacity)/maxCapacity, 2);
+        }
+      }
+      return 0;
+    }
+
+    public static double ScaledCost(double scale, double maxScale, double baseCost, double exponent) {
+      if (scale > 10) return baseCost*Math.Pow(10, exponent - 1);
+      return baseCost*Math.Pow(scale, exponent);
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/FeedstockCostEvaluator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/FeedstockCostEvaluator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/FeedstockCostEvaluator.cs	(revision 15711)
@@ -0,0 +1,104 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System;
+using System.Linq;
+using HeuristicLab.BioBoost.Representation;
+using HeuristicLab.BioBoost.Utils;
+
+namespace HeuristicLab.BioBoost.Evaluators {
+
+  [StorableClass]
+  [Item("FeedstockCostEvaluator", @"Calculates all feedstock costs for known products,
+for which both <Product.Label>Potentials and <Product.Label>Utilizations are available.
+The intermedate results are vectors of amounts and costs per product and region and a
+final output named <Product.Label>Cost for each product.")]
+  public class FeedstockCostEvaluator : BioBoostEvaluator {
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected FeedstockCostEvaluator(bool isDeserializing) : base(isDeserializing) { }
+    protected FeedstockCostEvaluator(FeedstockCostEvaluator original, Cloner cloner) : base(original, cloner) { }
+    public FeedstockCostEvaluator() { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new FeedstockCostEvaluator(this, cloner);
+    }
+    #endregion
+
+    /// <summary>
+    /// foreach product with both potential and utilization calculate
+    /// amounts = potential*utilization
+    /// costs = amounts*price*penalty(utilization)
+    /// cost = sum(costs)
+    /// </summary>
+    public override IOperation Apply() {
+      foreach (var p in ProblemData.Products) {
+        var totalProductCost = 0d;
+        var potentials = GetFromProblemData<DoubleArray>(LayerDescriptor.PotentialsFromProblemData.NameWithPrefix(p.Label));
+        var utilizations = GetFromScope<DoubleArray>(LayerDescriptor.Utilizations.NameWithPrefix(p.Label));
+        if (potentials == null || utilizations == null) continue;
+        var utilizationsEffective = (DoubleArray)utilizations.Clone();
+        var length = Math.Min(potentials.Length, utilizations.Length);
+        var amountsAtSource = new DoubleArray(length);
+        var feedstockCosts = new DoubleArray(length);
+        
+        // price/supply curve quadr. for utilization > 0.5
+        for (var i = 0; i < length; i++) {
+          var regionName = ProblemData.LocationNames[i];
+          var amount = potentials[i] * utilizations[i];
+          if (amount < 100) { // TODO: make this configurable
+            utilizationsEffective[i] = 0;
+            amount = 0;
+          }
+          amountsAtSource[i] = amount;
+          var cost = GetScaledCost(
+            p.GetRegionalBasePrice(regionName),
+            p.GetRegionalMaxPrice(regionName),
+            amount, utilizations[i]);
+          feedstockCosts[i] = cost;
+          totalProductCost += cost;
+        }
+
+        PutInScope(LayerDescriptor.UtilizationsEffective.NameWithPrefix(p.Label), utilizationsEffective, false);
+        PutInScope(LayerDescriptor.AmountsAtSource.NameWithPrefix(p.Label), amountsAtSource, true);
+        PutInScope(LayerDescriptor.TotalCostsAtSource.NameWithPrefix(p.Label) , feedstockCosts, false);
+        PutInScope(LayerDescriptor.RelativeCostAtSource.NameWithPrefix(p.Label), feedstockCosts.Zip(amountsAtSource, (c,a) => a == 0 ? 0 : c/a).ToDoubleArray(), false);
+        AddCost(LayerDescriptor.AcquisitionCosts.NameWithPrefix(p.Label), totalProductCost);     
+        AddInScope(LayerDescriptor.LocalAddedValue.Name, (DoubleArray)feedstockCosts.Clone(), false);
+      }
+         
+      return base.Apply();
+    }
+
+    public static double GetScaledCost(double basePrice, double maxPrice, double amount, double utilization) {
+      if (utilization > 0.5) {
+        var priceDifference = maxPrice - basePrice;
+         return amount*(priceDifference*Math.Pow((utilization - 0.5)*2, 2) + basePrice);
+      } else {
+       return amount*basePrice;
+      }
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/InitializationEvaluator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/InitializationEvaluator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/InitializationEvaluator.cs	(revision 15711)
@@ -0,0 +1,67 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.BioBoost.Representation;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Core;
+using HeuristicLab.Common;
+
+namespace HeuristicLab.BioBoost.Evaluators {
+  [StorableClass]
+  [Item("InitializationEvaluator", "Cleans up scope.")]
+  public class InitializationEvaluator : BioBoostEvaluator {
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected InitializationEvaluator(bool isDeserializing) : base(isDeserializing) {}
+    protected InitializationEvaluator(InitializationEvaluator original, Cloner cloner) : base(original, cloner) { }
+    public InitializationEvaluator() { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new InitializationEvaluator(this, cloner);
+    }
+    #endregion
+
+    public override IOperation Apply() {
+      var vars = new List<string>();
+      foreach(var var in ExecutionContext.Scope.Variables) {
+        vars.Add(var.Name);
+      }    
+      foreach (var var in vars) {
+        if (!LayerDescriptor.TransportTargets.IsSuffixOf(var) &&
+            !LayerDescriptor.Utilizations.IsSuffixOf(var) &&
+            var != "IntermediateResults" &&
+            var != "Costs" &&
+            !var.StartsWith("Selected")) {
+          RemoveFromScope(var);
+        }
+      }
+       ;
+      //var var = new Variable(label, value);
+      //if (vars.ContainsKey(label))
+      //  vars.Remove(label);
+
+     // RemoveFromScope(feedstock + BioBoostProblem.AmountsAtTargetName);
+
+      return base.Apply();
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/LogisticCostEvaluator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/LogisticCostEvaluator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/LogisticCostEvaluator.cs	(revision 15711)
@@ -0,0 +1,206 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.BioBoost.Data;
+using HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.BioBoost.Representation;
+using HeuristicLab.BioBoost.Utils;
+
+namespace HeuristicLab.BioBoost.Evaluators {
+  [StorableClass]
+  public class LogisticCostEvaluator : BioBoostEvaluator {
+
+    private class Variant : IComparable<Variant> {
+      public double HandlingCost;
+      public double TransportCost;
+      public double Penalty;
+      public double Distance;
+      public Logistic Logistic;
+      public double Amount;
+      public int CompareTo(Variant other) {
+        return (int)((HandlingCost + TransportCost) - (other.HandlingCost + other.TransportCost));
+      }
+    }
+
+    #region fields
+    private DoubleArray invest, maint, fuel, labor, other;
+    #endregion
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected LogisticCostEvaluator(bool isDeserializing) : base(isDeserializing) {}
+
+    protected LogisticCostEvaluator(LogisticCostEvaluator original, Cloner cloner) : base(original, cloner) {}
+
+    public LogisticCostEvaluator() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new LogisticCostEvaluator(this, cloner);
+    }
+    #endregion
+
+    public override IOperation Apply() {
+      var logistics = ProblemData.Logistics;
+      var distances = new Dictionary<string, DistanceMatrix>();
+      var emissions = new Dictionary<string, DoubleArray>();
+      invest = ProblemData.InvestmentCostFactors;
+      maint = ProblemData.MaintenanceCostFactors;
+      fuel = ProblemData.FuelCostFactors;
+      labor = ProblemData.LaborCostFactors;
+      other = ProblemData.OtherCostFactors;
+      var prices = ProblemData.Products.ToDictionary(p => p.Label, p => p.Price); // TODO: regional scaling for supplies and side-products?
+      foreach (var product in logistics.Select(l => l.Key)) {
+        var amountsAtSource = GetFromScope<DoubleArray>(LayerDescriptor.AmountsAtSource.NameWithPrefix(product));
+        var costsAtSource = GetFromScope<DoubleArray>(LayerDescriptor.TotalCostsAtSource.NameWithPrefix(product));
+        var transportTargets = GetFromScope<IntArray>(LayerDescriptor.TransportTargets.NameWithPrefix(product));
+        if (amountsAtSource == null || transportTargets == null) continue;
+        var length = amountsAtSource.Length;
+        var sources = new ItemArray<ItemList<IntValue>>(length);
+        var amountsAtTarget = new DoubleArray(length);
+        var chosenVariants = new List<Variant>(new Variant[length]);
+        var costsAtTarget = new DoubleArray(length);
+        var totalProductHandlingCost = 0d;
+        var totalProductTransportCost = 0d;
+        var totalPenalty = 0d;
+        for (int i = 0; i < length; i++) {
+          var amount = amountsAtSource[i];
+          if (amount <= 0) continue;
+          var j = transportTargets[i];
+          if (j == -1) {
+            amountsAtSource[i] = 0; // no transport -> no feedstock collected
+            continue;
+          }
+          var chosenVariant = ChooseVariant(logistics[product], amount, i, j, distances);
+          if (chosenVariant != null) {
+            amountsAtTarget[j] += Math.Min(chosenVariant.Amount, amount); // cannot have more than before
+            costsAtTarget[j] += costsAtSource[i] + chosenVariant.HandlingCost + chosenVariant.TransportCost +
+                                chosenVariant.Logistic.Transport.Emissions.TotalCost(prices, null)*chosenVariant.Amount*chosenVariant.Distance +
+                                chosenVariant.Logistic.Handling.Emissions.TotalCost(prices, null)*chosenVariant.Amount;
+            totalProductHandlingCost += chosenVariant.HandlingCost;
+            totalProductTransportCost += chosenVariant.TransportCost;
+            totalPenalty += chosenVariant.Penalty;
+            AddEmissions(emissions, chosenVariant.Logistic.Handling.Emissions, amount, i, j, length);
+            AddEmissions(emissions, chosenVariant.Logistic.Transport.Emissions, amount*chosenVariant.Distance, i, j, length);
+            chosenVariants[i] = chosenVariant;
+            if (sources[j] != null) {
+              sources[j].Add(new IntValue(i));
+            } else {
+              sources[j] = new ItemList<IntValue>(new [] { new IntValue(i) });
+            }
+          } else {
+            amountsAtSource[i] = 0; // will be AmountsTransportedFromSource
+          }
+        }
+        RenameInScope(LayerDescriptor.AmountsAtSource.NameWithPrefix(product), LayerDescriptor.AmountsTransportedFromSource.NameWithPrefix(product));
+        PutInScope(LayerDescriptor.TransportModes.NameWithPrefix(product), chosenVariants.Select("", v => v.Logistic.Mode).ToStringArray(), false);
+        PutInScope(LayerDescriptor.TransportCosts.NameWithPrefix(product), chosenVariants.Select(0, v => v.TransportCost).ToDoubleArray(), false);
+        PutInScope(LayerDescriptor.TransportCostsPerT.NameWithPrefix(product), chosenVariants.Select(0, v => v.Amount == 0 ? 0 : v.TransportCost / v.Amount).ToDoubleArray(), false);
+        PutInScope(LayerDescriptor.TransportCostsPerTkm.NameWithPrefix(product), chosenVariants.Select(0, v => v.Amount == 0 || v.Distance == 0 ? 0 : v.TransportCost / v.Amount / v.Distance).ToDoubleArray(), false);
+        PutInScope(LayerDescriptor.HandlingCosts.NameWithPrefix(product), chosenVariants.Select(0, v => v.HandlingCost).ToDoubleArray(), false);
+        PutInScope(LayerDescriptor.RelativeHandlingCosts.NameWithPrefix(product), chosenVariants.Select(0, v => v.Amount == 0 ? 0 : v.HandlingCost / v.Amount).ToDoubleArray(), false);
+        AddInScope(LayerDescriptor.AmountsAtTarget.NameWithPrefix(product), amountsAtTarget, false);
+        AddInScope(LayerDescriptor.TotalCostsAtTarget.NameWithPrefix(product), costsAtTarget, false);
+        PutInScope(LayerDescriptor.RelativeCostAtTarget.NameWithPrefix(product), costsAtTarget.Zip(amountsAtTarget, (c,a) => a == 0 ? 0 : c/a).ToDoubleArray(), false);
+        PutInScope(LayerDescriptor.TransportDistance.NameWithPrefix(product), chosenVariants.Select(0, v => v.Distance).ToDoubleArray(), false);
+        PutInScope(LayerDescriptor.Tkm.NameWithPrefix(product), chosenVariants.Select(0, v => v.Distance*v.Amount).ToDoubleArray(), false);
+        var transportPenalties = chosenVariants.Select(0, v => v.Penalty).ToDoubleArray();
+        PutInScope(LayerDescriptor.ExceedingTransportDistancePenalty.NameWithPrefix(product), transportPenalties, false);
+        AddInScope(LayerDescriptor.TotalPenalty.Name, (DoubleArray)transportPenalties.Clone(), false);
+        PutInScope(LayerDescriptor.TotalLogisticCosts.NameWithPrefix(product), chosenVariants.Select(0, v => v.TransportCost + v.HandlingCost).ToDoubleArray(), false);
+        PutInScope(LayerDescriptor.LogisticCostsPerTon.NameWithPrefix(product), chosenVariants.Select(0, v => v.Amount == 0 ? 0 : (v.TransportCost + v.HandlingCost)/v.Amount).ToDoubleArray(), false);
+        //PutInScope(LayerDescriptor.LogisticCostsPerTonKm.NameWithPrefix(product), chosenVariants.Select(0, v => v.Amount * v.Distance == 0 ? 0 : (v.TransportCost + v.HandlingCost)/v.Amount/v.Distance).ToDoubleArray(), false);
+        AddInScope(LayerDescriptor.LocalAddedValue.Name, chosenVariants.Select(0, v => v.HandlingCost + v.TransportCost).ToDoubleArray(), false);
+        PutInScope(LayerDescriptor.Sources.NameWithPrefix(product), sources, false);
+        AddCost(LayerDescriptor.HandlingCosts.NameWithPrefix(product), totalProductHandlingCost);
+        AddCost(LayerDescriptor.TransportCosts.NameWithPrefix(product), totalProductTransportCost);
+        AddCost(LayerDescriptor.ExceedingTransportDistancePenalty.NameWithPrefix(product), totalPenalty);
+      }
+      foreach (var e in emissions) {
+        AddInScope(LayerDescriptor.AmountsAtSource.NameWithPrefix(e.Key), e.Value, false);
+        AddInScope(LayerDescriptor.DischargeCosts.NameWithPrefix(e.Key), e.Value.Select(x => !prices.ContainsKey(e.Key) ? 0 : (prices[e.Key] * x)).ToDoubleArray(), false);
+      }
+      return base.Apply();
+    }
+
+    private Variant ChooseVariant(IEnumerable<Logistic> logistics, double amount, int i, int j, IDictionary<string, DistanceMatrix> distances) {
+      var variants = new List<Variant>();
+      foreach (var l in logistics) {
+        DistanceMatrix distanceMatrix = null;
+        if (!distances.TryGetValue(l.Distances, out distanceMatrix)) {
+          distanceMatrix = GetFromProblemData<DistanceMatrix>(l.Distances + "DistanceMatrix");
+          if (distanceMatrix != null)
+            distances[l.Distances] = distanceMatrix;
+          else 
+            throw new InvalidOperationException("Distance Matrix \"" + l.Distances +
+              "\" for logistic action \"" + l.Mode +
+              "\" of product \"" + l.Product + "\" could not be loaded");
+        }
+        if (distanceMatrix == null) continue;
+        var distance = distanceMatrix[i, j];
+        var actualAmount = Math.Min(Math.Max(amount, l.MinAmount), l.MaxAmount);
+        var v = new Variant {
+          Amount = actualAmount,
+          Logistic = l,
+          HandlingCost = GetLogisticActionCost(l.Handling, actualAmount*(1-l.WaterContent), i, j),
+          TransportCost = GetLogisticActionCost(l.Transport, actualAmount*distance*(1-l.WaterContent), i, j),
+          Distance = distance
+        };
+        if (distance > l.MaxDistance)
+          v.Penalty = Penalty(distance, l.MaxDistance, distanceMatrix.Max);
+        variants.Add(v);
+      }
+      variants.Sort();
+      return variants.FirstOrDefault();
+    }
+
+    public static double Penalty(double distance, double maxAllowedDistance, double maxPossibleDistance) {
+      return (distance - maxAllowedDistance)/maxPossibleDistance;
+    }
+
+    private double GetLogisticActionCost(LogisticAction a, double amount, int i, int j) {
+      return 
+        amount * (
+          a.Investment  *(invest[i] + invest[j]) +
+          a.Maintenance *( maint[i] +  maint[j]) +
+          a.Fuel        *(  fuel[i] +   fuel[j]) +
+          a.Labor       *( labor[i] +  labor[j]) +
+          a.Other       *( other[i] +  other[j]))/2;
+    }
+
+    private void AddEmissions(Dictionary<string, DoubleArray> totalEmissions, IEnumerable<IValueParameter> emissions, double amount, int i, int j, int length) {
+      foreach (var e in emissions) {
+        DoubleArray values = null;
+        if (!totalEmissions.TryGetValue(e.Name, out values)) {
+          totalEmissions.Add(e.Name, values = new DoubleArray(length));
+        }
+        values[i] += ((DoubleValue)e.Value).Value*amount/2;
+        values[j] += ((DoubleValue)e.Value).Value*amount/2;
+      }
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/MonolithicEvaluator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/MonolithicEvaluator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/MonolithicEvaluator.cs	(revision 15711)
@@ -0,0 +1,399 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.BioBoost.Data;
+using HeuristicLab.BioBoost.Representation;
+using HeuristicLab.BioBoost.Utils;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.BioBoost.Evaluators {
+  [StorableClass]
+  public class MonolithicEvaluator : AggregateEvaluator {
+
+    #region ISingleObjectiveEvaluator Members
+    public double Quality {
+      get { return QualityParameter.ActualValue.Value; }
+      set {  QualityParameter.ActualValue = new DoubleValue(value);}
+    }
+    #endregion
+
+    #region IMultiObjectEvaluator Members
+    private DoubleArray Qualities {
+      get { return QualitiesParameter.ActualValue; }
+      set {  QualitiesParameter.ActualValue = value;} }
+
+    #endregion
+
+    public IValueParameter<IntArray> QualityRoundingParameter { get { return (IValueParameter<IntArray>) Parameters["QualityRounding"]; } }
+    public OptionalConstrainedValueParameter<IDiscreteDoubleValueModifier> AlphaValueModifierParameter { get { return (OptionalConstrainedValueParameter<IDiscreteDoubleValueModifier>) Parameters["AlphaValueModifier"]; } }
+    public IValueLookupParameter<DoubleValue> AlphaParameter { get { return (IValueLookupParameter<DoubleValue>) Parameters["Alpha"]; } }
+
+    public IntArray QualityRounding { get { return QualityRoundingParameter.Value;  } }
+    public IDiscreteDoubleValueModifier AlphaValueModifier { get { return AlphaValueModifierParameter.Value; } }
+    public double Alpha { get { return AlphaParameter.ActualValue.Value; } }
+
+    private static object simplificationLock = new object();
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected MonolithicEvaluator(bool isDeserializing) : base(isDeserializing) { }
+    protected MonolithicEvaluator(MonolithicEvaluator orig, Cloner cloner) : base(orig, cloner) { }
+    public MonolithicEvaluator() {
+      Parameters.Add(new ValueParameter<IntArray>("QualityRounding", "The rounding cut-off for the quality (used e.g. for multi-object optimizaiton)."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("Alpha", "The weight of the first quality parameter", new DoubleValue(0.5)));
+      Parameters.Add(new OptionalConstrainedValueParameter<IDiscreteDoubleValueModifier>("AlphaValueModifier", "An operator to modify the value of alpha over time",
+        new ItemSet<IDiscreteDoubleValueModifier>( ApplicationManager.Manager.GetInstances<IDiscreteDoubleValueModifier>())));
+      foreach (var modifier in AlphaValueModifierParameter.ValidValues) {
+        modifier.StartIndexParameter.Value = new IntValue(0);
+        modifier.EndIndexParameter.ActualName = "MaximumGenerations";
+        modifier.ValueParameter.ActualName = AlphaParameter.ActualName;
+        modifier.IndexParameter.ActualName = "Generations";
+        modifier.StartValueParameter.Value = new DoubleValue(1);
+        modifier.EndValueParameter.Value = new DoubleValue(0.8);
+      }
+      // disable AggregateEvaluator heritage
+      InitializeCostsAndIntermediateResults = false;
+      OperatorGraph.InitialOperator = null;
+      OperatorGraph.Operators.Clear();
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MonolithicEvaluator(this, cloner);
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (!Parameters.ContainsKey("QualityRounding"))
+        Parameters.Add(new ValueParameter<IntArray>("QualityRounding", "The rounding cut-off for the quality (used e.g. for multi-object optimizaiton)."));
+      if (!Parameters.ContainsKey("Alpha"))
+        Parameters.Add(new ValueLookupParameter<DoubleValue>("Alpha", "The weight of the first quality parameter", new DoubleValue(0.5)));
+      if (!Parameters.ContainsKey("AlphaValueModifier")) {
+        Parameters.Add(new OptionalConstrainedValueParameter<IDiscreteDoubleValueModifier>("AlphaValueModifier",
+          "An operator to modify the value of alpha over time",
+          new ItemSet<IDiscreteDoubleValueModifier>(
+            ApplicationManager.Manager.GetInstances<IDiscreteDoubleValueModifier>())));
+        foreach (var modifier in AlphaValueModifierParameter.ValidValues) {
+          modifier.StartIndexParameter.Value = new IntValue(0);
+          modifier.EndIndexParameter.ActualName = "MaximumGenerations";
+          modifier.ValueParameter.ActualName = AlphaParameter.ActualName;
+          modifier.IndexParameter.ActualName = "Generations";
+          modifier.StartValueParameter.Value = new DoubleValue(1);
+          modifier.EndValueParameter.Value = new DoubleValue(0.8);
+        }
+      }
+    }
+    #endregion
+
+    public override IOperation Apply() {
+      var data = LoadOrCreateSimpleDataInScope();
+      RealVector utilizations =
+        GetFromScope<RealVector>(LayerDescriptor.Utilizations.NameWithPrefix(data.Echelons[0].FeedstockName));
+      var temp = new Temp(data.N);
+      temp.Amounts = CalculateFeedstockCosts(data, utilizations, temp);
+      for (int i = 0; i < data.Echelons.Count - 1; i++) {
+        IntegerVector transportTargets =
+          GetFromScope<IntegerVector>(LayerDescriptor.TransportTargets.NameWithPrefix(data.Echelons[i].FeedstockName));
+        temp.Amounts = CalculateLogisticCosts(data, i, temp, transportTargets);
+        CalculateConversionCosts(data, i, temp);
+      }
+      var totalAmount = temp.Amounts.Sum();
+      var maxPossibleAmount = data.Potentials.Sum();
+      for (int i = 0; i < data.Echelons.Count - 1; i++)
+        maxPossibleAmount *= data.Echelons[i].Conversion.MainProductConversionRate;
+      //var nrOfPlants = temp.Amounts.Count(a => a > 0);
+      var revenue = totalAmount*data.FinalProudctPrice;
+      var roi = temp.TotalCost == 0 ? revenue : (revenue-temp.TotalCost)/temp.TotalCost;
+      Quality = Alpha*(roi - temp.TotalPenalty) + (1-Alpha)*totalAmount/maxPossibleAmount;
+      Qualities = new DoubleArray(new[] {Quality, totalAmount});
+      //Qualities = new DoubleArray(new[] {Quality, Math.Log(nrOfPlants)/Math.Log(2)});
+      if (QualityRoundingParameter.Value != null) {
+        if (QualityRounding.Length > 0) {
+          Quality = Math.Round(Quality, QualityRounding[0]);
+          if (QualityRounding.Length >= Qualities.Length) {
+            for (int i = 0; i < Qualities.Length; i++) {
+              int precision = QualityRounding[i];
+              if (precision >= 0) {
+                Qualities[i] = Math.Round(Qualities[i], QualityRounding[i]);
+              } else {
+                var multiplier = Math.Pow(10, Math.Abs(precision));
+                Qualities[i] = Math.Round(Qualities[i]/multiplier)*multiplier;
+              }
+            }
+          }
+        }
+      }
+      var ops = new OperationCollection();
+      if (AlphaValueModifierParameter.ActualValue != null)
+        ops.Add(ExecutionContext.CreateChildOperation(AlphaValueModifier));
+      ops.Add(base.Apply());
+      return ops;
+    }
+
+    private SimpleProblemData LoadOrCreateSimpleDataInScope() {
+      var globalScope = ExecutionContext.Scope;
+      while (globalScope.Parent != null)
+        globalScope = globalScope.Parent;
+      SimpleProblemData data;
+      lock (simplificationLock) {
+        IVariable dataVariable;
+        if (!globalScope.Variables.TryGetValue("SimpleProblemData", out dataVariable) ||
+            !(dataVariable.Value is SimpleProblemData) ||
+             ((SimpleProblemData)dataVariable.Value).Echelons == null) {
+          data = new SimpleProblemData(ProblemData);
+          globalScope.Variables.Remove("SimpleProblemData");
+          globalScope.Variables.Add(new Variable("SimpleProblemData", data));
+        } else {
+          data = dataVariable.Value as SimpleProblemData;
+        }
+      }
+      return data;
+    }
+
+    private double[] CalculateFeedstockCosts(SimpleProblemData data, RealVector utilizations, Temp temp) {
+      double cost = 0;
+      var amountsAtSource = new double[data.N];
+      for (int i = 0; i < data.N; i++) {
+        var amount = data.Potentials[i]*utilizations[i];
+        if (amount < 100) amount = 0; // TODO: make this configurable
+        amountsAtSource[i] = amount;
+        cost += FeedstockCostEvaluator.GetScaledCost(data.FeedstockBasePrices[i], data.FeedstockMaxPrices[i], amount, utilizations[i]);
+      }
+      temp.TotalCost += cost;
+      return amountsAtSource;
+    }
+
+    private double[] CalculateLogisticCosts(SimpleProblemData data, int echelonNr, Temp temp, IntegerVector transportTargets) {
+      var echelon = data.Echelons[echelonNr];
+      var distanceMatrix = echelon.DistanceMatrix;
+      var logistic = echelon.Logistic;
+      double cost = 0;
+      double penalty = 0;
+      double[] amountsAtTarget = new double[data.N];
+      for (int i = 0; i < data.N; i++) {
+        if (temp.Amounts[i] <= 0) continue;
+        var amount = Brace(temp.Amounts[i], logistic.MinAmount, logistic.MaxAmount);
+        var target = transportTargets[i];
+        amountsAtTarget[target] += Math.Min(temp.Amounts[i], amount); // cannot have more than before
+        var distance = distanceMatrix[i, target];
+        if (distance > logistic.MaxDistance)
+          penalty += LogisticCostEvaluator.Penalty(distance, logistic.MaxDistance, distanceMatrix.Max);
+        cost += data.GetLogisticActionCost(logistic.Transport, amount*distance*(1-logistic.WaterContent), i, target);
+        cost += data.GetLogisticActionCost(logistic.Handling, amount*(1-logistic.WaterContent), i, target);
+      }
+      temp.TotalCost += cost;
+      temp.TotalPenalty += penalty;
+      return amountsAtTarget;
+    }
+
+    private static double Brace(double value, double min, double max) { return Math.Min(max, Math.Max(min, value)); }
+
+
+    private void CalculateConversionCosts(SimpleProblemData data, int echelonNr, Temp temp) {
+      var echelon = data.Echelons[echelonNr];
+      var conversion = echelon.Conversion;
+      double cost = 0;
+      double penalty = 0;
+      for (int i = 0; i < data.N; i++) {
+        var amount = temp.Amounts[i];
+        if (amount <= 0) continue;
+        var maxCapacity = echelon.MaxConversionCapacities[i];
+        amount = amount * (1-conversion.DryMatterLoss);
+        var capacity = amount/conversion.UtilizationFactor;
+        // NOTE: available capacities are ignored (unused anyway)
+        var scale = capacity/conversion.DesignCapacity;
+        var minScale = conversion.MinCapacity/conversion.DesignCapacity;
+        var maxScale = maxCapacity/conversion.DesignCapacity;
+        penalty += ConversionCostEvaluator.ScalingPenalty(scale, minScale, maxScale);
+        penalty += ConversionCostEvaluator.CapacityPenalty(capacity, maxCapacity);
+        cost += ConversionCostEvaluator.ScaledCost(scale, maxScale, conversion.Construction, conversion.ConstructionScalingExponent);
+        cost += ConversionCostEvaluator.ScaledCost(scale, maxScale, conversion.Maintenance, conversion.MaintenanceScalingExponent);
+        cost += conversion.Cost*amount; // side product costs and revenues have been factored in before
+        var storageCapacity = capacity/365*conversion.SafetyStock;
+        cost += data.GetLogisticActionCost(conversion.Storage, storageCapacity, i);
+        temp.Amounts[i] = amount*conversion.MainProductConversionRate;
+      }
+      temp.TotalCost += cost;
+      temp.TotalPenalty += penalty;
+    }
+
+    private T GetFromScope<T>(string variableName) where T: class{
+      var variables = ExecutionContext.Scope.Variables;
+      return variables[variableName].Value as T;
+    }
+  }
+
+  public sealed class Temp {
+    public double[] Amounts;
+    public double TotalCost;
+    public double TotalPenalty;
+    public Temp(int n) { Amounts = new double[n]; }
+  }
+
+  [StorableClass(StorableClassType.AllFieldsAndAllProperties)]
+  public sealed class SimpleProblemData : Item {
+
+    [StorableConstructor]
+    private SimpleProblemData(bool isDeserializing) : base(isDeserializing) { }
+
+    private SimpleProblemData(SimpleProblemData orig, Cloner cloner) : base(orig, cloner) {
+      FinalProudctPrice = orig.FinalProudctPrice;
+      N = orig.N;
+      Potentials = Util.Clone(orig.Potentials);
+      FeedstockBasePrices = Util.Clone(orig.FeedstockBasePrices);
+      FeedstockMaxPrices = Util.Clone(orig.FeedstockMaxPrices);
+      invest = Util.Clone(orig.invest);
+      fuel = Util.Clone(orig.fuel);
+      other = Util.Clone(orig.other);
+      Echelons = orig.Echelons.Select(cloner.Clone).ToList();
+    }
+
+    public SimpleProblemData(BioBoostProblemData data) {
+      N = data.LocationNames.Length;
+      var feedstockName = data.Utilizations.CheckedItems.First().Value.Value;
+      Potentials = ((IValueParameter<DoubleArray>) data.FeedstockPotentials[LayerDescriptor.PotentialsFromProblemData.NameWithPrefix(feedstockName)]).Value.ToArray();
+      var feedstock = data.Products.First(p => p.Label == feedstockName);
+      FeedstockBasePrices = data.LocationNames.Select(loc => feedstock.GetRegionalBasePrice(loc)).ToArray();
+      FeedstockMaxPrices = data.LocationNames.Select(loc => feedstock.GetRegionalMaxPrice(loc)).ToArray();
+      invest = data.InvestmentCostFactors.ToArray();
+      maint = data.MaintenanceCostFactors.ToArray();
+      fuel = data.FuelCostFactors.ToArray();
+      labor = data.LaborCostFactors.ToArray();
+      other = data.OtherCostFactors.ToArray();
+      var transportedProducts = data.TransportTargets.CheckedItems.Select(i => i.Value.Value).ToArray();
+      var prices = data.Products.ToDictionary(p => p.Label, p => p.Price);
+        // different prices (@source/@target) are not considered (unused anyway)
+      Echelons = new List<Echelon>(3);
+      for (int i = 0; i < transportedProducts.Length; i++) {
+        var echelon = new Echelon();
+        var productName = echelon.FeedstockName = transportedProducts[i];
+        var logistic = echelon.Logistic = (Logistic) data.Logistics[productName].First().Clone(); // TODO: make better choice
+        logistic.Transport.Other += logistic.Transport.Emissions.TotalCost(prices, null);
+        logistic.Handling.Other += logistic.Handling.Emissions.TotalCost(prices, null);
+        echelon.DistanceMatrix = GetFromProblemData<DistanceMatrix>(data, logistic.Distances + "DistanceMatrix");
+        var conversion = echelon.Conversion = (Conversion) data.Conversions[productName].First().Clone(); // TODO: make better choice?
+        echelon.MaxConversionCapacities =
+          data.LocationNames.Select(loc => ConversionCostEvaluator.GetMaxCapacity(conversion, loc)).ToArray();
+        conversion.MaybeInferMainProduct(prices);
+        conversion.Cost += conversion.Products.TotalCost(prices, conversion.MainProduct);
+        Echelons.Add(echelon);
+      }
+      var finalEchelon = new Echelon();
+      var finalProductName = finalEchelon.FeedstockName = data.FinalProducts.CheckedItems.First().Value.Value;
+      Echelons.Add(finalEchelon);
+      FinalProudctPrice = prices[finalProductName];
+    }
+
+    private static V GetValue<K,V>(IDictionary<K,V> d, K key, V defaultValue) {
+      V value;
+      if (d.TryGetValue(key, out value))
+        return value;
+      return defaultValue;
+    }
+
+    private static double GetValue(ValueParameterCollection parameters, string name, double defaultValue) {
+      IValueParameter param = null;
+      if (!parameters.TryGetValue(name, out param)) return defaultValue;
+      var doubleValueParam = param as IValueLookupParameter<DoubleValue>;
+      if (doubleValueParam == null) return defaultValue;
+      return doubleValueParam.Value.Value;
+    }
+
+    [StorableClass(StorableClassType.AllFieldsAndAllProperties)]
+    public sealed class Echelon : Item {
+
+      public Logistic Logistic;
+      public DistanceMatrix DistanceMatrix;
+      public double[] MaxConversionCapacities;
+      public Conversion Conversion;
+      public string FeedstockName;
+
+      [StorableConstructor]
+      private Echelon(bool isDeserializing) : base(isDeserializing) { }
+
+      public Echelon() { }
+
+      private Echelon(Echelon orig, Cloner cloner) {
+        Logistic = cloner.Clone(orig.Logistic);
+        DistanceMatrix = cloner.Clone(orig.DistanceMatrix);
+        MaxConversionCapacities = Util.Clone(orig.MaxConversionCapacities);
+        Conversion = cloner.Clone(orig.Conversion);
+        FeedstockName = Util.Clone(orig.FeedstockName);
+      }
+
+      public override IDeepCloneable Clone(Cloner cloner) {
+        return new Echelon(this, cloner);
+      }
+    }
+
+    public double FinalProudctPrice;
+    public int N;
+    public double[] Potentials;
+    public double[] FeedstockBasePrices;
+    public double[] FeedstockMaxPrices;
+    public double[] invest, maint, fuel, labor, other;
+    public List<Echelon> Echelons; // nr of echelons + 1 for final product
+
+    public double GetLogisticActionCost(LogisticAction a, double amount, int i, int j) {
+      return 
+        amount * (
+          a.Investment  *(invest[i] + invest[j]) +
+          a.Maintenance *( maint[i] +  maint[j]) +
+          a.Fuel        *(  fuel[i] +   fuel[j]) +
+          a.Labor       *( labor[i] +  labor[j]) +
+          a.Other       *( other[i] +  other[j]))/2;
+    }
+
+    public double GetLogisticActionCost(LogisticAction a, double amount, int i) {
+      return
+        amount * (
+          a.Investment  * invest[i] +
+          a.Maintenance *  maint[i] +
+          a.Fuel        *   fuel[i] +
+          a.Labor       *  labor[i] +
+          a.Other       *  other[i]);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SimpleProblemData(this, cloner);
+    }
+
+    public static  T GetFromProblemData<T>(BioBoostProblemData data, string label) where T : class, IItem {
+      IParameter param;
+      data.Parameters.TryGetValue(label, out param);
+      var valueParam = param as IValueParameter;
+      if (valueParam != null) return valueParam.Value as T;
+      if (param != null) return param.ActualValue as T;
+      return null;
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/ObjectPool.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/ObjectPool.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/ObjectPool.cs	(revision 15711)
@@ -0,0 +1,86 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.BioBoost.Evaluators {
+
+  /// <summary>
+  /// Object pool for reusing frequently created and discarded objects.
+  /// </summary>
+  /// <typeparam name="T"></typeparam>
+  public class ObjectPool<T> where T : new() {
+
+    private readonly Stack<T> pool;
+
+    public int MaxPoolSize { get; set; }
+
+    public Func<T> Create;
+    public Action<T> Clear;
+    public Func<T, int, bool> Accept; 
+
+    private static void DoNothing(T o) {}
+    private static bool DefaultAccept(T o, int count) { return count < 100; }
+
+    public ObjectPool() : this(() => new T(), DoNothing, DefaultAccept) {}
+
+    public ObjectPool(Func<T> create, Action<T> clear, Func<T, int, bool> accept) {
+      pool = new Stack<T>();
+      Create = create;
+      Clear = clear;
+      Accept = accept;
+    }
+
+    public T Get() {
+      lock (this) {
+        if (pool.Count > 0) {
+          return pool.Pop();
+        }
+      }
+      return Create();
+    }
+
+    public T GetCleared() {
+      lock (this) {
+        if (pool.Count > 0) {
+          var val = pool.Pop();
+          Clear(val);
+          return val;
+        }
+      }
+      return Create();
+    }
+
+    public void Return(T o) {
+      lock (this) {
+        if (Accept(o, pool.Count))
+          pool.Push(o);
+      }
+    }
+
+    public void Reset() {
+      lock (this)
+        pool.Clear();
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/SinkEvaluator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/SinkEvaluator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Evaluators/SinkEvaluator.cs	(revision 15711)
@@ -0,0 +1,85 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System.Linq;
+using HeuristicLab.BioBoost.Representation;
+
+namespace HeuristicLab.BioBoost.Evaluators {
+  [StorableClass]
+  public class SinkEvaluator : BioBoostEvaluator {
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected SinkEvaluator(bool isDeserializing) : base(isDeserializing) {}
+    protected SinkEvaluator(SinkEvaluator original, Cloner cloner) : base(original, cloner) { }
+    public SinkEvaluator() {
+      Parameters.Add(new ScopeParameter("Scope", "The scope to search products in."));
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SinkEvaluator(this, cloner);
+    }
+    #endregion
+
+    private static LayerDescriptor emptyLayerDescriptor = new LayerDescriptor("", "", "");
+
+    public override IOperation Apply() {
+      foreach (var product in ProblemData.Products) {
+        InvoiceProduct(product.Label, product.Price, emptyLayerDescriptor, LayerDescriptor.DischargeCosts);
+        InvoiceProduct(product.Label, product.PriceAtSource, LayerDescriptor.AmountsAtSource, LayerDescriptor.TotalCostsAtSource);
+        InvoiceProduct(product.Label, product.PriceAtTarget, LayerDescriptor.AmountsAtTarget, LayerDescriptor.TotalCostsAtTarget);
+      }
+      return base.Apply();
+    }
+
+    private void InvoiceProduct(string productName, double price, LayerDescriptor amountLayerDescriptor, LayerDescriptor costLayerDescriptor) {
+      var variables = ExecutionContext.Scope.Variables;
+      IVariable amountVariable, costsVariable;
+      if (!variables.TryGetValue(amountLayerDescriptor.NameWithPrefix(productName), out amountVariable)) return;
+      var amounts = amountVariable.Value as DoubleArray;
+      if (amounts == null) return;
+      var relativeProductionCosts = new DoubleArray(amounts.Length);
+      DoubleArray productionCosts = null;
+      if (variables.TryGetValue(costLayerDescriptor.NameWithPrefix(productName), out costsVariable)) {
+        productionCosts = costsVariable.Value as DoubleArray;
+      }
+      var totalCost = amounts.Sum()*-price;
+      var length = amounts.Length;
+      var costs = new DoubleArray(length);
+      for (int i = 0; i < length; i++) {
+        costs[i] = amounts[i]*-price;
+        if (productionCosts != null && amounts[i] != 0)
+          relativeProductionCosts[i] = productionCosts[i]/amounts[i];
+      }
+      if (totalCost != 0) {
+        AddInScope(LayerDescriptor.DischargeCosts.NameWithPrefix(productName), costs, false);
+        Costs.Add(new Result(costLayerDescriptor.NameWithPrefix(productName), new DoubleValue(totalCost)));
+        if (totalCost > 0)
+          AddInScope(LayerDescriptor.LocalAddedValue.Name, costs, false);
+      }
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/HeuristicLab.Problems.BioBoost-3.3.csproj
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/HeuristicLab.Problems.BioBoost-3.3.csproj	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/HeuristicLab.Problems.BioBoost-3.3.csproj	(revision 15711)
@@ -0,0 +1,327 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{61D4AF50-8A40-44B9-9CD0-413F65D2235C}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HeuristicLab.Problems.BioBoost</RootNamespace>
+    <AssemblyName>HeuristicLab.Problems.BioBoost-3.3</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <TargetFrameworkProfile />
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <CodeAnalysisLogFile>bin\Debug\HeuristicLab.BioBoost.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+    <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+    <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+    <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+    <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <CodeAnalysisLogFile>bin\Release\HeuristicLab.BioBoost.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+    <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+    <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+    <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+    <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <CodeAnalysisLogFile>bin\Debug\HeuristicLab.BioBoost.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+    <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+    <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+    <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+    <CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets>
+    <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+    <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <CodeAnalysisLogFile>bin\Release\HeuristicLab.BioBoost.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+    <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+    <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+    <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+    <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SignAssembly>false</SignAssembly>
+  </PropertyGroup>
+  <PropertyGroup>
+    <AssemblyOriginatorKeyFile>HeuristicLab.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="BruTile, Version=0.7.4.4, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\BruTile.0.7.4.4\lib\net40\BruTile.dll</HintPath>
+    </Reference>
+    <Reference Include="BruTile.Desktop, Version=0.7.4.4, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\BruTile.0.7.4.4\lib\net40\BruTile.Desktop.dll</HintPath>
+    </Reference>
+    <Reference Include="BruTile.Serialization">
+      <HintPath>..\..\packages\BruTile.0.7.4.4\lib\net40\BruTile.Serialization.dll</HintPath>
+    </Reference>
+    <Reference Include="Common.Logging, Version=2.0.0.0, Culture=neutral, PublicKeyToken=af08829b84f0328e, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\Common.Logging.2.0.0\lib\2.0\Common.Logging.dll</HintPath>
+    </Reference>
+    <Reference Include="GeoAPI, Version=1.7.2.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\GeoAPI.1.7.2\lib\net403-client\GeoAPI.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Analysis-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Analysis-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Collections-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Collections-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Common-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Common-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Common.Resources-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Common.Resources-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Core-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Core-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Data-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Data-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Encodings.IntegerVectorEncoding-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Encodings.IntegerVectorEncoding-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Encodings.RealVectorEncoding-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Encodings.RealVectorEncoding-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Operators-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Operators-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Optimization-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Optimization-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Optimization.Operators-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Optimization.Operators-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Parameters-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Parameters-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Persistence-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Persistence-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.PluginInfrastructure-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.PluginInfrastructure-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Random-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Random-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.SequentialEngine-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.SequentialEngine-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="NetTopologySuite, Version=1.13.2.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\NetTopologySuite.1.13.2\lib\net403-client\NetTopologySuite.dll</HintPath>
+    </Reference>
+    <Reference Include="NetTopologySuite.IO.GeoTools">
+      <HintPath>..\..\packages\NetTopologySuite.IO.1.13.2\lib\net403-client\NetTopologySuite.IO.GeoTools.dll</HintPath>
+    </Reference>
+    <Reference Include="NetTopologySuite.IO.MsSqlSpatial">
+      <HintPath>..\..\packages\NetTopologySuite.IO.1.13.2\lib\net403-client\NetTopologySuite.IO.MsSqlSpatial.dll</HintPath>
+    </Reference>
+    <Reference Include="NetTopologySuite.IO.PostGis">
+      <HintPath>..\..\packages\NetTopologySuite.IO.1.13.2\lib\net403-client\NetTopologySuite.IO.PostGis.dll</HintPath>
+    </Reference>
+    <Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="PowerCollections, Version=1.0.0.0, Culture=neutral, PublicKeyToken=2573bf8a1bdddcd5, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\NetTopologySuite.1.13.2\lib\net403-client\PowerCollections.dll</HintPath>
+    </Reference>
+    <Reference Include="ProjNet, Version=1.3.0.3, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\ProjNET4GeoAPI.1.3.0.3\lib\net403-client\ProjNet.dll</HintPath>
+    </Reference>
+    <Reference Include="SharpMap, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\packages\SharpMap.1.1.0\lib\net40-client\SharpMap.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Data.SQLite">
+      <HintPath>..\..\packages\System.Data.SQLite.MSIL.1.0.86.0\lib\net45\System.Data.SQLite.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Data.SQLite.Linq">
+      <HintPath>..\..\packages\System.Data.SQLite.MSIL.1.0.86.0\lib\net45\System.Data.SQLite.Linq.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Runtime.Serialization" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+    <Reference Include="YamlDotNet">
+      <HintPath>..\..\packages\YamlDotNet.3.8.0\lib\net35\YamlDotNet.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Analysis\MultiObjejctiveBioBoostSolutionAnalyzer.cs" />
+    <Compile Include="Analysis\BestBioBoostSolutionAnalyzer.cs" />
+    <Compile Include="Analysis\MultiOperatorUsageAnalyzer.cs" />
+    <Compile Include="Evaluators\MonolithicEvaluator.cs" />
+    <Compile Include="MultiobjectiveBioBoostProblem.cs" />
+    <Compile Include="BioBoostProblem.cs" />
+    <Compile Include="Data\Conversion.cs" />
+    <Compile Include="Data\CostFactors.cs" />
+    <Compile Include="Data\LogisticAction.cs" />
+    <Compile Include="Data\Logistic.cs" />
+    <Compile Include="Data\DataItem.cs" />
+    <Compile Include="Data\Product.cs" />
+    <Compile Include="Evaluators\AggregateEvaluator.cs" />
+    <Compile Include="Evaluators\BioBoostEvaluator.cs" />
+    <Compile Include="Evaluators\InitializationEvaluator.cs" />
+    <Compile Include="Operators\BioBoostOperator.cs" />
+    <Compile Include="Evaluators\ConcludingEvaluator.cs" />
+    <Compile Include="Evaluators\ConversionCostEvaluator.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Evaluators\ObjectPool.cs" />
+    <Compile Include="Evaluators\SinkEvaluator.cs" />
+    <Compile Include="Evaluators\LogisticCostEvaluator.cs" />
+    <Compile Include="Evaluators\FeedstockCostEvaluator.cs" />
+    <Compile Include="Operators\Crossover\CompoundCrossover.cs" />
+    <Compile Include="Operators\Crossover\MultiCrossover.cs" />
+    <Compile Include="Operators\Crossover\PlantBasedCrossover.cs" />
+    <Compile Include="Operators\LimitedDistanceTransportTargetCreator.cs" />
+    <Compile Include="Operators\Moves\MoveEvaluatorAdapter.cs" />
+    <Compile Include="Operators\Moves\MoveMakerAdapter.cs" />
+    <Compile Include="Operators\Moves\MoveGeneratorAdapter.cs" />
+    <Compile Include="Operators\Mutation\CompoundMutator.cs" />
+    <Compile Include="Operators\Mutation\CommonTargetIntegerVectorMutator.cs" />
+    <Compile Include="Operators\Mutation\CommonTargetSwappingIntegerVectorMutator.cs" />
+    <Compile Include="Operators\Mutation\BoundaryToggleRealVectorMutator.cs" />
+    <Compile Include="Operators\Mutation\EmptyMutator.cs" />
+    <Compile Include="Operators\Mutation\PlantKiller.cs" />
+    <Compile Include="Operators\Mutation\PlantSupplierToggler.cs" />
+    <Compile Include="Operators\Mutation\PlantSupplierUtilizationExchanger.cs" />
+    <Compile Include="Operators\Mutation\PlantSupplierEqualizer.cs" />
+    <Compile Include="Operators\Mutation\PlantSupplierRandomizer.cs" />
+    <Compile Include="Operators\Mutation\PlantScalingMutator.cs" />
+    <Compile Include="Operators\Mutation\PlantBasedUtilizationModifier.cs" />
+    <Compile Include="Operators\Mutation\PlantMerger.cs" />
+    <Compile Include="Operators\Mutation\PlantSplitter.cs" />
+    <Compile Include="Operators\Mutation\MultiMutator.cs" />
+    <Compile Include="Operators\Mutation\PlantMover.cs" />
+    <Compile Include="Operators\Mutation\TargetMergingIntegerVectorMutator.cs" />
+    <Compile Include="Operators\Mutation\MultiIntegerVectorMutator.cs" />
+    <Compile Include="Operators\Mutation\NeighborBasedIntegerVectorMutator.cs" />
+    <Compile Include="Operators\Mutation\DistanceBasedIntegerVectorMutator.cs" />
+    <Compile Include="Operators\Transformation\FeedstockTransformer.cs" />
+    <Compile Include="Operators\Transformation\FeedstockInflater.cs" />
+    <Compile Include="Operators\Transformation\FeedstockDeflater.cs" />
+    <Compile Include="Persistence\GeometryFeatureProviderSerializer.cs" />
+    <Compile Include="Persistence\GeometrySerializer.cs" />
+    <Compile Include="Plugin.cs" />
+    <Compile Include="ProblemDescription\BioBoostProblemData.cs" />
+    <Compile Include="ProblemDescription\SolutionSpaceDiscoverer.cs" />
+    <Compile Include="ProblemDescription\DistanceMatrix.cs" />
+    <Compile Include="ProblemDescription\NeighborhoodTable.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Persistence\ShapeFileLoader.cs" />
+    <Compile Include="Representation\BioBoostCompoundSolution.cs" />
+    <Compile Include="Representation\LayerDescriptor.cs" />
+    <Compile Include="SolutionCreation\BioBoostSolutionCreator.cs" />
+    <Compile Include="SolutionCreation\ConstantValueRealVectorCreator.cs" />
+    <Compile Include="SolutionCreation\LimitedValuesIntegerVectorCreator.cs" />
+    <Compile Include="SolutionCreation\IdentityIntegerVectorCreator.cs" />
+    <Compile Include="Utils\Closure.cs" />
+    <Compile Include="Utils\DictionaryExtensions.cs" />
+    <Compile Include="Utils\EnumerableExtensions.cs" />
+    <Compile Include="Utils\ListExtensions.cs" />
+    <Compile Include="Utils\StepFunction.cs" />
+    <Compile Include="Utils\Util.cs" />
+    <Compile Include="Utils\ValueParameterCollectionExtensions.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="app.config" />
+    <None Include="HeuristicLab.snk" />
+    <None Include="packages.config" />
+    <None Include="Plugin.cs.frame" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <PropertyGroup>
+    <PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+set ProjectDir=$(ProjectDir)
+set SolutionDir=$(SolutionDir)
+set Outdir=$(Outdir)
+
+call PreBuildEvent.cmd
+</PreBuildEvent>
+    <PreBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">
+export ProjectDir=$(ProjectDir)
+export SolutionDir=$(SolutionDir)
+
+$SolutionDir/PreBuildEvent.sh
+</PreBuildEvent>
+  </PropertyGroup>
+  <!-- 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>
+  -->
+</Project>
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/MultiobjectiveBioBoostProblem.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/MultiobjectiveBioBoostProblem.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/MultiobjectiveBioBoostProblem.cs	(revision 15711)
@@ -0,0 +1,146 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.BioBoost.Analysis;
+using HeuristicLab.BioBoost.Evaluators;
+using HeuristicLab.BioBoost.Operators.Crossover;
+using HeuristicLab.BioBoost.Operators.Mutation;
+using HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.BioBoost.SolutionCreation;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System;
+
+namespace HeuristicLab.BioBoost {
+
+  [Item("Multiobjective BioBoost Problem", "EU-wide aggregate biomass logistics simulation (multiobjective).")]
+  [Creatable("Problems")]
+  [StorableClass]
+  public class MultiobjectiveBioBoostProblem : MultiObjectiveHeuristicOptimizationProblem<AggregateEvaluator, BioBoostSolutionCreator>, IStorableContent {
+
+    #region IStorableContent Members
+    public string Filename { get; set; }
+    #endregion
+
+    #region Parameters
+    public ValueParameter<BioBoostProblemData> ProblemDataParameter {
+      get { return (ValueParameter<BioBoostProblemData>) Parameters["ProblemData"]; }
+    }
+    public ValueParameter<IntMatrix> RegionBoundsParameter {
+      get { return (ValueParameter<IntMatrix>) Parameters["RegionBounds"]; }
+    }
+    public ValueParameter<IntValue> NRegionsParameter {
+      get { return (ValueParameter<IntValue>) Parameters["NRegions"]; }
+    }
+    public ValueParameter<BoolValue> RemoveIntermediateResultsParameter {
+      get { return (ValueParameter<BoolValue>) Parameters["RemoveIntermediateResults"]; }
+    }
+    #endregion
+
+    #region Parameter Values
+    public BioBoostProblemData ProblemData {
+      get { return ProblemDataParameter.Value; }
+    }
+    public IntMatrix RegionBounds {
+      get { return RegionBoundsParameter.Value; }
+      set { RegionBoundsParameter.Value = value; }
+    }
+    public int NRegions {
+      get { return NRegionsParameter.Value.Value; }
+      set { NRegionsParameter.Value = new IntValue(value); }
+    }
+    public bool RemoveIntermediateResults {
+      get { return RemoveIntermediateResultsParameter.Value.Value; }
+    }
+    #endregion
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected MultiobjectiveBioBoostProblem(bool isDeserializing) : base(isDeserializing) {}
+    protected MultiobjectiveBioBoostProblem(MultiobjectiveBioBoostProblem orig, Cloner cloner) : base(orig, cloner) {
+      RegisterEvents();
+    }
+    public MultiobjectiveBioBoostProblem() {
+      Parameters.Add(new ValueParameter<BioBoostProblemData>("ProblemData", "Encapsulation of all data describing the problem instance."));
+      Parameters.Add(new ValueParameter<IntMatrix>("RegionBounds", "Bounds for valid region ids.", new IntMatrix(new int[,]{{0, 0}})));
+      Parameters.Add(new ValueParameter<IntValue>("NRegions", "Number of regions.", new IntValue(0)));
+      Parameters.Add(new ValueParameter<BoolValue>("RemoveIntermediateResults", "Whether to remove intermediate results created during evaluation.", new BoolValue(true)));
+      Maximization = new BoolArray(new [] {true, true});
+      RegionBoundsParameter.Hidden = true;
+      RegisterEvents();
+      Operators.Add(new CompoundCrossover());
+      Operators.Add(new MultiCrossover());
+      Operators.Add(new PlantBasedCrossover());
+      Operators.Add(new BoundaryToggleRealVectorMutator());
+      Operators.Add(new CompoundMutator());
+      Operators.Add(new EmptyMutator());
+      Operators.Add(new MultiMutator());
+      Operators.Add(new PlantKiller());
+      Operators.Add(new PlantMerger());
+      Operators.Add(new PlantMover());
+      Operators.Add(new PlantScalingMutator());
+      Operators.Add(new PlantSupplierEqualizer());
+      Operators.Add(new PlantSupplierRandomizer());
+      Operators.Add(new PlantSupplierToggler());
+      Operators.Add(new PlantSupplierUtilizationExchanger());
+      Operators.Add(new MultiObjectiveBioBoostSolutionAnalyzer());
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MultiobjectiveBioBoostProblem(this, cloner);
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterEvents();
+    }
+    #endregion
+
+    #region events
+    private void RegisterEvents() {
+      NRegionsParameter.ToStringChanged += new EventHandler(NRegionsParameterChanged);
+      ProblemDataParameter.ValueChanged += UpdateEventRegistration;
+      UpdateEventRegistration(this, EventArgs.Empty);
+    }
+
+    private BioBoostProblemData registeredProblemData = null;
+
+    private void UpdateEventRegistration(object sender, EventArgs eventArgs) {
+      if (registeredProblemData == ProblemData) return;
+      if (registeredProblemData != null) {
+        registeredProblemData.LocationNamesParameter.ToStringChanged -= LocationNamesChanged;
+      }
+      ProblemData.LocationNamesParameter.ToStringChanged += LocationNamesChanged;
+      registeredProblemData = ProblemData;
+    }
+
+    private void LocationNamesChanged(object sender, EventArgs e) {
+      NRegions = ProblemData.LocationNames.Length;
+    }
+
+    private void NRegionsParameterChanged(object sender, EventArgs e) {
+      RegionBounds = new IntMatrix(new int[,] {{0, NRegions}});
+    }
+    #endregion
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/BioBoostOperator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/BioBoostOperator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/BioBoostOperator.cs	(revision 15711)
@@ -0,0 +1,90 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.BioBoost.Representation;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.BioBoost.Operators {
+  public abstract class BioBoostOperator : SingleSuccessorOperator {
+
+    #region Parameters
+    public ILookupParameter<BioBoostProblemData> ProblemDataParameter {
+      get { return (ILookupParameter<BioBoostProblemData>) Parameters["ProblemData"]; }
+    }
+    #endregion
+
+    #region Parameter Values
+    public BioBoostProblemData ProblemData {
+      get { return ProblemDataParameter.ActualValue; }
+    }
+    #endregion
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected BioBoostOperator(bool isDeserializing) : base(isDeserializing) {}
+
+    protected BioBoostOperator(BioBoostOperator original, Cloner cloner) : base(original, cloner) { }
+
+    protected BioBoostOperator() {
+      Parameters.Add(new LookupParameter<BioBoostProblemData>("ProblemData", "Contains fixed values describing the problem."));
+    }
+    #endregion
+
+    protected T GetFromProblemData<T>(string label) where T : class, IItem {
+      IParameter param;
+      if(LayerDescriptor.PotentialsFromProblemData.IsSuffixOf(label)) {
+        ProblemData.FeedstockPotentials.TryGetValue(label, out param);
+      } else {
+        ProblemData.Parameters.TryGetValue(label, out param);
+      }
+      var valueParam = param as IValueParameter;
+      if (valueParam != null) return valueParam.Value as T;
+      if (param != null) return param.ActualValue as T;
+      return null;
+    }
+
+    protected T GetFromScope<T>(string label) where T : class, IItem {
+      IVariable var = null;
+      ExecutionContext.Scope.Variables.TryGetValue(label, out var);
+      if (var != null) return var.Value as T;
+      return null;
+    }
+
+    protected void RemoveFromScope(string label) {
+      ExecutionContext.Scope.Variables.Remove(label);
+    }
+
+    protected void RenameInScope(string oldLabel, string newLabel) {
+      var vars = ExecutionContext.Scope.Variables;
+      IVariable var;
+      if (!vars.TryGetValue(oldLabel, out var)) return;
+      vars.Remove(oldLabel);
+      if (vars.ContainsKey(newLabel))
+        vars.Remove(newLabel);
+      vars.Add(new Variable(newLabel, var.Value));
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Crossover/CompoundCrossover.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Crossover/CompoundCrossover.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Crossover/CompoundCrossover.cs	(revision 15711)
@@ -0,0 +1,141 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.PluginInfrastructure;
+using System.Linq;
+using HeuristicLab.BioBoost.Representation;
+using DiscreteIntegerVectorCrossover = HeuristicLab.Encodings.IntegerVectorEncoding.DiscreteCrossover;
+using DiscreteRealVectorCrossover = HeuristicLab.Encodings.RealVectorEncoding.DiscreteCrossover;
+using SinglePointRealVectorCrossover = HeuristicLab.Encodings.RealVectorEncoding.SinglePointCrossover;
+using SinglePointInteverVectorCrossover = HeuristicLab.Encodings.IntegerVectorEncoding.SinglePointCrossover;
+
+namespace HeuristicLab.BioBoost.Operators.Crossover {
+  [StorableClass]
+  public class CompoundCrossover : SingleSuccessorOperator, ICrossover {
+
+    #region Parameters
+    public ValueLookupParameter<IntMatrix> RegionBoundsParameter {
+      get { return (ValueLookupParameter<IntMatrix>) Parameters["RegionBounds"]; }
+    } 
+    public LookupParameter<BioBoostProblemData> ProblemDataParameter {
+      get { return (LookupParameter<BioBoostProblemData>) Parameters["ProblemData"]; }
+    }
+    public ConstrainedValueParameter<IIntegerVectorCrossover> TransportTargetCrossoverParameter {
+      get { return (ConstrainedValueParameter<IIntegerVectorCrossover>) Parameters["TransportTargetCrossover"]; }
+    }
+    public ConstrainedValueParameter<IRealVectorCrossover> FeedstockUtilizationCrossoverParameter {
+      get { return (ConstrainedValueParameter<IRealVectorCrossover>) Parameters["FeedstockUtilizationCrossover"]; }
+    }
+    #endregion
+
+    #region Parameter Values
+    public BioBoostProblemData ProblemData {
+      get { return ProblemDataParameter.ActualValue; }
+    }
+    #endregion
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected CompoundCrossover(bool isDeserializing) : base(isDeserializing) {}
+    protected CompoundCrossover(CompoundCrossover orig, Cloner cloner) : base(orig, cloner) { }
+    public CompoundCrossover() {
+      Parameters.Add(new LookupParameter<BioBoostProblemData>("ProblemData", "The data store of the detailed problem description."));
+      Parameters.Add(new ValueLookupParameter<IntMatrix>("RegionBounds", "The limits of valid region ids."));
+      Parameters.Add(new ConstrainedValueParameter<IIntegerVectorCrossover>("TransportTargetCrossover", "The manipulator to apply to the transport target vectors."));
+      Parameters.Add(new ConstrainedValueParameter<IRealVectorCrossover>("FeedstockUtilizationCrossover", "The manipulator for the feedstock utilization vectors."));
+      foreach (var op in ApplicationManager.Manager.GetInstances<IIntegerVectorCrossover>()) {
+        var bop = op as IBoundedIntegerVectorOperator;
+        if (bop != null)
+          bop.BoundsParameter.ActualName = RegionBoundsParameter.ActualName;
+        TransportTargetCrossoverParameter.ValidValues.Add(op);
+      }
+      foreach (var op in ApplicationManager.Manager.GetInstances<IRealVectorCrossover>()) {
+        op.BoundsParameter.Value = new DoubleMatrix(new double[,]{{0, 1}});
+        FeedstockUtilizationCrossoverParameter.ValidValues.Add(op);
+      }
+      TransportTargetCrossoverParameter.Value =
+        TransportTargetCrossoverParameter.ValidValues.FirstOrDefault(c => c.GetType() == typeof (MultiIntegerVectorCrossover));
+      FeedstockUtilizationCrossoverParameter.Value =
+        FeedstockUtilizationCrossoverParameter.ValidValues.FirstOrDefault(
+          c => c.GetType() == typeof (MultiRealVectorCrossover));
+      var tc = (MultiIntegerVectorCrossover) TransportTargetCrossoverParameter.Value;
+      foreach (var op in tc.Operators) {
+        if (op is DiscreteIntegerVectorCrossover ||
+            op is SinglePointInteverVectorCrossover) {
+          // accept
+        } else {
+          tc.Operators.SetItemCheckedState(op, false);
+        }
+      }
+      var uc = (MultiRealVectorCrossover) FeedstockUtilizationCrossoverParameter.Value;
+      foreach (var op in uc.Operators) {
+        if (op is BlendAlphaCrossover ||
+            op is DiscreteRealVectorCrossover ||
+            op is HeuristicCrossover ||
+            op is LocalCrossover ||
+            op is RandomConvexCrossover ||
+            op is SinglePointRealVectorCrossover ||
+            op is UniformAllPositionsArithmeticCrossover ||
+            op is UniformSomePositionsArithmeticCrossover) {
+          // accept
+        } else {
+          uc.Operators.SetItemCheckedState(op, false);
+        }
+      }
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CompoundCrossover(this, cloner);
+    }
+    #endregion
+
+    public override IOperation Apply() {
+      var ops = new OperationCollection(base.Apply());
+      foreach (var n in ProblemData.TransportTargets.CheckedItems) {
+        if (TransportTargetCrossoverParameter.ActualValue != null) {
+          var t = (IIntegerVectorCrossover) TransportTargetCrossoverParameter.ActualValue.Clone();
+          t.ParentsParameter.ActualName = LayerDescriptor.TransportTargets.NameWithPrefix(n.Value.Value);
+          t.ChildParameter.ActualName = LayerDescriptor.TransportTargets.NameWithPrefix(n.Value.Value);
+          ops.Add(ExecutionContext.CreateChildOperation(t));
+        }
+      }
+      foreach (var n in ProblemData.Utilizations.CheckedItems) {
+        if (FeedstockUtilizationCrossoverParameter.ActualValue != null) {
+          var u = (IRealVectorCrossover) FeedstockUtilizationCrossoverParameter.ActualValue.Clone();
+          u.ParentsParameter.ActualName = LayerDescriptor.Utilizations.NameWithPrefix(n.Value.Value);
+          u.ChildParameter.ActualName = LayerDescriptor.Utilizations.NameWithPrefix(n.Value.Value);
+          ops.Add(ExecutionContext.CreateChildOperation(u));
+        }
+      }
+      return ops;
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Crossover/MultiCrossover.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Crossover/MultiCrossover.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Crossover/MultiCrossover.cs	(revision 15711)
@@ -0,0 +1,67 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.PluginInfrastructure;
+using System;
+
+namespace HeuristicLab.BioBoost.Operators.Mutation {
+  [StorableClass]
+  public class MultiCrossover : StochasticMultiBranch<ICrossover>, ICrossover, IStochasticOperator {
+
+    public override bool CanChangeName {
+      get { return false; }
+    }
+
+    protected override bool CreateChildOperation {
+      get { return true; }
+    }
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected MultiCrossover(bool isDeserializing) : base(isDeserializing) {}
+    protected MultiCrossover(MultiCrossover orig, Cloner cloner) : base(orig, cloner) {}
+    public MultiCrossover() {
+      foreach (var t in ApplicationManager.Manager.GetTypes(typeof(ICrossover), Assembly.GetExecutingAssembly())) {
+        if (t == this.GetType()) continue; // avoid infinite recursion
+        ICrossover instance = null;
+        try {
+          instance = Activator.CreateInstance(t) as ICrossover;
+        } catch {}
+        if (instance != null) Operators.Add(instance);
+      }
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MultiCrossover(this, cloner);
+    }
+    #endregion
+
+    public override IOperation InstrumentedApply() {
+        if (Operators.Count == 0) throw new InvalidOperationException(Name + ": Please add at least one crossover to choose from.");
+        return base.InstrumentedApply();
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Crossover/PlantBasedCrossover.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Crossover/PlantBasedCrossover.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Crossover/PlantBasedCrossover.cs	(revision 15711)
@@ -0,0 +1,196 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Diagnostics;
+using HeuristicLab.BioBoost.Data;
+using HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.BioBoost.Utils;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.PluginInfrastructure;
+using System.Linq;
+using HeuristicLab.BioBoost.Representation;
+using HeuristicLab.Random;
+using DiscreteIntegerVectorCrossover = HeuristicLab.Encodings.IntegerVectorEncoding.DiscreteCrossover;
+using DiscreteRealVectorCrossover = HeuristicLab.Encodings.RealVectorEncoding.DiscreteCrossover;
+
+namespace HeuristicLab.BioBoost.Operators.Crossover {
+  [StorableClass]
+  public class PlantBasedCrossover : SingleSuccessorOperator, ICrossover, IStochasticOperator {
+
+    #region Parameters
+    public ValueLookupParameter<IntMatrix> RegionBoundsParameter {
+      get { return (ValueLookupParameter<IntMatrix>)Parameters["RegionBounds"]; }
+    }
+    public LookupParameter<BioBoostProblemData> ProblemDataParameter {
+      get { return (LookupParameter<BioBoostProblemData>)Parameters["ProblemData"]; }
+    }
+    public ILookupParameter<IRandom> RandomParameter { get { return (ILookupParameter<IRandom>) Parameters["Random"]; } }
+    public IValueLookupParameter<IntValue> OrderingParameter { get { return (IValueLookupParameter<IntValue>) Parameters["Ordering"]; } }
+    public IValueLookupParameter<IntValue> FrequencyParameter { get { return (IValueLookupParameter<IntValue>) Parameters["Frequency"]; } }
+    public IValueLookupParameter<PercentValue> FairnessParameter { get { return (IValueLookupParameter<PercentValue>) Parameters["Fairness"]; } }
+    #endregion
+
+    #region Parameter Values
+    public BioBoostProblemData ProblemData { get { return ProblemDataParameter.ActualValue; } }
+    public IRandom Random { get { return RandomParameter.ActualValue; } }
+    public int Ordering { get { return OrderingParameter.ActualValue.Value; } }
+    public int Frequency { get { return FrequencyParameter.ActualValue.Value; } }
+    public double Fairness { get { return FairnessParameter.ActualValue.Value; } }
+    #endregion
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected PlantBasedCrossover(bool isDeserializing) : base(isDeserializing) { }
+    protected PlantBasedCrossover(PlantBasedCrossover orig, Cloner cloner) : base(orig, cloner) { }
+
+    public PlantBasedCrossover() {
+      Parameters.Add(new LookupParameter<BioBoostProblemData>("ProblemData", "The data store of the detailed problem description."));
+      Parameters.Add(new ValueLookupParameter<IntMatrix>("RegionBounds", "The limits of valid region ids."));
+      Parameters.Add(new LookupParameter<IRandom>("Random", "A/The random value generator."));
+      Parameters.Add(new ValueLookupParameter<IntValue>("Ordering", "Choose ordering 1: largest-first, -1: smallest first, 0: random", new IntValue(1)));
+      Parameters.Add(new ValueLookupParameter<IntValue>("Frequency", "Number of crossover points -1: random, 0: after every plant, n: n times", new IntValue(1)));
+      Parameters.Add(new ValueLookupParameter<PercentValue>("Fairness", "Amount of fairness: 0 don't bother, 1 avoid favoring one parent", new PercentValue(0)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new PlantBasedCrossover(this, cloner);
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    public void AfterDeserialization() {
+      if (!Parameters.ContainsKey("Ordering"))
+        Parameters.Add(new ValueLookupParameter<IntValue>("Ordering", "Choose ordering 1: largest-first, -1: smallest first, 0: random", new IntValue(0)));
+      if (!Parameters.ContainsKey("Frequency"))
+        Parameters.Add(new ValueLookupParameter<IntValue>("Frequency", "Number of crossover points -n: random (1-n), 0: ignore (order-based only), n: n times", new IntValue(0)));
+      if (!Parameters.ContainsKey("Fairness"))
+        Parameters.Add(new ValueLookupParameter<PercentValue>("Fairness", "Amount of fairness 0: don't bother -  1: avoid favoring one parent", new PercentValue(0)));
+    }
+    #endregion
+
+    public override IOperation Apply() {
+      var nParents = ExecutionContext.Scope.SubScopes.Count;
+      if (nParents == 0) return base.Apply();
+      foreach (var product in ProblemData.TransportTargets.CheckedItems) {
+        var targets = new IntegerVector[nParents];
+        var utilizations = new RealVector[nParents];
+        foreach (var i in Enumerable.Range(0, nParents))
+          GetVectors(ExecutionContext.Scope.SubScopes[i], product.Value.Value, out targets[i], out utilizations[i]);
+        if (targets.Any(t => t == null)) continue;
+        var plants = Enumerable.Range(0, nParents)
+          .Select(parent => targets[parent].Select((target, source) => new {parent, target, source}).GroupBy(p => p.target))
+          .Aggregate((x, y) => x.Concat(y))
+          .ToArray();
+        if (Ordering == 0) Util.Shuffle(plants, Random);
+        else if (Ordering < 0) Array.Sort(plants, (g1, g2) => g1.Count() - g2.Count());
+        else if (Ordering > 0) Array.Sort(plants, (g1, g2) => g2.Count() - g1.Count());
+        var freq = Math.Min(Math.Abs(Frequency), plants.Length);
+        var nTotalAssignedRegions = 0;
+        var nAssignRegions = new int[nParents];
+        var length = targets[0].Length;
+        var assignedRegions = Enumerable.Repeat(false, length).ToArray();
+        var newTargets = new IntegerVector(length);
+        var newUtilizations = utilizations[0] != null ? new RealVector(length) : null;
+        if (freq == 0) { // order-based
+          foreach (var plant in plants) {
+            if (nTotalAssignedRegions >= length) break;
+            if (nAssignRegions[plant.First().parent] > Fairness*nTotalAssignedRegions/nParents) // skip overrepresented parent's plant
+              break;
+            foreach (var supplier in plant) {
+              if (nTotalAssignedRegions >= length) break;
+              if (assignedRegions[supplier.source]) continue;
+              assignedRegions[supplier.source] = true;
+              newTargets[supplier.source] = supplier.target;
+              if (newUtilizations != null)
+                newUtilizations[supplier.source] = utilizations[supplier.parent][supplier.source];
+              nTotalAssignedRegions++;
+            }
+          }
+        } else { // frequency-based
+          var nCrossoverPoints = Frequency < 0 ? Random.Next(freq) : freq;
+          var crossoverPoints = Enumerable.Range(0, plants.Length);
+          if (nCrossoverPoints != plants.Length)
+            crossoverPoints = crossoverPoints.SampleRandom(Random, nCrossoverPoints);
+          var plantsByParent = plants.GroupBy(g => g.First().parent).OrderBy(g => g.Key).Select(g => g.ToQueue()).ToArray();
+          int currentParent = 0;
+          int i = 0; 
+          foreach (var maxI in crossoverPoints) {
+            for (; i < maxI; i++) {
+              if (nAssignRegions[currentParent] > Fairness*nTotalAssignedRegions/nParents) // skip overrepresented parent's plant
+              foreach (var supplier in plantsByParent[currentParent].Dequeue()) {
+                if (nTotalAssignedRegions >= length) break;
+                if (assignedRegions[supplier.source]) continue;
+                assignedRegions[supplier.source] = true;
+                newTargets[supplier.source] = supplier.target;
+                if (newUtilizations != null)
+                  newUtilizations[supplier.source] = utilizations[supplier.parent][supplier.source];
+                nTotalAssignedRegions++;
+              }
+            }
+            currentParent = (currentParent + 1)%nParents;
+          }
+        }
+        foreach (var region in assignedRegions // fill unassigned regions
+          .Select((b, i) => new {selected = b, idx = i})
+          .Where(p => !p.selected).Select(p => p.idx)) { // unassigned regions
+          int newParent;
+          if (Random.NextDouble() < Fairness) { // choose a fair parent
+            newParent = nAssignRegions.Select((parent, n) => new {parent, n}).OrderBy(p => p.n).Select(p => p.parent).First();
+          } else {
+            newParent = Random.Next(nParents);
+          }
+          // assignedRegions[region] = true;
+          newTargets[region] = targets[newParent][region];
+          if (newUtilizations != null)
+            newUtilizations[region] = utilizations[newParent][region];
+        }
+        SaveVectors(ExecutionContext.Scope, product.Value.Value, newTargets, newUtilizations);
+      }
+      return base.Apply();
+    }
+
+    private void GetVectors(IScope scope, string product, out IntegerVector targets, out RealVector utilizations) {
+      IVariable targetsVar, utilizationsVar;
+      scope.Variables.TryGetValue(LayerDescriptor.TransportTargets.NameWithPrefix(product), out targetsVar);
+      scope.Variables.TryGetValue(LayerDescriptor.Utilizations.NameWithPrefix(product), out utilizationsVar);
+      targets = null;
+      utilizations = null;
+      if (targetsVar != null) targets = targetsVar.Value as IntegerVector;
+      if (utilizationsVar != null) utilizations = utilizationsVar.Value as RealVector;
+    }
+
+    private void SaveVectors(IScope scope, string product, IntegerVector targets, RealVector utilizations) {
+      scope.Variables.Add(new Variable(LayerDescriptor.TransportTargets.NameWithPrefix(product), targets));
+      scope.Variables.Add(new Variable(LayerDescriptor.Utilizations.NameWithPrefix(product), utilizations));
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/LimitedDistanceTransportTargetCreator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/LimitedDistanceTransportTargetCreator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/LimitedDistanceTransportTargetCreator.cs	(revision 15711)
@@ -0,0 +1,101 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Linq;
+using HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Random;
+
+namespace HeuristicLab.BioBoost.Operators {
+
+  [StorableClass]
+  public class LimitedDistanceTransportTargetCreator : BioBoostOperator, IIntegerVectorCreator {
+
+    #region IntegerVectorCreator
+    public IValueLookupParameter<IRandom> RandomParameter { get { return (IValueLookupParameter<IRandom>) Parameters["Random"]; } }
+    public IValueLookupParameter<IntMatrix> BoundsParameter { get { return (IValueLookupParameter<IntMatrix>) Parameters["Bounds"]; } }
+    public IValueLookupParameter<IntValue> LengthParameter { get { return (IValueLookupParameter<IntValue>) Parameters["Length"]; } }
+    public IValueLookupParameter<IntValue> TournamentSizeParameter { get { return (IValueLookupParameter<IntValue>) Parameters["TournamentSize"]; } }
+    public ILookupParameter<IntegerVector> IntegerVectorParameter { get { return (ILookupParameter<IntegerVector>) Parameters["IntegerVector"]; } }
+    public LookupParameter<DistanceMatrix> DistanceMatrixParameter { get { return (LookupParameter<DistanceMatrix>) Parameters["DistanceMatrix"]; } }
+    public ValueParameter<BoolValue> DistanceMatrixInProblemDataParameter { get { return (ValueParameter<BoolValue>) Parameters["DistanceMatrixInProblemData"]; } }
+    #endregion
+
+    public bool DistanceMatrixInProblemData { get { return DistanceMatrixInProblemDataParameter.Value.Value; } }
+    public DistanceMatrix DistanceMatrix {
+      get {
+        if (DistanceMatrixInProblemData) {
+          return ((IValueParameter<DistanceMatrix>) ProblemData.Parameters[DistanceMatrixParameter.ActualName]).Value;
+        } else {
+          return DistanceMatrixParameter.ActualValue;
+        }
+      }
+    }
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected LimitedDistanceTransportTargetCreator(bool isDeserializing) : base(isDeserializing) { }
+
+    protected LimitedDistanceTransportTargetCreator(LimitedDistanceTransportTargetCreator orig, Cloner cloner) : base(orig, cloner) {}
+
+    public LimitedDistanceTransportTargetCreator() {
+      Parameters.Add(new ValueLookupParameter<IntMatrix>("Bounds", "The list of limits for each dimension (wrapped around if too short)"));
+      Parameters.Add(new ValueLookupParameter<IntValue>("Length", "The length of the integer vector to be created"));
+      Parameters.Add(new LookupParameter<IntegerVector>("IntegerVector", "The newly created integer vector"));
+      Parameters.Add(new ValueLookupParameter<IRandom>("Random", "The random number generator to use."));
+      Parameters.Add(new ValueLookupParameter<IntValue>("TournamentSize", "The tournament size as a fraction of the length. (higher values yield closer targets, 0 is random)", new IntValue(5)));
+      Parameters.Add(new LookupParameter<DistanceMatrix>("DistanceMatrix", "The distance matrix to use", "StreetDistanceMatrix")); // TODO: check this
+      Parameters.Add(new ValueParameter<BoolValue>("DistanceMatrixInProblemData", "Whether to look for the distance matrix in problem data or in scope.", new BoolValue(true)));
+      DistanceMatrixParameter.Hidden = false;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) { return new LimitedDistanceTransportTargetCreator(this, cloner); }
+    #endregion
+
+    public override IOperation Apply() {
+      var random = RandomParameter.ActualValue;
+      var length = LengthParameter.ActualValue.Value;
+      var v = new IntegerVector(length);
+      var tournamentSize = Math.Min(length, Math.Max(1, TournamentSizeParameter.ActualValue.Value));
+      var bounds = BoundsParameter.ActualValue;
+      for (int i = 0; i < length; i++) {
+        var min = bounds[i%bounds.Rows, 0];
+        var max = bounds[i%bounds.Rows, 1];
+        var range = max - min;
+        var sample = tournamentSize > length/3
+          ? Enumerable.Range(min, range).SampleRandom(random, tournamentSize).ToList()
+          : Enumerable.Range(0, tournamentSize).Select(j => random.Next(range) + min).ToList();
+        v[i] = sample
+          .Select(j => new {j, dist = DistanceMatrix[i, j]})
+          .OrderBy(x => x.dist)
+          .First().j;
+      }
+      IntegerVectorParameter.ActualValue = v;
+      return base.Apply();
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Moves/MoveEvaluatorAdapter.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Moves/MoveEvaluatorAdapter.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Moves/MoveEvaluatorAdapter.cs	(revision 15711)
@@ -0,0 +1,76 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Linq;
+using HeuristicLab.BioBoost.Evaluators;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.BioBoost.Operators.Moves {
+
+  [StorableClass]
+  public class MoveEvaluatorAdapter : SingleSuccessorOperator, ISingleObjectiveMoveEvaluator {
+
+    public IConstrainedValueParameter<ISingleObjectiveEvaluator> EvaluatorParameter {
+      get { return (IConstrainedValueParameter<ISingleObjectiveEvaluator>) Parameters["Evaluator"]; }
+    }
+
+    public ISingleObjectiveEvaluator Evaluator { get { return EvaluatorParameter.Value; } }
+
+    #region construction & cloning
+
+    [StorableConstructor]
+    public MoveEvaluatorAdapter(bool isDeserializing) : base(isDeserializing) {}
+
+    public MoveEvaluatorAdapter(MoveEvaluatorAdapter orig, Cloner cloner) : base(orig, cloner) { }
+
+    public MoveEvaluatorAdapter() {
+      Parameters.Add(new LookupParameter<DoubleValue>("MoveQuality", "the move quality"));
+      var evaluators = new ItemSet<ISingleObjectiveEvaluator>();
+      evaluators.Add(new AggregateEvaluator());
+      evaluators.Add(new MonolithicEvaluator());
+      Parameters.Add(new ConstrainedValueParameter<ISingleObjectiveEvaluator>("Evaluator", "The actual evaluator.", evaluators));
+      EvaluatorParameter.Value = EvaluatorParameter.ValidValues.FirstOrDefault(e => e.GetType() == typeof(MonolithicEvaluator));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) { return new MoveEvaluatorAdapter(this, cloner); }
+
+    #endregion
+
+    public ILookupParameter<DoubleValue> QualityParameter { get { return Evaluator.QualityParameter; } }
+
+    public ILookupParameter<DoubleValue> MoveQualityParameter { get { return (ILookupParameter<DoubleValue>) Parameters["MoveQuality"]; } }
+
+    public override IOperation Apply() {
+      var evaluator = (ISingleObjectiveEvaluator)Evaluator.Clone();
+      evaluator.QualityParameter.ActualName = MoveQualityParameter.ActualName;
+      return new OperationCollection {
+        ExecutionContext.CreateChildOperation(evaluator),
+        base.Apply(),
+      };
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Moves/MoveGeneratorAdapter.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Moves/MoveGeneratorAdapter.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Moves/MoveGeneratorAdapter.cs	(revision 15711)
@@ -0,0 +1,77 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Linq;
+using HeuristicLab.BioBoost.Operators.Mutation;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.BioBoost.Operators.Moves {
+
+  [StorableClass]
+  public class MoveGeneratorAdapter : SingleSuccessorOperator, IMoveGenerator {
+
+    public IConstrainedValueParameter<IManipulator> ManipulatorParameter { get { return (IConstrainedValueParameter<IManipulator>) Parameters["Manipulator"]; } }
+    public IManipulator Manipulator { get { return ManipulatorParameter.Value; } }
+
+    public IValueLookupParameter<IntValue> SampleSizeParameter { get { return (IValueLookupParameter<IntValue>) Parameters["SampleSize"]; } }
+    public int SampleSize { get { return SampleSizeParameter.ActualValue.Value; } }
+
+    #region construction & cloning
+    [StorableConstructor]
+    public MoveGeneratorAdapter(bool isDeserializing) : base(isDeserializing) { }
+
+    public MoveGeneratorAdapter(MoveGeneratorAdapter orig, Cloner cloner) : base(orig, cloner) { }
+
+    public MoveGeneratorAdapter() {
+      Parameters.Add(new ValueLookupParameter<IntValue>("SampleSize", "The number of moves to generate."));
+      Parameters.Add(new LookupParameter<IntValue>("Generations", "rename value to iterations", "Iterations"));
+      Parameters.Add(new LookupParameter<IntValue>("MaximumGenerations", "rename value to maximum iterations", "MaximumIterations"));
+      Parameters.Add(new ConstrainedValueParameter<IManipulator>("Manipulator", "The actual maniuplator that should be wrapped.",
+        new ItemSet<IManipulator>(ApplicationManager.Manager.GetInstances<IManipulator>())));
+      ManipulatorParameter.Value =
+        ManipulatorParameter.ValidValues.FirstOrDefault(m => m.GetType() == typeof (MultiMutator));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) { return new MoveGeneratorAdapter(this, cloner); }
+    #endregion
+
+    public override IOperation Apply() {
+      var successors = new OperationCollection();
+      for (int i = 0; i < SampleSize; i++) {
+        var subscope = new Scope(i.ToString());
+        foreach (var variable in ExecutionContext.Scope.Variables) {
+          subscope.Variables.Add(new Variable(variable.Name, (IItem) variable.Value.Clone()));
+        }
+        ExecutionContext.Scope.SubScopes.Add(subscope);
+        successors.Add(ExecutionContext.CreateChildOperation((IOperator) Manipulator.Clone(), subscope));
+      }
+      successors.Add(base.Apply());
+      return successors;
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Moves/MoveMakerAdapter.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Moves/MoveMakerAdapter.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Moves/MoveMakerAdapter.cs	(revision 15711)
@@ -0,0 +1,71 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Linq;
+using HeuristicLab.BioBoost.Evaluators;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.BioBoost.Operators.Moves {
+
+  [StorableClass]
+  public class MoveMakerAdapter : SingleSuccessorOperator, IMoveMaker {
+
+    public IConstrainedValueParameter<ISingleObjectiveEvaluator> EvaluatorParameter { get { return (IConstrainedValueParameter<ISingleObjectiveEvaluator>) Parameters["Evaluator"]; } }
+    public ISingleObjectiveEvaluator Evaluator { get { return EvaluatorParameter.Value; } }
+
+    #region construction & cloning
+    [StorableConstructor]
+    public MoveMakerAdapter(bool isDeserializing) : base(isDeserializing) { }
+
+    public MoveMakerAdapter(MoveMakerAdapter orig, Cloner cloner) : base(orig, cloner) { }
+
+    public MoveMakerAdapter() {
+      Parameters.Add(new LookupParameter<DoubleValue>("MoveQuality", "the move quality"));
+      Parameters.Add(new ConstrainedValueParameter<ISingleObjectiveEvaluator>("Evaluator", "The actual evaluator.",
+        new ItemSet<ISingleObjectiveEvaluator>(ApplicationManager.Manager.GetInstances<ISingleObjectiveEvaluator>())));
+      EvaluatorParameter.Value =
+        EvaluatorParameter.ValidValues.FirstOrDefault(e => e.GetType() == typeof (MonolithicEvaluator));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) { return new MoveMakerAdapter(this, cloner); }
+    #endregion
+
+    public ILookupParameter<DoubleValue> QualityParameter { get { return Evaluator.QualityParameter; } }
+
+    public ILookupParameter<DoubleValue> MoveQualityParameter { get { return (ILookupParameter<DoubleValue>) Parameters["MoveQuality"]; } }
+
+    public override IOperation Apply() {
+      var parentScope = ExecutionContext.Scope.Parent;
+      foreach (var variable in ExecutionContext.Scope.Variables) {
+        parentScope.Variables.Remove(variable.Name);
+        parentScope.Variables.Add(new Variable(variable.Name, variable.Value));
+      }
+      return base.Apply();
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/BoundaryToggleRealVectorMutator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/BoundaryToggleRealVectorMutator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/BoundaryToggleRealVectorMutator.cs	(revision 15711)
@@ -0,0 +1,56 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System;
+
+namespace HeuristicLab.BioBoost.Operators.Mutation {
+  [StorableClass]
+  public class BoundaryToggleRealVectorMutator : RealVectorManipulator {
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected BoundaryToggleRealVectorMutator(bool isDeserializing) : base(isDeserializing) { }
+    protected BoundaryToggleRealVectorMutator(BoundaryToggleRealVectorMutator orig, Cloner cloner) : base(orig, cloner) { }
+    public BoundaryToggleRealVectorMutator() { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new BoundaryToggleRealVectorMutator(this, cloner);
+    }
+    #endregion
+
+    protected override void Manipulate(IRandom random, RealVector realVector) {
+      var bounds = BoundsParameter.ActualValue;
+      var idx = random.Next(realVector.Length);
+      var value = realVector[idx];
+      var lowerBound = bounds[idx % bounds.Rows, 0];
+      var upperBound = bounds[idx % bounds.Rows, 1];
+      if (value <= lowerBound || value >= upperBound) {
+        value = random.Next()*Math.Abs(upperBound - lowerBound) + Math.Min(lowerBound, upperBound);
+      } else {
+        value = random.NextDouble() <= 0.5 ? lowerBound : upperBound;
+      }
+      realVector[idx] = value;
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/CommonTargetIntegerVectorMutator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/CommonTargetIntegerVectorMutator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/CommonTargetIntegerVectorMutator.cs	(revision 15711)
@@ -0,0 +1,78 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Random;
+using System;
+using System.Linq;
+
+namespace HeuristicLab.BioBoost.Operators.Mutation {
+  [StorableClass]
+  public class CommonTargetIntegerVectorMutator : BoundedIntegerVectorManipulator {
+
+    public LookupParameter<BioBoostProblemData> ProblemDataParameter {
+      get { return (LookupParameter<BioBoostProblemData>) Parameters["ProblemData"]; }
+    }
+
+    public ValueLookupParameter<DoubleValue> AvgBundleMutationRatioParameter {
+      get { return (ValueLookupParameter<DoubleValue>) Parameters["AvgBundleMutationRatio"]; }
+    }
+
+    public double AvgBundleMutationRatio {
+      get { return AvgBundleMutationRatioParameter.ActualValue.Value; }
+    }
+
+
+    public BioBoostProblemData ProblemData {
+      get { return ProblemDataParameter.ActualValue; }
+    }
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected CommonTargetIntegerVectorMutator(bool isDeserializing) : base(isDeserializing) {}
+    protected CommonTargetIntegerVectorMutator(CommonTargetIntegerVectorMutator orig, Cloner cloner) : base(orig, cloner) {}
+    public CommonTargetIntegerVectorMutator() {
+      Parameters.Add(new LookupParameter<BioBoostProblemData>("ProblemData", "The problem instance description container."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("AvgBundleMutationRatio", "The average ratio of modified targets in a bundle.", new PercentValue(1)));
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CommonTargetIntegerVectorMutator(this, cloner);
+    }
+    #endregion
+
+    protected override void ManipulateBounded(IRandom random, IntegerVector integerVector, IntMatrix bounds) {
+      var ratio = new NormalDistributedRandom(random, Math.Min(1, Math.Max(0, AvgBundleMutationRatio)), 0.1).NextDouble();
+      var targetGroups = integerVector.Select((t, i) => new {t, i}).GroupBy(x => x.t, x => x.i).ToList();
+      var targetGroup = targetGroups[random.Next(targetGroups.Count)];
+      var targets = targetGroup.Shuffle(random).ToList();
+      var newTarget = ProblemData.Neighbors.GetRandomNeighbor(targetGroup.Key, random, bounds[0, 1]);
+      foreach (var i in targets.Take(Math.Max(1, (int)Math.Round(ratio*(targets.Count-1))))) {
+        integerVector[i] = newTarget;
+      }
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/CommonTargetSwappingIntegerVectorMutator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/CommonTargetSwappingIntegerVectorMutator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/CommonTargetSwappingIntegerVectorMutator.cs	(revision 15711)
@@ -0,0 +1,90 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Random;
+using System;
+using System.Linq;
+
+namespace HeuristicLab.BioBoost.Operators.Mutation {
+  [StorableClass]
+  public class CommonTargetSwappingIntegerVectorMutator : BoundedIntegerVectorManipulator {
+
+    public LookupParameter<BioBoostProblemData> ProblemDataParameter {
+      get { return (LookupParameter<BioBoostProblemData>) Parameters["ProblemData"]; }
+    }
+
+    public ValueLookupParameter<DoubleValue> AvgBundleMutationRatioParameter {
+      get { return (ValueLookupParameter<DoubleValue>) Parameters["AvgBundleMutationRatio"]; }
+    }
+
+    public double AvgBundleMutationRatio {
+      get { return AvgBundleMutationRatioParameter.ActualValue.Value; }
+    }
+
+
+    public BioBoostProblemData ProblemData {
+      get { return ProblemDataParameter.ActualValue; }
+    }
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected CommonTargetSwappingIntegerVectorMutator(bool isDeserializing) : base(isDeserializing) {}
+    protected CommonTargetSwappingIntegerVectorMutator(CommonTargetSwappingIntegerVectorMutator orig, Cloner cloner) : base(orig, cloner) {}
+    public CommonTargetSwappingIntegerVectorMutator() {
+      Parameters.Add(new LookupParameter<BioBoostProblemData>("ProblemData", "The problem instance description container."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("AvgBundleMutationRatio", "The average ratio of modified targets in a bundle.", new PercentValue(0.25)));
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CommonTargetSwappingIntegerVectorMutator(this, cloner);
+    }
+    #endregion
+
+    protected override void ManipulateBounded(IRandom random, IntegerVector integerVector, IntMatrix bounds) {
+      var ratio =
+        new NormalDistributedRandom(random, Math.Min(1, Math.Max(0, AvgBundleMutationRatio)), 0.25).NextDouble();
+      var targetGroups = integerVector
+        .Select((t, i) => new {t, i})
+        .GroupBy(x => x.t, x => x.i)
+        .Shuffle(random)
+        .Take(2)
+        .ToList();
+      if (targetGroups.Count == 2) {
+        var targetList1 = targetGroups[0].Shuffle(random).ToList();
+        var targetList2 = targetGroups[1].Shuffle(random).ToList();
+        foreach (var i in targetList1.Take(Math.Max(1, (int)Math.Round(ratio*targetList1.Count)))) {
+          integerVector[i] = targetGroups[1].Key;
+        }
+        foreach (var i in targetList2.Take(Math.Max(1, (int)Math.Round(ratio*targetList2.Count)))) {
+          integerVector[i] = targetGroups[0].Key;
+        }
+      } else if (targetGroups.Count == 1) {
+        integerVector[random.Next(integerVector.Length)] = random.Next(integerVector.Length);
+      }
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/CompoundMutator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/CompoundMutator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/CompoundMutator.cs	(revision 15711)
@@ -0,0 +1,195 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.BioBoost.Operators.Transformation;
+using HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.BioBoost.Utils;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.PluginInfrastructure;
+using System.Linq;
+using HeuristicLab.BioBoost.Representation;
+using UniformOnePositionManipulator = HeuristicLab.Encodings.IntegerVectorEncoding.UniformOnePositionManipulator;
+using UniformOnePositionRealVectorManipulator = HeuristicLab.Encodings.RealVectorEncoding.UniformOnePositionManipulator;
+
+namespace HeuristicLab.BioBoost.Operators.Mutation {
+  [StorableClass]
+  public class CompoundMutator : SingleSuccessorOperator, IManipulator, IStochasticOperator {
+
+
+    #region Parameters
+    public ValueLookupParameter<IntMatrix> RegionBoundsParameter { get { return (ValueLookupParameter<IntMatrix>) Parameters["RegionBounds"]; } } 
+    public LookupParameter<BioBoostProblemData> ProblemDataParameter { get { return (LookupParameter<BioBoostProblemData>) Parameters["ProblemData"]; } }
+    public OptionalConstrainedValueParameter<IIntegerVectorManipulator> TransportTargetManipulatorParameter { get { return (OptionalConstrainedValueParameter<IIntegerVectorManipulator>) Parameters["TransportTargetManipulator"]; } }
+    public OptionalConstrainedValueParameter<IRealVectorManipulator> FeedstockUtilizationManipulatorParameter { get { return (OptionalConstrainedValueParameter<IRealVectorManipulator>) Parameters["FeedstockUtilizationManipulator"]; } }
+    public ILookupParameter<IRandom> RandomParameter { get { return (ILookupParameter<IRandom>) Parameters["Random"]; } }
+    public ILookupParameter<IntValue> MaximumGenerationsParameter { get { return (ILookupParameter<IntValue>) Parameters["MaximumGenerations"]; } }
+    public ILookupParameter<IntValue> GenerationsParameter { get { return (ILookupParameter<IntValue>) Parameters["Generations"]; } }
+    public ILookupParameter<PercentValue> MinGenerationPercentageForUtilzationMutationParameter { get { return (ILookupParameter<PercentValue>) Parameters["MinGenerationPercentageForUtilzationMutation"]; } }
+    public ILookupParameter<PercentValue> ProbabilityOfCombinedMutationParameter { get { return (ILookupParameter<PercentValue>) Parameters["ProbabilityOfCombinedMutation"]; } }
+    #endregion
+
+    #region Parameter Values
+    public IIntegerVectorManipulator TransportTargetManipulator { get { return (IIntegerVectorManipulator) TransportTargetManipulatorParameter.ActualValue; } }
+    public IRealVectorManipulator FeedstockUtilizationManipulator { get { return (IRealVectorManipulator) FeedstockUtilizationManipulatorParameter.ActualValue; } }
+    public BioBoostProblemData ProblemData { get { return ProblemDataParameter.ActualValue; } }
+    public IRandom Random { get { return RandomParameter.ActualValue; } }
+    public int MaximumGenerations { get { return MaximumGenerationsParameter.ActualValue.Value; } }
+    public int Generations { get { return GenerationsParameter.ActualValue.Value; } }
+    public double MinGenerationPercentageForUtilzationMutation { get { return MinGenerationPercentageForUtilzationMutationParameter.ActualValue.Value; } }
+    public double ProbabilityOfCombinedMutation { get { return ProbabilityOfCombinedMutationParameter.ActualValue.Value; } }
+    #endregion
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected CompoundMutator(bool isDeserializing) : base(isDeserializing) {}
+    protected CompoundMutator(CompoundMutator orig, Cloner cloner) : base(orig, cloner) { }
+    public CompoundMutator() {
+      Parameters.Add(new LookupParameter<BioBoostProblemData>("ProblemData", "The data store of the detailed problem description."));
+      Parameters.Add(new ValueLookupParameter<IntMatrix>("RegionBounds", "The limits of valid region ids."));
+      Parameters.Add(new OptionalConstrainedValueParameter<IIntegerVectorManipulator>("TransportTargetManipulator", "The manipulator to apply to the transport target vectors."));
+      Parameters.Add(new OptionalConstrainedValueParameter<IRealVectorManipulator>("FeedstockUtilizationManipulator", "The manipulator for the feedstock utilization vectors."));
+      Parameters.Add(new ValueLookupParameter<IRandom>("Random", "The random number generator used."));
+      Parameters.Add(new LookupParameter<IntValue>("MaximumGenerations", "The maximum number of generations."));
+      Parameters.Add(new LookupParameter<IntValue>("Generations", "The current number of generations."));
+      Parameters.Add(new ValueLookupParameter<PercentValue>("MinGenerationPercentageForUtilzationMutation", "The minimum percentage of generations (Generations/MaxGenerations) until mutation of utilizations become enabled.", new PercentValue(0.5)));
+      Parameters.Add(new ValueLookupParameter<PercentValue>("ProbabilityOfCombinedMutation", "Probability of mutating both utilization and transport. Don't set to 100% otherwise intermediates are not touched anymore.", new PercentValue(0.3)));
+      foreach (var op in ApplicationManager.Manager.GetInstances<IRealVectorManipulator>()) {
+        op.BoundsParameter.Value = new DoubleMatrix(new double[,] {{0, 1}});
+        FeedstockUtilizationManipulatorParameter.ValidValues.Add(op);
+      }
+      foreach (var op in ApplicationManager.Manager.GetInstances<IIntegerVectorManipulator>()) {
+        var bop = op as BoundedIntegerVectorManipulator;
+        if (bop != null)
+          bop.BoundsParameter.ActualName = RegionBoundsParameter.ActualName;
+        if (op.Parameters.ContainsKey("Bounds") && op.Parameters["Bounds"] is ILookupParameter<IntMatrix>) {
+          ((ILookupParameter<IntMatrix>) op.Parameters["Bounds"]).ActualName = RegionBoundsParameter.ActualName;
+        }
+        TransportTargetManipulatorParameter.ValidValues.Add(op);
+      }
+      FeedstockUtilizationManipulatorParameter.Value =
+        FeedstockUtilizationManipulatorParameter.ValidValues.FirstOrDefault(
+          c => c.GetType() == typeof (MultiRealVectorManipulator));
+      TransportTargetManipulatorParameter.Value =
+        TransportTargetManipulatorParameter.ValidValues.FirstOrDefault(
+          c => c.GetType() == typeof (MultiIntegerVectorManipulator));
+      var um = (MultiRealVectorManipulator) FeedstockUtilizationManipulator;
+      foreach (var op in um.Operators) {
+        if (op is PolynomialAllPositionManipulator) {
+          ((PolynomialAllPositionManipulator) op).ContiguityParameter.Value = new DoubleValue(20);
+        } else if (op is PolynomialOnePositionManipulator) {
+          ((PolynomialOnePositionManipulator) op).ContiguityParameter.Value = new DoubleValue(8);
+        } else if (op is UniformOnePositionRealVectorManipulator) {
+          // nothing to do
+        } else {
+          um.Operators.SetItemCheckedState(op, false);
+        }
+      }
+      var tm = (MultiIntegerVectorManipulator) TransportTargetManipulator;
+      foreach (var op in tm.Operators) {
+        if (op is UniformSomePositionsManipulator ||
+            op is UniformOnePositionManipulator ||
+            op is CommonTargetIntegerVectorMutator ||
+            op is CommonTargetSwappingIntegerVectorMutator ||
+            op is TargetMergingIntegerVectorManipulator ||
+            op is DistanceBasedIntegerVectorMutator) {
+          // accept
+        } else {
+          tm.Operators.SetItemCheckedState(op, false);
+        }
+      }
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CompoundMutator(this, cloner);
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (!Parameters.ContainsKey("MaximumGenerations"))
+        Parameters.Add(new LookupParameter<IntValue>("MaximumGenerations", "The maximum number of generations."));
+      if (!Parameters.ContainsKey("Generations"))
+        Parameters.Add(new LookupParameter<IntValue>("Generations", "The current number of generations."));
+      if (!Parameters.ContainsKey("MinGenerationPercentageForUtilzationMutation"))
+        Parameters.Add(new ValueLookupParameter<PercentValue>("MinGenerationPercentageForUtilzationMutation", "The minimum percentage of generations (Generations/MaxGenerations) until mutation of utilizations become enabled.", new PercentValue(0.5)));
+      if (!Parameters.ContainsKey("ProbabilityOfCombinedMutation"))
+        Parameters.Add(new ValueLookupParameter<PercentValue>("ProbabilityOfCombinedMutation", "Probability of mutating both utilization and transport. Don't set to 100% otherwise intermediates are not touched anymore.", new PercentValue(0.3)));
+    }
+    #endregion
+
+    public override IOperation Apply() {
+      var ops = new OperationCollection(base.Apply());
+      var targets = ProblemData.TransportTargets.CheckedItems.Select(t => t.Value.Value).ToArray();
+      var utilizations = ProblemData.Utilizations.CheckedItems.Select(t => t.Value.Value).ToArray();
+      var feedstockUtilizationManipulator = FeedstockUtilizationManipulator;
+      if (1.0*Generations/MaximumGenerations < MinGenerationPercentageForUtilzationMutation && TransportTargetManipulator != null) {
+        feedstockUtilizationManipulator = null;
+      }
+      if (feedstockUtilizationManipulator == null && TransportTargetManipulator == null) {
+        // do nothing
+      } else if (feedstockUtilizationManipulator == null) {
+        ops.AddRange(CreateTransportMutation(targets[Random.Next(targets.Length)]));
+      } else if (TransportTargetManipulator == null) {
+        ops.AddRange(CreateUtilizationMutation(utilizations[Random.Next(utilizations.Length)]));
+      } else {
+        if (Random.Next() > ProbabilityOfCombinedMutation) {
+          int n = utilizations.Length;
+          int r = Random.Next(n + targets.Length);
+          ops.AddRange(
+            r < n
+              ? CreateUtilizationMutation(utilizations[r])
+              : CreateTransportMutation(targets[r - n]));
+        } else {
+          var feedstocks = new HashSet<string>(utilizations.Concat(targets)).ToArray();
+          var feedstock = feedstocks[Random.Next(feedstocks.Length)];
+          ops.AddRange(CreateUtilizationMutation(feedstock));
+          ops.AddRange(CreateTransportMutation(feedstock));
+        }
+      }
+      return ops;
+    }
+
+    private IEnumerable<IOperation> CreateUtilizationMutation(string name) {
+      yield return ExecutionContext.CreateChildOperation(new FeedstockDeflater {ProductName = name});
+      var u = (IRealVectorManipulator) FeedstockUtilizationManipulatorParameter.ActualValue.Clone();
+      u.RealVectorParameter.ActualName = LayerDescriptor.Utilizations.NameWithPrefix(name);
+      yield return ExecutionContext.CreateChildOperation(u);
+      yield return ExecutionContext.CreateChildOperation(new FeedstockInflater {ProductName = name});
+    }
+
+    private IEnumerable<IOperation> CreateTransportMutation(string name) {
+      yield return ExecutionContext.CreateChildOperation(new FeedstockDeflater {ProductName = name});
+      var t = (IIntegerVectorManipulator)TransportTargetManipulator.Clone();
+      t.IntegerVectorParameter.ActualName = LayerDescriptor.TransportTargets.NameWithPrefix(name);
+      yield return ExecutionContext.CreateChildOperation(t);
+      yield return ExecutionContext.CreateChildOperation(new FeedstockInflater {ProductName = name});
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/DistanceBasedIntegerVectorMutator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/DistanceBasedIntegerVectorMutator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/DistanceBasedIntegerVectorMutator.cs	(revision 15711)
@@ -0,0 +1,123 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System;
+using System.Linq;
+
+namespace HeuristicLab.BioBoost.Operators.Mutation {
+  [StorableClass]
+  public class DistanceBasedIntegerVectorMutator : IntegerVectorManipulator {
+
+
+    #region Parameters
+    public LookupParameter<DistanceMatrix> DistanceMatrixParameter { get { return (LookupParameter<DistanceMatrix>) Parameters["DistanceMatrix"]; } }
+    public ValueParameter<BoolValue> DistanceMatrixInProblemDataParameter { get { return (ValueParameter<BoolValue>) Parameters["DistanceMatrixInProblemData"]; } }
+    public ILookupParameter<BioBoostProblemData> ProblemDataParameter { get { return (ILookupParameter<BioBoostProblemData>) Parameters["ProblemData"]; } }
+    public ILookupParameter<IntArray> ViableSourcesParameter { get { return (ILookupParameter<IntArray>) Parameters["ViableSources"]; } }
+    public ILookupParameter<IntArray> ViableTargetsParameter { get { return (ILookupParameter<IntArray>) Parameters["ViableTargets"]; } }
+    public IValueLookupParameter<DoubleValue> MaximumDistanceParameter { get { return (IValueLookupParameter<DoubleValue>) Parameters["MaximumDistance"]; } }
+
+    #endregion
+
+    #region Parameter Values
+    public DistanceMatrix DistanceMatrix {
+      get {
+        if (DistanceMatrixInProblemData) {
+          return ((IValueParameter<DistanceMatrix>) ProblemData.Parameters[DistanceMatrixParameter.ActualName]).Value;
+        } else {
+          return DistanceMatrixParameter.ActualValue;
+        }
+      }
+    }
+    public bool DistanceMatrixInProblemData { get { return DistanceMatrixInProblemDataParameter.Value.Value; } }
+    public BioBoostProblemData ProblemData { get { return ProblemDataParameter.ActualValue; } }
+    public IntArray ViableSources { get { return ViableSourcesParameter.ActualValue; } }
+    public IntArray ViableTargets { get { return ViableTargetsParameter.ActualValue; } }
+    public double MaximumDistance { get { return MaximumDistanceParameter.ActualValue.Value;  } }
+    #endregion
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected DistanceBasedIntegerVectorMutator(bool isDeserializing) : base(isDeserializing) {}
+    protected DistanceBasedIntegerVectorMutator(DistanceBasedIntegerVectorMutator orig, Cloner cloner) : base(orig, cloner) {}
+    public DistanceBasedIntegerVectorMutator() {
+      Parameters.Add(new LookupParameter<DistanceMatrix>("DistanceMatrix", "The distance matrix to use", "StreetDistanceMatrix")); // TODO: check this
+      Parameters.Add(new ValueParameter<BoolValue>("DistanceMatrixInProblemData", "Whether to look for the distance matrix in problem data or in scope.", new BoolValue(true)));
+      Parameters.Add(new LookupParameter<BioBoostProblemData>("ProblemData", "Contains fixed values describing the problem."));
+      Parameters.Add(new LookupParameter<IntArray>("ViableSources", "A list with all indices of viable source regions."));
+      Parameters.Add(new LookupParameter<IntArray>("ViableTargets", "A list with all indices of viable target regions."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("MaximumDistance", "the maximum distance from source to target allowed for mutation", new DoubleValue(Double.MaxValue)));
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new DistanceBasedIntegerVectorMutator(this, cloner);
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (!Parameters.ContainsKey("ViableSources"))
+        Parameters.Add(new LookupParameter<IntArray>("ViableSources", "A list with all indices of viable source regions."));
+      if (!Parameters.ContainsKey("ViableTargets"))
+        Parameters.Add(new LookupParameter<IntArray>("ViableTargets", "A list with all indices of viable target regions."));
+      if (!Parameters.ContainsKey("MaximumDistance"))
+        Parameters.Add(new ValueLookupParameter<DoubleValue>("MaximumDistance", "the maximum distance from source to target allowed for mutation", new DoubleValue(Double.MaxValue)));
+    }
+    #endregion
+
+    protected override void Manipulate(IRandom random, IntegerVector integerVector) {
+      var sources = ViableSources ?? new IntArray(Enumerable.Range(0, integerVector.Length).ToArray());
+      var targets = ViableTargets ?? new IntArray(Enumerable.Range(0, integerVector.Length).ToArray());
+      var source = random.Next(sources.Length);
+      var target = integerVector[sources[source]];
+      var neighborDistances = new double[0].Select((d, idx) => new {index = idx, distance = d}).ToList();
+      var distances = DistanceMatrix;
+      var maxDistance = 0d;
+      for (int j = 0; j < targets.Length; j++) {
+        if (distances[source, targets[j]] > MaximumDistance) continue;
+        var dist = distances[target, targets[j]];
+        neighborDistances.Add(new {index = targets[j], distance = dist});
+        maxDistance = Math.Max(dist, maxDistance);
+      }
+      neighborDistances = neighborDistances.Select(p => new {p.index, distance = maxDistance - p.distance}).ToList();
+      neighborDistances.Sort((a, b) => b.distance.CompareTo(a.distance));
+      var totalDistance = neighborDistances.Sum(p => p.distance);
+      var threshold = random.NextDouble()*totalDistance;
+      var sum = 0d;
+      var index = 0;
+      while (index < neighborDistances.Count && sum < threshold) {
+        sum += neighborDistances[index].distance;
+        index++;
+      }
+      if (index < 0 || index >= neighborDistances.Count) {
+        integerVector[sources[source]] = sources[source];  // reset to local transport if no choices exist
+      } else {
+        integerVector[sources[source]] = neighborDistances[index].index;
+      }
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/EmptyMutator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/EmptyMutator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/EmptyMutator.cs	(revision 15711)
@@ -0,0 +1,43 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.BioBoost.Operators.Mutation {
+
+  [StorableClass]
+  public class EmptyMutator : SingleSuccessorOperator, IManipulator {
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected EmptyMutator(bool isDeserializing) : base(isDeserializing) {}
+    protected EmptyMutator(EmptyMutator orig, Cloner cloner) : base(orig, cloner) {}
+    public EmptyMutator() {}
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new EmptyMutator(this, cloner);
+    }
+    #endregion
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/MultiIntegerVectorMutator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/MultiIntegerVectorMutator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/MultiIntegerVectorMutator.cs	(revision 15711)
@@ -0,0 +1,104 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Collections;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.PluginInfrastructure;
+using System;
+using System.Linq;
+
+namespace HeuristicLab.BioBoost.Operators.Mutation {
+  [StorableClass]
+  public class MultiIntegerVectorManipulator : StochasticMultiBranch<IIntegerVectorManipulator>, IIntegerVectorManipulator, IStochasticOperator {
+
+    public override bool CanChangeName {
+      get { return false; }
+    }
+
+    protected override bool CreateChildOperation {
+      get { return true; }
+    }
+
+    public ILookupParameter<IntegerVector> IntegerVectorParameter {
+      get { return (ILookupParameter<IntegerVector>)Parameters["IntegerVector"]; }
+    }
+    public IValueLookupParameter<IntMatrix> BoundsParameter {
+      get { return (IValueLookupParameter<IntMatrix>)Parameters["Bounds"]; }
+    }
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected MultiIntegerVectorManipulator(bool isDeserializing) : base(isDeserializing) {}
+    protected MultiIntegerVectorManipulator(MultiIntegerVectorManipulator orig, Cloner cloner) : base(orig, cloner) {}
+    public MultiIntegerVectorManipulator() {
+      Parameters.Add(new LookupParameter<IntegerVector>("IntegerVector", "The integer vector that is being manipulating."));
+      Parameters.Add(new ValueLookupParameter<IntMatrix>("Bounds", "The lower and upper bounds for each dimension of the vector."));
+
+      foreach (var t in ApplicationManager.Manager.GetTypes(typeof(IIntegerVectorManipulator))) {
+        if (t == this.GetType()) continue; // avoid infinite recursion
+        IIntegerVectorManipulator instance = null;
+        try {
+          instance = Activator.CreateInstance(t) as IIntegerVectorManipulator;
+        } catch {}
+        if (instance != null) Operators.Add(instance);
+      }
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MultiIntegerVectorManipulator(this, cloner);
+    }
+    #endregion
+
+    protected override void Operators_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<IIntegerVectorManipulator>> e) {
+      base.Operators_ItemsReplaced(sender, e);
+      ParameterizeManipulators();
+    }
+
+    protected override void Operators_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<IIntegerVectorManipulator>> e) {
+      base.Operators_ItemsAdded(sender, e);
+      ParameterizeManipulators();
+    }
+
+    private void ParameterizeManipulators() {
+      foreach (var op in Operators.OfType<IIntegerVectorManipulator>()) {
+        op.IntegerVectorParameter.ActualName = IntegerVectorParameter.Name;
+      }
+      foreach (var op in Operators.OfType<IBoundedIntegerVectorOperator>()) {
+        op.BoundsParameter.ActualName = BoundsParameter.Name;
+      }
+      foreach (var op in Operators.OfType<IStochasticOperator>()) {
+        op.RandomParameter.ActualName = RandomParameter.Name;
+      }
+    }
+
+    public override IOperation InstrumentedApply()
+    {
+        if (Operators.Count == 0) throw new InvalidOperationException(Name + ": Please add at least one real vector manipulator to choose from.");
+        return base.InstrumentedApply();
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/MultiMutator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/MultiMutator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/MultiMutator.cs	(revision 15711)
@@ -0,0 +1,168 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Collections;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.PluginInfrastructure;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HeuristicLab.BioBoost.Operators.Mutation {
+  [StorableClass]
+  public class MultiMutator : StochasticMultiBranch<IManipulator>, IManipulator, IStochasticOperator {
+
+    public override bool CanChangeName { get { return false; } }
+
+    protected override bool CreateChildOperation { get { return true; } }
+
+    public IValueLookupParameter<IntValue> SeriesLengthParameter { get { return (IValueLookupParameter<IntValue>)Parameters["SeriesLength"]; } }
+    public ValueParameter<PercentArray> MinGenerationPercentagesParameter { get { return (ValueParameter<PercentArray>)Parameters["MinGenerationPercentages"]; } }
+    public ILookupParameter<IntValue> GenerationsParameter { get { return (ILookupParameter<IntValue>)Parameters["Generations"]; } }
+    public ILookupParameter<IntValue> MaxGenerationsParameter { get { return (ILookupParameter<IntValue>)Parameters["MaximumGenerations"]; } }
+    public PercentArray MinGenerationPercentages {
+      get { return MinGenerationPercentagesParameter.Value; }
+      set { MinGenerationPercentagesParameter.Value = value; }
+    }
+
+    public int SeriesLength { get { return SeriesLengthParameter.ActualValue.Value; } }
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected MultiMutator(bool isDeserializing) : base(isDeserializing) { }
+    protected MultiMutator(MultiMutator orig, Cloner cloner) : base(orig, cloner) { }
+    public MultiMutator() {
+      Parameters.Add(new ValueLookupParameter<IntValue>("SeriesLength", "The number of manipulations to perform at once", new IntValue(1)));
+      Parameters.Add(new ValueParameter<PercentArray>("MinGenerationPercentages", "Relative number of generations before the respetive mutation becomes active.", new PercentArray(0)));
+      Parameters.Add(new LookupParameter<IntValue>("Generations", "Current number of generations/iterations."));
+      Parameters.Add(new LookupParameter<IntValue>("MaximumGenerations", "Maximum number of generations/iterations."));
+      foreach (var t in ApplicationManager.Manager.GetTypes(typeof(IManipulator), Assembly.GetExecutingAssembly())) {
+        if (t == this.GetType() || typeof(IIntegerVectorManipulator).IsAssignableFrom(t)) continue;
+        IManipulator instance = null;
+        try {
+          instance = Activator.CreateInstance(t) as IManipulator;
+        } catch { }
+        if (instance != null) Operators.Add(instance);
+      }
+      for (int i = 0; i < Operators.Count; i++) {
+        if (Operators[i] is CompoundMutator ||
+            Operators[i] is PlantMerger ||
+            Operators[i] is PlantSplitter ||
+            Operators[i] is PlantMover) {
+          // everything is fine
+        } else if (Operators[i] is PlantSupplierToggler ||
+                   Operators[i] is PlantSupplierUtilizationExchanger ||
+                   Operators[i] is PlantSupplierEqualizer ||
+                   Operators[i] is PlantSupplierRandomizer ||
+                   Operators[i] is PlantScalingMutator) {
+          MinGenerationPercentages[i] = 0.5;
+        } else if (Operators[i] is EmptyMutator) {
+          MinGenerationPercentages[i] = 0.8;
+        } else if (Operators[i] is PlantKiller) {
+          MinGenerationPercentages[i] = 0.9;
+        } else {
+          Operators.SetItemCheckedState(Operators[i], false);
+        }
+      }
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MultiMutator(this, cloner);
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (!Parameters.ContainsKey("MinGenerationPercentages")) {
+        Parameters.Add(new ValueParameter<PercentArray>("MinGenerationPercentages", "Relative number of generations before the respetive mutation becomes active.", new PercentArray(Operators.Count)));
+      }
+      if (!Parameters.ContainsKey("Generations"))
+        Parameters.Add(new LookupParameter<IntValue>("Generations", "Current number of generations/iterations."));
+      if (!Parameters.ContainsKey("MaximumGenerations"))
+        Parameters.Add(new LookupParameter<IntValue>("MaximumGenerations", "Maximum number of generations/iterations."));
+      if (!Parameters.ContainsKey("SeriesLength"))
+        Parameters.Add(new ValueLookupParameter<IntValue>("SeriesLength", "The number of manipulations to perform at once", new IntValue(1)));
+    }
+    #endregion
+
+    protected override void Operators_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<IManipulator>> e) {
+      base.Operators_ItemsAdded(sender, e);
+      if (MinGenerationPercentages.Length >= Operators.Count) return;
+      var added = e.Items.OrderBy(x => x.Index).ToList();
+      int insertCount = 0;
+      var percentages = new PercentArray(Operators.Count);
+      for (int i = 0; i < Operators.Count; i++) {
+        if (insertCount < added.Count && i == added[insertCount].Index) {
+          percentages[i] = 0;
+          insertCount++;
+        } else if (i - insertCount < MinGenerationPercentages.Length) {
+          percentages[i] = MinGenerationPercentages[i - insertCount];
+        } else percentages[i] = 0;
+      }
+      MinGenerationPercentages = percentages;
+    }
+
+    protected override void Operators_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<IManipulator>> e) {
+      base.Operators_ItemsRemoved(sender, e);
+      if (MinGenerationPercentages.Length <= Operators.Count) return;
+      var percentages = new List<double>(MinGenerationPercentages);
+      var sorted = e.Items.OrderByDescending(x => x.Index);
+      foreach (var item in sorted)
+        if (percentages.Count > item.Index) percentages.RemoveAt(item.Index);
+      MinGenerationPercentages = new PercentArray(percentages.ToArray());
+    }
+
+    public override IOperation InstrumentedApply() {
+      if (Operators.Count == 0) throw new InvalidOperationException(Name + ": Please add at least one manipulator to choose from.");
+      if (MaxGenerationsParameter.ActualValue == null || GenerationsParameter.ActualValue == null || MinGenerationPercentages.Max() == 0)
+        return base.InstrumentedApply();
+      DoubleArray probability = null;
+      try {
+        var generationPercentage = 1.0 * GenerationsParameter.ActualValue.Value / MaxGenerationsParameter.ActualValue.Value;
+        for (int i = 0; i < Probabilities.Length; i++) {
+          if (MinGenerationPercentages[i] > generationPercentage) {
+            if (probability == null) probability = (DoubleArray)Probabilities.Clone(); // backup old probabilities
+            Probabilities[i] = 0;
+          }
+        }
+        if (SeriesLength == 1) {
+          return base.InstrumentedApply();
+        } else {
+          var operations = new OperationCollection();
+          for (var i = 0; i < SeriesLength; i++) {
+            operations.Add(base.InstrumentedApply());
+          }
+          return operations;
+        }
+      } finally {
+        // restore old probabilities
+        if (probability != null)
+          Probabilities = probability;
+      }
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/NeighborBasedIntegerVectorMutator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/NeighborBasedIntegerVectorMutator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/NeighborBasedIntegerVectorMutator.cs	(revision 15711)
@@ -0,0 +1,60 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.BioBoost.Operators.Mutation {
+  [StorableClass]
+  public class NeighborBasedIntegerVectorMutator : BoundedIntegerVectorManipulator {
+
+    public LookupParameter<BioBoostProblemData> ProblemDataParameter {
+      get { return (LookupParameter<BioBoostProblemData>) Parameters["ProblemData"]; }
+    }
+
+    public BioBoostProblemData ProblemData {
+      get { return ProblemDataParameter.ActualValue; }
+    }
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected NeighborBasedIntegerVectorMutator(bool isDeserializing) : base(isDeserializing) {}
+    protected NeighborBasedIntegerVectorMutator(NeighborBasedIntegerVectorMutator orig, Cloner cloner) : base(orig, cloner) {}
+    public NeighborBasedIntegerVectorMutator() {
+      Parameters.Add(new LookupParameter<BioBoostProblemData>("ProblemData", "The problem instance description container."));
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NeighborBasedIntegerVectorMutator(this, cloner);
+    }
+    #endregion
+
+    protected override void ManipulateBounded(IRandom random, IntegerVector integerVector, IntMatrix bounds) {
+      var source = random.Next(integerVector.Length);
+      var target = integerVector[source];
+      integerVector[source] = ProblemData.Neighbors.GetRandomNeighbor(target, random, bounds[0, 1]);
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantBasedUtilizationModifier.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantBasedUtilizationModifier.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantBasedUtilizationModifier.cs	(revision 15711)
@@ -0,0 +1,147 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.BioBoost.Representation;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.BioBoost.Operators.Mutation {
+  [StorableClass]
+  public abstract class PlantBasedUtilizationModifier : SingleSuccessorOperator, IManipulator, IStochasticOperator {
+
+    #region Parameters
+    public LookupParameter<BioBoostProblemData> ProblemDataParameter { get { return (LookupParameter<BioBoostProblemData>) Parameters["ProblemData"]; } }
+    public LookupParameter<DistanceMatrix> DistanceMatrixParameter { get { return (LookupParameter<DistanceMatrix>) Parameters["DistanceMatrix"]; } }
+    public ValueParameter<BoolValue> DistanceMatrixInProblemDataParameter { get { return (ValueParameter<BoolValue>) Parameters["DistanceMatrixInProblemData"]; } }
+    public ValueLookupParameter<IntMatrix> RegionBoundsParameter { get { return (ValueLookupParameter<IntMatrix>) Parameters["RegionBounds"]; } }
+    public ILookupParameter<IRandom> RandomParameter { get { return (ILookupParameter<IRandom>) Parameters["Random"]; } }
+    public IValueLookupParameter<DoubleMatrix> BoundsParameter { get { return (IValueLookupParameter<DoubleMatrix>) Parameters["Bounds"]; } }
+    #endregion
+
+    #region Parameter Values
+    public BioBoostProblemData ProblemData { get { return ProblemDataParameter.ActualValue; } }
+    public IntMatrix RegionBounds { get { return RegionBoundsParameter.ActualValue; } }
+    public DoubleMatrix Bounds { get { return BoundsParameter.ActualValue; } }
+    public IRandom Random { get { return RandomParameter.ActualValue; } }
+    public bool DistanceMatrixInProblemData { get { return DistanceMatrixInProblemDataParameter.Value.Value; } }
+    public DistanceMatrix DistanceMatrix {
+      get {
+        if (DistanceMatrixInProblemData)
+          return ((IValueParameter<DistanceMatrix>) ProblemData.Parameters[DistanceMatrixParameter.ActualName]).Value;
+        else return DistanceMatrixParameter.ActualValue;
+      }
+    }
+    #endregion
+
+    #region Construction & Cloning
+
+    [StorableConstructor]
+    public PlantBasedUtilizationModifier(bool isDeserializing) {}
+    public PlantBasedUtilizationModifier(PlantBasedUtilizationModifier orig, Cloner cloner) : base(orig, cloner) {}
+    public PlantBasedUtilizationModifier() {
+      Parameters.Add(new LookupParameter<BioBoostProblemData>("ProblemData", "The data store of the detailed problem description."));
+      Parameters.Add(new LookupParameter<DistanceMatrix>("DistanceMatrix", "The distance matrix to use", "StreetDistanceMatrix")); // TODO: check this
+      Parameters.Add(new ValueParameter<BoolValue>("DistanceMatrixInProblemData", "Whether to look for the distance matrix in problem data or in scope.", new BoolValue(true)));
+      Parameters.Add(new ValueLookupParameter<IntMatrix>("RegionBounds", "The limits of valid region ids."));
+      Parameters.Add(new ValueLookupParameter<DoubleMatrix>("Bounds", "The limits for manipulating utilizations.", new DoubleMatrix(new [,]{{0d, 1d}})));
+      Parameters.Add(new LookupParameter<IRandom>("Random", "The random number generator."));
+    }
+
+    #endregion
+
+    public override IOperation Apply() {
+      var scope = ExecutionContext.Scope;
+      var productLinks = ProblemData.ProductLinks;
+      var feedstock =
+        ProblemData.TransportTargets.CheckedItems.ElementAt(
+          Random.Next(ProblemData.TransportTargets.CheckedItems.Count())).Value.Value;
+      var supplyTransports = scope.Variables[LayerDescriptor.TransportTargets.NameWithPrefix(feedstock)].Value as IntegerVector;
+      if (supplyTransports == null) return base.Apply();
+      var plants = supplyTransports.Select((target, source) => new {target, source}).GroupBy(p => p.target).ToList();
+      var plant = plants.ElementAt(Random.Next(plants.Count));
+      var suppliers = plant.Select(s => s.source).ToList();
+      var utilizations = GetUtilizations(scope, feedstock);
+      var preceedingFeedstock = GetPreceedingFeedstock(scope, feedstock, productLinks);
+      while (utilizations == null && preceedingFeedstock != null) {
+        var transportTargets = GetTransportTargets(scope, preceedingFeedstock);
+        if (transportTargets == null)
+          throw new InvalidOperationException("Error preceeding feedstock \"" + preceedingFeedstock + "\" of \"" + feedstock + "\" has no transport targets");
+        suppliers = // collect supplier's suppliers
+          suppliers.Select(s => transportTargets.Select((target, source) => new {source, target}).Where(p => p.target == s).Select(p => p.source))
+            .Aggregate((x, y) => x.Concat(y))
+            .ToList();
+        utilizations = GetUtilizations(scope, preceedingFeedstock);
+        preceedingFeedstock = GetPreceedingFeedstock(scope, preceedingFeedstock, productLinks);
+      }
+      if (utilizations == null) {
+        throw new InvalidOperationException("Error in supply chain: product " + feedstock +
+                                            " does not have an underlying feedstock");
+      }
+      if (suppliers.Count > 0)
+        Redistribute(utilizations, suppliers);
+      return base.Apply();
+    }
+
+    private string GetPreceedingFeedstock(IScope scope, string feedstock, StringMatrix productLinks) {
+      for (int i = 0; i < productLinks.Rows; i++) {
+        if (productLinks[i, 1] == feedstock)
+          return productLinks[i, 0];
+      }
+      return null;
+    }
+
+    private IntegerVector GetTransportTargets(IScope scope, string feedstock) {
+      IVariable v = null;
+      if (scope.Variables.TryGetValue(LayerDescriptor.TransportTargets.NameWithPrefix(feedstock), out v))
+        return v.Value as IntegerVector;
+      return null;
+    }
+
+
+    private RealVector GetUtilizations(IScope scope, string feedstock) {
+      IVariable v = null;
+      if (scope.Variables.TryGetValue(LayerDescriptor.Utilizations.NameWithPrefix(feedstock), out v))
+        return v.Value as RealVector;
+      return null;
+    }
+
+    public abstract void Redistribute(RealVector utilizations, List<int> supplierIndices);
+
+    public double EnforceBounds(double value, int idx) {
+      var min = Bounds[idx%Bounds.Rows, 0];
+      var max = Bounds[idx%Bounds.Rows, 1];
+      if (value < min) return min;
+      if (value > max) return max;
+      return value;
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantKiller.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantKiller.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantKiller.cs	(revision 15711)
@@ -0,0 +1,47 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.BioBoost.Operators.Mutation {
+
+  public class PlantKiller : PlantBasedUtilizationModifier {
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    public PlantKiller(bool isDeserializing) {}
+    public PlantKiller(PlantKiller orig, Cloner cloner) : base(orig, cloner) {}
+    public PlantKiller() {}
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new PlantKiller(this, cloner);
+    }
+    #endregion
+
+    public override void Redistribute(RealVector utilizations, List<int> supplierIndices) {
+      foreach (var i in supplierIndices) {
+        utilizations[i] = 0;
+      }
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantMerger.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantMerger.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantMerger.cs	(revision 15711)
@@ -0,0 +1,138 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.BioBoost.Representation;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.BioBoost.Operators.Mutation {
+
+  public class PlantMerger : SingleSuccessorOperator, IManipulator, IStochasticOperator {
+
+    #region Parameters
+    public LookupParameter<BioBoostProblemData> ProblemDataParameter { get { return (LookupParameter<BioBoostProblemData>) Parameters["ProblemData"]; } }
+    public LookupParameter<DistanceMatrix> DistanceMatrixParameter { get { return (LookupParameter<DistanceMatrix>) Parameters["DistanceMatrix"]; } }
+    public ValueParameter<BoolValue> DistanceMatrixInProblemDataParameter { get { return (ValueParameter<BoolValue>) Parameters["DistanceMatrixInProblemData"]; } }
+    public ValueLookupParameter<IntMatrix> RegionBoundsParameter { get { return (ValueLookupParameter<IntMatrix>) Parameters["RegionBounds"]; } } 
+    public ILookupParameter<IRandom> RandomParameter { get { return (ILookupParameter<IRandom>) Parameters["Random"]; } }
+    #endregion
+
+    #region Parameter Values
+    public BioBoostProblemData ProblemData { get { return ProblemDataParameter.ActualValue; } }
+    public IntMatrix RegionBounds { get { return RegionBoundsParameter.ActualValue; } }
+    public IRandom Random { get { return RandomParameter.ActualValue; } }
+    public bool DistanceMatrixInProblemData { get { return DistanceMatrixInProblemDataParameter.Value.Value; } }
+    public DistanceMatrix DistanceMatrix {
+      get {
+        if (DistanceMatrixInProblemData) {
+          return ((IValueParameter<DistanceMatrix>) ProblemData.Parameters[DistanceMatrixParameter.ActualName]).Value;
+        } else {
+          return DistanceMatrixParameter.ActualValue;
+        }
+      }
+    }
+    #endregion
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    public PlantMerger(bool isDeserializing) {}
+    public PlantMerger(PlantMerger orig, Cloner cloner) : base(orig, cloner) {}
+
+    public PlantMerger() {
+      Parameters.Add(new LookupParameter<BioBoostProblemData>("ProblemData", "The data store of the detailed problem description."));
+      Parameters.Add(new LookupParameter<DistanceMatrix>("DistanceMatrix", "The distance matrix to use", "StreetDistanceMatrix")); // TODO: check this
+      Parameters.Add(new ValueParameter<BoolValue>("DistanceMatrixInProblemData", "Whether to look for the distance matrix in problem data or in scope.", new BoolValue(true)));
+      Parameters.Add(new ValueLookupParameter<IntMatrix>("RegionBounds", "The limits of valid region ids."));
+      Parameters.Add(new LookupParameter<IRandom>("Random", "The random number generator."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new PlantMerger(this, cloner);
+    }
+    #endregion
+
+    public override IOperation Apply() {
+      var scope = ExecutionContext.Scope;
+      var dm = DistanceMatrix;
+      var feedstock =
+        ProblemData.TransportTargets.CheckedItems.ElementAt(
+          Random.Next(ProblemData.TransportTargets.CheckedItems.Count())).Value.Value;
+      string product = null;
+      var productLinks = ProblemData.ProductLinks;
+      for (int i = 0; i < productLinks.Rows; i++) {
+        if (productLinks[i, 0] == feedstock)
+          product = productLinks[i, 1];
+      }
+      var supplyTransports = scope.Variables[LayerDescriptor.TransportTargets.NameWithPrefix(feedstock)].Value as IntegerVector;
+      var productTransportName = LayerDescriptor.TransportTargets.NameWithPrefix(product);
+      var productTransports = product == null || !scope.Variables.ContainsKey(productTransportName) ? null
+        : scope.Variables[productTransportName].Value as IntegerVector;
+      if (supplyTransports != null) {
+        var plants = supplyTransports.Select((target, source) => new {target, source}).GroupBy(p => p.target).ToList();
+        var plant = plants.ElementAt(Random.Next(plants.Count));
+        var allowedRegions = new HashSet<int>(plants.Select(p => p.Key));
+        var newTarget = FindNewTarget(plant.Key, Random, dm, allowedRegions);
+        foreach (var supplier in plant) {
+          supplyTransports[supplier.source] = newTarget;
+        }
+        if (productTransports != null) {
+          var temp = productTransports[newTarget];
+          productTransports[newTarget] = productTransports[plant.Key];
+          productTransports[plant.Key] = temp;
+        }
+      }
+      return base.Apply();
+    }
+
+    private int FindNewTarget(int oldTarget, IRandom random, DistanceMatrix distances, IEnumerable<int> allowedRegions) {
+      var neighborDistances = new double[0].Select((d, idx) => new {index = idx, distance = d}).ToList();
+      var maxDistance = 0d;
+      foreach (int j in allowedRegions) {
+        var dist = distances[oldTarget, j];
+        neighborDistances.Add(new {index = j, distance = dist});
+        maxDistance = Math.Max(dist, maxDistance);
+      }
+      neighborDistances = neighborDistances.Select(p => new {p.index, distance = maxDistance - p.distance}).ToList();
+      neighborDistances.Sort((a, b) => b.distance.CompareTo(a.distance));
+      var totalDistance = neighborDistances.Sum(p => p.distance);
+      var threshold = random.NextDouble()*totalDistance;
+      var sum = 0d;
+      var index = 0;
+      while (index < neighborDistances.Count && sum < threshold) {
+        sum += neighborDistances[index].distance;
+        index++;
+      }
+      index = Math.Min(index, neighborDistances.Count - 1);
+      return neighborDistances[index].index;
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantMover.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantMover.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantMover.cs	(revision 15711)
@@ -0,0 +1,156 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.BioBoost.Representation;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.BioBoost.Operators.Mutation {
+
+  public class PlantMover : SingleSuccessorOperator, IManipulator, IStochasticOperator {
+
+    #region Parameters
+    public LookupParameter<BioBoostProblemData> ProblemDataParameter { get { return (LookupParameter<BioBoostProblemData>) Parameters["ProblemData"]; } }
+    public LookupParameter<DistanceMatrix> DistanceMatrixParameter { get { return (LookupParameter<DistanceMatrix>) Parameters["DistanceMatrix"]; } }
+    public ValueParameter<BoolValue> DistanceMatrixInProblemDataParameter { get { return (ValueParameter<BoolValue>) Parameters["DistanceMatrixInProblemData"]; } }
+    public ValueLookupParameter<IntMatrix> RegionBoundsParameter { get { return (ValueLookupParameter<IntMatrix>) Parameters["RegionBounds"]; } } 
+    public ILookupParameter<IRandom> RandomParameter { get { return (ILookupParameter<IRandom>) Parameters["Random"]; } }
+    public IValueLookupParameter<PercentValue> MergeAvoidanceProbabilityParameter { get { return (IValueLookupParameter<PercentValue>) Parameters["MergeAvoidanceProbability"]; } }
+    public IValueLookupParameter<PercentValue> SplitProbabilityParameter { get { return (IValueLookupParameter<PercentValue>) Parameters["SplitProbability"]; } }
+    public IValueLookupParameter<PercentValue> MovePercentageParameter { get { return (IValueLookupParameter<PercentValue>) Parameters["MovePercentage"]; } }
+    #endregion
+
+
+
+    #region Parameter Values
+    public BioBoostProblemData ProblemData { get { return ProblemDataParameter.ActualValue; } }
+    public IntMatrix RegionBounds { get { return RegionBoundsParameter.ActualValue; } }
+    public IRandom Random { get { return RandomParameter.ActualValue; } }
+    public bool DistanceMatrixInProblemData { get { return DistanceMatrixInProblemDataParameter.Value.Value; } }
+    public DistanceMatrix DistanceMatrix {
+      get {
+        if (DistanceMatrixInProblemData) {
+          return ((IValueParameter<DistanceMatrix>) ProblemData.Parameters[DistanceMatrixParameter.ActualName]).Value;
+        } else {
+          return DistanceMatrixParameter.ActualValue;
+        }
+      }
+    }
+    public double MergeAvoidanceProbability { get { return MergeAvoidanceProbabilityParameter.Value.Value; } }
+    public double SplitProbability { get { return SplitProbabilityParameter.Value.Value; } }
+    public double MovePercentage { get { return MovePercentageParameter.Value.Value; } }
+    #endregion
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    public PlantMover(bool isDeserializing) {}
+    public PlantMover(PlantMover orig, Cloner cloner) : base(orig, cloner) {}
+
+    public PlantMover() {
+      Parameters.Add(new LookupParameter<BioBoostProblemData>("ProblemData", "The data store of the detailed problem description."));
+      Parameters.Add(new LookupParameter<DistanceMatrix>("DistanceMatrix", "The distance matrix to use", "StreetDistanceMatrix")); // TODO: check this
+      Parameters.Add(new ValueParameter<BoolValue>("DistanceMatrixInProblemData", "Whether to look for the distance matrix in problem data or in scope.", new BoolValue(true)));
+      Parameters.Add(new ValueLookupParameter<IntMatrix>("RegionBounds", "The limits of valid region ids."));
+      Parameters.Add(new LookupParameter<IRandom>("Random", "The random number generator."));
+      Parameters.Add(new ValueLookupParameter<PercentValue>("MergeAvoidanceProbability", "Probability that a moved plant will avoid existing plant locations.", new PercentValue(1)));
+      Parameters.Add(new ValueLookupParameter<PercentValue>("SplitProbability", "Probability that only part of the suppliers will follow to the new location.", new PercentValue(0)));
+      Parameters.Add(new ValueLookupParameter<PercentValue>("MovePercentage", "In case a plant is split, the percentage of suppliers that will move.", new PercentValue(0.5)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new PlantMover(this, cloner);
+    }
+    #endregion
+
+    public override IOperation Apply() {
+      var scope = ExecutionContext.Scope;
+      var dm = DistanceMatrix;
+      var feedstock =
+        ProblemData.TransportTargets.CheckedItems.ElementAt(
+          Random.Next(ProblemData.TransportTargets.CheckedItems.Count())).Value.Value;
+      string product = null;
+      var productLinks = ProblemData.ProductLinks;
+      for (int i = 0; i < productLinks.Rows; i++) {
+        if (productLinks[i, 0] == feedstock)
+          product = productLinks[i, 1];
+      }
+      var supplyTransports = scope.Variables[LayerDescriptor.TransportTargets.NameWithPrefix(feedstock)].Value as IntegerVector;
+      var productTransportName = LayerDescriptor.TransportTargets.NameWithPrefix(product);
+      var productTransports = product == null || !scope.Variables.ContainsKey(productTransportName) ? null
+        : scope.Variables[productTransportName].Value as IntegerVector;
+      if (supplyTransports != null) {
+        var plants = supplyTransports.Select((target, source) => new {target, source}).GroupBy(p => p.target).ToList();
+        var plant = plants.ElementAt(Random.Next(plants.Count));
+        var forbiddenRegions = new HashSet<int>();
+        if (Random.NextDouble() > MergeAvoidanceProbability) {
+          forbiddenRegions = new HashSet<int>(plants.Select(p => p.Key));
+        }
+        var newTarget = FindNewTarget(plant.Key, Random, dm, forbiddenRegions);
+        bool split = Random.NextDouble() < SplitProbability;
+        foreach (var supplier in plant) {
+          if (!split || Random.NextDouble() <= MovePercentage) {
+            supplyTransports[supplier.source] = newTarget;
+          }
+        }
+        if (productTransports != null) {
+          var temp = productTransports[newTarget];
+          productTransports[newTarget] = productTransports[plant.Key];
+          productTransports[plant.Key] = temp;
+        }
+      }
+      return base.Apply();
+    }
+
+    private int FindNewTarget(int oldTarget, IRandom random, DistanceMatrix distances, HashSet<int> forbiddenRegions) {
+      var neighborDistances = new double[0].Select((d, idx) => new {index = idx, distance = d}).ToList();
+      var maxDistance = 0d;
+      for (int j = 0; j < distances.Columns; j++) {
+        if (forbiddenRegions.Contains(j)) continue;
+        var dist = distances[oldTarget, j];
+        neighborDistances.Add(new {index = j, distance = dist});
+        maxDistance = Math.Max(dist, maxDistance);
+      }
+      neighborDistances = neighborDistances.Select(p => new {p.index, distance = maxDistance - p.distance}).ToList();
+      neighborDistances.Sort((a, b) => b.distance.CompareTo(a.distance));
+      var totalDistance = neighborDistances.Sum(p => p.distance);
+      var threshold = random.NextDouble()*totalDistance;
+      var sum = 0d;
+      var index = 0;
+      while (index < neighborDistances.Count && sum < threshold) {
+        sum += neighborDistances[index].distance;
+        index++;
+      }
+      index = Math.Min(index, neighborDistances.Count - 1);
+      return neighborDistances[index].index;
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantScalingMutator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantScalingMutator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantScalingMutator.cs	(revision 15711)
@@ -0,0 +1,52 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.BioBoost.Utils;
+using HeuristicLab.Common;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.BioBoost.Operators.Mutation {
+
+  [StorableClass]
+  public class PlantScalingMutator : PlantBasedUtilizationModifier {
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    public PlantScalingMutator(bool isDeserializing) {}
+    public PlantScalingMutator(PlantScalingMutator orig, Cloner cloner) : base(orig, cloner) {}
+    public PlantScalingMutator() {}
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new PlantScalingMutator(this, cloner);
+    }
+    #endregion
+
+    public override void Redistribute(RealVector utilizations, List<int> supplierIndices) {
+      var scale = Util.Sqr(Random.NextDouble() + 0.5); // 25% - 225%
+      foreach (var i in supplierIndices) {
+        utilizations[i] = EnforceBounds(utilizations[i] * scale, i);
+      }
+    }
+
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantSplitter.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantSplitter.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantSplitter.cs	(revision 15711)
@@ -0,0 +1,154 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.BioBoost.Representation;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.BioBoost.Operators.Mutation {
+
+  public class PlantSplitter : SingleSuccessorOperator, IManipulator, IStochasticOperator {
+
+    #region Parameters
+    public LookupParameter<BioBoostProblemData> ProblemDataParameter { get { return (LookupParameter<BioBoostProblemData>) Parameters["ProblemData"]; } }
+    public LookupParameter<DistanceMatrix> DistanceMatrixParameter { get { return (LookupParameter<DistanceMatrix>) Parameters["DistanceMatrix"]; } }
+    public ValueParameter<BoolValue> DistanceMatrixInProblemDataParameter { get { return (ValueParameter<BoolValue>) Parameters["DistanceMatrixInProblemData"]; } }
+    public ValueLookupParameter<IntMatrix> RegionBoundsParameter { get { return (ValueLookupParameter<IntMatrix>) Parameters["RegionBounds"]; } } 
+    public ILookupParameter<IRandom> RandomParameter { get { return (ILookupParameter<IRandom>) Parameters["Random"]; } }
+    public IValueLookupParameter<PercentValue> MergeAvoidanceProbabilityParameter { get { return (IValueLookupParameter<PercentValue>) Parameters["MergeAvoidanceProbability"]; } }
+    public IValueLookupParameter<PercentValue> SplitProbabilityParameter { get { return (IValueLookupParameter<PercentValue>) Parameters["SplitProbability"]; } }
+    public IValueLookupParameter<PercentValue> MovePercentageParameter { get { return (IValueLookupParameter<PercentValue>) Parameters["MovePercentage"]; } }
+    #endregion
+
+    #region Parameter Values
+    public BioBoostProblemData ProblemData { get { return ProblemDataParameter.ActualValue; } }
+    public IntMatrix RegionBounds { get { return RegionBoundsParameter.ActualValue; } }
+    public IRandom Random { get { return RandomParameter.ActualValue; } }
+    public bool DistanceMatrixInProblemData { get { return DistanceMatrixInProblemDataParameter.Value.Value; } }
+    public DistanceMatrix DistanceMatrix {
+      get {
+        if (DistanceMatrixInProblemData) {
+          return ((IValueParameter<DistanceMatrix>) ProblemData.Parameters[DistanceMatrixParameter.ActualName]).Value;
+        } else {
+          return DistanceMatrixParameter.ActualValue;
+        }
+      }
+    }
+    public double MergeAvoidanceProbability { get { return MergeAvoidanceProbabilityParameter.Value.Value; } }
+    public double SplitProbability { get { return SplitProbabilityParameter.Value.Value; } }
+    public double MovePercentage { get { return MovePercentageParameter.Value.Value; } }
+    #endregion
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    public PlantSplitter(bool isDeserializing) {}
+    public PlantSplitter(PlantSplitter orig, Cloner cloner) : base(orig, cloner) {}
+
+    public PlantSplitter() {
+      Parameters.Add(new LookupParameter<BioBoostProblemData>("ProblemData", "The data store of the detailed problem description."));
+      Parameters.Add(new LookupParameter<DistanceMatrix>("DistanceMatrix", "The distance matrix to use", "StreetDistanceMatrix")); // TODO: check this
+      Parameters.Add(new ValueParameter<BoolValue>("DistanceMatrixInProblemData", "Whether to look for the distance matrix in problem data or in scope.", new BoolValue(true)));
+      Parameters.Add(new ValueLookupParameter<IntMatrix>("RegionBounds", "The limits of valid region ids."));
+      Parameters.Add(new LookupParameter<IRandom>("Random", "The random number generator."));
+      Parameters.Add(new ValueLookupParameter<PercentValue>("MergeAvoidanceProbability", "Probability that a moved plant will avoid existing plant locations.", new PercentValue(1)));
+      Parameters.Add(new ValueLookupParameter<PercentValue>("SplitProbability", "Probability that only part of the suppliers will follow to the new location.", new PercentValue(1)));
+      Parameters.Add(new ValueLookupParameter<PercentValue>("MovePercentage", "In case a plant is split, the percentage of suppliers that will move.", new PercentValue(0.5)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new PlantSplitter(this, cloner);
+    }
+    #endregion
+
+    public override IOperation Apply() {
+      var scope = ExecutionContext.Scope;
+      var dm = DistanceMatrix;
+      var feedstock =
+        ProblemData.TransportTargets.CheckedItems.ElementAt(
+          Random.Next(ProblemData.TransportTargets.CheckedItems.Count())).Value.Value;
+      string product = null;
+      var productLinks = ProblemData.ProductLinks;
+      for (int i = 0; i < productLinks.Rows; i++) {
+        if (productLinks[i, 0] == feedstock)
+          product = productLinks[i, 1];
+      }
+      var supplyTransports = scope.Variables[LayerDescriptor.TransportTargets.NameWithPrefix(feedstock)].Value as IntegerVector;
+      var productTransportName = LayerDescriptor.TransportTargets.NameWithPrefix(product);
+      var productTransports = product == null || !scope.Variables.ContainsKey(productTransportName) ? null
+        : scope.Variables[productTransportName].Value as IntegerVector;
+      if (supplyTransports != null) {
+        var plants = supplyTransports.Select((target, source) => new {target, source}).GroupBy(p => p.target).ToList();
+        var plant = plants.ElementAt(Random.Next(plants.Count));
+        var forbiddenRegions = new HashSet<int>();
+        if (Random.NextDouble() > MergeAvoidanceProbability) {
+          forbiddenRegions = new HashSet<int>(plants.Select(p => p.Key));
+        }
+        var newTarget = FindNewTarget(plant.Key, Random, dm, forbiddenRegions);
+        bool split = Random.NextDouble() < SplitProbability;
+        foreach (var supplier in plant) {
+          if (!split || Random.NextDouble() <= MovePercentage) {
+            supplyTransports[supplier.source] = newTarget;
+          }
+        }
+        if (productTransports != null) {
+          var temp = productTransports[newTarget];
+          productTransports[newTarget] = productTransports[plant.Key];
+          productTransports[plant.Key] = temp;
+        }
+      }
+      return base.Apply();
+    }
+
+    private int FindNewTarget(int oldTarget, IRandom random, DistanceMatrix distances, HashSet<int> forbiddenRegions) {
+      var neighborDistances = new double[0].Select((d, idx) => new {index = idx, distance = d}).ToList();
+      var maxDistance = 0d;
+      for (int j = 0; j < distances.Columns; j++) {
+        if (forbiddenRegions.Contains(j)) continue;
+        var dist = distances[oldTarget, j];
+        neighborDistances.Add(new {index = j, distance = dist});
+        maxDistance = Math.Max(dist, maxDistance);
+      }
+      neighborDistances = neighborDistances.Select(p => new {p.index, distance = maxDistance - p.distance}).ToList();
+      neighborDistances.Sort((a, b) => b.distance.CompareTo(a.distance));
+      var totalDistance = neighborDistances.Sum(p => p.distance);
+      var threshold = random.NextDouble()*totalDistance;
+      var sum = 0d;
+      var index = 0;
+      while (index < neighborDistances.Count && sum < threshold) {
+        sum += neighborDistances[index].distance;
+        index++;
+      }
+      index = Math.Min(index, neighborDistances.Count - 1);
+      return neighborDistances[index].index;
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantSupplierEqualizer.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantSupplierEqualizer.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantSupplierEqualizer.cs	(revision 15711)
@@ -0,0 +1,52 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.BioBoost.Operators.Mutation {
+
+  [StorableClass]
+  public class PlantSupplierEqualizer : PlantBasedUtilizationModifier {
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    public PlantSupplierEqualizer(bool isDeserializing) {}
+    public PlantSupplierEqualizer(PlantSupplierEqualizer orig, Cloner cloner) : base(orig, cloner) {}
+    public PlantSupplierEqualizer() {}
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new PlantSupplierEqualizer(this, cloner);
+    }
+    #endregion
+
+    public override void Redistribute(RealVector utilizations, List<int> supplierIndices) {
+      var average = supplierIndices.Select(i => utilizations[i]).Average();
+      foreach (var i in supplierIndices) {
+        utilizations[i] = average;
+      }
+    }
+
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantSupplierRandomizer.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantSupplierRandomizer.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantSupplierRandomizer.cs	(revision 15711)
@@ -0,0 +1,51 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.BioBoost.Utils;
+using HeuristicLab.Common;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.BioBoost.Operators.Mutation {
+
+  [StorableClass]
+  public class PlantSupplierRandomizer : PlantBasedUtilizationModifier {
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    public PlantSupplierRandomizer(bool isDeserializing) {}
+    public PlantSupplierRandomizer(PlantSupplierRandomizer orig, Cloner cloner) : base(orig, cloner) {}
+    public PlantSupplierRandomizer() {}
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new PlantSupplierRandomizer(this, cloner);
+    }
+    #endregion
+
+    public override void Redistribute(RealVector utilizations, List<int> supplierIndices) {
+      foreach (var i in supplierIndices) {
+        utilizations[i] = EnforceBounds(utilizations[i] * Util.Sqr(Random.NextDouble() + 0.5), i);
+      }
+    }
+
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantSupplierToggler.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantSupplierToggler.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantSupplierToggler.cs	(revision 15711)
@@ -0,0 +1,57 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Random;
+
+namespace HeuristicLab.BioBoost.Operators.Mutation {
+
+  [StorableClass]
+  public class PlantSupplierToggler : PlantBasedUtilizationModifier {
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    public PlantSupplierToggler(bool isDeserializing) {}
+    public PlantSupplierToggler(PlantSupplierToggler orig, Cloner cloner) : base(orig, cloner) {}
+    public PlantSupplierToggler() {}
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new PlantSupplierToggler(this, cloner);
+    }
+    #endregion
+
+    public override void Redistribute(RealVector utilizations, List<int> supplierIndices) {
+      var i = supplierIndices.SampleRandom(Random, 1).First();
+      if (utilizations[i] > 0) {
+        utilizations[i] = 0;
+      } else {
+        var min = Bounds[i%Bounds.Rows, 0];
+        var max = Bounds[i%Bounds.Rows, 1];
+        utilizations[i] = (max + min)/2;
+      }
+    }
+
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantSupplierUtilizationExchanger.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantSupplierUtilizationExchanger.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/PlantSupplierUtilizationExchanger.cs	(revision 15711)
@@ -0,0 +1,55 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Random;
+
+namespace HeuristicLab.BioBoost.Operators.Mutation {
+
+  [StorableClass]
+  public class PlantSupplierUtilizationExchanger : PlantBasedUtilizationModifier {
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    public PlantSupplierUtilizationExchanger(bool isDeserializing) {}
+    public PlantSupplierUtilizationExchanger(PlantSupplierUtilizationExchanger orig, Cloner cloner) : base(orig, cloner) {}
+    public PlantSupplierUtilizationExchanger() {}
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new PlantSupplierUtilizationExchanger(this, cloner);
+    }
+    #endregion
+
+    public override void Redistribute(RealVector utilizations, List<int> supplierIndices) {
+      var suppliers = supplierIndices.SampleRandom(Random, 2).ToArray();
+      if (suppliers.Length >= 2) {
+        var temp = utilizations[suppliers[0]];
+        utilizations[suppliers[0]] = utilizations[suppliers[1]];
+        utilizations[suppliers[1]] = temp;
+      }
+    }
+
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/TargetMergingIntegerVectorMutator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/TargetMergingIntegerVectorMutator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Mutation/TargetMergingIntegerVectorMutator.cs	(revision 15711)
@@ -0,0 +1,114 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Random;
+using System;
+using System.Linq;
+
+namespace HeuristicLab.BioBoost.Operators.Mutation {
+  [StorableClass]
+  public class TargetMergingIntegerVectorManipulator : BoundedIntegerVectorManipulator {
+
+    #region Parameters
+    public LookupParameter<DistanceMatrix> DistanceMatrixParameter {
+      get { return (LookupParameter<DistanceMatrix>) Parameters["DistanceMatrix"]; }
+    }
+    public ValueParameter<BoolValue> DistanceMatrixInProblemDataParameter {
+      get { return (ValueParameter<BoolValue>) Parameters["DistanceMatrixInProblemData"]; }
+    }
+    public ILookupParameter<BioBoostProblemData> ProblemDataParameter {
+      get { return (ILookupParameter<BioBoostProblemData>) Parameters["ProblemData"]; }
+    }
+    public ValueLookupParameter<DoubleValue> AvgBundleMutationRatioParameter {
+      get { return (ValueLookupParameter<DoubleValue>) Parameters["AvgBundleMutationRatio"]; }
+    }
+    #endregion
+
+    #region Parameter Values
+    public DistanceMatrix DistanceMatrix {
+      get {
+        if (DistanceMatrixInProblemData) {
+          return ((IValueParameter<DistanceMatrix>) ProblemData.Parameters[DistanceMatrixParameter.ActualName]).Value;
+        } else {
+          return DistanceMatrixParameter.ActualValue;
+        }
+      }
+    }
+    public bool DistanceMatrixInProblemData { get { return DistanceMatrixInProblemDataParameter.Value.Value; } }
+    public BioBoostProblemData ProblemData { get { return ProblemDataParameter.ActualValue; } }
+    public double AvgBundleMutationRatio { get { return AvgBundleMutationRatioParameter.ActualValue.Value; } }
+    #endregion
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected TargetMergingIntegerVectorManipulator(bool isDeserializing) : base(isDeserializing) {}
+    protected TargetMergingIntegerVectorManipulator(TargetMergingIntegerVectorManipulator orig, Cloner cloner) : base(orig, cloner) {}
+    public TargetMergingIntegerVectorManipulator() {
+      Parameters.Add(new LookupParameter<DistanceMatrix>("DistanceMatrix", "The distance matrix to use", "StreetDistanceMatrix"));
+      Parameters.Add(new ValueParameter<BoolValue>("DistanceMatrixInProblemData", "Whether to look for the distance matrix in problem data or in scope.", new BoolValue(true)));
+      Parameters.Add(new LookupParameter<BioBoostProblemData>("ProblemData", "The problem instance description container."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("AvgBundleMutationRatio", "The average ratio of modified targets in a bundle.", new PercentValue(1)));
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new TargetMergingIntegerVectorManipulator(this, cloner);
+    }
+    #endregion
+
+    protected override void ManipulateBounded(IRandom random, IntegerVector integerVector, IntMatrix bounds) {
+      var ratio =
+        new NormalDistributedRandom(random, Math.Min(1, Math.Max(0, AvgBundleMutationRatio)), 0.5).NextDouble();
+      var targetGroups = integerVector
+        .Select((t, i) => new {t, i})
+        .GroupBy(x => x.t, x => x.i)
+        .Shuffle(random)
+        .Take(2)
+        .ToList();
+      if (targetGroups.Count == 2) {
+        var dm = DistanceMatrix;
+        var key1 = targetGroups[0].Key;
+        var key2 = targetGroups[1].Key;
+        var targetList1 = targetGroups[0].Shuffle(random).ToList();
+        var targetList2 = targetGroups[1].Shuffle(random).ToList();
+        var center = Enumerable
+          .Range(0, integerVector.Length)
+          .Select(i => new {idx = i, dist = dm[key1, i] + dm[key2, i]})
+          .MinItems(d => d.dist)
+          .Shuffle(random)
+          .First();
+        foreach (var i in targetList1.Take(Math.Max(1, (int)Math.Round(ratio*targetList1.Count)))) {
+          integerVector[i] = center.idx;
+        }
+        foreach (var i in targetList2.Take(Math.Max(1, (int)Math.Round(ratio*targetList2.Count)))) {
+          integerVector[i] = center.idx;
+        }
+      } else if (targetGroups.Count == 1) {
+        integerVector[random.Next(integerVector.Length)] = random.Next(integerVector.Length);
+      }
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Transformation/FeedstockDeflater.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Transformation/FeedstockDeflater.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Transformation/FeedstockDeflater.cs	(revision 15711)
@@ -0,0 +1,95 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System.Collections.Generic;
+using HeuristicLab.BioBoost.Representation;
+
+namespace HeuristicLab.BioBoost.Operators.Transformation {
+
+  [StorableClass]
+  public class FeedstockDeflater : FeedstockTransformer {
+
+    public ILookupParameter<IntArray> ViableSourcesParameter { get { return (ILookupParameter<IntArray>) Parameters["ViableSources"]; } }
+    public ILookupParameter<IntArray> ViableTargetsParameter { get { return (ILookupParameter<IntArray>) Parameters["ViableTargets"]; } }
+
+    public IntArray ViableSources { set { ViableSourcesParameter.ActualValue = value; } }
+    public IntArray ViableTargets { set { ViableTargetsParameter.ActualValue = value; } }
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected FeedstockDeflater(bool isDeserializing) : base(isDeserializing) {}
+    protected FeedstockDeflater(FeedstockDeflater orig, Cloner cloner) : base(orig, cloner) {}
+    public FeedstockDeflater() {
+      Parameters.Add(new LookupParameter<IntArray>("ViableSources", "A list with all indices of viable source regions."));
+      Parameters.Add(new LookupParameter<IntArray>("ViableTargets", "A list with all indices of viable target regions."));
+    }
+    public override IDeepCloneable  Clone(Cloner cloner) {
+      return new FeedstockDeflater(this, cloner);
+    }
+    #endregion
+
+    public override IOperation Apply() {
+      var product = ProductName;
+      var potentials = GetFromProblemData<DoubleArray>(LayerDescriptor.PotentialsFromProblemData.NameWithPrefix(product));
+      var utilizations = GetFromScope<RealVector>(LayerDescriptor.Utilizations.NameWithPrefix(product));
+      if (potentials != null && utilizations != null) {
+        var newUtilizations = new List<double>();
+        for (int i = 0; i < potentials.Length; i++) {
+          if (potentials[i] > 0) {
+            newUtilizations.Add(utilizations[i]);
+          }
+        }
+        TransformValue(LayerDescriptor.Utilizations.NameWithPrefix(product), new RealVector(newUtilizations.ToArray()));
+      }
+      var targets = GetFromScope<IntegerVector>(LayerDescriptor.TransportTargets.NameWithPrefix(product));
+      var viableSources = new List<int>();
+      if (potentials != null && targets != null) {
+        for (int i = 0; i < potentials.Length; i++) {
+          if (potentials[i] > 0) {
+            viableSources.Add(i);
+          }
+        }
+        ViableSources = new IntArray(viableSources.ToArray());
+      }
+      var conversion = ProblemData.Conversions[product].FirstOrDefault();
+      var viableTargets = new List<int>();
+      if (conversion != null && targets != null) {
+        for (int i = 0; i < targets.Length; i++) {
+          if (GetMaxCapacity(i, conversion.MaxCapacities, Double.MaxValue) > 0) {
+            viableTargets.Add(i);
+          }
+        }
+        ViableTargets = new IntArray(viableTargets.ToArray());
+      } 
+      return base.Apply();
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Transformation/FeedstockInflater.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Transformation/FeedstockInflater.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Transformation/FeedstockInflater.cs	(revision 15711)
@@ -0,0 +1,65 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System.Collections.Generic;
+using HeuristicLab.BioBoost.Representation;
+
+namespace HeuristicLab.BioBoost.Operators.Transformation {
+
+  [StorableClass]
+  public class FeedstockInflater : FeedstockTransformer {
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected FeedstockInflater(bool isDeserializing) : base(isDeserializing) {}
+    protected FeedstockInflater(FeedstockInflater orig, Cloner cloner) : base(orig, cloner) {}
+    public FeedstockInflater() {}
+    public override IDeepCloneable  Clone(Cloner cloner) {
+      return new FeedstockInflater(this, cloner);
+    }
+    #endregion
+
+    public override IOperation Apply() {
+      var product = ProductName;
+      var potentials = GetFromProblemData<DoubleArray>(LayerDescriptor.PotentialsFromProblemData.NameWithPrefix(product));
+      var utilizations = GetFromScope<RealVector>(LayerDescriptor.Utilizations.NameWithPrefix(product));
+      if (potentials != null && utilizations != null) {
+        var newUtilizations = new List<double>();
+        var skipped = 0;
+        for (int i = 0; i < potentials.Length; i++) {
+          if (potentials[i] > 0) {
+            newUtilizations.Add(utilizations[i - skipped]);
+          } else {
+            skipped++;
+            newUtilizations.Add(0);
+          }
+        }
+        TransformValue(LayerDescriptor.Utilizations.NameWithPrefix(product), new RealVector(newUtilizations.ToArray()));
+      }
+      return base.Apply();
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Transformation/FeedstockTransformer.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Transformation/FeedstockTransformer.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Operators/Transformation/FeedstockTransformer.cs	(revision 15711)
@@ -0,0 +1,76 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.BioBoost.Operators.Transformation {
+
+  [StorableClass]
+  public class FeedstockTransformer : BioBoostOperator {
+
+
+    public ValueLookupParameter<StringValue> ProductNameParameter { get { return (ValueLookupParameter<StringValue>) Parameters["ProductName"]; } }
+
+    public string ProductName {
+      get { return ProductNameParameter.Value.Value; }
+      set { ProductNameParameter.Value = new StringValue(value);}
+    }
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected FeedstockTransformer(bool isDeserializing) : base(isDeserializing) {}
+    protected FeedstockTransformer(FeedstockTransformer orig, Cloner cloner) : base(orig, cloner) {}
+    public FeedstockTransformer() {
+      Parameters.Add(new ValueLookupParameter<StringValue>("ProductName", "The product name to be transformed."));
+    }
+    public override IDeepCloneable  Clone(Cloner cloner) {
+      return new FeedstockTransformer(this, cloner);
+    }
+    #endregion
+
+    public override IOperation Execute(IExecutionContext context, System.Threading.CancellationToken cancellationToken) {
+      return base.Execute(context, cancellationToken);
+    }
+
+    protected void TransformValue<T>(string valueName, T value) where T : class, IItem {
+      IParameter param;
+      if (!Parameters.TryGetValue(valueName, out param)) {
+        param = new LookupParameter<T>(valueName, "Transformed value.");
+        ((ILookupParameter) param).ExecutionContext = ExecutionContext;
+        Parameters.Add(param);
+      }
+      param.ActualValue = value;
+    }
+
+
+    protected double GetMaxCapacity(int i, ValueParameterCollection maxCapacities, double defaultValue) {
+      var regionName = ProblemData.LocationNames[i];
+      IValueParameter param;
+      if (maxCapacities.TryGetValue(regionName, out param)) return ((DoubleValue) param.Value).Value;
+      if (maxCapacities.TryGetValue("Default", out param)) return ((DoubleValue) param.Value).Value;
+      return defaultValue;
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Persistence/GeometryFeatureProviderSerializer.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Persistence/GeometryFeatureProviderSerializer.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Persistence/GeometryFeatureProviderSerializer.cs	(revision 15711)
@@ -0,0 +1,82 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 GeoAPI.Geometries;
+using HeuristicLab.Persistence.Core;
+using HeuristicLab.Persistence.Interfaces;
+using SharpMap.Data;
+using SharpMap.Data.Providers;
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Linq;
+
+namespace HeuristicLab.BioBoost.Persistence {
+
+  public class GeometryFeatureProviderSerializer : ICompositeSerializer {
+
+    #region ICompositeSerializer Members
+
+    public int Priority { get { return 200; } }
+
+    public bool CanSerialize(Type type) {
+      return type == typeof (GeometryFeatureProvider);
+    }
+
+    public object CreateInstance(Type type, IEnumerable<Tag> metaInfo) {
+      var table = new FeatureDataTable();
+      foreach (var tag in metaInfo)
+        table.Columns.Add(tag.Name, (Type)tag.Value);
+      return new GeometryFeatureProvider(table);
+    }
+
+    public IEnumerable<Tag> CreateMetaInfo(object obj) {
+      var gfp = obj as GeometryFeatureProvider;
+      return from DataColumn col in gfp.Features.Columns select new Tag(col.ColumnName, col.DataType);
+    }
+
+    public IEnumerable<Tag> Decompose(object obj) {
+      var gfp = obj as GeometryFeatureProvider;
+      foreach (FeatureDataRow row in gfp.Features.Rows) {
+        yield return new Tag(row.ItemArray);
+        yield return new Tag(row.Geometry);
+      }
+    }
+
+    public string JustifyRejection(Type type) {
+      return "Not a GeometryFeatureProvider";
+    }
+
+    public void Populate(object instance, IEnumerable<Tag> tags, Type type) {
+      var gfp = instance as GeometryFeatureProvider;
+      var it = tags.GetEnumerator();
+      while (it.MoveNext()) {
+        var row = (FeatureDataRow) gfp.Features.LoadDataRow((object[]) it.Current.Value, LoadOption.OverwriteChanges);
+        if (it.MoveNext())
+          row.Geometry = (IGeometry) it.Current.Value;
+        else
+          throw new PersistenceException("invalid data format for GeometryDataProvider: interleaved pairs of features and geometries expected");
+      }
+    }
+
+    #endregion
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Persistence/GeometrySerializer.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Persistence/GeometrySerializer.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Persistence/GeometrySerializer.cs	(revision 15711)
@@ -0,0 +1,70 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 GeoAPI.Geometries;
+using HeuristicLab.Persistence.Core;
+using HeuristicLab.Persistence.Interfaces;
+using NetTopologySuite.IO;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HeuristicLab.BioBoost.Persistence {
+  
+  public class GeometrySerializer : ICompositeSerializer {
+
+    #region ICompositeSerializer Members
+
+    public int Priority {
+      get { return 300; }
+    }
+
+    public bool CanSerialize(Type type) {
+      return type.GetInterfaces().Contains(typeof (IGeometry));
+    }
+
+    public string JustifyRejection(Type type) {
+      return "type does not implement interface IGeometry";
+    }
+
+    public object CreateInstance(Type type, IEnumerable<Tag> metaInfo) {
+      return new WKBReader().Read((byte[]) metaInfo.First().Value);
+    }
+
+    public IEnumerable<Tag> CreateMetaInfo(object obj) {
+      var g = obj as IGeometry;
+      return new[] {new Tag("WKB", new WKBWriter().Write(g))};
+    }
+
+    public IEnumerable<Tag> Decompose(object obj) {
+      // object was fully decomposed in CreateMetaInfo
+      return new Tag[0];
+    }
+
+
+    public void Populate(object instance, IEnumerable<Tag> tags, Type type) {
+      // object was fully populated in CreateInstance
+    }
+
+
+    #endregion
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Persistence/ShapeFileLoader.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Persistence/ShapeFileLoader.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Persistence/ShapeFileLoader.cs	(revision 15711)
@@ -0,0 +1,48 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 SharpMap.Data;
+using SharpMap.Data.Providers;
+using System.Data;
+using System.IO;
+using System.Linq;
+
+namespace HeuristicLab.BioBoost.Persistence {
+
+  public static class ShapeFileLoader {
+    public static GeometryFeatureProvider LoadShapeFile(string filename) {
+      var shapefile = new ShapeFile(filename, true, true);
+      shapefile.Open();
+      var table = new FeatureDataTable {TableName = Path.GetFileNameWithoutExtension(shapefile.Filename)};
+      bool addColumns = true;
+      foreach (var row in shapefile.GetObjectIDsInView(shapefile.GetExtents()).Select(shapefile.GetFeature)) {
+        if (addColumns && row.Table != null) {
+          foreach (DataColumn col in row.Table.Columns)
+            table.Columns.Add(col.ColumnName, col.DataType);
+          addColumns = false;
+        }
+        var newRow = (FeatureDataRow) table.LoadDataRow(row.ItemArray, LoadOption.OverwriteChanges);
+        newRow.Geometry = row.Geometry;
+      }
+      return new GeometryFeatureProvider(table);
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Plugin.cs.frame
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Plugin.cs.frame	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Plugin.cs.frame	(revision 15711)
@@ -0,0 +1,55 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.BioBoost {
+  [Plugin("HeuristicLab.Problems.BioBoost", "Plugin for project BioBoost for logistic network optimization", "3.3.12.$WCREV$")]
+  [PluginFile("HeuristicLab.Problems.BioBoost-3.3.dll", PluginFileType.Assembly)]
+  [PluginFile("BruTile.dll", PluginFileType.Assembly)]
+  [PluginFile("BruTile.Desktop.dll", PluginFileType.Assembly)]
+  [PluginFile("BruTile.Serialization.dll", PluginFileType.Assembly)]
+  [PluginFile("Common.Logging.dll", PluginFileType.Assembly)]
+  [PluginFile("GeoAPI.dll", PluginFileType.Assembly)]
+  [PluginFile("NetTopologySuite.dll", PluginFileType.Assembly)]
+  [PluginFile("NetTopologySuite.IO.GeoTools.dll", PluginFileType.Assembly)]
+  [PluginFile("NetTopologySuite.IO.MsSqlSpatial.dll", PluginFileType.Assembly)]
+  [PluginFile("NetTopologySuite.IO.PostGis.dll", PluginFileType.Assembly)]
+  [PluginFile("Newtonsoft.Json.dll", PluginFileType.Assembly)]
+  [PluginFile("PowerCollections.dll", PluginFileType.Assembly)]
+  [PluginFile("ProjNet.dll", PluginFileType.Assembly)]
+  [PluginFile("SharpMap.dll", PluginFileType.Assembly)]
+  [PluginFile("YamlDotNet.dll", PluginFileType.Assembly)]
+  [PluginDependency("HeuristicLab.Analysis", "3.3")]
+  [PluginDependency("HeuristicLab.Collections", "3.3")]
+  [PluginDependency("HeuristicLab.Common", "3.3")]
+  [PluginDependency("HeuristicLab.Common.Resources", "3.3")]
+  [PluginDependency("HeuristicLab.Core", "3.3")]
+  [PluginDependency("HeuristicLab.Data", "3.3")]
+  [PluginDependency("HeuristicLab.Encodings.IntegerVectorEncoding", "3.3")]
+  [PluginDependency("HeuristicLab.Encodings.RealVectorEncoding", "3.3")]
+  [PluginDependency("HeuristicLab.Operators", "3.3")]
+  [PluginDependency("HeuristicLab.Optimization", "3.3")]
+  [PluginDependency("HeuristicLab.Parameters", "3.3")]
+  [PluginDependency("HeuristicLab.Persistence", "3.3")]
+  [PluginDependency("HeuristicLab.Random", "3.3")]
+  public class Plugin : PluginBase {}
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/ProblemDescription/BioBoostProblemData.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/ProblemDescription/BioBoostProblemData.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/ProblemDescription/BioBoostProblemData.cs	(revision 15711)
@@ -0,0 +1,727 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Data;
+using System.Diagnostics;
+using System.Text.RegularExpressions;
+using HeuristicLab.BioBoost.Data;
+using HeuristicLab.BioBoost.Evaluators;
+using HeuristicLab.BioBoost.Persistence;
+using HeuristicLab.BioBoost.Utils;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using SharpMap.Data;
+using SharpMap.Data.Providers;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using GeoAPI.Geometries;
+using HeuristicLab.BioBoost.Representation;
+
+namespace HeuristicLab.BioBoost.ProblemDescription {
+
+  [StorableClass]
+  public class BioBoostProblemData : ParameterizedNamedItem {
+
+    #region Events
+    public event EventHandler GeometryChanged;
+    protected void OnGeometryChanged() {
+      var h = GeometryChanged;
+      if (h != null) h(this, EventArgs.Empty);
+    }
+    #endregion
+
+    public new ParameterCollection Parameters {
+      get { return base.Parameters; }
+    }
+
+    // this prevents geometries from being checked by tree traversal
+    private readonly Closure<GeometryFeatureProvider> geometry = new Closure<GeometryFeatureProvider>(Closure<GeometryFeatureProvider>.Encapsulation.Referenced);
+
+    [Storable]
+    public GeometryFeatureProvider Geometry {
+      get { return geometry.Value; }
+      private set { geometry.Value = value; }
+    }
+
+    #region IStorableContent Members
+    public string Filename { get; set; }
+    #endregion
+
+    #region Parameters
+    public ValueParameter<StringArray> LocationNamesParameter {
+      get { return (ValueParameter<StringArray>)Parameters["LocationNames"]; }
+    }
+    public ValueParameter<NeighborhoodTable> NeighborsParameter {
+      get { return (ValueParameter<NeighborhoodTable>)Parameters["Neighbors"]; }
+    }
+    private ValueParameter<ItemCollection<DataItem>> DataItemsParameter {
+      get { return (ValueParameter<ItemCollection<DataItem>>)Parameters["DataItems"]; }
+    }
+    public ValueParameter<ParameterCollection> FeedstockPotentialsParameter {
+      get { return (ValueParameter<ParameterCollection>)Parameters["FeedstockPotentials"]; }
+    }
+    public ValueParameter<DoubleArray> InvestmentCostFactorsParameter {
+      get { return (ValueParameter<DoubleArray>)Parameters["InvestmentCostFactors"]; }
+    }
+    public ValueParameter<DoubleArray> MaintenanceCostFactorsParameter {
+      get { return (ValueParameter<DoubleArray>)Parameters["MaintenanceCostFactors"]; }
+    }
+    public ValueParameter<DoubleArray> FuelCostFactorsParameter {
+      get { return (ValueParameter<DoubleArray>)Parameters["FuelCostFactors"]; }
+    }
+    public ValueParameter<DoubleArray> LaborCostFactorsParameter {
+      get { return (ValueParameter<DoubleArray>)Parameters["LaborCostFactors"]; }
+    }
+    public ValueParameter<DoubleArray> OtherCostFactorsParameter {
+      get { return (ValueParameter<DoubleArray>)Parameters["OtherCostFactors"]; }
+    }
+    public ValueParameter<CheckedItemList<StringValue>> UtilizationsParameter {
+      get { return (ValueParameter<CheckedItemList<StringValue>>)Parameters["Utilizations"]; }
+    }
+    public ValueParameter<CheckedItemList<StringValue>> TransportTargetsParameter {
+      get { return (ValueParameter<CheckedItemList<StringValue>>)Parameters["TransportTargets"]; }
+    }
+    public ValueParameter<CheckedItemList<StringValue>> FinalProductsParameter {
+      get { return (ValueParameter<CheckedItemList<StringValue>>)Parameters["FinalProducts"]; }
+    }
+    public IValueParameter<DoubleMatrix> SplitRegionDistanceFactorsParameter {
+      get { return (IValueParameter<DoubleMatrix>) Parameters["SplitRegionDistanceFactors"]; }
+    }
+    public IValueParameter<StringMatrix> ProductLinksParameter { get { return (IValueParameter<StringMatrix>) Parameters["ProductLinks"]; } }
+    #endregion
+
+    #region Parameter Values
+    public StringArray LocationNames {
+      get { return LocationNamesParameter.Value; }
+      set { LocationNamesParameter.Value = value; }
+    }
+    public NeighborhoodTable Neighbors {
+      get { return NeighborsParameter.Value; }
+      set { NeighborsParameter.Value = value; }
+    }
+    public ItemCollection<DataItem> DataItems {
+      get { return DataItemsParameter.Value; }
+      private set {
+        DataItemsParameter.Value = value;
+        Products = value.OfType<Product>().ToList();
+        Conversions = value.OfType<Conversion>().ToLookup(c => c.Feedstock, c => c);
+        Logistics = value.OfType<Logistic>().ToLookup(l => l.Product, l => l);
+      }
+    }
+    public ParameterCollection FeedstockPotentials {
+      get { return FeedstockPotentialsParameter.Value; }
+      set { FeedstockPotentialsParameter.Value = value; }
+    }
+    public DoubleArray InvestmentCostFactors {
+      get { return InvestmentCostFactorsParameter.Value; }
+      set { InvestmentCostFactorsParameter.Value = value; }
+    }
+    public DoubleArray MaintenanceCostFactors {
+      get { return MaintenanceCostFactorsParameter.Value; }
+      set { MaintenanceCostFactorsParameter.Value = value; }
+    }
+    public DoubleArray FuelCostFactors {
+      get { return FuelCostFactorsParameter.Value; }
+      set { FuelCostFactorsParameter.Value = value; }
+    }
+    public DoubleArray LaborCostFactors {
+      get { return LaborCostFactorsParameter.Value; }
+      set { LaborCostFactorsParameter.Value = value; }
+    }
+    public DoubleArray OtherCostFactors {
+      get { return OtherCostFactorsParameter.Value; }
+      set { OtherCostFactorsParameter.Value = value; }
+    }
+    public CheckedItemList<StringValue> Utilizations {
+      get { return UtilizationsParameter.Value; }
+      set { UtilizationsParameter.Value = value; }
+    }
+    public CheckedItemList<StringValue> TransportTargets {
+      get { return TransportTargetsParameter.Value; }
+      set { TransportTargetsParameter.Value = value; }
+    }
+    public CheckedItemList<StringValue> FinalProducts {
+      get { return FinalProductsParameter.Value; }
+      set { FinalProductsParameter.Value = value; }
+    }
+    public DoubleMatrix SplitRegionDistanceFactors {
+      get { return SplitRegionDistanceFactorsParameter.Value; }
+      set { SplitRegionDistanceFactorsParameter.Value = value; }
+    }
+    public IEnumerable<Product> Products { get; private set; }
+    public ILookup<string, Conversion> Conversions { get; private set; }
+    public ILookup<string, Logistic> Logistics { get; private set; }
+    public StringMatrix ProductLinks {
+      get { return ProductLinksParameter.Value; }
+      set { ProductLinksParameter.Value = value; }
+    }
+    #endregion
+
+    #region Construction & Cloning
+
+    [StorableConstructor]
+    protected BioBoostProblemData(bool isDeserializing) : base(isDeserializing) { }
+    protected BioBoostProblemData(BioBoostProblemData orig, Cloner cloner)
+      : base(orig, cloner) {
+      Geometry = orig.Geometry;
+      DataItems = DataItems; // invoke setter to populate Products, Conversions and Logistics
+    }
+    public BioBoostProblemData() {
+      Parameters.Add(new ValueParameter<StringArray>("LocationNames", "The names of the individual locations."));
+      Parameters.Add(new ValueParameter<NeighborhoodTable>("Neighbors", "The table of neighborhood degrees."));
+      Parameters.Add(new ValueParameter<ItemCollection<DataItem>>("DataItems", "Data descriptors, e.g. for products or logistics and conversion processes."));
+      Parameters.Add(new ValueParameter<ParameterCollection>("FeedstockPotentials", "Imported feedstock potentials."));
+      Parameters.Add(new ValueParameter<DoubleArray>("InvestmentCostFactors", "The scaling factors for investment costs."));
+      Parameters.Add(new ValueParameter<DoubleArray>("MaintenanceCostFactors", "The scaling factors for maintenance costs."));
+      Parameters.Add(new ValueParameter<DoubleArray>("FuelCostFactors", "The scaling factors for fuel costs."));
+      Parameters.Add(new ValueParameter<DoubleArray>("LaborCostFactors", "The scaling factors for labor costs."));
+      Parameters.Add(new ValueParameter<DoubleArray>("OtherCostFactors", "The scaling factors for other costs."));
+      Parameters.Add(new ValueParameter<CheckedItemList<StringValue>>("Utilizations", "The possible utilization vectors."));
+      Parameters.Add(new ValueParameter<CheckedItemList<StringValue>>("TransportTargets", "The possible transport target vectors."));
+      Parameters.Add(new ValueParameter<CheckedItemList<StringValue>>("FinalProducts", "The list of possible final products used for quality evaluation."));
+      Parameters.Add(new ValueParameter<DoubleMatrix>("SplitRegionDistanceFactors", "Describes the reduction in distance if the region would be split into different numbers of smaller regions"));
+      Parameters.Add(new ValueParameter<StringMatrix>("ProductLinks", "List of tuples of product names that are linked in the logistic chain"));
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new BioBoostProblemData(this, cloner);
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    public void AfterDeserialization() {
+      DataItems = DataItems; // invoke setter to populate Products, Conversions and Logistics
+      TryUpgradeStringArrayToCheckedItemList("Utilizations");
+      TryUpgradeStringArrayToCheckedItemList("TransportTargets");
+      if (!Parameters.ContainsKey("SplitRegionDistanceFactors"))
+        Parameters.Add(new ValueParameter<DoubleMatrix>("SplitRegionDistanceFactors", "Describes the reduction in distance if the region would be split into different numbers of smaller regions"));
+      if (!Parameters.ContainsKey("ProductLinks"))
+        Parameters.Add(new ValueParameter<StringMatrix>("ProductLinks", "List of tuples of product names that are linked in the logistic chain"));
+      if (!Parameters.ContainsKey("FinalProducts"))
+        Parameters.Add(new ValueParameter<CheckedItemList<StringValue>>("FinalProducts", "The list of possible final products used for quality evaluation."));
+    }
+
+    private void TryUpgradeStringArrayToCheckedItemList(string parameterName) {
+      var oldParameter = Parameters[parameterName] as ValueParameter<StringArray>;
+      if (oldParameter != null) {
+        var newParameter = new ValueParameter<CheckedItemList<StringValue>>(oldParameter.Name, oldParameter.Description);
+        Parameters.Remove(parameterName);
+        foreach (var s in oldParameter.Value)
+          newParameter.Value.Add(new StringValue(s), true);
+        Parameters.Add(newParameter);
+      }
+    }
+    #endregion
+
+    public override void CollectParameterValues(IDictionary<string, IItem> values) {
+      base.CollectParameterValues(values);
+      foreach (var di in DataItems) {
+        di.CollectParameterValues(values);
+      }
+    }
+
+    #region Data Parsing & Import
+    private void AddParameter<TValue>(string name, TValue value) where TValue : class, IItem {
+      Parameters.Remove(name);
+      Parameters.Add(new ValueParameter<TValue>(name, value));
+    }
+
+    public void LoadFeedstockPotentials(string filename) {
+      var feedstockPotentials = new List<Tuple<string, List<double>>>();
+      var regionNames = new List<string>();
+      bool headerDone = false;
+      foreach (var line in File.ReadLines(filename)) {
+        var fields = line.Split(';');
+        if (!headerDone) {
+          feedstockPotentials.AddRange(
+            fields.Skip(1).Select(feedstockName => Tuple.Create(feedstockName, new List<double>())));
+          headerDone = true;
+        } else {
+          regionNames.Add(fields[0]);
+          for (int i = 1; i < fields.Length; i++) {
+            double value;
+            double.TryParse(fields[i], NumberStyles.Float, NumberFormatInfo.InvariantInfo, out value);
+            feedstockPotentials[i - 1].Item2.Add(value);
+          }
+        }
+      }
+
+      if (LocationNames.Length > 0) {
+        var newRegionNames = new HashSet<string>(regionNames);
+        newRegionNames.ExceptWith(LocationNames);
+        var indexTable = LocationNames.Concat(newRegionNames)
+          .Select((n, i) => new { idx = i, name = n })
+          .ToDictionary(p => p.name, p => p.idx);
+        if (newRegionNames.Count > 0)
+          LocationNames = new StringArray(LocationNames.Concat(newRegionNames).ToArray());
+        foreach (var fp in feedstockPotentials) {
+          var potentials = new DoubleArray(indexTable.Count);
+          var potentialName = LayerDescriptor.PotentialsFromProblemData.NameWithPrefix(fp.Item1);
+          for (int i = 0; i < regionNames.Count; i++) {
+            potentials[indexTable[regionNames[i]]] = fp.Item2[i];
+          }
+          FeedstockPotentials.Remove(potentialName);
+          FeedstockPotentials.Add(new ValueParameter<DoubleArray>(potentialName, potentials));
+        }
+      } else {
+        LocationNames = new StringArray(regionNames.ToArray());
+        foreach (var fp in feedstockPotentials) {
+          FeedstockPotentials.Add(new ValueParameter<DoubleArray>(LayerDescriptor.PotentialsFromProblemData.NameWithPrefix(fp.Item1), new DoubleArray(fp.Item2.ToArray())));
+        }
+      }
+
+
+      Configure();
+    }
+
+    public void LoadShapeFile(string filename) {
+      Geometry = ShapeFileLoader.LoadShapeFile(filename);
+      OnGeometryChanged();
+    }
+
+    public void AddDoubleArrayParameters(IEnumerable<string> fields, IList<string> names, string prefix) {
+      int i = 0;
+      foreach (var f in fields) {
+        if (i >= names.Count) break;
+        var subfields = f.Split('/');
+        var values = new List<double>();
+        foreach (var sf in subfields) {
+          double d;
+          Double.TryParse(sf, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out d);
+          values.Add(d);
+        }
+        AddParameter(names[i] + prefix, new DoubleArray(values.ToArray()));
+        i++;
+      }
+    }
+
+    public void AddDoubleValueParameters(IEnumerable<string> fields, IList<string> names, string prefix) {
+      int i = 0;
+      foreach (var f in fields) {
+        if (i >= names.Count) break;
+        double d;
+        Double.TryParse(f, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out d);
+        AddParameter(names[i] + prefix, new DoubleValue(d));
+        i++;
+      }
+    }
+
+    public void AddIntValueParameters(IEnumerable<string> fields, IList<string> names, string prefix) {
+      int i = 0;
+      foreach (var f in fields) {
+        if (i >= names.Count) break;
+        int n;
+        Int32.TryParse(f, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out n);
+        AddParameter(names[i] + prefix, new IntValue(n));
+        i++;
+      }
+    }
+
+    public void LoadDistanceMatrix(string filename) {
+      var newLocationNames = new HashSet<string>();
+      var tuples = new List<Tuple<string, string, double>>();
+      var matrixName = "";
+      foreach (var line in File.ReadLines(filename)) {
+        var l = line.Trim();
+        if (l.StartsWith("#")) {
+          matrixName = l.TrimStart("# ".ToCharArray());
+        } else {
+          var fields = l.Split(';').ToList();
+          newLocationNames.Add(fields[0]);
+          newLocationNames.Add(fields[1]);
+          double d;
+          Double.TryParse(fields[2], NumberStyles.Float, NumberFormatInfo.InvariantInfo, out d);
+          tuples.Add(Tuple.Create(fields[0], fields[1], d));
+        }
+      }
+      newLocationNames.ExceptWith(LocationNames);
+      if (newLocationNames.Count > 0) {
+        LocationNames = new StringArray(LocationNames.Concat(newLocationNames).ToArray());
+        foreach (ValueParameter<DoubleArray> p in FeedstockPotentials) {
+          p.Value = new DoubleArray(p.Value.Concat(new double[newLocationNames.Count]).ToArray());
+        }
+      }
+      var dm = new DistanceMatrix();
+      dm.Load(tuples, LocationNames, -1);
+      matrixName += "DistanceMatrix";
+      if (Parameters.ContainsKey(matrixName))
+        Parameters.Remove(matrixName);
+      Parameters.Add(new ValueParameter<DistanceMatrix>(matrixName, dm));
+      Configure();
+    }
+
+    public void LoadSplitRegionDistanceFactors(string filename) {
+      // format: regionName;factor2;factor3;factor4;...
+      var newLocationNames = new HashSet<string>();
+      var splits = new Dictionary<string, List<double>>();
+      int maxN = 0;
+      foreach (var line in File.ReadLines(filename)) {
+        var l = line.Trim();
+        if (l.ToUpper().StartsWith("NUTS")) continue;
+        var fields = line.Split(';').ToList();
+        newLocationNames.Add(fields[0]);
+        splits.Add(fields[0], fields.Skip(1).Select(s => ParseDouble(s, 1)).ToList());
+        maxN = Math.Max(fields.Count, maxN);
+      }
+      newLocationNames.ExceptWith(LocationNames);
+      if (newLocationNames.Count > 0) {
+        LocationNames = new StringArray(LocationNames.Concat(newLocationNames).ToArray());
+        SplitRegionDistanceFactors = new DoubleMatrix(LocationNames.Length, maxN - 1, 
+          Enumerable.Range(2, maxN - 1).Select(d => d.ToString(NumberFormatInfo.InvariantInfo)),
+          LocationNames);
+        for (int row = 0; row < SplitRegionDistanceFactors.Rows; row++) {
+          List<double> values;
+          if (splits.TryGetValue(LocationNames[row], out values)) {
+            for (int col = 0; col < values.Count; col++) {
+              SplitRegionDistanceFactors[row, col] = values[col];
+            }
+          }
+        }
+      }
+    }
+
+    public static double ParseDouble(string s, double defaultValue = 0) {
+      double d;
+      if (Double.TryParse(s, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out d))
+        return d;
+      return defaultValue;
+    }
+
+    public void RemoveRegions(Regex regex) {
+      RemoveRegions(LocationNames.Where(n => regex.IsMatch(n)));
+    }
+
+    public void KeepRegions(Regex regex) {
+      RemoveRegions(LocationNames.Where(n => !regex.IsMatch(n)));
+    }
+
+    public void RemoveRegions(IEnumerable<string> regionNames) {
+      var regionNameSet = new HashSet<string>(regionNames);
+      var removedIndices =
+        LocationNames.Select((r, i) => new { r, i })
+                     .Where(ri => regionNameSet.Contains(ri.r))
+                     .Select(ri => ri.i)
+                     .ToList();
+      // remove region names
+      int nLocationNamesBefore = LocationNames.Length;
+      LocationNames = new StringArray(LocationNames.RemoveAtIndices(removedIndices).ToArray());
+      int nLocationNamesAfter = LocationNames.Length;
+      Debug.Assert(nLocationNamesBefore - removedIndices.Count == nLocationNamesAfter);
+      // remove region potentials
+      foreach (var potentialName in FeedstockPotentials.Select(p => p.Name).ToList()) {
+        var potentials = FeedstockPotentials[potentialName];
+        FeedstockPotentials.Remove(potentialName);
+        FeedstockPotentials.Add(
+          new ValueParameter<DoubleArray>(
+            potentialName,
+            new DoubleArray(((ValueParameter<DoubleArray>)potentials).Value.RemoveAtIndices(removedIndices).ToArray())));
+      }
+      // remove region distances
+      foreach (var distanceMatrixParam in Parameters.Where(p => p.Name.EndsWith("DistanceMatrix"))) {
+        var valueParam = distanceMatrixParam as IValueParameter;
+        if (valueParam != null && typeof(DistanceMatrix).IsAssignableFrom(valueParam.DataType)) {
+          var matrix = (DistanceMatrix)valueParam.Value;
+          valueParam.Value = matrix.CopyAndRemoveIndices(removedIndices);
+        }
+      }
+      // remove region neighbors
+      if (Neighbors != null)
+        Neighbors = Neighbors.CopyAndRemoveIndices(removedIndices);
+      // remove shapes & and create new geometry (copy on write)
+      var locationNameset = new HashSet<string>(LocationNames);
+      var keptRows = Geometry.Features.Cast<FeatureDataRow>()
+        .Where(row => locationNameset.Contains(row["NUTS_ID"]))
+        .ToList();
+      var newFeatures = new FeatureDataTable();
+      foreach (DataColumn column in Geometry.Features.Columns) {
+        newFeatures.Columns.Add(column.ColumnName, column.DataType);
+      }
+      foreach (FeatureDataRow row in keptRows) {
+        var newRow = (FeatureDataRow)newFeatures.LoadDataRow(row.ItemArray, LoadOption.OverwriteChanges);
+        newRow.Geometry = (IGeometry) row.Geometry.Clone();
+      }
+      newFeatures.AcceptChanges();
+      Geometry = new GeometryFeatureProvider(newFeatures);
+      OnGeometryChanged();
+      Configure();
+    }
+
+    public void LoadNeighbors(string filename) {
+      var locationNames = LocationNames.Select((n, i) => new { n, i }).ToDictionary(p => p.n, p => p.i);
+      var neighbors = new NeighborhoodTable();
+      foreach (var line in File.ReadLines(filename)) {
+        var fields = line.Split(';');
+        int id1, id2, degree;
+        if (locationNames.TryGetValue(fields[0], out id1) &&
+            locationNames.TryGetValue(fields[1], out id2) &&
+            Int32.TryParse(fields[2], out degree))
+          neighbors.AddEntry(id1, id2, degree);
+      }
+      neighbors.Check();
+      Neighbors = neighbors;
+    }
+
+    public void LoadDescriptors(string filename) {
+      var newItems = new ItemCollection<DataItem>(DataItem.ParseFile(filename));
+      if (DataItems != null) {
+        foreach (var oldItem in DataItems) {
+          if (!newItems.Any(i => i.IsEquivalentTo(oldItem)))
+            newItems.Add(oldItem);
+        }
+      }
+      DataItems = newItems;
+      Configure();
+    }
+
+    private void Configure() {
+      DistributeCostFactors();
+      DiscoverSolutionSpace();
+    }
+
+    private void DistributeCostFactors() {
+      int length = LocationNames.Length;
+      InvestmentCostFactors = new DoubleArray(length);
+      MaintenanceCostFactors = new DoubleArray(length);
+      FuelCostFactors = new DoubleArray(length);
+      LaborCostFactors = new DoubleArray(length);
+      OtherCostFactors = new DoubleArray(length);
+      var costFactorDescriptors = DataItems.OfType<CostFactors>().FirstOrDefault();
+      if (costFactorDescriptors == null) return;
+      for (int i = 0; i < length; i++) {
+        var countryCode = LocationNames[i].Substring(0, 2);
+        InvestmentCostFactors[i] = GetDoubleValueValue(costFactorDescriptors.Investment, countryCode, 1);
+        MaintenanceCostFactors[i] = GetDoubleValueValue(costFactorDescriptors.Maintenance, countryCode, 1);
+        FuelCostFactors[i] = GetDoubleValueValue(costFactorDescriptors.Fuel, countryCode, 1);
+        LaborCostFactors[i] = GetDoubleValueValue(costFactorDescriptors.Labor, countryCode, 1);
+        OtherCostFactors[i] = GetDoubleValueValue(costFactorDescriptors.Other, countryCode, 1);
+      }
+    }
+
+    private void DiscoverSolutionSpace() {
+      if (DataItems == null || DataItems.Count == 0) return;
+      var products = Products;
+      var logistics = Logistics;
+      var conversions = DataItems.OfType<Conversion>().ToList();
+
+      // perform conceptual logistic simulation
+      var usableProducts = products
+        .Where(product => FeedstockPotentials.ContainsKey(LayerDescriptor.PotentialsFromProblemData.NameWithPrefix(product.Label)))
+        .ToList();
+      var transportableProducts = usableProducts
+        .Where(p => logistics.Contains(p.Label))
+        .ToList();
+      var feasibleDecentralConversions = conversions
+        .Where(c => transportableProducts.Any(p => p.Label == c.Feedstock))
+        .ToList();
+      var possibleIntermediates = feasibleDecentralConversions
+        .Aggregate(Enumerable.Empty<string>(),
+                   (intermediates, conv) => intermediates.Concat(conv.Products.Select(p => p.Name)))
+        .ToList();
+      var transportableIntermediates = possibleIntermediates
+        .Where(logistics.Contains) // && intermediate exists as product?
+        .ToList();
+      var feasibleCentralConversions = conversions
+        .Where(c => transportableIntermediates.Any(i => i == c.Feedstock))
+        .ToList();
+      var finalProductLists = feasibleCentralConversions
+        .Select(c => c.Products.Where(p => { var v = (p.Value as DoubleValue); return v != null && v.Value > 0; }).Select(p => p.Name));
+      var finalProductList = finalProductLists.Aggregate(Enumerable.Empty<string>(), (x, y) => x.Concat(y));
+      var uniqueFinalProducts = finalProductList.GroupBy(p => p).Select(p => p.Key);
+      var valuableFinalProducts = uniqueFinalProducts.Where(productName => Products.Any(p => p.Label == productName && p.Price > 0));
+      var finalProducts = valuableFinalProducts.ToList();
+
+      // TODO: forward simulation sanity checks
+      // non-sold products
+      // non-(transported/converted/sold) intermediates
+      // non-transported/converted feedstocks
+
+      // reverse pruning
+      // select only central conversions for which valuable end-products exist
+      var necessaryCentralConversions = feasibleCentralConversions
+        .Where(c => c.Products.Any(p => products.Any(p1 => p1.Label == p.Name && p1.Price > 0)))
+        .ToList();
+      // transport only intermediates that need to be converted
+      var neccessaryIntermediates = transportableIntermediates
+        .Where(i => necessaryCentralConversions.Any(c => c.Feedstock == i))
+        .ToList();
+      // select only intermediates that either
+      // - need to transported and are further processed or
+      // - can be sold
+      var feasibleIntermediates = neccessaryIntermediates.Concat(
+        possibleIntermediates.Where(i => products.Any(p => p.Label == i && p.Price > 0)))
+        .ToList();
+      // produce only selected intermediates
+      var necessaryDecentralConversions = feasibleDecentralConversions
+        .Where(c => c.Products.Any(p => feasibleIntermediates.Contains(p.Name)))
+        .ToList();
+      // transport and buy only feedstocks that are converted and sold
+      var necessaryFeedstocks = necessaryDecentralConversions
+        .Select(c => c.Feedstock).ToList();
+
+      // enable feedstocks directly to central conversion? Yes, it automatically becomes a decentral conversion
+      // TODO: allow more than two echelons?
+
+      // configure search space:
+      UpdateSearchSpace(Utilizations, necessaryFeedstocks);
+      UpdateSearchSpace(TransportTargets, necessaryFeedstocks.Concat(neccessaryIntermediates));
+      UpdateSearchSpace(FinalProducts, finalProducts);
+
+      var q =
+        (from p1 in necessaryFeedstocks.Concat(neccessaryIntermediates)
+          from p2 in neccessaryIntermediates
+          where conversions.Any(c => c.Feedstock == p1 && c.Products.ContainsKey(p2))
+          select new {p1, p2}).Concat(
+        from p1 in neccessaryIntermediates
+        from p2 in finalProducts
+        where conversions.Any(c => c.Feedstock == p1 && c.Products.ContainsKey(p2))
+        select new {p1, p2})
+       .Distinct().ToList();
+      var productLinks = new StringMatrix(q.Count, 2);
+      for (int i = 0; i < q.Count; i++) {
+        productLinks[i, 0] = q[i].p1;
+        productLinks[i, 1] = q[i].p2;
+      }
+      ProductLinks = productLinks;
+
+    }
+
+    private void UpdateSearchSpace(CheckedItemList<StringValue> choices, IEnumerable<string> requirements) {
+      var req = new HashSet<string>(requirements);
+      for (int i = 0; i < choices.Count; i++) {
+        if (req.Contains(choices[i].Value)) {
+          req.Remove(choices[i].Value); // already there, not required anymore
+        } else {
+          choices.SetItemCheckedState(i, false);
+        }
+      }
+      foreach (var r in req) {
+        choices.Add(new StringValue(r), true);
+      }
+    }
+
+    private static double GetDoubleValueValue(ValueParameterCollection parameters, string name, double defaultValue) {
+      IValueParameter param;
+      if (!parameters.TryGetValue(name, out param)) return defaultValue;
+      var doubleValue = param.Value as DoubleValue;
+      if (doubleValue == null) return defaultValue;
+      return doubleValue.Value;
+    }
+
+    #endregion
+
+    #region Data Consistency Checks
+    public string CheckGeoData() {
+      var warnings = new List<string>();
+      CheckDistanceMatrices(warnings);
+      var shapeNames = CheckShapeNames(warnings);
+      var locationNames = CheckLocationNames(warnings);
+      FindMissing(warnings, locationNames, shapeNames, "locations without shapes");
+      FindMissing(warnings, shapeNames, locationNames, "shapes without data");
+      var totalPotentials = new double[LocationNames.Length];
+      foreach (var p in FeedstockPotentials.OfType<ValueParameter<DoubleArray>>()) {
+        totalPotentials = totalPotentials.Zip(p.Value, (a, b) => a + b).ToArray();
+        FindZeros(warnings, p.Value, p.Name);
+      }
+      FindZeros(warnings, totalPotentials, "any potential");
+      return string.Join("\n\n", warnings);
+    }
+
+    private void FindZeros(List<string> warnings, IEnumerable<double> values, string name) {
+      var zeros = values.Select((v, i) => new { v, i }).Where(p => p.v == 0).Select(p => LocationNames[p.i]).ToList();
+      if (zeros.Count > 0)
+        warnings.Add(string.Format("{0} regions with zero of {1}:\n  {2}",
+          zeros.Count, name, string.Join(", ", zeros)));
+    }
+
+    private static void FindMissing(List<string> warnings, IEnumerable<string> items, IEnumerable<string> other, string message) {
+      var missingItems = new HashSet<string>(items);
+      missingItems.ExceptWith(other);
+      if (missingItems.Count > 0)
+        warnings.Add(string.Format("{0} {1}:\n  {2}",
+          missingItems.Count, message, string.Join(", ", missingItems)));
+    }
+
+    private HashSet<string> CheckLocationNames(List<string> warnings) {
+      var duplicates = new List<String>();
+      var locationNames = new HashSet<string>();
+      foreach (var n in LocationNames) {
+        if (locationNames.Contains(n))
+          duplicates.Add(n);
+        locationNames.Add(n);
+      }
+      if (duplicates.Count > 0)
+        warnings.Add(string.Format("{0} duplicate location names:\n  {1}",
+          duplicates.Count, string.Join(", ", duplicates)));
+      return locationNames;
+    }
+
+    private HashSet<string> CheckShapeNames(List<string> warnings) {
+      var duplicates = new List<string>();
+      var shapeNames = new HashSet<string>();
+      foreach (FeatureDataRow row in Geometry.Features.Rows) {
+        var n = (string)row["NUTS_ID"];
+        if (shapeNames.Contains(n))
+          duplicates.Add(n);
+        shapeNames.Add(n);
+      }
+      if (duplicates.Count > 0)
+        warnings.Add(string.Format("{0} duplicate shape names:\n  {1}",
+          duplicates.Count, String.Join(", ", duplicates)));
+      return shapeNames;
+    }
+
+    private void CheckDistanceMatrices(List<string> warnings) {
+      foreach (var distanceMatrixParam in Parameters.Where(p => p.Name.EndsWith("DistanceMatrix"))) {
+        var valueParam = distanceMatrixParam as IValueParameter;
+        if (valueParam != null && typeof(DistanceMatrix).IsAssignableFrom(valueParam.DataType))
+          FindUnconnectedRegions((DistanceMatrix)valueParam.Value, warnings);
+      }
+    }
+
+    private void FindUnconnectedRegions(DistanceMatrix dm, List<string> warnings) {
+      var unconnected = new List<string>();
+      var hardlyConnected = new List<string>();
+      for (int i = 0; i < dm.Size; i++) {
+        var nConnected = 0;
+        for (int j = 0; j < i; j++) {
+          if (dm[i, j] > 0) nConnected++;
+        }
+        if (nConnected == 0)
+          unconnected.Add(LocationNames[i]);
+        else if (1.0 * nConnected < 1.0 * LocationNames.Length / 100)
+          hardlyConnected.Add(LocationNames[i]);
+      }
+      if (unconnected.Count > 0)
+        warnings.Add(string.Format("{0} unconnected regions:\n  {1}",
+          unconnected.Count, string.Join(", ", unconnected)));
+      if (hardlyConnected.Count > 0)
+        warnings.Add(string.Format("{0} connected to fewer than 1% of regions:\n  {1}",
+          hardlyConnected.Count, string.Join(", ", hardlyConnected)));
+    }
+
+    // TODO: check consistency of conversion process
+    #endregion
+  }
+}
+
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/ProblemDescription/DistanceMatrix.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/ProblemDescription/DistanceMatrix.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/ProblemDescription/DistanceMatrix.cs	(revision 15711)
@@ -0,0 +1,273 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Globalization;
+using System.Linq;
+
+namespace HeuristicLab.BioBoost.ProblemDescription {
+
+  [Item("DistanceMatrix", "Represents a space-efficient, symmetric distance matrix of double values.")]
+  [StorableClass]
+  public class DistanceMatrix : NamedItem, IStringConvertibleMatrix {
+
+    public new static Image StaticItemImage {
+      get { return Common.Resources.VSImageLibrary.Class; }
+    }
+
+    [Storable]
+    public int Size { get; private set; }
+
+    [Storable]
+    public double Max { get; private set; }
+
+    [Storable]
+    public double Min { get; private set; }
+
+    [Storable]
+    private IEnumerable<double> Values_Persistence {
+      get { return values; }
+      set { values = new List<double>(value);}
+    }
+
+    private List<double> values;
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected DistanceMatrix(bool isDeserializing) : base(isDeserializing) { }
+    protected DistanceMatrix(DistanceMatrix original, Cloner cloner)
+      : base(original, cloner) {
+      values = original.values.ToList();
+      Size = original.Size;
+      Min = original.Min;
+      Max = original.Max;
+      Name = original.Name;
+    }
+    public DistanceMatrix() {
+      values = new List<double>();
+      Size = 0;
+      Min = Double.NaN;
+      Max = Double.NaN;
+      Name = this.ItemName;
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new DistanceMatrix(this, cloner);
+    }
+    #endregion
+
+    protected virtual bool Validate(string value, out string errorMessage) {
+      double val;
+      if (!double.TryParse(value, out val)) {
+        errorMessage = string.Format(
+          "Invalid Value (Valid Value Format: '{0}')",
+          FormatPatterns.GetDoubleFormatPattern());
+        return false;
+      } else {
+        errorMessage = string.Empty;
+        return true;
+      }
+    }
+
+    protected int GetLinearIndex(int row, int col) {
+      if (row >= col)
+        return row*(row + 1)/2 + col;
+      else
+        return col*(col + 1)/2 + row;
+    }
+
+    public double this[int row, int col] {
+      get {
+        var value = values[GetLinearIndex(row, col)];
+        return value >= 0 ? value :
+          row == col ? Max*2 : Max*4;
+      }
+      set {
+        var i = GetLinearIndex(row, col);
+        var oldValue = values[i];
+        values[GetLinearIndex(row, col)] = value;
+        CheckBounds(oldValue, value);
+        OnItemChanged(row, col);
+        OnToStringChanged();
+      }
+    }
+
+    protected void CheckBounds(double oldValue, double value) {
+      if (Double.IsNaN(Max) || value > Max) {
+        Max = value;
+      } else if (oldValue == Max) {
+        Max = values.Max();
+      }
+      if (Double.IsNaN(Min) || value < Min) {
+        Min = value;
+      } else if (oldValue == Min) {
+        Min = values.Min();
+      }
+    }
+
+    protected virtual string GetValue(int rowIndex, int columIndex) {
+      return this[rowIndex, columIndex].ToString(CultureInfo.InvariantCulture);
+    }
+
+    protected virtual bool SetValue(string value, int rowIndex, int columnIndex) {
+      double val;
+      if (double.TryParse(value, out val)) {
+        this[rowIndex, columnIndex] = val;
+        return true;
+      } else {
+        return false;
+      }
+    }
+
+    public void Load(IEnumerable<Tuple<string, string, double>> labeledValues, IEnumerable<string> finalOrder, double defaultValue) {
+      var dict = labeledValues.ToDictionary(t => new {x = t.Item1, y = t.Item2}, t => t.Item3);
+      var labels = finalOrder.ToList();
+      Size = labels.Count;
+      values.Clear();
+      for (int i = 0; i<Size; i++) {
+        for (int j = 0; j<=i; j++) {
+          double value;
+          if (dict.TryGetValue(new { x = labels[i], y = labels[j] }, out value)) {
+            values.Add(value);
+          } else if (dict.TryGetValue(new { x = labels[j], y = labels[i] }, out value)) {
+            values.Add(value);
+          } else {
+            values.Add(defaultValue);
+          }
+        }
+      }
+      Min = values.Min();
+      Max = values.Max();
+      OnRowNamesChanged();
+      OnColumnNamesChanged();
+      OnRowsChanged();
+      OnColumnsChanged();
+      OnReset();
+    }
+
+    public DistanceMatrix CopyAndRemoveIndices(IEnumerable<int> indices) {
+      var idx = new HashSet<int>(indices);
+      int ii = 0, jj = 0;
+      var dm = new DistanceMatrix {Size = Size - idx.Count};
+      for (int i = 0; i < Size; i++) {
+        if (!idx.Contains(i)) {
+          for (int j = 0; j <= i; j++) {
+            if (!idx.Contains(j)) {
+              //dm[ii, jj] = this[i, j];
+              dm.values.Add(this[i, j]);
+            }
+            jj++;
+          }
+        }
+        ii++;
+      }
+      dm.Min = dm.values.Count > 0 ? dm.values.Min() : 0;
+      dm.Max = dm.values.Count > 0 ? dm.values.Max() : 0;
+      OnRowNamesChanged();
+      OnColumnNamesChanged();
+      OnRowsChanged();
+      OnColumnsChanged();
+      OnReset();
+      return dm;
+    }
+
+    #region IStringConvertibleMatrix Members
+
+    public int Rows { get { return Size; } set { throw new NotImplementedException(); } }
+    public int Columns { get { return Size; } set { throw new NotImplementedException(); } }
+    public bool ReadOnly { get { return true; } }
+
+    public IEnumerable<string> RowNames {
+      get { return Enumerable.Range(0, Size).Select(i => i.ToString(CultureInfo.InvariantCulture)); }
+      set { throw new NotImplementedException(); }
+    }
+    public IEnumerable<string> ColumnNames {
+      get { return RowNames; }
+      set { throw new NotImplementedException(); }
+    }
+    public bool SortableView {
+      get { return false; }
+      set { throw new NotImplementedException(); }
+    }
+
+
+    bool IStringConvertibleMatrix.Validate(string value, out string errorMessage) {
+      return Validate(value, out errorMessage);
+    }
+    string IStringConvertibleMatrix.GetValue(int rowIndex, int columIndex) {
+      return GetValue(rowIndex, columIndex);
+    }
+    bool IStringConvertibleMatrix.SetValue(string value, int rowIndex, int columnIndex) {
+      return SetValue(value, rowIndex, columnIndex);
+    }
+
+    public event EventHandler RowsChanged;
+    public event EventHandler ColumnsChanged;
+    public event EventHandler RowNamesChanged;
+    public event EventHandler ColumnNamesChanged;
+    public event EventHandler Reset;
+    public event EventHandler<EventArgs<int, int>> ItemChanged;
+    public event EventHandler SortableViewChanged;
+
+    #endregion
+
+    #region Events
+    protected void OnRowsChanged() {
+      var handler = RowsChanged;
+      if (handler != null)
+        handler(this, EventArgs.Empty);
+    }
+    protected void OnColumnsChanged() {
+      var handler = ColumnsChanged;
+      if (handler != null)
+        handler(this, EventArgs.Empty);
+    }
+    protected void OnRowNamesChanged() {
+      var handler = RowNamesChanged;
+      if (handler != null)
+        handler(this, EventArgs.Empty);
+    }
+    protected void OnColumnNamesChanged() {
+      var handler = ColumnNamesChanged;
+      if (handler != null)
+        handler(this, EventArgs.Empty);
+    }
+    protected void OnReset() {
+      var handler = Reset;
+      if (handler != null)
+        handler(this, EventArgs.Empty);
+    }
+    protected void OnItemChanged(int row, int col) {
+      var handler = ItemChanged;
+      if (handler != null) {
+        handler(this, new EventArgs<int, int>(row, col));
+        if (row != col)
+          handler(this, new EventArgs<int, int>(col, row));
+      }
+    }
+    #endregion
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/ProblemDescription/NeighborhoodTable.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/ProblemDescription/NeighborhoodTable.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/ProblemDescription/NeighborhoodTable.cs	(revision 15711)
@@ -0,0 +1,221 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+
+namespace HeuristicLab.BioBoost.ProblemDescription {
+  
+  [StorableClass]
+  public class NeighborhoodTable : Item, IStringConvertibleMatrix {
+
+    public struct Key : IComparable<Key> {
+      public Key(int id, int degree) {
+        Id = id;
+        Degree = degree;
+      }
+      public int Id;
+      public int Degree;
+
+      public int CompareTo(Key other) {
+        return Id.CompareTo(other.Id) == 0 ? Degree.CompareTo(other.Degree) : Id.CompareTo(other.Id);
+      }
+
+      public override string ToString() {
+        return string.Format("{0}[{1}]", Id, Degree);
+      }
+    }
+
+    [Storable]
+    private Dictionary<Key, HashSet<int>> table;
+
+    [Storable]
+    private Dictionary<int, HashSet<int>> degrees;
+
+    [Storable]
+    private int maxNNeighborsByDegree;
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected NeighborhoodTable(bool isDeserializing) : base(isDeserializing) {}
+    protected NeighborhoodTable(NeighborhoodTable orig, Cloner cloner) : base(orig, cloner) {
+      table = orig.table.ToDictionary(p => p.Key, p => p.Value);
+      degrees = orig.degrees.ToDictionary(p => p.Key, p => p.Value);
+      maxNNeighborsByDegree = orig.maxNNeighborsByDegree;
+    }
+    public NeighborhoodTable() {
+      table = new Dictionary<Key, HashSet<int>>();
+      degrees = new Dictionary<int, HashSet<int>>();
+      maxNNeighborsByDegree = 0;
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NeighborhoodTable(this, cloner);
+    }
+    #endregion
+
+    public void AddEntry(int id1, int id2, int degree) {
+      var key = new Key(id1, degree);
+      HashSet<int> forwardSet;
+      if (table.TryGetValue(key, out forwardSet)) {
+        forwardSet.Add(id2);
+        maxNNeighborsByDegree = Math.Max(maxNNeighborsByDegree, forwardSet.Count);
+      } else {
+        table[key] = new HashSet<int> {id2};
+        maxNNeighborsByDegree = Math.Max(maxNNeighborsByDegree, 1);
+      }
+      HashSet<int> deg;
+      if (degrees.TryGetValue(id1, out deg)) {
+        deg.Add(degree);
+      } else {
+        degrees[id1] = new HashSet<int> {degree};
+      }
+    }
+
+    public HashSet<int> GetNeighbors(int id, int degree) {
+      return table[new Key(id, degree)];
+    }
+
+    public Dictionary<int, HashSet<int>>  GetNeighbors(int id) {
+      return degrees[id].ToDictionary(deg => deg, deg => table[new Key(id, deg)]);
+    }
+
+    public HashSet<int>[] GetNeighborsFlat(int id) {
+      HashSet<int> neighborDegrees;
+      if (degrees.TryGetValue(id, out neighborDegrees))
+        return neighborDegrees.OrderBy(d => d).Select(d => table[new Key(id, d)]).ToArray();
+      return new HashSet<int>[0];
+    }
+
+    private double Sqr(double x) { return x*x; }
+
+    public int GetRandomNeighbor(int id, IRandom random, int maxId) {
+      var neighbors = GetNeighborsFlat(id);
+      if (neighbors.Length == 0) return id;
+      var classIndex = (int) Math.Round(Sqr(random.NextDouble())*(neighbors.Length));
+      if (classIndex >= neighbors.Length)
+        return random.Next(maxId);
+      var clazz = neighbors[classIndex];
+      return clazz.ElementAt(random.Next(clazz.Count));
+    }
+
+    public void Check() {
+      var errors = new List<string>();
+      foreach (var key in table.Keys) {
+        foreach (var neighbor in table[key]) {
+          HashSet<int> reverseNeighbors;
+          if (table.TryGetValue(new Key(neighbor, key.Degree), out reverseNeighbors))
+            if (reverseNeighbors.Contains(key.Id))
+              continue;
+          errors.Add(string.Format("Reverse relationship of {0}->{1} at degree {2} not found",
+            key.Id, neighbor, key.Degree));
+        }
+      }
+      var uniqueNeighbors = new Dictionary<int, HashSet<int>>();
+      foreach (var key in table.Keys) {
+        HashSet<int> neighbors;
+        if (!uniqueNeighbors.TryGetValue(key.Id, out neighbors)) {
+          neighbors = new HashSet<int>();
+        }
+        foreach (var neighbor in table[key]) {
+          if (neighbors.Contains(neighbor))
+            errors.Add(string.Format("Duplicate neighbor {0} of {1} with multiple degrees", neighbor, key.Id));
+        }
+      }
+      if (errors.Count > 0)
+        throw new Exception(string.Format("NeighborhoodTable Check Failed:\n{0}", string.Join("\n", errors)));
+    }
+
+    #region Implementation of IStringConvertibleMatrix
+
+    public bool Validate(string value, out string errorMessage) {
+      throw new NotImplementedException();
+    }
+
+    public string GetValue(int rowIndex, int columnIndex) {
+      return table.OrderBy(p => p.Key).ElementAt(rowIndex).Value.ElementAt(columnIndex).ToString(CultureInfo.InvariantCulture);
+    }
+
+    public bool SetValue(string value, int rowIndex, int columnIndex) {
+      throw new NotImplementedException();
+    }
+
+    public int Rows { get { return table.Count; } set { throw new NotImplementedException(); } }
+    public int Columns { get { return 2+maxNNeighborsByDegree; } set { throw new NotImplementedException(); } }
+
+    public IEnumerable<string> ColumnNames {
+      get {
+        return new[] {"ID", "Degree"}.Concat(
+          Enumerable.Range(0, maxNNeighborsByDegree).Select(n => string.Format("Neighbor {0}", n)));
+      }
+      set { throw new NotImplementedException(); }
+    }
+    public IEnumerable<string> RowNames {
+      get { return Enumerable.Range(0, Rows).Select(i => i.ToString(CultureInfo.InvariantCulture)); } 
+      set { throw new NotImplementedException(); }
+    }
+
+    public bool SortableView { get { return false; } set { throw new NotImplementedException(); } }
+    public bool ReadOnly { get { return true; } }
+
+    public event EventHandler ColumnsChanged;
+    public event EventHandler RowsChanged;
+    public event EventHandler ColumnNamesChanged;
+    public event EventHandler RowNamesChanged;
+    public event EventHandler SortableViewChanged;
+    public event EventHandler<EventArgs<int, int>> ItemChanged;
+    public event EventHandler Reset;
+
+    #endregion
+
+    public NeighborhoodTable CopyAndRemoveIndices(IEnumerable<int> removedIndices) {
+      if (table.Count == 0)
+        return new NeighborhoodTable();
+      var removedIndexSet = new HashSet<int>(removedIndices);
+      int i = 0;
+      var mapping = Enumerable
+        .Range(0, table.Keys.Select(k => k.Id).Max() + 1)
+        .ToDictionary(
+          oldIdx => oldIdx,
+          oldIdx => {
+            if (removedIndexSet.Contains(oldIdx)) return -1;
+            return i++;
+          });
+      var newTable = new NeighborhoodTable();
+      foreach (var entry in table.Keys) {
+        foreach (var neighbor in table[entry]) {
+          var newSource = mapping[entry.Id];
+          var newTarget = mapping[neighbor];
+          if (newSource != -1 && newTarget != -1) {
+            newTable.AddEntry(newSource, newTarget, entry.Degree);
+          }
+        }
+      }
+      newTable.Check();
+      return newTable;
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/ProblemDescription/SolutionSpaceDiscoverer.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/ProblemDescription/SolutionSpaceDiscoverer.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/ProblemDescription/SolutionSpaceDiscoverer.cs	(revision 15711)
@@ -0,0 +1,157 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.BioBoost.Data;
+using HeuristicLab.Data;
+
+namespace HeuristicLab.BioBoost.ProblemDescription {
+  public class SolutionSpaceDiscoverer {
+
+    private enum ProductCheck { None, NonFeasible, InProgress, Feasible };
+
+    // caches
+    private readonly List<Product> products;
+    private readonly HashSet<string> transportableProductNames;
+    private readonly List<Conversion> conversions;
+    private readonly Dictionary<string, double> prices;
+    private readonly Dictionary<Product, List<Conversion>> choices;  
+
+    // status
+    private readonly Dictionary<Product, ProductCheck> currentChecks;
+
+    // results
+    public List<string> FeasibleFeedstocks { get; private set; }
+    public List<string> FeasibleTransports { get; private set; } 
+    public Dictionary<string, List<string>> FeasibleChoices { get; private set; } 
+    public Dictionary<string, string> FeasibilityAnalysis { get; private set; }
+    public int MaxDepth { get; private set; }
+
+    public SolutionSpaceDiscoverer(IEnumerable<string> feedstockNames, List<Product> products, IEnumerable<Logistic> logistics, IEnumerable<Conversion> conversions) {
+      this.products = products.ToList();
+      transportableProductNames = new HashSet<string>();
+      foreach (var l in logistics) {
+        transportableProductNames.Add(l.Product);
+      }
+      this.conversions = conversions.ToList();
+      this.prices = products.ToDictionary(p => p.Label, p => p.Price);
+      this.choices = new Dictionary<Product, List<Conversion>>();
+
+      this.currentChecks = products.ToDictionary(p => p, p => ProductCheck.None);
+
+      this.FeasibilityAnalysis = products.ToDictionary(p => p.Label, p => string.Empty);
+      this.FeasibleFeedstocks = new List<string>();
+      this.FeasibleTransports = new List<string>();
+      this.MaxDepth = 0;
+      var feedstocks = new HashSet<string>(feedstockNames);
+      var feedstockProducts = products.Where(p => feedstocks.Contains(p.Label)).ToList();
+      foreach (var input in feedstockProducts) {
+        if (CheckProduct(input)) {
+          FeasibleFeedstocks.Add(input.Label);
+        }
+      }
+      foreach (var pair in currentChecks) {
+        if (pair.Value == ProductCheck.Feasible) {
+          FeasibleTransports.Add(pair.Key.Label);
+          List<Conversion> newChoices = null;
+          if (choices.TryGetValue(pair.Key, out newChoices)) {
+            FeasibleChoices.Add(pair.Key.Label, newChoices.Select(c => c.Label).ToList());
+          }
+        }
+      }
+    }
+
+    public SolutionSpaceDiscoverer(IEnumerable<string> feedstockNames, List<DataItem> dataItems)
+      : this(feedstockNames, dataItems.OfType<Product>().ToList(), dataItems.OfType<Logistic>(), dataItems.OfType<Conversion>()) {}
+
+
+    private bool CheckProduct(Product inputProduct, int currentDepth = 1) {
+
+      switch (currentChecks[inputProduct]) {
+        case ProductCheck.Feasible:
+          return true;
+        case ProductCheck.NonFeasible:
+          return false;
+        case ProductCheck.InProgress:
+          FeasibilityAnalysis[inputProduct.Label] += "not checked recursively: circular dependency";
+          return false;
+        case ProductCheck.None:
+          break;
+      }
+      currentChecks[inputProduct] = ProductCheck.InProgress;
+
+      // transportable?
+      if (!transportableProductNames.Contains(inputProduct.Label)) {
+        currentChecks[inputProduct] = ProductCheck.NonFeasible;
+        FeasibilityAnalysis[inputProduct.Label] += "NOT transportable";
+        return false; // not transportable
+      }
+
+      // convertable?
+      var otherOutputProducts = new HashSet<Product>();
+      var profitableOutputProducts = new HashSet<Product>();
+      var profitableConversions = new List<Conversion>();
+      foreach (var c in conversions.Where(c => c.Feedstock == inputProduct.Label)) {
+
+        // outputs?
+        foreach (var outputProductParameter in c.Products) {
+          var outputProductName = outputProductParameter.Name;
+          var outputAmount = outputProductParameter.Value as DoubleValue;
+          if (string.IsNullOrEmpty(outputProductName))
+            continue; // no product
+          var product = products.FirstOrDefault(p2 => p2.Label == outputProductName);
+          if (product == null || outputAmount == null)
+            continue; // not a real product
+          double amount = outputAmount.Value;
+          double price;
+          if (prices.TryGetValue(product.Label, out price) && price*amount > 0) {
+            profitableOutputProducts.Add(product);
+          } else {
+            otherOutputProducts.Add(product);
+          }
+        }
+        // recurse
+        foreach (var p in profitableOutputProducts)
+          CheckProduct(p, currentDepth + 1);
+        var otherProfits = otherOutputProducts.Any(p => CheckProduct(p, currentDepth + 1));
+
+        // analyze
+        if (profitableOutputProducts.Count == 0 && !otherProfits) {
+          currentChecks[inputProduct] = ProductCheck.NonFeasible;
+          FeasibilityAnalysis[inputProduct.Label] += "NO profitable direct or indirect output products";
+        } else {
+          currentChecks[inputProduct] = ProductCheck.Feasible;
+          MaxDepth = Math.Max(MaxDepth, currentDepth);
+          profitableConversions.Add(c);
+          if (profitableOutputProducts.Count > 0) FeasibilityAnalysis[inputProduct.Label] += "profitable direct output products ";
+          if (otherProfits) FeasibilityAnalysis[inputProduct.Label] += "profitable indirect output products";
+        }
+      }
+
+      // conclusion
+      if (profitableConversions.Count > 1)
+        choices.Add(inputProduct, profitableConversions);
+      return profitableConversions.Count > 0;
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Properties/AssemblyInfo.cs.frame
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Properties/AssemblyInfo.cs.frame	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Properties/AssemblyInfo.cs.frame	(revision 15711)
@@ -0,0 +1,56 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.InteropServices;
+
+// 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.Problems.BioBoost")]
+[assembly: AssemblyDescription("HeuristicLab plugin for simulation-based optimization of logistic networks (as developed in the EU-FP7 project BioBoost)")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("HeuristicLab")]
+[assembly: AssemblyCopyright("(c) 2002-2015 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("d421a20c-e329-4fa5-b8b1-0cc9a78b75b3")]
+
+// 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.3.0.0")]
+[assembly: AssemblyFileVersion("3.3.12.$WCREV$")]
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Representation/BioBoostCompoundSolution.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Representation/BioBoostCompoundSolution.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Representation/BioBoostCompoundSolution.cs	(revision 15711)
@@ -0,0 +1,633 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using HeuristicLab.BioBoost.Evaluators;
+using HeuristicLab.BioBoost.Operators.Mutation;
+using HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.BioBoost.Utils;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using NetTopologySuite.GeometriesGraph;
+using SharpMap;
+using SharpMap.Data.Providers;
+using SharpMap.Layers;
+using SharpMap.Utilities.Wfs;
+// using YamlDotNet.RepresentationModel.Serialization.NodeTypeResolvers;
+
+namespace HeuristicLab.BioBoost.Representation {
+  [StorableClass]
+  public sealed class BioBoostCompoundSolution : ParameterizedNamedItem, IStorableContent {
+    public class TransportInfo {
+      public string Product;
+      public int SrcRegionIdx;
+      public int DestRegionIdx;
+      public string SrcRegion;
+      public string DestRegion;
+      public string Mode;
+      public double Distance;
+      public double Amount;
+    }
+
+    [Storable]
+    public Dictionary<string, IntArray> IntValues;
+
+    [Storable]
+    public Dictionary<string, DoubleArray> DoubleValues;
+
+    [Storable]
+    public Dictionary<string, StringArray> StringValues;
+
+    [Storable]
+    public Dictionary<string, ItemArray<ItemList<IntValue>>> TransportTargets;
+
+    [Storable]
+    private BioBoostProblemData problemDataRef;
+
+    public BioBoostProblemData ProblemDataReference {
+      get { return problemDataRef; }
+      set {
+        if (problemDataRef != value) {
+          problemDataRef = value;
+          EvaluateAndUpdateAllResults(); // also raises OnSolutionChanged (re-evaluation is only done when the problem is set by an external entity)
+        }
+      }
+    }
+
+
+    #region Parameters
+    public ValueParameter<StringArray> LocationNamesParameter {
+      get { return (ValueParameter<StringArray>)Parameters["LocationNames"]; }
+    }
+
+    public FixedValueParameter<DoubleValue> QualityParameter {
+      get { return (FixedValueParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+
+    public ValueParameter<DoubleArray> QualitiesParameter {
+      get { return (ValueParameter<DoubleArray>)Parameters["Qualities"]; }
+    }
+    #endregion
+
+    #region Parameter Values
+    public StringArray LocationNames {
+      get { return LocationNamesParameter.Value; }
+      private set { LocationNamesParameter.Value = value; }
+    }
+
+    public double Quality {
+      get { return QualityParameter.Value.Value; }
+      private set { QualityParameter.Value.Value = value; }
+    }
+    public DoubleArray Qualities {
+      get { return QualitiesParameter.Value; }
+      private set { QualitiesParameter.Value = value; }
+    }
+    #endregion
+
+    private readonly Closure<GeometryFeatureProvider> geometry = new Closure<GeometryFeatureProvider>(Closure<GeometryFeatureProvider>.Encapsulation.Referenced);
+
+    [Storable]
+    public GeometryFeatureProvider Geometry { get { return geometry.Value; } private set { geometry.Value = value; } }
+
+    public event EventHandler SolutionChanged;
+
+    private void OnSolutionChanged() {
+      var handler = SolutionChanged;
+      if (handler != null)
+        handler(this, EventArgs.Empty);
+    }
+
+    private static bool IsSlimKey(string key) {
+      if (LayerDescriptor.Utilizations.IsSuffixOf(key)) return true;
+      if (LayerDescriptor.ConverterCapacities.IsSuffixOf(key)) return true;
+      if (LayerDescriptor.RelativeCostAtSource.IsSuffixOf(key)) return true;
+      return false;
+    }
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    private BioBoostCompoundSolution(bool isDeserializing) : base(isDeserializing) { }
+    private BioBoostCompoundSolution(BioBoostCompoundSolution orig, Cloner cloner, bool full = true)
+      : base(orig, cloner) {
+      problemDataRef = orig.problemDataRef; // doesn't re-evaluate the solution
+      Geometry = orig.Geometry;
+      Quality = orig.Quality;
+      Qualities = (DoubleArray)orig.Qualities.Clone();
+      IntValues = orig.IntValues.ToDictionary(kvp => kvp.Key, kvp => (IntArray)kvp.Value.Clone());
+      if (full) {
+        DoubleValues = orig.DoubleValues.ToDictionary(kvp => kvp.Key, kvp => (DoubleArray)kvp.Value.Clone());
+        StringValues = orig.StringValues.ToDictionary(kvp => kvp.Key, kvp => (StringArray)kvp.Value.Clone());
+        if (orig.TransportTargets != null)
+          TransportTargets = orig.TransportTargets.ToDictionary(kvp => kvp.Key, kvp => (ItemArray<ItemList<IntValue>>)kvp.Value.Clone());
+      } else {
+        DoubleValues = orig.DoubleValues.Where(kvp => IsSlimKey(kvp.Key)).ToDictionary(kvp => kvp.Key, kvp => (DoubleArray)kvp.Value.Clone());
+        StringValues = new Dictionary<string, StringArray>();
+        if (orig.TransportTargets != null)
+          TransportTargets = new Dictionary<string, ItemArray<ItemList<IntValue>>>();
+      }
+    }
+    private BioBoostCompoundSolution() {
+      Parameters.Add(new ValueParameter<StringArray>("LocationNames", "The names of the different locations."));
+      Parameters.Add(new FixedValueParameter<DoubleValue>("Quality", "The quality of the solution as produced by the evaluator.", new DoubleValue()));
+      Parameters.Add(new ValueParameter<DoubleArray>("Qualities", "The quality criteria of the solution as produced by the evaluator.", new DoubleArray()));
+      IntValues = new Dictionary<string, IntArray>();
+      DoubleValues = new Dictionary<string, DoubleArray>();
+      StringValues = new Dictionary<string, StringArray>();
+      TransportTargets = new Dictionary<string, ItemArray<ItemList<IntValue>>>();
+    }
+
+
+    private bool TryAddValue(IScope scope, string valueName) {
+      IVariable var;
+      if (!scope.Variables.TryGetValue(valueName, out var))
+        return false;
+      var doubleArray = var.Value as DoubleArray;
+      if (doubleArray != null && !DoubleValues.ContainsKey(valueName)) {
+        DoubleValues.Add(valueName, (DoubleArray)doubleArray.Clone());
+        return true;
+      }
+      var intArray = var.Value as IntArray;
+      if (intArray != null && !IntValues.ContainsKey(valueName)) {
+        IntValues.Add(valueName, (IntArray)intArray.Clone());
+        return true;
+      }
+      var stringArray = var.Value as StringArray;
+      if (stringArray != null && !StringValues.ContainsKey(valueName)) {
+        StringValues.Add(valueName, (StringArray)stringArray.Clone());
+        return true;
+      }
+      var itemArray = var.Value as ItemArray<ItemList<IntValue>>;
+      if (itemArray != null && !TransportTargets.ContainsKey(valueName)) {
+        TransportTargets.Add(valueName, (ItemArray<ItemList<IntValue>>)itemArray.Clone());
+      }
+      return false;
+    }
+
+    private bool TryAddValue(BioBoostProblemData problemData, string valueName) {
+      IParameter param;
+      if (problemData.FeedstockPotentials.TryGetValue(valueName, out param)) {
+        var valueParam = param as IValueParameter;
+        if (valueParam != null) {
+          var doubleArray = valueParam.Value as DoubleArray;
+          if (doubleArray != null && !DoubleValues.ContainsKey(valueName)) {
+            DoubleValues.Add(valueName, (DoubleArray)doubleArray.Clone());
+            return true;
+          }
+          var intArray = valueParam.Value as IntArray;
+          if (intArray != null && !IntValues.ContainsKey(valueName)) {
+            IntValues.Add(valueName, (IntArray)intArray.Clone());
+            return true;
+          }
+          var stringArray = valueParam.Value as StringArray;
+          if (stringArray != null && !StringValues.ContainsKey(valueName)) {
+            StringValues.Add(valueName, (StringArray)stringArray.Clone());
+            return true;
+          }
+          var itemArray = valueParam.Value as ItemArray<ItemList<IntValue>>;
+          if (itemArray != null && !TransportTargets.ContainsKey(valueName)) {
+            TransportTargets.Add(valueName, (ItemArray<ItemList<IntValue>>)itemArray.Clone());
+            return true;
+          }
+        }
+      }
+      return false;
+    }
+
+    public BioBoostCompoundSolution(IScope scope, BioBoostProblemData problemData)
+      : this() {
+      this.problemDataRef = problemData; // not cloned on purpose
+      Geometry = problemData.Geometry; // TODO: maybe clone geometry once?
+      LocationNames = (StringArray)problemData.LocationNames.Clone();
+      IVariable qualityVariable;
+      // TotalCost is the quality produced by the aggregate evaluator
+      if (scope.Variables.TryGetValue("TotalCost", out qualityVariable)) {
+        Quality = ((DoubleValue)qualityVariable.Value).Value; // TODO: should be read only
+      } else if (scope.Variables.TryGetValue("Quality", out qualityVariable)) {
+        Quality = ((DoubleValue)qualityVariable.Value).Value; // TODO: should be read only
+      }
+      if (scope.Variables.TryGetValue("QualityCriteria", out qualityVariable)) {
+        Qualities = (DoubleArray)qualityVariable.Value.Clone(); // TODO: should be read only
+      }
+      var isUpgradedSolution = scope.Variables.Any(v => v.Name.Contains(LayerDescriptor.AmountsAtSource.FullName));
+      foreach (var p in problemData.Products) {
+        if (!isUpgradedSolution) {
+          if (TryAddValue(scope, LayerDescriptor.TransportTargets.NameWithPrefix(p.Label)))
+            TryAddValue(scope, LayerDescriptor.Utilizations.NameWithPrefix(p.Label));
+        } else {
+          TryAddValue(problemData, LayerDescriptor.PotentialsFromProblemData.NameWithPrefix(p.Label));
+          TryAddValue(scope, p.Label); // emissions
+          foreach (var layer in LayerDescriptor.Layers) { TryAddValue(scope, layer.NameWithPrefix(p.Label)); }
+        }
+      }
+      if (isUpgradedSolution)
+        foreach (var layer in LayerDescriptor.Layers) { TryAddValue(scope, layer.Name); }
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new BioBoostCompoundSolution(this, cloner);
+    }
+    public BioBoostCompoundSolution SlimClone() {
+      return new BioBoostCompoundSolution(this, new Cloner(), false);
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (StringValues == null)
+        StringValues = new Dictionary<string, StringArray>();
+      // backwards compatibility
+      if (!Parameters.ContainsKey("Quality"))
+        Parameters.Add(new FixedValueParameter<DoubleValue>("Quality", new DoubleValue(double.NaN))); // TODO: use different quality value to indicate that the value is not known?
+      if (!Parameters.ContainsKey("Qualities"))
+        Parameters.Add(new ValueParameter<DoubleArray>("Qualities", "The quality criteria of the solution as produced by the evaluator.", new DoubleArray()));
+    }
+    #endregion
+
+    public void UpdateTo(BioBoostCompoundSolution bestSolution) {
+      if (LocationNames.SequenceEqual(bestSolution.LocationNames)) { // TODO: replace with comparison of problem reference
+        Quality = bestSolution.Quality;
+        Qualities = (DoubleArray)bestSolution.Qualities.Clone();
+        IntValues = bestSolution.IntValues.ToDictionary(kvp => kvp.Key, kvp => (IntArray)kvp.Value.Clone());
+        DoubleValues = bestSolution.DoubleValues.ToDictionary(kvp => kvp.Key, kvp => (DoubleArray)kvp.Value.Clone());
+        StringValues = bestSolution.StringValues.ToDictionary(kvp => kvp.Key, kvp => (StringArray)kvp.Value.Clone());
+        TransportTargets = bestSolution.TransportTargets.ToDictionary(kvp => kvp.Key, kvp => (ItemArray<ItemList<IntValue>>)kvp.Value.Clone());
+        OnSolutionChanged();
+      } else {
+        throw new ArgumentException("Invalid solution update, proposed solution has different problem instance.");
+      }
+    }
+
+    public static DoubleArray FindAmountsTransportedFromSource(IEnumerable<KeyValuePair<string, DoubleArray>> dict, string productName) {
+      if (LayerDescriptor.TransportTargets.IsSuffixOf(productName))
+        productName = LayerDescriptor.TransportTargets.RemoveSuffixFrom(productName);
+      foreach (var kvp in dict) {
+        if (LayerDescriptor.AmountsTransportedFromSource.IsSuffixOf(kvp.Key) &&
+          LayerDescriptor.AmountsTransportedFromSource.RemoveSuffixFrom(kvp.Key) == productName)
+          return kvp.Value;
+      }
+      return null;
+    }
+
+    #region convenience methods for retrieving values
+
+    public double TotalFeedstockCosts {
+      get {
+        // first get the list of feedstock (all products which are utilized)
+        var feedStockLabels =
+          DoubleValues.Keys
+            .Where(k => LayerDescriptor.Utilizations.IsSuffixOf(k))
+            .Select(k => LayerDescriptor.Utilizations.RemoveSuffixFrom(k));
+
+        return feedStockLabels
+          .Select(feedstock => DoubleValues[LayerDescriptor.TotalCostsAtSource.NameWithPrefix(feedstock)].Sum()) // sum over regions           
+          .Sum(); // sum over feedstock
+      }
+    }
+
+    public double TotalTransportCosts {
+      get {
+        // here we add transport and handling costs
+        // keys for all transport costs end with BioBoostProblem.TransportCostsName 
+        // keys for all handling costs end with BioBoostProblem.HandlingCostsName 
+        return DoubleValues
+          .Where(kvp => LayerDescriptor.TransportCosts.IsSuffixOf(kvp.Key) || LayerDescriptor.HandlingCosts.IsSuffixOf(kvp.Key))
+          .Select(kvp => kvp.Value.Sum()) // sum over all regions
+          .Sum(); // sum over all products
+      }
+    }
+
+    public double TotalCosts {
+      get {
+        // we add all costs (including all revenues from selling products)
+        // assumes that revenues are also labeled as costs!
+        return DoubleValues
+          .Where(kvp => kvp.Key.EndsWith("Cost") || kvp.Key.EndsWith("Costs"))
+          .Sum(kvp => kvp.Value.Where(v => v > 0).Sum());  // sum over products and regions
+      }
+    }
+
+    public double TotalTransportFuelAmount {
+      get {
+        // assumes that the values are stored as  "TransportFuel" + BioBoostProblem.AmountsAtSourceName
+        return DoubleValues
+          .Where(kvp => kvp.Key == LayerDescriptor.AmountsAtSource.NameWithPrefix("TransportFuel"))
+          .Sum(kvp => kvp.Value.Sum());
+      }
+    }
+
+    public IEnumerable<TransportInfo> Transports {
+      get {
+        foreach (var pair in TransportVectors) {
+          var prod = pair.Item1;
+          var modes = StringValues[LayerDescriptor.TransportModes.NameWithPrefix(prod)];
+          var distances = DoubleValues[LayerDescriptor.TransportDistance.NameWithPrefix(prod)];
+          var amounts = DoubleValues[LayerDescriptor.AmountsTransportedFromSource.NameWithPrefix(prod)];
+          for (int srcIdx = 0; srcIdx < pair.Item2.Length; srcIdx++) {
+            var destIdx = pair.Item2[srcIdx];
+            if (destIdx == -1) continue;
+            var info = new TransportInfo {
+              Product = prod,
+              SrcRegionIdx = srcIdx,
+              DestRegionIdx = destIdx,
+              SrcRegion = LocationNames[srcIdx],
+              DestRegion = LocationNames[destIdx],
+              Mode = modes[srcIdx],
+              Distance = distances[srcIdx],
+              Amount = amounts[srcIdx]
+            };
+            yield return info;
+          }
+        }
+      }
+    }
+
+    public IEnumerable<Tuple<string, int[]>> TransportVectors {
+      get {
+        // here we yield one tuple for each product containing the product name and transport target map
+        // we know transport targets are int-arrays and the key ends with 'BioBoostProblem.TransportTargetsName'
+        foreach (var p in IntValues.Where(p => LayerDescriptor.TransportTargets.IsSuffixOf(p.Key))) {
+          var productLabel = LayerDescriptor.TransportTargets.RemoveSuffixFrom(p.Key);
+          yield return Tuple.Create(productLabel, p.Value.ToArray());
+        }
+      }
+    }
+
+    public IEnumerable<Tuple<string, double[]>> UtilizationVectors {
+      get {
+        // here we yield one tuple for each feedstock containing the feedstock name and the utilization factor
+        // we know feedstock utilizations are double-arrays and the key ends with 'BioBoostProblem.UtilizationsName'
+        foreach (var p in DoubleValues.Where(p => LayerDescriptor.Utilizations.IsSuffixOf(p.Key))) {
+          var productLabel = LayerDescriptor.Utilizations.RemoveSuffixFrom(p.Key);
+          yield return Tuple.Create(productLabel, p.Value.ToArray());
+        }
+      }
+    }
+
+    public double GetUtilization(string feedstock, string currentRegion) {
+      return DoubleValues[LayerDescriptor.Utilizations.NameWithPrefix(feedstock)][IndexOfLoc(currentRegion)];
+    }
+
+    public void SetUtilization(string feedstock, string currentRegion, double newUtil) {
+      SetUtilization(feedstock, IndexOfLoc(currentRegion), newUtil);
+    }
+    public void SetUtilization(string feedstock, int regionIdx, double newUtil) {
+      DoubleValues[LayerDescriptor.Utilizations.NameWithPrefix(feedstock)][regionIdx] = newUtil;
+      EvaluateAndUpdateAllResults();
+    }
+
+    public void SetTransport(string product, int srcIdx, int destIdx) {
+      IntValues[LayerDescriptor.TransportTargets.NameWithPrefix(product)][srcIdx] = destIdx;
+      EvaluateAndUpdateAllResults();
+    }
+    public void SetTransport(string product, string srcNuts, string destNuts) {
+      SetTransport(product, IndexOfLoc(srcNuts), IndexOfLoc(destNuts));
+    }
+
+    public void EvaluateAndUpdateAllResults() {
+      if (problemDataRef == null) {
+        // for old persisted problems
+        throw new NotSupportedException("The problem data has not been set for this solution. Editing and re-evaluation is not possible");
+      }
+      var evalScope = AggregateEvaluator.Evaluate(
+        problemDataRef,
+        DoubleValues.Where(kvp => LayerDescriptor.Utilizations.IsSuffixOf(kvp.Key)),
+        IntValues.Where(kvp => LayerDescriptor.TransportTargets.IsSuffixOf(kvp.Key))
+        );
+
+      var newSolution = new BioBoostCompoundSolution(evalScope, problemDataRef);
+      this.UpdateTo(newSolution);
+    }
+
+    private int IndexOfLoc(string locationName) {
+      for (int i = 0; i < LocationNames.Length; i++) {
+        if (LocationNames[i] == locationName) return i;
+      }
+      return -1;
+    }
+    #endregion
+
+    public override void CollectParameterValues(IDictionary<string, IItem> values) {
+      base.CollectParameterValues(values);
+
+      // also produce additional values (virtual parameters) for most important results
+      foreach (var kvp in DoubleValues) {
+        var vFiltered = kvp.Value.Where(x => x > 0);
+        if (!vFiltered.Any()) continue;
+
+        if (kvp.Key.Contains("Relative") || kvp.Key.Contains("Capacities")) {
+          values.Add(kvp.Key + " (min)", new DoubleValue(vFiltered.Min()));
+          values.Add(kvp.Key + " (max)", new DoubleValue(vFiltered.Max()));
+          values.Add(kvp.Key + " (avg)", new DoubleValue(vFiltered.Average()));
+        } else if (kvp.Key.Contains("Utilization")) {
+          values.Add(kvp.Key + " (count)", new DoubleValue(vFiltered.Count())); // |{u | u > 0}|
+          values.Add(kvp.Key + " (avg)", new DoubleValue(vFiltered.Average()));
+        } else if (!kvp.Key.Contains("Potentials")) {
+          values.Add(kvp.Key + " (sum)", new DoubleValue(kvp.Value.Sum()));
+          values.Add(kvp.Key + " (count)", new DoubleValue(vFiltered.Count()));
+          values.Add(kvp.Key + " (min)", new DoubleValue(vFiltered.Min()));
+          values.Add(kvp.Key + " (max)", new DoubleValue(vFiltered.Max()));
+          values.Add(kvp.Key + " (avg)", new DoubleValue(vFiltered.Average()));
+        }
+      }
+
+      var finalProductNames = DoubleValues.Keys.Where(k => LayerDescriptor.AmountsAtSource.IsSuffixOf(k))
+        .Select(k => LayerDescriptor.AmountsAtSource.RemoveSuffixFrom(k));
+      finalProductNames = finalProductNames
+        .Where(k => DoubleValues.ContainsKey(LayerDescriptor.DischargeCosts.NameWithPrefix(k)) &&
+                    DoubleValues[LayerDescriptor.DischargeCosts.NameWithPrefix(k)].Sum() < 0);
+
+      foreach (var finalProductName in finalProductNames) {
+        var costs = DoubleValues
+          .Where(kvp => !kvp.Key.StartsWith(finalProductName))
+          .Where(kvp => kvp.Key.EndsWith("Costs") || kvp.Key.EndsWith("Cost"))
+          .Select(kvp => kvp.Value.Sum())
+          .Sum();
+
+        var amount = DoubleValues[LayerDescriptor.AmountsAtSource.NameWithPrefix(finalProductName)].Sum();
+
+        values.Add(finalProductName + " net cost [€/a]", new DoubleValue(costs));
+        values.Add(finalProductName + " net cost [€/t]", new DoubleValue(costs / amount));
+      }
+    }
+
+
+    public double PerformPostProcessing(TextWriter logger = null) {
+      // DeletePenalizedFeedstockTransportsUtilizations();
+      // DeletePlantsWithScalingFactorBelow(0.8, feedstockName);
+      // DeletePlantsWithScalingFactorBelow(0.8, intermediateName);
+      // DeleteEmptyPlants(intermediateName); // maybe this is covered by previous functions?
+      string feedstockName = null, intermediateName = null;
+      IDictionary<int, int[]> decentralPlantSources = null, centralPlantSources = null;
+      foreach (var transportTargets in IntValues.Where(kvp => LayerDescriptor.TransportTargets.IsSuffixOf(kvp.Key))) {
+        var name = LayerDescriptor.TransportTargets.RemoveSuffixFrom(transportTargets.Key);
+        var utilizationLayerName = LayerDescriptor.Utilizations.NameWithPrefix(name);
+        var utilizationsKvp = DoubleValues.FirstOrDefault(kvp => kvp.Key == utilizationLayerName);
+        if (utilizationsKvp.Key != null) {
+          feedstockName = name;
+          decentralPlantSources = transportTargets.Value.SourceIndices();
+        } else {
+          intermediateName = name;
+          centralPlantSources = transportTargets.Value.SourceIndices();
+        }
+      }
+      if (feedstockName == null || intermediateName == null || decentralPlantSources == null ||
+          centralPlantSources == null)
+        throw new Exception("Post Processing Failed");
+
+      var utilizations =
+        DoubleValues.First(kvp => kvp.Key == LayerDescriptor.Utilizations.NameWithPrefix(feedstockName)).Value;
+      var feedstockUsageBefore =
+        utilizations.Zip(
+          (DoubleArray)((IValueParameter)problemDataRef.FeedstockPotentials[feedstockName + "Potentials"]).Value,
+          (u, p) => u * p).Sum();
+
+      // remove penalized transports
+      var feedstockTransportPenaltyLayer =
+        DoubleValues.First(
+          kvp => kvp.Key == LayerDescriptor.ExceedingTransportDistancePenalty.NameWithPrefix(feedstockName)).Value;
+      var removableSuppliers = feedstockTransportPenaltyLayer
+        .Select((penalty, idx) => new { penalty, idx })
+        .Where(pi => pi.penalty > 0)
+        .Select(pi => new List<int> { pi.idx }).ToList();
+
+      // remove undersize central plants
+      var centralConversion = ProblemDataReference.Conversions[feedstockName].First();
+      var minCentralScalingFactor = centralConversion.MinCapacity / centralConversion.DesignCapacity;
+      var centralScalingFactors =
+        DoubleValues.First(kvp => kvp.Key == LayerDescriptor.ScalingFactors.NameWithPrefix(intermediateName)).Value;
+      removableSuppliers.AddRange(centralScalingFactors
+        .Select((factor, idx) => new { factor, idx })
+        .Where(fi => fi.factor < minCentralScalingFactor)
+        .Select(fi => GetSuppliers(new[] { centralPlantSources, decentralPlantSources }, fi.idx).ToList())
+        .Where(l => l.Count > 0));
+
+      // remove undersize decentral plants
+      var decentralConversion = ProblemDataReference.Conversions[intermediateName].First();
+      var minDeCentralScalingFactor = decentralConversion.MinCapacity / decentralConversion.DesignCapacity;
+      var decentralScalingFactors =
+        DoubleValues.First(kvp => kvp.Key == LayerDescriptor.ScalingFactors.NameWithPrefix(feedstockName)).Value;
+      removableSuppliers.AddRange(decentralScalingFactors
+        .Select((factor, idx) => new { factor, idx })
+        .Where(fi => fi.factor < minDeCentralScalingFactor)
+        .Select(fi => GetSuppliers(new[] { decentralPlantSources }, fi.idx).ToList())
+        .Where(l => l.Count > 0));
+
+      EvaluateAndUpdateAllResults();
+      if (logger != null) logger.Write("Pruning plants (q={0})...", Quality);
+      int successes = 0;
+      int k = 0, lastK = 0;
+      foreach (var variant in removableSuppliers) {
+        var oldUtilizations = (DoubleArray)utilizations.Clone();
+        var oldQuality = Quality;
+        foreach (int j in variant) utilizations[j] = 0;
+        DoubleValues.Remove(LayerDescriptor.Utilizations.NameWithPrefix(feedstockName));
+        DoubleValues.Add(LayerDescriptor.Utilizations.NameWithPrefix(feedstockName), utilizations);
+        EvaluateAndUpdateAllResults();
+        if (Quality < oldQuality) {
+          for (int i = 0; i < utilizations.Length; i++) utilizations[i] = oldUtilizations[i];
+          DoubleValues.Remove(LayerDescriptor.Utilizations.NameWithPrefix(feedstockName));
+          DoubleValues.Add(LayerDescriptor.Utilizations.NameWithPrefix(feedstockName), utilizations);
+        } else {
+          successes++;
+        }
+        if (k++ > lastK + removableSuppliers.Count / 20 && logger != null) {
+          logger.Write("{0}%...", k * 100 / removableSuppliers.Count);
+          lastK = k;
+        }
+      }
+      EvaluateAndUpdateAllResults();
+      if (logger != null) logger.WriteLine("... pruned {0} of {1} variants (q={2})", successes, removableSuppliers.Count, Quality);
+
+      var feedstockUsageAfter =
+        utilizations.Zip((DoubleArray)((IValueParameter)problemDataRef.FeedstockPotentials[feedstockName + "Potentials"]).Value,
+          (u, p) => u * p).Sum();
+      var utilizationFactor = feedstockUsageAfter / feedstockUsageBefore;
+      return utilizationFactor;
+    }
+
+    public static IEnumerable<int> GetSuppliers(IEnumerable<IDictionary<int, int[]>> suppliers, int i) {
+      var lists = suppliers.ToList();
+      switch (lists.Count) {
+        case 0: {
+            yield break;
+          }
+        case 1: {
+            foreach (var j in lists[0].ElementAtOrDefault(i, new int[0]))
+              yield return j;
+            break;
+          }
+        default: {
+            foreach (
+              var x in lists[0].ApplyAt(i,
+                  v => v.Select(j => GetSuppliers(lists.Skip(1), j))
+                        .Aggregate(Enumerable.Empty<int>(), (l1, l2) => l1.Concat(l2)),
+                  () => new int[0]))
+              yield return x;
+            break;
+          }
+      }
+    }
+
+    #region unused
+    public void CreateJsonSolution() {
+      var builder = new StringBuilder();
+      builder.Append("{ \"type\": \"FeatureCollection\", \n\"features\": [");
+      for (int i = 0; i < LocationNames.Length; i++) {
+        if (i > 0) builder.Append(",");
+        builder.Append("\n{ \"type\": \"Feature\", \"properties\": { \"NUTS_ID\": \"");
+        builder.Append(LocationNames[i]);
+        builder.Append("\"");
+        foreach (var kvp in IntValues) {
+          var target = LocationNames[i];
+          if (kvp.Value[i] >= 0) {
+            target = LocationNames[kvp.Value[i]];
+          }
+          builder.Append(",\n                                     \"");
+          builder.Append(kvp.Key);
+          builder.Append("\": \"");
+          builder.Append(target);
+          builder.Append("\"");
+        }
+        foreach (var kvp in DoubleValues) {
+          builder.Append(",\n                                     \"");
+          builder.Append(kvp.Key);
+          builder.Append("\": ");
+          builder.Append(kvp.Value[i].ToString("R", CultureInfo.InvariantCulture));
+        }
+        builder.Append("} }");
+      }
+      builder.Append("\n]\n}");
+
+      File.WriteAllText(@"c:\temp\test.json", builder.ToString());
+    }
+    #endregion
+
+    public string Filename { get; set; }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Representation/LayerDescriptor.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Representation/LayerDescriptor.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Representation/LayerDescriptor.cs	(revision 15711)
@@ -0,0 +1,206 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Reflection;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.BioBoost.Representation {
+
+  public interface ILayerDescriptor : IItem {
+    string Name { get; }
+    string Unit { get; }
+    string Description { get; }
+    string Separator { get; }
+    string FullName { get; }
+  }
+
+  public interface IValueLayer {
+    LayerDescriptor LayerDescriptor { get; }
+    double this[int idx] { get; set; }
+  }
+
+  public interface IAggregator {
+    IEnumerable<IValueLayer> Aggregate(IEnumerable<IValueLayer> layers, ItemArray<ItemList<IntValue>> sources);
+  }
+
+  public class SumAggregator : IAggregator {
+    public ILayerDescriptor TargetLayerDescriptor { get; private set; }
+    public SumAggregator(ILayerDescriptor descriptor) { TargetLayerDescriptor = descriptor; }
+    public IEnumerable<IValueLayer> Aggregate(IEnumerable<IValueLayer> layers, ItemArray<ItemList<IntValue>> sources) {
+      foreach (var layer in layers) {
+        if (layer.LayerDescriptor == TargetLayerDescriptor) {
+          //yield return 
+        }
+      }
+      yield break;
+    }
+  }
+
+  [StorableClass(StorableClassType.AllFieldsAndAllProperties)]
+  public class LayerDescriptor : Item, ILayerDescriptor {
+
+    public string Name  { get; private set; }
+    public string Unit { get; private set; }
+    public string Description { get; private set; }
+    public string Separator { get; private set; }
+    public string FullName { get; private set; }
+
+    protected LayerDescriptor(bool isDeserializing) : base(isDeserializing) { }
+    protected LayerDescriptor(LayerDescriptor orig, Cloner cloner) : base(orig, cloner) { }
+
+    public LayerDescriptor(string name, string unit, string separator = " ") {
+      Name = name;
+      Unit = unit;
+      Separator = separator;
+      FullName = separator + name;
+    }
+
+    public string NameWithPrefix(string prefix) { return string.Format("{0}{1}", prefix, FullName); }
+    public bool IsSuffixOf(string s) { return s.EndsWith(FullName); }
+    public string RemoveSuffixFrom(string s) {
+      if (!s.EndsWith(FullName)) return s;
+      return s.Substring(0, s.Length - FullName.Length);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) { return new LayerDescriptor(this, cloner); }
+
+    public static LayerDescriptor AmountsAtSource = new LayerDescriptor("amounts at source", "t/a");
+    public static LayerDescriptor AmountsAtTarget = new LayerDescriptor("amounts at target", "t/a");
+    public static LayerDescriptor AmountsTransportedFromSource = new LayerDescriptor("amounts transported from source", "t/a");
+    public static LayerDescriptor PotentialsFromProblemData = new LayerDescriptor("Potentials", "t/a", "");
+    public static LayerDescriptor Utilizations = new LayerDescriptor("Utilizations", "");
+    public static LayerDescriptor UtilizationsEffective = new LayerDescriptor("utilizations (effective)", "");
+    public static LayerDescriptor TransportTargets = new LayerDescriptor("Transport Targets", "region");
+    public static LayerDescriptor ConverterCapacities = new LayerDescriptor("converter capacities", "t/a");
+    public static LayerDescriptor StorageCapacities = new LayerDescriptor("storage capacities", "t/a");
+    public static LayerDescriptor AcquisitionCosts = new LayerDescriptor("acquisition costs", "€/a");
+    public static LayerDescriptor DischargeCosts = new LayerDescriptor("discharge costs", "€/a");
+    public static LayerDescriptor TransportCosts = new LayerDescriptor("transport costs", "€/a");
+    public static LayerDescriptor TransportCostsPerT = new LayerDescriptor("transport costs (per t)", "€/t");
+    public static LayerDescriptor TransportCostsPerTkm = new LayerDescriptor("transport costs (per tkm)", "€/tkm");
+    public static LayerDescriptor HandlingCosts = new LayerDescriptor("handling costs", "€/a");
+    public static LayerDescriptor RelativeHandlingCosts = new LayerDescriptor("handling costs (relative)", "€/t");
+    public static LayerDescriptor TransportModes = new LayerDescriptor("transport modes", "mode");
+    public static LayerDescriptor ConversionCosts = new LayerDescriptor("conversion costs", "€/a");
+    public static LayerDescriptor TotalAmortizedConversionCosts = new LayerDescriptor("total amortized conversion costs (incl. OPEX, CAPEX)", "€/a");
+    public static LayerDescriptor RelativeTotalAmortizedConversionCosts = new LayerDescriptor("total amortized conversion costs (incl. OPEX, CAPEX, relative)", "€/t");
+    public static LayerDescriptor ConversionPlantConstructionCost = new LayerDescriptor("conversion plant construction costs", "€/a");
+    public static LayerDescriptor ConversionPlantOperationCost = new LayerDescriptor("conversion plant operation costs", "€/a");
+    public static LayerDescriptor RelativeConversionCosts = new LayerDescriptor("conversion costs (relative)", "€/t");
+    public static LayerDescriptor RelativeConversionPlantConstructionCosts = new LayerDescriptor("conversion plant construction costs (relative)", "€/t");
+    public static LayerDescriptor RelativeConversionPlantOperationCosts = new LayerDescriptor("conversion plant operation costs (relative)", "€/t");
+    public static LayerDescriptor StorageCost = new LayerDescriptor("storage costs", "€/a");
+    public static LayerDescriptor RelativeStorageCost = new LayerDescriptor("storage costs (relative)", "€/t");
+    public static LayerDescriptor TransportDistance = new LayerDescriptor("transport distances", "km");
+    public static LayerDescriptor ExceedingTransportDistancePenalty = new LayerDescriptor("transport penalties", "");
+    public static LayerDescriptor Tkm = new LayerDescriptor("tkm", "tkm");
+    public static LayerDescriptor MaxConversionCapacity = new LayerDescriptor("converter capacities (max)", "t/a");
+    public static LayerDescriptor ScalingPenalty = new LayerDescriptor("converter scaling penalties", "");
+    public static LayerDescriptor TotalCostsAtTarget = new LayerDescriptor("total costs at target", "€/a");
+    public static LayerDescriptor TotalCostsAtSource = new LayerDescriptor("total costs at source", "€/a");
+    public static LayerDescriptor LocalAddedValue = new LayerDescriptor("local added value", "€/a", "");
+    public static LayerDescriptor RelativeCostAtSource = new LayerDescriptor("total costs at source (relative)", "€/t");
+    public static LayerDescriptor RelativeCostAtTarget = new LayerDescriptor("total costs at target (relative)", "€/t");
+    public static LayerDescriptor AmountsAtTargetConverted = new LayerDescriptor("amounts converted at target", "t/a");
+    public static LayerDescriptor TotalLogisticCosts = new LayerDescriptor("logistics costs", "€/a");
+    public static LayerDescriptor LogisticCostsPerTon = new LayerDescriptor("logistics costs (per t)", "€/t");
+    public static LayerDescriptor LogisticCostsPerTonKm = new LayerDescriptor("logistics costs (per tkm)", "€/tkm");
+    public static LayerDescriptor TotalDirectConversionCost = new LayerDescriptor("conversion costs (incl. supplies)", "€/a");
+    public static LayerDescriptor RelativeTotalDirectConversionCost = new LayerDescriptor("conversion costs (incl. supplies, relative)", "€/t");
+    public static LayerDescriptor TotalPenalty = new LayerDescriptor("total penalties", "", "");
+    public static LayerDescriptor Sources = new LayerDescriptor("conversion plant sources", "");
+    public static LayerDescriptor ScalingFactors = new LayerDescriptor("conversion plant scaling factors", "");
+    public static LayerDescriptor ExceedingCapacityPenalties = new LayerDescriptor("exceeding capacity penalties", "");
+
+    //public static LayerDescriptor AverageUtilizations = new LayerDescriptor("average utilizations", "t/a");
+    //public static LayerDescriptor AverageAmountsFromSource = new LayerDescriptor("average amounts from source", "t/a");
+    //public static LayerDescriptor AggregateAmountsFromSource = new LayerDescriptor("aggregate amounts from source", "t/a");
+    //public static LayerDescriptor AverageCostsFromSource = new LayerDescriptor("average costs from source", "t/a");
+    //public static LayerDescriptor AggregateCostsFromSource = new LayerDescriptor("aggregate costs from source", "t/a");
+
+    public static LayerDescriptor FeedstockCosts = new LayerDescriptor("feedstock costs", "€/a");
+    public static LayerDescriptor FeedstockCostsRelative = new LayerDescriptor("feedstock costs (relative)", "€/t");
+    //public static LayerDescriptor AggregatedAverageFeedstockCosts = new LayerDescriptor("aggregated average feedstock costs", "€/a");
+    //public static LayerDescriptor AggregatedFeedstockTransportCosts = new LayerDescriptor("aggregated feedstock transport costs", "€/a");
+    //public static LayerDescriptor RelativeAggregatedFeedstockTransportCosts = new LayerDescriptor("aggregated feedstock transport costs (relative)", "€/t");
+    //public static LayerDescriptor AggregatedFeedstockHandlingCosts = new LayerDescriptor("aggregated feedstock handling costs", "€/a");
+    //public static LayerDescriptor RelativeAggregatedFeedstockHandlingCosts = new LayerDescriptor("aggregated feedstock handling costs (relative)", "€/t");
+    //public static LayerDescriptor AggregatedFeedstockStorageCosts = new LayerDescriptor("aggregated feedstock storage costs", "€/a");
+    //public static LayerDescriptor RelativeAggregatedFeedstockStorageCosts = new LayerDescriptor("aggregated feedstock storage costs (relative)", "€/t");
+    public static LayerDescriptor DecentralLogisticCosts = new LayerDescriptor("logistic costs (decentral aggregated)", "€/a");
+    public static LayerDescriptor DecentralLogisticCostsRelative = new LayerDescriptor("logistic costs (decentral aggregated, relative)", "€/t");
+    //public static LayerDescriptor AggregatedDirectConversionCosts = new LayerDescriptor("aggregated direct conversion costs", "€/a");
+    //public static LayerDescriptor RelativeAggregatedDirectConversionCosts = new LayerDescriptor("aggregated direct conversion costs (relative)", "€/t");
+    //public static LayerDescriptor AggregatedConversionOperationCosts = new LayerDescriptor("aggregated conversion operation costs", "€/a");
+    //public static LayerDescriptor RelativeAggregatedConversionOperationCosts = new LayerDescriptor("aggregated conversion operation costs (relative)", "€/t");
+    //public static LayerDescriptor AggregatedConversionConstructionCosts = new LayerDescriptor("aggregated conversion construction costs", "€/a");
+    //public static LayerDescriptor RelativeAggregatedConversionConstructionCosts = new LayerDescriptor("aggregated conversion construction costs (relative)", "€/t");
+    public static LayerDescriptor DecentralConversionCosts = new LayerDescriptor("conversion costs (decentral aggregated)", "€/a");
+    public static LayerDescriptor DecentralConversionCostsRelative = new LayerDescriptor("conversion costs (decentral aggregated, relative)", "€/t");
+    public static LayerDescriptor CentralConversionCostsRelative = new LayerDescriptor("conversion costs (central aggregated, relative)", "€/t");
+    // ...
+    public static LayerDescriptor CentralLogisticCosts = new LayerDescriptor("logistic costs (central aggregated)", "€/a");
+    public static LayerDescriptor CentralLogisticCostsRelative = new LayerDescriptor("logistic costs (central aggregated, relative)", "€/t");
+
+    public static LayerDescriptor RoiFollowed = new LayerDescriptor("roi (followed)", "€/€");
+    public static LayerDescriptor RoiAggregated = new LayerDescriptor("roi (aggregated)", "€/€");
+
+
+
+    private static readonly List<LayerDescriptor> LAYERS = new List<LayerDescriptor>();
+
+    private static void DiscoverLayers() {
+        if (LAYERS.Count == 0) {
+          LAYERS.AddRange(
+            typeof (LayerDescriptor)
+              .GetFields(BindingFlags.Static | BindingFlags.Public)
+              .Select(f => f.GetValue(null))
+              .Where(v => v is LayerDescriptor)
+              .Cast<LayerDescriptor>()
+              .OrderByDescending(l => l.Name.Length));
+          foreach (var l1 in LAYERS) {
+            foreach (var l2 in LAYERS) {
+              if (l1 != l2 && l1.IsSuffixOf(l2.FullName))
+                throw new InvalidOperationException(string.Format("Layer overlap detected \"{0}\" is suffix of \"{1}\"", l1.FullName, l2.FullName));
+            }
+          }
+        }
+    }
+
+    public static IEnumerable<LayerDescriptor> Layers {
+      get {  DiscoverLayers(); return LAYERS; }
+    }
+
+    public static LayerDescriptor GetLayer(string fullName) {
+      DiscoverLayers();
+      foreach (var layer in LAYERS) {
+        if (layer.IsSuffixOf(fullName)) return layer;
+      }
+      return null;
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/SolutionCreation/BioBoostSolutionCreator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/SolutionCreation/BioBoostSolutionCreator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/SolutionCreation/BioBoostSolutionCreator.cs	(revision 15711)
@@ -0,0 +1,123 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.BioBoost.ProblemDescription;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.PluginInfrastructure;
+using System.Linq;
+using HeuristicLab.BioBoost.Representation;
+
+namespace HeuristicLab.BioBoost.SolutionCreation {
+
+  [StorableClass]
+  public class BioBoostSolutionCreator : SingleSuccessorOperator, ISolutionCreator {
+
+    #region Parameters
+    public ValueLookupParameter<IntMatrix> RegionBoundsParameter {
+      get { return (ValueLookupParameter<IntMatrix>) Parameters["RegionBounds"]; }
+    } 
+    public ValueLookupParameter<IntValue> NRegionsParameter {
+      get { return (ValueLookupParameter<IntValue>) Parameters["NRegions"]; }
+    } 
+    public ConstrainedValueParameter<IRealVectorCreator> RealVectorCreatorParameter {
+      get { return (ConstrainedValueParameter<IRealVectorCreator>) Parameters["RealVectorCreator"]; }
+    }
+    public ConstrainedValueParameter<IIntegerVectorCreator> IntegerVectorCreatorParameter {
+      get { return (ConstrainedValueParameter<IIntegerVectorCreator>) Parameters["IntegerVectorCreator"]; }
+    }
+    public LookupParameter<BioBoostProblemData> ProblemDataParameter {
+      get { return (LookupParameter<BioBoostProblemData>) Parameters["ProblemData"]; }
+    }
+    #endregion
+
+    #region Parameter Values
+    public IntMatrix RegionBounds {
+      get { return RegionBoundsParameter.ActualValue; }
+    }
+    public IRealVectorCreator RealVectorCreator {
+      get { return RealVectorCreatorParameter.Value; }
+      set { RealVectorCreatorParameter.Value = value; }
+    }
+    public IIntegerVectorCreator IntegerVectorCreator {
+      get { return IntegerVectorCreatorParameter.Value; }
+      set { IntegerVectorCreatorParameter.Value = value; }
+    }
+    public BioBoostProblemData ProblemData {
+      get { return ProblemDataParameter.ActualValue; }
+      set { ProblemDataParameter.ActualValue = value; }
+    }
+    #endregion
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected BioBoostSolutionCreator(bool isDeserializing) : base(isDeserializing) {}
+    protected BioBoostSolutionCreator(BioBoostSolutionCreator orig, Cloner cloner) : base(orig, cloner) {}
+    public BioBoostSolutionCreator() {
+      Parameters.Add(new ValueLookupParameter<IntMatrix>("RegionBounds", "Limits of valid region ids."));
+      Parameters.Add(new ValueLookupParameter<IntValue>("NRegions", "Number of regions."));
+      Parameters.Add(new ConstrainedValueParameter<IRealVectorCreator>("RealVectorCreator", "Creator for initial feedstock utilizations."));
+      Parameters.Add(new ConstrainedValueParameter<IIntegerVectorCreator>("IntegerVectorCreator", "Creator for transport traget initialization."));
+      Parameters.Add(new LookupParameter<BioBoostProblemData>("ProblemData", "The problem data store."));
+      RegionBoundsParameter.Hidden = true;
+      foreach (var op in ApplicationManager.Manager.GetInstances<IRealVectorCreator>()) {
+        op.BoundsParameter.Value = new DoubleMatrix(new double[,] {{0, 1}});
+        op.LengthParameter.ActualName = NRegionsParameter.ActualName;
+        RealVectorCreatorParameter.ValidValues.Add(op);
+      }
+      foreach (var op in ApplicationManager.Manager.GetInstances<IIntegerVectorCreator>()) {
+        op.BoundsParameter.ActualName = RegionBoundsParameter.ActualName;
+        op.LengthParameter.ActualName = NRegionsParameter.ActualName;
+        IntegerVectorCreatorParameter.ValidValues.Add(op);
+      }
+      RealVectorCreatorParameter.Value = RealVectorCreatorParameter.ValidValues.FirstOrDefault(c => c.GetType() == typeof (ConstantValueRealVectorCreator));
+      IntegerVectorCreatorParameter.Value = IntegerVectorCreatorParameter.ValidValues.FirstOrDefault( c => c.GetType() == typeof (UniformRandomIntegerVectorCreator));
+      ((ConstantValueRealVectorCreator) RealVectorCreator).Value = 0.5;
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new BioBoostSolutionCreator(this, cloner);
+    }
+    #endregion
+
+    public override IOperation Apply() {
+      var ops = new OperationCollection(base.Apply());
+      foreach (var n in ProblemData.TransportTargets.CheckedItems) {
+        var op = (IIntegerVectorCreator)IntegerVectorCreator.Clone();
+        op.IntegerVectorParameter.ActualName = LayerDescriptor.TransportTargets.NameWithPrefix(n.Value.Value);
+        ops.Add(ExecutionContext.CreateChildOperation(op));
+      }
+      foreach (var n in ProblemData.Utilizations.CheckedItems) {
+        var op = (IRealVectorCreator)RealVectorCreator.Clone();
+        op.RealVectorParameter.ActualName = LayerDescriptor.Utilizations.NameWithPrefix(n.Value.Value);
+        ops.Add(ExecutionContext.CreateChildOperation(op));
+      }
+      return ops;
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/SolutionCreation/ConstantValueRealVectorCreator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/SolutionCreation/ConstantValueRealVectorCreator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/SolutionCreation/ConstantValueRealVectorCreator.cs	(revision 15711)
@@ -0,0 +1,62 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System.Linq;
+
+namespace HeuristicLab.BioBoost.SolutionCreation {
+
+  [StorableClass]
+  public class ConstantValueRealVectorCreator : RealVectorCreator {
+
+    public IValueLookupParameter<DoubleValue> ValueParameter {
+      get { return (IValueLookupParameter<DoubleValue>) Parameters["Value"]; }
+    }
+
+    public double Value {
+      get { return ValueParameter.ActualValue.Value; }
+      set { ValueParameter.Value = new DoubleValue(value); }
+    }
+
+      #region Construction & Cloning
+    [StorableConstructor]
+    protected ConstantValueRealVectorCreator(bool isDeserializing) : base(isDeserializing) {}
+    protected ConstantValueRealVectorCreator(ConstantValueRealVectorCreator orig, Cloner cloner) : base(orig, cloner) {}
+    public ConstantValueRealVectorCreator() {
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("Value", "The constant value to be replicated.", new DoubleValue(1)));
+      BoundsParameter.Value = new DoubleMatrix(new double[,] {{1, 1}});
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ConstantValueRealVectorCreator(this, cloner);
+    }
+    #endregion
+
+    protected override RealVector Create(IRandom random, IntValue length, DoubleMatrix bounds) {
+      return new RealVector(Enumerable.Repeat(Value, length.Value).ToArray());
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/SolutionCreation/IdentityIntegerVectorCreator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/SolutionCreation/IdentityIntegerVectorCreator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/SolutionCreation/IdentityIntegerVectorCreator.cs	(revision 15711)
@@ -0,0 +1,49 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System.Linq;
+
+namespace HeuristicLab.BioBoost.SolutionCreation {
+
+  [StorableClass]
+  public class IdentityIntegerVectorCreator : IntegerVectorCreator {
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected IdentityIntegerVectorCreator(bool isDeserializing) : base(isDeserializing) {}
+    protected IdentityIntegerVectorCreator(IdentityIntegerVectorCreator orig, Cloner cloner) : base(orig, cloner) {}
+    public IdentityIntegerVectorCreator() { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new IdentityIntegerVectorCreator(this, cloner);
+    }
+    #endregion
+
+    protected override IntegerVector Create(IRandom random, IntValue length, IntMatrix bounds) {
+      return new IntegerVector(Enumerable.Range(0, length.Value).ToArray());
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/SolutionCreation/LimitedValuesIntegerVectorCreator.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/SolutionCreation/LimitedValuesIntegerVectorCreator.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/SolutionCreation/LimitedValuesIntegerVectorCreator.cs	(revision 15711)
@@ -0,0 +1,68 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System.Linq;
+
+namespace HeuristicLab.BioBoost.SolutionCreation {
+
+  [StorableClass]
+  public class LimitedValuesIntegerVectorCreator : IntegerVectorCreator {
+
+    #region parameters
+    public ValueLookupParameter<IntValue> NrOfValuesParameter {
+      get { return (ValueLookupParameter<IntValue>) Parameters["NrOfValues"]; }
+    }
+    #endregion
+
+    #region parameter values
+    public IntValue NrOfValues {
+      get { return NrOfValuesParameter.ActualValue; }
+      set { NrOfValuesParameter.ActualValue = value; }
+    }
+    #endregion
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected LimitedValuesIntegerVectorCreator(bool isDeserializing) : base(isDeserializing) {}
+    protected LimitedValuesIntegerVectorCreator(LimitedValuesIntegerVectorCreator orig, Cloner cloner) : base(orig, cloner) {}
+    public LimitedValuesIntegerVectorCreator() {
+      Parameters.Add(new ValueLookupParameter<IntValue>("NrOfValues", "Nr of distinct values to chose from.", new IntValue(1)));
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new LimitedValuesIntegerVectorCreator(this, cloner);
+    }
+    #endregion
+
+    protected override IntegerVector Create(IRandom random, IntValue length, IntMatrix bounds) {
+      var nrOfValues = NrOfValues.Value;
+      var len = length.Value;
+      var values = Enumerable.Range(0, nrOfValues).Select(i => random.Next(len)).ToList();
+      return new IntegerVector(Enumerable.Range(0, len).Select(i => values[random.Next(nrOfValues)]).ToArray());
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Utils/Closure.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Utils/Closure.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Utils/Closure.cs	(revision 15711)
@@ -0,0 +1,85 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System;
+
+namespace HeuristicLab.BioBoost.Utils {
+
+  /// <summary>
+  /// Wraps a field into a local variable inside the constructor. This evades
+  /// object graph traversal as the actual value is no longer discoverable by
+  /// reflection. Use with Caution!
+  /// </summary>
+  /// <typeparam name="T">The Type of the value to be wrapped.</typeparam>
+  [StorableClass]
+  public class Closure<T> : IDeepCloneable {
+
+    public enum Encapsulation { Cloned, Referenced };
+
+    [Storable]
+    private readonly Encapsulation encapsulation;
+
+    [Storable]
+    public T Value { get { return Getter(); } set { Setter(value); } }
+
+    public Func<T> Getter;
+    public Action<T> Setter;
+
+    [StorableConstructor]
+    protected Closure(bool isDeserializing) {
+      T value = default(T);
+      Getter = () => value;
+      Setter = v => value = v;
+    }
+    protected Closure(Closure<T> orig, Cloner cloner) {
+      T value = default(T);
+      Getter = () => value;
+      Setter = v => value = v;
+      encapsulation = orig.encapsulation;
+      cloner.RegisterClonedObject(orig, this);
+      if (encapsulation == Encapsulation.Referenced) {
+        Value = orig.Value;
+      } else {
+        var cloneable = orig.Value as IDeepCloneable;
+        if (cloneable != null)
+          Value = (T) cloner.Clone(cloneable);
+        else
+          Value = orig.Value;
+      }
+    }
+    public Closure(Encapsulation encapsulation) {
+      this.encapsulation = encapsulation;
+      T value = default(T);
+      Getter = () => value;
+      Setter = v => value = v;
+    }
+
+    public object Clone() {
+      return Clone(new Cloner());
+    }
+
+    public IDeepCloneable Clone(Cloner cloner) {
+      return new Closure<T>(this, cloner);
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Utils/DictionaryExtensions.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Utils/DictionaryExtensions.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Utils/DictionaryExtensions.cs	(revision 15711)
@@ -0,0 +1,52 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.BioBoost.Utils {
+  public static class DictionaryExtensions {
+
+    public static void ApplyAt<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key, Action<TValue> f) {
+      TValue value;
+      if (dict.TryGetValue(key, out value)) {
+        f(value);
+      }
+    }
+
+    public static TReturn ApplyAt<TKey, TValue, TReturn>(this IDictionary<TKey, TValue> dict, TKey key, Func<TValue, TReturn> f, Func<TReturn> fnull) {
+      TValue value;
+      if (dict.TryGetValue(key, out value)) {
+        return f(value);
+      }
+      return fnull();
+    }
+
+    public static TValue ElementAtOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key, TValue defaultValue) {
+      TValue value;
+      if (dict.TryGetValue(key, out value)) {
+        return value;
+      } else {
+        return defaultValue;
+      }
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Utils/EnumerableExtensions.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Utils/EnumerableExtensions.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Utils/EnumerableExtensions.cs	(revision 15711)
@@ -0,0 +1,91 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Diagnostics;
+using System.Linq;
+using HeuristicLab.Data;
+
+namespace HeuristicLab.BioBoost.Utils {
+
+  public class AnonymousEqualityComparer<T> : EqualityComparer<T> {
+
+    public Func<T, T, bool> ComparerFunction { get; private set; } 
+
+    public AnonymousEqualityComparer(Func<T, T, bool> comparer) { ComparerFunction = comparer; }
+
+    public override bool Equals(T x, T y) { return ComparerFunction(x, y); }
+
+    public override int GetHashCode(T obj) { return obj == null ? 0 : obj.GetHashCode(); }
+  }
+
+  public static class ListExtensions {
+
+    public static void AddRange<T>(this IList<T> l, IEnumerable<T> elements) { foreach (var e in elements) l.Add(e); }
+
+    public static IEnumerable<T> RemoveAtIndices<T>(this IEnumerable<T> l, IEnumerable<int> orderedIndices) {
+      int i = 0;
+      var listIt = l.GetEnumerator();
+      var idxIt = orderedIndices.GetEnumerator();
+      bool done = !idxIt.MoveNext();
+      while (listIt.MoveNext()) {
+        Debug.Assert(done || idxIt.Current >= i);
+        if (!done && idxIt.Current == i) {
+          done = !idxIt.MoveNext();
+        } else {
+          yield return listIt.Current;
+        }
+        i++;
+      }
+    }
+
+    public static Queue<T> ToQueue<T>(this IEnumerable<T> l) { return new Queue<T>(l); }
+
+    public static IEnumerable<TResult> Select<T, TResult>(this IEnumerable<T> l, TResult defaultValue, Func<T, TResult> f) {
+      return l.Select(x => x == null ? defaultValue : f(x));
+    }
+
+    public static DoubleArray ToDoubleArray(this IEnumerable<double> t) { return new DoubleArray(t.ToArray()); }
+    public static StringArray ToStringArray(this IEnumerable<string> t) { return new StringArray(t.ToArray()); }
+
+    public static IEnumerable<IGrouping<TKey, TResult>> GroupBy<T, TKey, TResult>(this IEnumerable<T> source,
+      Func<T, TKey> keySelector, Func<T, TResult> resultSelector, Func<TKey, TKey, bool> equalityComparer) {
+      return source.GroupBy(keySelector, resultSelector, new AnonymousEqualityComparer<TKey>(equalityComparer));
+    }
+
+    public static HashSet<T> ToHashSet<T>(this IEnumerable<T> values) { return new HashSet<T>(values); }
+
+    public static TResult FuncOverIndices<T, TResult>(this IEnumerable<T> values, ISet<int> indices, Func<IEnumerable<T>, TResult> func) {
+      return func(values.Select((v, i) => new {v, i}).Where(p => indices.Contains(p.i)).Select(p => p.v));
+    }
+
+    public static IDictionary<int, int[]> SourceIndices(this IEnumerable<int> targets) {
+      return targets
+        .Select((t, idx) => new {t, idx})
+        .GroupBy(ti => ti.t)
+        .ToDictionary(
+          tis => tis.Key,
+          tis => tis.Select(ti => ti.idx).ToArray());
+    } 
+  }
+
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Utils/ListExtensions.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Utils/ListExtensions.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Utils/ListExtensions.cs	(revision 15711)
@@ -0,0 +1,110 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.BioBoost.Utils {
+  public static class EnumerableExtensions {
+    public static IEnumerable<Tuple<T1, T2>> Zip<T1, T2>(IEnumerable<T1> e1, IEnumerable<T2> e2) {
+      var it1 = e1.GetEnumerator();
+      var it2 = e2.GetEnumerator();
+      while (it1.MoveNext() && it2.MoveNext()) {
+        yield return new Tuple<T1, T2>(it1.Current, it2.Current);
+      }
+    }
+    public static IEnumerable<Tuple<T1, T2, T3>> Zip<T1, T2, T3>(IEnumerable<T1> e1, IEnumerable<T2> e2, IEnumerable<T3> e3) {
+      var it1 = e1.GetEnumerator();
+      var it2 = e2.GetEnumerator();
+      var it3 = e3.GetEnumerator();
+      while (it1.MoveNext() && it2.MoveNext() && it3.MoveNext()) {
+        yield return new Tuple<T1, T2, T3>(it1.Current, it2.Current, it3.Current);
+      }
+      if (it1.MoveNext() || it2.MoveNext() || it3.MoveNext())
+        throw new InvalidOperationException("Iterators have different lengths");
+    }
+    public static IEnumerable<Tuple<T1, T2, T3, T4>> Zip<T1, T2, T3, T4>(IEnumerable<T1> e1, IEnumerable<T2> e2, IEnumerable<T3> e3, IEnumerable<T4> e4) {
+      var it1 = e1.GetEnumerator();
+      var it2 = e2.GetEnumerator();
+      var it3 = e3.GetEnumerator();
+      var it4 = e4.GetEnumerator();
+      while (it1.MoveNext() && it2.MoveNext() && it3.MoveNext() && it4.MoveNext()) {
+        yield return new Tuple<T1, T2, T3, T4>(it1.Current, it2.Current, it3.Current, it4.Current);
+      }
+      if (it1.MoveNext() || it2.MoveNext() || it3.MoveNext() || it4.MoveNext())
+        throw new InvalidOperationException("Iterators have different lengths");
+    }
+    public static IEnumerable<Tuple<T1, T2, T3, T4, T5>> Zip<T1, T2, T3, T4, T5>(IEnumerable<T1> e1, IEnumerable<T2> e2, IEnumerable<T3> e3, IEnumerable<T4> e4, IEnumerable<T5> e5) {
+      var it1 = e1.GetEnumerator();
+      var it2 = e2.GetEnumerator();
+      var it3 = e3.GetEnumerator();
+      var it4 = e4.GetEnumerator();
+      var it5 = e5.GetEnumerator();
+      while (it1.MoveNext() && it2.MoveNext() && it3.MoveNext() && it4.MoveNext() && it5.MoveNext()) {
+        yield return new Tuple<T1, T2, T3, T4, T5>(it1.Current, it2.Current, it3.Current, it4.Current, it5.Current);
+      }
+      if (it1.MoveNext() || it2.MoveNext() || it3.MoveNext() || it4.MoveNext() || it5.MoveNext())
+        throw new InvalidOperationException("Iterators have different lengths");
+    }
+    public static IEnumerable<Tuple<T1, T2, T3, T4, T5, T6>> Zip<T1, T2, T3, T4, T5, T6>(IEnumerable<T1> e1, IEnumerable<T2> e2, IEnumerable<T3> e3, IEnumerable<T4> e4, IEnumerable<T5> e5, IEnumerable<T6> e6) {
+      var it1 = e1.GetEnumerator();
+      var it2 = e2.GetEnumerator();
+      var it3 = e3.GetEnumerator();
+      var it4 = e4.GetEnumerator();
+      var it5 = e5.GetEnumerator();
+      var it6 = e6.GetEnumerator();
+      while (it1.MoveNext() && it2.MoveNext() && it3.MoveNext() && it4.MoveNext() && it5.MoveNext() && it6.MoveNext()) {
+        yield return new Tuple<T1, T2, T3, T4, T5, T6>(it1.Current, it2.Current, it3.Current, it4.Current, it5.Current, it6.Current);
+      }
+      if (it1.MoveNext() || it2.MoveNext() || it3.MoveNext() || it4.MoveNext() || it5.MoveNext() || it6.MoveNext())
+        throw new InvalidOperationException("Iterators have different lengths");
+    }
+    public static IEnumerable<Tuple<T1, T2, T3, T4, T5, T6, T7>> Zip<T1, T2, T3, T4, T5, T6, T7>(IEnumerable<T1> e1, IEnumerable<T2> e2, IEnumerable<T3> e3, IEnumerable<T4> e4, IEnumerable<T5> e5, IEnumerable<T6> e6, IEnumerable<T7> e7) {
+      var it1 = e1.GetEnumerator();
+      var it2 = e2.GetEnumerator();
+      var it3 = e3.GetEnumerator();
+      var it4 = e4.GetEnumerator();
+      var it5 = e5.GetEnumerator();
+      var it6 = e6.GetEnumerator();
+      var it7 = e7.GetEnumerator();
+      while (it1.MoveNext() && it2.MoveNext() && it3.MoveNext() && it4.MoveNext() && it5.MoveNext() && it6.MoveNext() && it7.MoveNext()) {
+        yield return new Tuple<T1, T2, T3, T4, T5, T6, T7>(it1.Current, it2.Current, it3.Current, it4.Current, it5.Current, it6.Current, it7.Current);
+      }
+      if (it1.MoveNext() || it2.MoveNext() || it3.MoveNext() || it4.MoveNext() || it5.MoveNext() || it6.MoveNext() || it7.MoveNext())
+        throw new InvalidOperationException("Iterators have different lengths");
+    }
+    public static IEnumerable<Tuple<T1, T2, T3, T4, T5, T6, T7, T8>> Zip<T1, T2, T3, T4, T5, T6, T7, T8>(IEnumerable<T1> e1, IEnumerable<T2> e2, IEnumerable<T3> e3, IEnumerable<T4> e4, IEnumerable<T5> e5, IEnumerable<T6> e6, IEnumerable<T7> e7, IEnumerable<T8> e8) {
+      var it1 = e1.GetEnumerator();
+      var it2 = e2.GetEnumerator();
+      var it3 = e3.GetEnumerator();
+      var it4 = e4.GetEnumerator();
+      var it5 = e5.GetEnumerator();
+      var it6 = e6.GetEnumerator();
+      var it7 = e7.GetEnumerator();
+      var it8 = e8.GetEnumerator();
+      while (it1.MoveNext() && it2.MoveNext() && it3.MoveNext() && it4.MoveNext() && it5.MoveNext() && it6.MoveNext() && it7.MoveNext() && it8.MoveNext()) {
+        yield return new Tuple<T1, T2, T3, T4, T5, T6, T7, T8>(it1.Current, it2.Current, it3.Current, it4.Current, it5.Current, it6.Current, it7.Current, it8.Current);
+      }
+      if (it1.MoveNext() || it2.MoveNext() || it3.MoveNext() || it4.MoveNext() || it5.MoveNext() || it6.MoveNext() || it7.MoveNext() || it8.MoveNext())
+        throw new InvalidOperationException("Iterators have different lengths");
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Utils/StepFunction.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Utils/StepFunction.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Utils/StepFunction.cs	(revision 15711)
@@ -0,0 +1,109 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text.RegularExpressions;
+
+namespace HeuristicLab.BioBoost.Utils {
+
+  [StorableClass]
+  [Item("StepFunction", "A simple step function specifying upper bounds and corresponding values.")]
+  public class StepFunction : ParameterizedNamedItem {
+
+    #region parameters
+    public IValueLookupParameter<DoubleMatrix> ValuesParameter {
+      get { return (IValueLookupParameter<DoubleMatrix>) Parameters["Values"]; }
+    }
+    public DoubleMatrix Values {
+      get { return ValuesParameter.Value; }
+      set { ValuesParameter.Value = value; }
+    }
+    #endregion
+
+    #region Construction & Cloning
+    public StepFunction() {
+      Parameters.Add(new ValueLookupParameter<DoubleMatrix>("Values", "The upper bounds and corresponding values.", new DoubleMatrix(0, 2, new[] {"Upper Bound", "Value"})));
+    }
+    [StorableConstructor]
+    protected StepFunction(bool isDeserializing) : base(isDeserializing) {}
+    protected StepFunction(StepFunction orig, Cloner cloner) : base(orig, cloner) {}
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new StepFunction(this, cloner);
+    }
+    #endregion
+
+    public void Sort() {
+      if (Values.Columns != 2)
+        throw new InvalidOperationException("StepFunction values need two columns (upper bound and value)");
+      var steps = Enumerable.Range(0, Values.Rows).Select(i => new {s = Values[i, 0], v = Values[i, 1]}).OrderBy(p => p.s).ToList();
+      for (int i = 0; i<Values.Rows; i++) {
+        Values[i, 0] = steps[i].s;
+        Values[i, 1] = steps[i].v;
+      }
+    }
+
+    public double GetValue(double x) {
+      int i = 0;
+      while (i < Values.Rows-1 && x > Values[i, 0]) i++;
+      return Values[i, 1];
+    }
+
+    public static StepFunction Parse(String s, String rowSepRegex="/", String colSepRegex="->") {
+      var values = new List<Tuple<double, double>>();
+      foreach (var row in Regex.Split(s, rowSepRegex)) {
+        var cols = Regex.Split(row, colSepRegex);
+        if (cols.Length != 2) {
+          throw new ArgumentException("step function must contain two rows (separated by /" + colSepRegex + "/");
+        }
+        try {
+          values.Add(new Tuple<double, double>(ParseDouble(cols[0]), ParseDouble(cols[1])));
+        }
+        catch (Exception x) {
+          if (x is FormatException || x is ArgumentNullException || x is OverflowException) {
+            throw new ArgumentException(String.Format("could not parse row \"{0}\"", row), x);
+          }
+        }
+      }
+      var sf = new StepFunction();
+      var matrix = new DoubleMatrix(values.Count, 2, new[] {"Upper Bound", "Value"});
+      for (int i = 0; i < values.Count; i++) {
+        matrix[i, 0] = values[i].Item1;
+        matrix[i, 1] = values[i].Item2;
+      }
+      sf.Values = matrix;
+      sf.Sort();
+      return sf;
+    }
+
+
+    public static double ParseDouble(String s) {
+      return Double.Parse(s, NumberStyles.Float, NumberFormatInfo.InvariantInfo);
+    }
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Utils/Util.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Utils/Util.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Utils/Util.cs	(revision 15711)
@@ -0,0 +1,54 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Drawing;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.BioBoost.Utils {
+  public class Util {
+
+    public static double Distance(Point p1, Point p2) {
+      return Math.Sqrt(Sqr(p1.X - p2.X) + Sqr(p1.Y - p2.Y));
+    }
+
+    public static double Sqr(double x) { return x * x; }
+
+    public static void Shuffle<T>(T[] elements, IRandom random) {
+      for (int i = elements.Length - 1; i > 0; i--) {
+        // Swap element "i" with a random earlier element (including itself)
+        int swapIndex = random.Next(i + 1);
+        T temp = elements[swapIndex];
+        elements[swapIndex] = elements[i];
+        elements[i] = temp;
+      }
+    }
+
+    public static T[] Clone<T>(T[] t) {
+      return (T[]) (t == null ? null : t.Clone());
+    }
+
+    public static T Clone<T>(T t) where T : ICloneable {
+      return (T) (t == null ? null : t.Clone());
+    }
+
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Utils/ValueParameterCollectionExtensions.cs
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Utils/ValueParameterCollectionExtensions.cs	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/Utils/ValueParameterCollectionExtensions.cs	(revision 15711)
@@ -0,0 +1,49 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+
+namespace HeuristicLab.BioBoost.Utils {
+
+  public static class ValueParameterCollectionExtensions {
+    /// <summary>
+    /// total conversion cost including costs for required supplies minus revenue for side products.
+    /// </summary>
+    /// <param name="productsAndAmounts">the list of products and amounts</param>
+    /// <param name="productPrices">a dictionary containing the prices to use</param>
+    /// <param name="mainProductName">the main product i.e. no side product and hence excluded from this calculation</param>
+    /// <returns></returns>
+    public static double TotalCost(this ValueParameterCollection productsAndAmounts, IDictionary<string, double> productPrices, string mainProductName) {
+      double cost = 0;
+      foreach (var p in productsAndAmounts) {
+        var productName = p.Name;
+        var amount = p.Value as DoubleValue;
+        double price;
+        if (amount != null && productName != mainProductName && productPrices.TryGetValue(p.Name, out price)) {
+          cost -= amount.Value*price; // as amount*price is sales revenue -amount*price is cost ;-)
+        }
+      }
+      return cost;
+    } 
+  }
+}
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/app.config
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/app.config	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/app.config	(revision 15711)
@@ -0,0 +1,15 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <runtime>
+    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+      <dependentAssembly>
+        <assemblyIdentity name="GeoAPI" publicKeyToken="a1a0da7def465678" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-1.7.3.0" newVersion="1.7.3.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="NetTopologySuite" publicKeyToken="f580a05016ebada1" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-1.13.3.0" newVersion="1.13.3.0" />
+      </dependentAssembly>
+    </assemblyBinding>
+  </runtime>
+</configuration>
Index: addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/packages.config
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/packages.config	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/HeuristicLab.Problems.BioBoost/3.3/packages.config	(revision 15711)
@@ -0,0 +1,13 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="BruTile" version="0.7.4.4" targetFramework="net45" />
+  <package id="Common.Logging" version="2.0.0" targetFramework="net45" />
+  <package id="GeoAPI" version="1.7.2" targetFramework="net45" />
+  <package id="NetTopologySuite" version="1.13.2" targetFramework="net45" />
+  <package id="NetTopologySuite.IO" version="1.13.2" targetFramework="net45" />
+  <package id="Newtonsoft.Json" version="4.5.11" targetFramework="net45" />
+  <package id="ProjNET4GeoAPI" version="1.3.0.3" targetFramework="net45" />
+  <package id="SharpMap" version="1.1.0" targetFramework="net45" />
+  <package id="System.Data.SQLite.MSIL" version="1.0.86.0" targetFramework="net45" />
+  <package id="YamlDotNet" version="3.8.0" targetFramework="net45" />
+</packages>
Index: addons/HeuristicLab.Problems.BioBoost/PreBuildEvent.cmd
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/PreBuildEvent.cmd	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/PreBuildEvent.cmd	(revision 15711)
@@ -0,0 +1,2 @@
+IF EXIST "%ProjectDir%\Properties\AssemblyInfo.cs.frame" SubWCRev "%ProjectDir%\" "%ProjectDir%\Properties\AssemblyInfo.cs.frame" "%ProjectDir%\Properties\AssemblyInfo.cs"
+IF EXIST "%ProjectDir%\Plugin.cs.frame" SubWCRev "%ProjectDir%\" "%ProjectDir%\Plugin.cs.frame" "%ProjectDir%\Plugin.cs"
Index: addons/HeuristicLab.Problems.BioBoost/packages/repositories.config
===================================================================
--- addons/HeuristicLab.Problems.BioBoost/packages/repositories.config	(revision 15711)
+++ addons/HeuristicLab.Problems.BioBoost/packages/repositories.config	(revision 15711)
@@ -0,0 +1,5 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<repositories>
+  <repository path="..\HeuristicLab.Problems.BioBoost.Views\3.3\packages.config" />
+  <repository path="..\HeuristicLab.Problems.BioBoost\3.3\packages.config" />
+</repositories>
