Index: exampleparties/randomparty/randomparty/RandomParty.py
===================================================================
--- exampleparties/randomparty/randomparty/RandomParty.py	(revision 66)
+++ exampleparties/randomparty/randomparty/RandomParty.py	(revision 67)
@@ -2,5 +2,5 @@
 from random import randint
 import traceback
-from typing import cast, Dict, List
+from typing import cast, Dict, List, Set, Collection
 
 from geniusweb.actions.Accept import Accept
@@ -9,8 +9,13 @@
 from geniusweb.actions.Offer import Offer
 from geniusweb.actions.PartyId import PartyId
+from geniusweb.actions.Vote import Vote
+from geniusweb.actions.Votes import Votes
+from geniusweb.bidspace.AllBidsList import AllBidsList
 from geniusweb.inform.ActionDone import ActionDone
 from geniusweb.inform.Finished import Finished
 from geniusweb.inform.Inform import Inform
+from geniusweb.inform.OptIn import OptIn
 from geniusweb.inform.Settings import Settings
+from geniusweb.inform.Voting import Voting
 from geniusweb.inform.YourTurn import YourTurn
 from geniusweb.issuevalue.Bid import Bid
@@ -23,4 +28,5 @@
 from geniusweb.profileconnection.ProfileConnectionFactory import ProfileConnectionFactory
 from geniusweb.progress.ProgressRounds import ProgressRounds
+from geniusweb.utils import val
 
 
@@ -39,10 +45,10 @@
         #self.getReporter().log(logging.INFO,"received info:"+str(info))
         if isinstance(info,Settings) :
-            settings:Settings=cast(Settings,info)    
-            self._me = settings.getID()
-            self._protocol:str = str(settings.getProtocol().getURI())
-            self._progress = settings.getProgress()
+            self._settings:Settings=cast(Settings,info)    
+            self._me = self._settings.getID()
+            self._protocol:str = str(self._settings.getProtocol().getURI())
+            self._progress = self._settings.getProgress()
             if "Learn" ==  self._protocol:
-                self.getConnection().send(LearningDone(self._me))
+                self.getConnection().send(LearningDone(self._me)) #type:ignore
             else:
                 self._profile = ProfileConnectionFactory.create(info.getProfile().getURI(), self.getReporter())
@@ -57,4 +63,10 @@
         elif isinstance(info, Finished):
             self.terminate()
+        elif isinstance(info, Voting):
+            # MOPAC protocol
+            self._lastvotes = self._vote(cast(Voting, info));
+            val(self.getConnection()).send(self._lastvotes)
+        elif isinstance(info, OptIn):
+            val(self.getConnection()).send(self._lastvotes)
         else:
             self.getReporter().log(logging.WARNING, "Ignoring unknown info "+str(info))
@@ -63,9 +75,9 @@
     # Override
     def getCapabilities(self) -> Capabilities:
-        return Capabilities( set([ "SAOP", "Learn"]), set(['geniusweb.profile.utilityspace.LinearAdditive']))
+        return Capabilities( set([ "SAOP", "Learn", "MOPAC"]), set(['geniusweb.profile.utilityspace.LinearAdditive']))
 
     # Override
     def getDescription(self) -> str:
-        return "Offers random bids until a bid with sufficient utility is offered"
+        return "Offers random bids until a bid with sufficient utility is offered. Parameters minPower and maxPower can be used to control voting behaviour."
 
     # Override
@@ -98,9 +110,19 @@
 
     def _getRandomBid(self, domain:Domain) -> Bid:
-        values:Dict[str, Value]={iss: self._randValue(domain.getValues(iss)) \
-                for iss in domain.getIssues()}
-        return Bid(values)
+        allBids = AllBidsList(domain)
+        return allBids.get(randint(0, allBids.size()-1))
+    
+    def _vote(self, voting:Voting) ->Votes :
+        '''
+        @param voting the {@link Voting} object containing the options
         
-    def _randValue(self, vals:ValueSet) -> Value:
-        values= list(vals)
-        return values[randint(0, len(values)-1)]
+        @return our next Votes.
+        '''
+        val = self._settings.getParameters().get("minPower");
+        minpower:int = val if isinstance(val, int) else 2
+        val = self._settings.getParameters().get("maxPower");
+        maxpower:int = val if isinstance(val,int) else  9999999;
+
+        votes:Set[Vote]  = set([Vote(self._me, offer.getBid(), minpower, maxpower)\
+                for offer in voting.getOffers() if self._isGood(offer.getBid())])
+        return Votes(self._me, votes);
Index: exampleparties/randomparty/requirements.txt
===================================================================
--- exampleparties/randomparty/requirements.txt	(revision 66)
+++ exampleparties/randomparty/requirements.txt	(revision 67)
@@ -1,3 +1,3 @@
-https://tracinsy.ewi.tudelft.nl/pubtrac/GeniusWebPython/export/59/geniuswebcore/dist/geniusweb-1.0.0.tar.gz
+https://tracinsy.ewi.tudelft.nl/pubtrac/GeniusWebPython/export/66/geniuswebcore/dist/geniusweb-1.1.0.tar.gz
 mypy
 
Index: exampleparties/randomparty/setup.py
===================================================================
--- exampleparties/randomparty/setup.py	(revision 66)
+++ exampleparties/randomparty/setup.py	(revision 67)
@@ -3,10 +3,10 @@
 setup(
     name='randomparty',
-    version='1.0.0',    
+    version='1.1.0',    
     description='A python3 party that places random bids with sufficient utility',
     url='https://tracinsy.ewi.tudelft.nl/pubtrac/GeniusWeb',
     author='W.Pasman',
     packages=['randomparty'],
-    install_requires=[ "geniusweb@https://tracinsy.ewi.tudelft.nl/pubtrac/GeniusWebPython/export/59/geniuswebcore/dist/geniusweb-1.0.0.tar.gz"],
+    install_requires=[ "geniusweb@https://tracinsy.ewi.tudelft.nl/pubtrac/GeniusWebPython/export/66/geniuswebcore/dist/geniusweb-1.1.0.tar.gz"],
     py_modules=['party']
 )
Index: exampleparties/randomparty/test/RandomPartyTest.py
===================================================================
--- exampleparties/randomparty/test/RandomPartyTest.py	(revision 66)
+++ exampleparties/randomparty/test/RandomPartyTest.py	(revision 67)
@@ -1,4 +1,6 @@
 from datetime import datetime
 from decimal import Decimal
+import json
+from pathlib import Path
 from typing import cast, List
 import unittest
@@ -8,11 +10,17 @@
 from geniusweb.actions.Offer import Offer
 from geniusweb.actions.PartyId import PartyId
+from geniusweb.actions.Votes import Votes
+from geniusweb.bidspace.AllBidsList import AllBidsList
 from geniusweb.connection.ConnectionEnd import ConnectionEnd
 from geniusweb.inform.ActionDone import ActionDone
 from geniusweb.inform.Inform import Inform
 from geniusweb.inform.Settings import Settings
+from geniusweb.inform.Voting import Voting
 from geniusweb.inform.YourTurn import YourTurn
 from geniusweb.issuevalue.Bid import Bid
 from geniusweb.issuevalue.NumberValue import NumberValue
+from geniusweb.profile.Profile import Profile
+from geniusweb.profile.utilityspace.LinearAdditive import LinearAdditive
+from geniusweb.profile.utilityspace.UtilitySpace import UtilitySpace
 from geniusweb.progress.ProgressTime import ProgressTime
 from geniusweb.references.Parameters import Parameters
@@ -20,7 +28,9 @@
 from geniusweb.references.ProtocolRef import ProtocolRef
 from geniusweb.references.Reference import Reference
+from pyson.ObjectMapper import ObjectMapper
+from tudelft.utilities.listener.DefaultListenable import DefaultListenable
+from uri.uri import URI  # type: ignore 
+
 from randomparty.RandomParty import RandomParty
-from tudelft.utilities.listener.DefaultListenable import DefaultListenable
-from uri import URI  # type: ignore 
 
 
@@ -37,5 +47,5 @@
 
     def getRemoteURI(self)->URI: 
-        return None
+        return URI("whatever")
     
     def close(self):
@@ -49,9 +59,22 @@
     
 class RandomPartyTest(unittest.TestCase):
-    id = PartyId("party1")
+    pyson = ObjectMapper()
+    
+    PARTY1 = PartyId("party1")
     profileref = ProfileRef(URI("file:test/resources/japantrip1.json"))
+    PROFILE = ProfileRef(URI("file:test/resources/testprofile.json"))
     protocolref = ProtocolRef(URI("SAOP"))
+    mopacProtocol = ProtocolRef(URI("MOPAC"));
     progress=ProgressTime(1000, datetime.fromtimestamp(12345))
     parameters=Parameters()
+    mopacSettings = Settings(PARTY1,  PROFILE, mopacProtocol,progress, parameters)
+    serialized =  Path("test/resources/testprofile.json").read_text("utf-8")
+    profile:UtilitySpace = pyson.parse(json.loads(serialized), LinearAdditive) #type:ignore     
+
+    def setUp(self):
+        self.party=RandomParty()
+        self.connection = MyConn()
+        # we load the profile here too, to find a good bid
+    
 
     def test_smoke(self):
@@ -59,31 +82,27 @@
         
     def testConnect(self):
-        connection = MyConn()
         party=RandomParty()
-        party.connect(connection)
+        party.connect(self.connection)
         party.disconnect()
         
         
     def testSendInfo(self):
-        settings  = Settings(self.id, self.profileref, self.protocolref, self.progress, self.parameters )
+        settings  = Settings(self.PARTY1, self.profileref, self.protocolref, self.progress, self.parameters )
         
-        connection = MyConn()
-        party=RandomParty()
-        party.connect(connection)
-        connection.notifyListeners(settings)
-        party.disconnect()
-        self.assertEquals([], connection.getActions())
+        self.party.connect(self.connection)
+        self.connection.notifyListeners(settings)
+        self.party.disconnect()
+        self.assertEquals([], self.connection.getActions())
         
     def testSendYourTurn(self):
-        settings  = Settings(self.id, self.profileref, self.protocolref, self.progress, self.parameters )
+        self.assertEqual(0, len(self.connection.getActions()))
+        settings  = Settings(self.PARTY1, self.profileref, self.protocolref, self.progress, self.parameters )
 
-        connection = MyConn()
-        party=RandomParty()
-        party.connect(connection)
-        connection.notifyListeners(settings)
-        connection.notifyListeners(YourTurn())
-        party.disconnect()
+        self.party.connect(self.connection)
+        self.connection.notifyListeners(settings)
+        self.connection.notifyListeners(YourTurn())
+        self.party.disconnect()
         
-        actions = connection.getActions()
+        actions = self.connection.getActions()
         self.assertEquals(1, len(actions))
         self.assertTrue(isinstance(actions[0], Offer))
@@ -91,5 +110,5 @@
 
     def testSendOfferAndYourTurn(self):
-        settings  = Settings(self.id, self.profileref, self.protocolref, self.progress, self.parameters )
+        settings  = Settings(self.PARTY1, self.profileref, self.protocolref, self.progress, self.parameters )
 
         # nonsense bid, party should not accept
@@ -97,14 +116,32 @@
         offer = Offer(PartyId('other'), bid)
 
-        connection = MyConn()
-        party=RandomParty()
-        party.connect(connection)
-        connection.notifyListeners(settings)
-        connection.notifyListeners(ActionDone(offer))
-        connection.notifyListeners(YourTurn())
-        party.disconnect()
+        self.party.connect(self.connection)
+        self.connection.notifyListeners(settings)
+        self.connection.notifyListeners(ActionDone(offer))
+        self.connection.notifyListeners(YourTurn())
+        self.party.disconnect()
         
-        actions = connection.getActions()
+        actions = self.connection.getActions()
         self.assertEquals(1, len(actions))
         self.assertTrue(isinstance(actions[0], Offer))
 
+
+    def testVoting(self) :
+        self.assertEqual(0, len(self.connection.getActions()))
+        self.party.connect(self.connection);
+        self.party.notifyChange(self.mopacSettings);
+
+        bid = self._findGoodBid()
+        offer = Offer(self.PARTY1, bid)
+        self.party.notifyChange(Voting([offer],{self.PARTY1: 1}))
+        self.assertEqual(1, len(self.connection.getActions()))
+        action = self.connection.getActions()[0]
+        self.assertTrue(isinstance(action,Votes))
+        self.assertEqual(1, len(action.getVotes()))
+        self.assertEqual(bid, next(iter(action.getVotes())).getBid())
+        
+    def _findGoodBid(self)-> Bid:
+        for bid in AllBidsList(self.profile.getDomain()):
+            if self.profile.getUtility(bid) > 0.7:
+                     return bid;
+        raise ValueError("Test can not be done: there is no good bid with utility>0.7");
Index: exampleparties/randomparty/test/resources/testprofile.json
===================================================================
--- exampleparties/randomparty/test/resources/testprofile.json	(revision 67)
+++ exampleparties/randomparty/test/resources/testprofile.json	(revision 67)
@@ -0,0 +1,47 @@
+{
+	"LinearAdditiveUtilitySpace": {
+		"issueUtilities": {
+			"issue2": {
+				"NumberValueSetUtilities": {
+					"lowValue": 12,
+					"lowUtility": 0.3,
+					"highValue": 18,
+					"highUtility": 0.9
+				}
+			},
+			"issue1": {
+				"DiscreteValueSetUtilities": {
+					"valueUtilities": {
+						"issue1value1": 0.2,
+						"issue1value2": 0.8
+					}
+				}
+			}
+		},
+		"issueWeights": {
+			"issue2": 0.4,
+			"issue1": 0.6
+		},
+		"domain": {
+			"name": "test",
+			"issuesValues": {
+				"issue2": {
+					"range": { "low":12,"high":18,"step":1 }
+				},
+				"issue1": {
+					"values": [
+						"issue1value1",
+						"issue1value2"
+					]
+				}
+			}
+		},
+		"name": "testprofile",
+		"reservationBid": {
+			"issuevalues": {
+				"issue1": "issue1value1",
+				"issue2": 12
+			}
+		}
+	}
+}
