Index: /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.4/EvaluationCache.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.4/EvaluationCache.cs	(revision 13179)
+++ /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.4/EvaluationCache.cs	(revision 13180)
@@ -30,4 +30,5 @@
 using System.Text.RegularExpressions;
 using System.Threading;
+using Google.ProtocolBuffers;
 using HeuristicLab.Common;
 using HeuristicLab.Common.Resources;
@@ -47,13 +48,28 @@
 
       public readonly string Key;
-      public double Value;
-
-      public CacheEntry(string key, double value) {
-        Key = key;
-        Value = value;
+
+      private QualityMessage message;
+      private byte[] rawMessage;
+
+      public byte[] RawMessage {
+        get { return rawMessage; }
+        set {
+          rawMessage = value;
+          message = null;
+        }
       }
 
       public CacheEntry(string key) {
         Key = key;
+      }
+
+      public QualityMessage GetMessage(ExtensionRegistry extensions) {
+        if (message == null && rawMessage != null)
+          message = QualityMessage.ParseFrom(ByteString.CopyFrom(rawMessage), extensions);
+        return message;
+      }
+      public void SetMessage(QualityMessage value) {
+        message = value;
+        rawMessage = value.ToByteArray();
       }
 
@@ -69,10 +85,30 @@
       }
 
+      public string QualityString(IFormatProvider formatProvider = null) {
+        if (formatProvider == null) formatProvider = CultureInfo.CurrentCulture;
+        if (RawMessage == null) return "-";
+        var msg = message ?? CreateBasicQualityMessage();
+        switch (msg.Type) {
+          case QualityMessage.Types.Type.SingleObjectiveQualityMessage:
+            return msg.GetExtension(SingleObjectiveQualityMessage.QualityMessage_).Quality.ToString(formatProvider);
+          case QualityMessage.Types.Type.MultiObjectiveQualityMessage:
+            var qualities = msg.GetExtension(MultiObjectiveQualityMessage.QualityMessage_).QualitiesList;
+            return string.Format("[{0}]", string.Join(",", qualities.Select(q => q.ToString(formatProvider))));
+          default:
+            return "-";
+        }
+      }
+      private QualityMessage CreateBasicQualityMessage() {
+        var extensions = ExtensionRegistry.CreateInstance();
+        ExternalEvaluationMessages.RegisterAllExtensions(extensions);
+        return QualityMessage.ParseFrom(ByteString.CopyFrom(rawMessage), extensions);
+      }
+
       public override string ToString() {
-        return string.Format("{{{0} : {1}}}", Key, Value);
-      }
-    }
-
-    public delegate double Evaluator(SolutionMessage message);
+        return string.Format("{{{0} : {1}}}", Key, QualityString());
+      }
+    }
+
+    public delegate QualityMessage Evaluator(SolutionMessage message);
     #endregion
 
@@ -126,16 +162,24 @@
 
     #region Persistence
+    #region BackwardsCompatibility3.4
     [Storable(Name = "Cache")]
     private IEnumerable<KeyValuePair<string, double>> Cache_Persistence {
-      get {
-        if (IsPersistent) {
-          return GetCacheValues();
-        } else {
-          return Enumerable.Empty<KeyValuePair<string, double>>();
-        }
-      }
+      get { return Enumerable.Empty<KeyValuePair<string, double>>(); }
       set {
-        SetCacheValues(value);
-      }
+        var rawMessages = value.ToDictionary(kvp => kvp.Key,
+          kvp => QualityMessage.CreateBuilder()
+            .SetSolutionId(0)
+            .SetExtension(
+              SingleObjectiveQualityMessage.QualityMessage_,
+              SingleObjectiveQualityMessage.CreateBuilder().SetQuality(kvp.Value).Build())
+            .Build().ToByteArray());
+        SetCacheValues(rawMessages);
+      }
+    }
+    #endregion
+    [Storable(Name = "CacheNew")]
+    private IEnumerable<KeyValuePair<string, byte[]>> CacheNew_Persistence {
+      get { return IsPersistent ? GetCacheValues() : Enumerable.Empty<KeyValuePair<string, byte[]>>(); }
+      set { SetCacheValues(value); }
     }
     [StorableHook(HookType.AfterDeserialization)]
@@ -149,5 +193,5 @@
     protected EvaluationCache(bool deserializing) : base(deserializing) { }
     protected EvaluationCache(EvaluationCache original, Cloner cloner)
-      : base(original, cloner) {
+        : base(original, cloner) {
       SetCacheValues(original.GetCacheValues());
       Hits = original.Hits;
@@ -190,5 +234,5 @@
     }
 
-    public double GetValue(SolutionMessage message, Evaluator evaluate) {
+    public QualityMessage GetValue(SolutionMessage message, Evaluator evaluate, ExtensionRegistry extensions) {
       var entry = new CacheEntry(message.ToString());
       bool lockTaken = false;
@@ -205,5 +249,5 @@
             Monitor.Exit(cacheLock);
             OnChanged();
-            return node.Value.Value;
+            return node.Value.GetMessage(extensions);
           } else {
             if (!waited && activeEvaluations.Contains(entry.Key)) {
@@ -217,10 +261,9 @@
               OnChanged();
               try {
-                entry.Value = evaluate(message);
+                entry.SetMessage(evaluate(message));
                 Monitor.Enter(cacheLock, ref lockTaken);
                 index[entry] = list.AddLast(entry);
                 Trim();
-              }
-              finally {
+              } finally {
                 if (!lockTaken)
                   Monitor.Enter(cacheLock, ref lockTaken);
@@ -231,10 +274,9 @@
               }
               OnChanged();
-              return entry.Value;
+              return entry.GetMessage(extensions);
             }
           }
         }
-      }
-      finally {
+      } finally {
         if (lockTaken)
           Monitor.Exit(cacheLock);
@@ -250,16 +292,16 @@
     }
 
-    private IEnumerable<KeyValuePair<string, double>> GetCacheValues() {
+    private IEnumerable<KeyValuePair<string, byte[]>> GetCacheValues() {
       lock (cacheLock) {
-        return index.ToDictionary(kvp => kvp.Key.Key, kvp => kvp.Key.Value);
-      }
-    }
-
-    private void SetCacheValues(IEnumerable<KeyValuePair<string, double>> value) {
+        return index.ToDictionary(kvp => kvp.Key.Key, kvp => kvp.Key.RawMessage);
+      }
+    }
+
+    private void SetCacheValues(IEnumerable<KeyValuePair<string, byte[]>> value) {
       lock (cacheLock) {
-        list = new LinkedList<CacheEntry>();
-        index = new Dictionary<CacheEntry, LinkedListNode<CacheEntry>>();
+        if (list == null) list = new LinkedList<CacheEntry>();
+        if (index == null) index = new Dictionary<CacheEntry, LinkedListNode<CacheEntry>>();
         foreach (var kvp in value) {
-          var entry = new CacheEntry(kvp.Key) { Value = kvp.Value };
+          var entry = new CacheEntry(kvp.Key) { RawMessage = kvp.Value };
           index[entry] = list.AddLast(entry);
         }
@@ -274,5 +316,5 @@
               "\"{0}\", {1}",
               Regex.Replace(entry.Key, "\\s", "").Replace("\"", "\"\""),
-              entry.Value));
+              entry.QualityString(CultureInfo.InvariantCulture)));
           }
         }
Index: /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.4/ExternalEvaluationProblem.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.4/ExternalEvaluationProblem.cs	(revision 13179)
+++ /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.4/ExternalEvaluationProblem.cs	(revision 13180)
@@ -38,5 +38,5 @@
   [Creatable(CreatableAttribute.Categories.ExternalEvaluationProblems, Priority = 100)]
   [StorableClass]
-  public class ExternalEvaluationProblem : SingleObjectiveBasicProblem<IEncoding> {
+  public class ExternalEvaluationProblem : SingleObjectiveBasicProblem<IEncoding>, IExternalEvaluationProblem {
 
     public static new Image StaticItemImage {
@@ -89,5 +89,5 @@
       Parameters.Add(new OptionalValueParameter<EvaluationCache>("Cache", "Cache of previously evaluated solutions."));
       Parameters.Add(new ValueParameter<CheckedItemCollection<IEvaluationServiceClient>>("Clients", "The clients that are used to communicate with the external application.", new CheckedItemCollection<IEvaluationServiceClient>() { new EvaluationServiceClient() }));
-      Parameters.Add(new ValueParameter<SolutionMessageBuilder>("MessageBuilder", "The message builder that converts from HeuristicLab objects to SolutionMessage representation.", new SolutionMessageBuilder()));
+      Parameters.Add(new ValueParameter<SolutionMessageBuilder>("MessageBuilder", "The message builder that converts from HeuristicLab objects to SolutionMessage representation.", new SolutionMessageBuilder()) { Hidden = true });
       Parameters.Add(new FixedValueParameter<SingleObjectiveOptimizationSupportScript>("SupportScript", "A script that can provide neighborhood and analyze the results of the optimization.", new SingleObjectiveOptimizationSupportScript()));
 
@@ -101,6 +101,13 @@
 
     public override double Evaluate(Individual individual, IRandom random) {
-      return Cache == null ? EvaluateOnNextAvailableClient(BuildSolutionMessage(individual)).Quality
-        : Cache.GetValue(BuildSolutionMessage(individual), m => EvaluateOnNextAvailableClient(m).Quality);
+      var qualityMessage = Evaluate(BuildSolutionMessage(individual));
+      if (!qualityMessage.HasExtension(SingleObjectiveQualityMessage.QualityMessage_))
+        throw new InvalidOperationException("The received message is not a SingleObjectiveQualityMessage.");
+      return qualityMessage.GetExtension(SingleObjectiveQualityMessage.QualityMessage_).Quality;
+    }
+    public virtual QualityMessage Evaluate(SolutionMessage solutionMessage) {
+      return Cache == null
+        ? EvaluateOnNextAvailableClient(solutionMessage)
+        : Cache.GetValue(solutionMessage, EvaluateOnNextAvailableClient, GetQualityMessageExtensions());
     }
 
@@ -114,7 +121,14 @@
     #endregion
 
-    #region Evaluation Helpers
+    public virtual ExtensionRegistry GetQualityMessageExtensions() {
+      var extensions = ExtensionRegistry.CreateInstance();
+      extensions.Add(SingleObjectiveQualityMessage.QualityMessage_);
+      return extensions;
+    }
+
+    #region Evaluation
     private HashSet<IEvaluationServiceClient> activeClients = new HashSet<IEvaluationServiceClient>();
     private object clientLock = new object();
+
     private QualityMessage EvaluateOnNextAvailableClient(SolutionMessage message) {
       IEvaluationServiceClient client = null;
@@ -130,6 +144,5 @@
       try {
         return client.Evaluate(message, GetQualityMessageExtensions());
-      }
-      finally {
+      } finally {
         lock (clientLock) {
           activeClients.Remove(client);
@@ -139,12 +152,8 @@
     }
 
-    protected virtual ExtensionRegistry GetQualityMessageExtensions() {
-      return ExtensionRegistry.CreateInstance();
-    }
-
-    private SolutionMessage BuildSolutionMessage(Individual individual) {
+    private SolutionMessage BuildSolutionMessage(Individual individual, int solutionId = 0) {
       lock (clientLock) {
         SolutionMessage.Builder protobufBuilder = SolutionMessage.CreateBuilder();
-        protobufBuilder.SolutionId = 0;
+        protobufBuilder.SolutionId = solutionId;
         var scope = new Scope();
         individual.CopyToScope(scope);
@@ -152,7 +161,6 @@
           try {
             MessageBuilder.AddToMessage(variable.Value, variable.Name, protobufBuilder);
-          }
-          catch (ArgumentException ex) {
-            throw new InvalidOperationException(string.Format("ERROR while building solution message: Parameter {0} cannot be added to the message", name), ex);
+          } catch (ArgumentException ex) {
+            throw new InvalidOperationException(string.Format("ERROR while building solution message: Parameter {0} cannot be added to the message", Name), ex);
           }
         }
Index: /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.4/HeuristicLab.Problems.ExternalEvaluation-3.4.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.4/HeuristicLab.Problems.ExternalEvaluation-3.4.csproj	(revision 13179)
+++ /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.4/HeuristicLab.Problems.ExternalEvaluation-3.4.csproj	(revision 13180)
@@ -134,4 +134,6 @@
     <Compile Include="Drivers\EvaluationStreamChannel.cs" />
     <Compile Include="Drivers\EvaluationTCPChannel.cs" />
+    <Compile Include="Interfaces\IExternalEvaluationProblem.cs" />
+    <Compile Include="MultiObjectiveExternalEvaluationProblem.cs" />
     <Compile Include="ExternalEvaluationProblem.cs" />
     <Compile Include="Interfaces\IEvaluationServiceClient.cs" />
Index: /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.4/Interfaces/IExternalEvaluationProblem.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.4/Interfaces/IExternalEvaluationProblem.cs	(revision 13180)
+++ /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.4/Interfaces/IExternalEvaluationProblem.cs	(revision 13180)
@@ -0,0 +1,35 @@
+﻿#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 Google.ProtocolBuffers;
+using HeuristicLab.Core;
+using HeuristicLab.Optimization;
+
+namespace HeuristicLab.Problems.ExternalEvaluation {
+  public interface IExternalEvaluationProblem : IProblem {
+
+    EvaluationCache Cache { get; }
+    CheckedItemCollection<IEvaluationServiceClient> Clients { get; }
+
+    QualityMessage Evaluate(SolutionMessage solutionMessage);
+    ExtensionRegistry GetQualityMessageExtensions();
+  }
+}
Index: /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.4/MultiObjectiveExternalEvaluationProblem.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.4/MultiObjectiveExternalEvaluationProblem.cs	(revision 13180)
+++ /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.4/MultiObjectiveExternalEvaluationProblem.cs	(revision 13180)
@@ -0,0 +1,170 @@
+﻿#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.Threading;
+using Google.ProtocolBuffers;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.ExternalEvaluation {
+  [Item("Multi Objective External Evaluation Problem", "A multi-objective problem that is evaluated in a different process.")]
+  [Creatable(CreatableAttribute.Categories.ExternalEvaluationProblems, Priority = 200)]
+  [StorableClass]
+  public class MultiObjectiveExternalEvaluationProblem : MultiObjectiveBasicProblem<IEncoding>, IExternalEvaluationProblem {
+
+    public static new Image StaticItemImage {
+      get { return HeuristicLab.Common.Resources.VSImageLibrary.Type; }
+    }
+
+    #region Parameters
+    public OptionalValueParameter<EvaluationCache> CacheParameter {
+      get { return (OptionalValueParameter<EvaluationCache>)Parameters["Cache"]; }
+    }
+    public IValueParameter<CheckedItemCollection<IEvaluationServiceClient>> ClientsParameter {
+      get { return (IValueParameter<CheckedItemCollection<IEvaluationServiceClient>>)Parameters["Clients"]; }
+    }
+    public IValueParameter<SolutionMessageBuilder> MessageBuilderParameter {
+      get { return (IValueParameter<SolutionMessageBuilder>)Parameters["MessageBuilder"]; }
+    }
+    //public IFixedValueParameter<MultiObjectiveOptimizationSupportScript> SupportScriptParameter {
+    //  get { return (IFixedValueParameter<MultiObjectiveOptimizationSupportScript>)Parameters["SupportScript"]; }
+    //}
+    #endregion
+
+    #region Properties
+    public EvaluationCache Cache {
+      get { return CacheParameter.Value; }
+    }
+    public CheckedItemCollection<IEvaluationServiceClient> Clients {
+      get { return ClientsParameter.Value; }
+    }
+    public SolutionMessageBuilder MessageBuilder {
+      get { return MessageBuilderParameter.Value; }
+    }
+    //public MultiObjectiveOptimizationSupportScript OptimizationSupportScript {
+    //  get { return SupportScriptParameter.Value; }
+    //}
+    //private IMultiObjectiveOptimizationSupport OptimizationSupport {
+    //  get { return SupportScriptParameter.Value; }
+    //}
+    #endregion
+
+    [StorableConstructor]
+    protected MultiObjectiveExternalEvaluationProblem(bool deserializing) : base(deserializing) { }
+    protected MultiObjectiveExternalEvaluationProblem(MultiObjectiveExternalEvaluationProblem original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MultiObjectiveExternalEvaluationProblem(this, cloner);
+    }
+    public MultiObjectiveExternalEvaluationProblem()
+      : base() {
+      Parameters.Remove("Maximization"); // readonly in base class
+      Parameters.Add(new FixedValueParameter<BoolArray>("Maximization", "Set to false if the problem should be minimized.", new BoolArray()));
+      Parameters.Add(new OptionalValueParameter<EvaluationCache>("Cache", "Cache of previously evaluated solutions."));
+      Parameters.Add(new ValueParameter<CheckedItemCollection<IEvaluationServiceClient>>("Clients", "The clients that are used to communicate with the external application.", new CheckedItemCollection<IEvaluationServiceClient>() { new EvaluationServiceClient() }));
+      Parameters.Add(new ValueParameter<SolutionMessageBuilder>("MessageBuilder", "The message builder that converts from HeuristicLab objects to SolutionMessage representation.", new SolutionMessageBuilder()) { Hidden = true });
+      //Parameters.Add(new FixedValueParameter<MultiObjectiveOptimizationSupportScript>("SupportScript", "A script that can analyze the results of the optimization.", new MultiObjectiveOptimizationSupportScript()));
+
+      //Operators.Add(new BestScopeSolutionAnalyzer()); pareto front
+    }
+
+    #region Multi Objective Problem Overrides
+    public override bool[] Maximization {
+      get {
+        return Parameters.ContainsKey("Maximization") ? ((IValueParameter<BoolArray>)Parameters["Maximization"]).Value.ToArray() : new bool[0];
+      }
+    }
+
+    public override double[] Evaluate(Individual individual, IRandom random) {
+      var qualityMessage = Evaluate(BuildSolutionMessage(individual));
+      if (!qualityMessage.HasExtension(MultiObjectiveQualityMessage.QualityMessage_))
+        throw new InvalidOperationException("The received message is not a MultiObjectiveQualityMessage.");
+      return qualityMessage.GetExtension(MultiObjectiveQualityMessage.QualityMessage_).QualitiesList.ToArray();
+    }
+    public virtual QualityMessage Evaluate(SolutionMessage solutionMessage) {
+      return Cache == null
+        ? EvaluateOnNextAvailableClient(solutionMessage)
+        : Cache.GetValue(solutionMessage, EvaluateOnNextAvailableClient, GetQualityMessageExtensions());
+    }
+
+    public override void Analyze(Individual[] individuals, double[][] qualities, ResultCollection results, IRandom random) {
+      //OptimizationSupport.Analyze(individuals, qualities, results, random);
+    }
+
+    #endregion
+
+    public virtual ExtensionRegistry GetQualityMessageExtensions() {
+      var extensions = ExtensionRegistry.CreateInstance();
+      extensions.Add(MultiObjectiveQualityMessage.QualityMessage_);
+      return extensions;
+    }
+
+    #region Evaluation
+    private HashSet<IEvaluationServiceClient> activeClients = new HashSet<IEvaluationServiceClient>();
+    private object clientLock = new object();
+
+    private QualityMessage EvaluateOnNextAvailableClient(SolutionMessage message) {
+      IEvaluationServiceClient client = null;
+      lock (clientLock) {
+        client = Clients.CheckedItems.FirstOrDefault(c => !activeClients.Contains(c));
+        while (client == null && Clients.CheckedItems.Any()) {
+          Monitor.Wait(clientLock);
+          client = Clients.CheckedItems.FirstOrDefault(c => !activeClients.Contains(c));
+        }
+        if (client != null)
+          activeClients.Add(client);
+      }
+      try {
+        return client.Evaluate(message, GetQualityMessageExtensions());
+      } finally {
+        lock (clientLock) {
+          activeClients.Remove(client);
+          Monitor.PulseAll(clientLock);
+        }
+      }
+    }
+
+    private SolutionMessage BuildSolutionMessage(Individual individual, int solutionId = 0) {
+      lock (clientLock) {
+        SolutionMessage.Builder protobufBuilder = SolutionMessage.CreateBuilder();
+        protobufBuilder.SolutionId = solutionId;
+        var scope = new Scope();
+        individual.CopyToScope(scope);
+        foreach (var variable in scope.Variables) {
+          try {
+            MessageBuilder.AddToMessage(variable.Value, variable.Name, protobufBuilder);
+          } catch (ArgumentException ex) {
+            throw new InvalidOperationException(string.Format("ERROR while building solution message: Parameter {0} cannot be added to the message", Name), ex);
+          }
+        }
+        return protobufBuilder.Build();
+      }
+    }
+    #endregion
+  }
+}
Index: /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.4/Protos/ExternalEvaluationMessages.proto
===================================================================
--- /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.4/Protos/ExternalEvaluationMessages.proto	(revision 13179)
+++ /trunk/sources/HeuristicLab.Problems.ExternalEvaluation/3.4/Protos/ExternalEvaluationMessages.proto	(revision 13180)
@@ -64,12 +64,31 @@
 }
 
+// Nested Extensions http://www.indelible.org/ink/protobuf-polymorphism/
 message QualityMessage {
   required int32 solutionId = 1;
-  required double quality = 2;
-
+  enum Type {
+    SingleObjectiveQualityMessage = 1;
+    MultiObjectiveQualityMessage = 2;
+  }
+  required Type type = 2;
   extensions 1000 to max;
 }
+
+message SingleObjectiveQualityMessage {
+  extend QualityMessage {
+    required SingleObjectiveQualityMessage qualityMessage = 1000;  // unique QualityMessage extension number
+  }
+  required double quality = 1;
+}
+message MultiObjectiveQualityMessage {
+  extend QualityMessage {
+    required MultiObjectiveQualityMessage qualityMessage = 1001;  // unique QualityMessage extension number
+  }
+  repeated double qualities = 1;
+}
+
   
 service EvaluationService {
-  rpc Evaluate (SolutionMessage) returns (QualityMessage);
+  rpc EvaluateSingleObjective (SolutionMessage) returns (SingleObjectiveQualityMessage);
+  rpc EvaluateMultiObjectives (SolutionMessage) returns (MultiObjectiveQualityMessage);
 }
