Index: geniuswebcore/geniusweb/protocol/NegoState.py
===================================================================
--- geniuswebcore/geniusweb/protocol/NegoState.py	(revision 94)
+++ geniuswebcore/geniusweb/protocol/NegoState.py	(revision 95)
@@ -1,3 +1,4 @@
 from abc import ABC
+from typing import List
 
 from pyson.JsonSubTypes import JsonSubTypes
@@ -6,4 +7,5 @@
 
 from geniusweb.protocol.NegoSettings import NegoSettings
+from geniusweb.protocol.session.SessionResult import SessionResult
 
 
@@ -20,4 +22,5 @@
 	record the final result as well
 	'''
+
 	def getSettings(self) -> NegoSettings: 
 		'''
@@ -25,5 +28,5 @@
 		'''
 
-	def isFinal(self, currentTimeMsLint)-> bool :
+	def isFinal(self, currentTimeMsLint) -> bool:
 		'''
 		@param currentTimeMs the current time in ms since 1970, see
@@ -34,2 +37,10 @@
 		        changes can occur, including no more protocol errors.
 		'''
+
+	def getResults(self) -> List[SessionResult]:
+		'''
+		@return List of the{@link SessionResult}s. Each SessionResult is a short
+		        report of the final outcome. Assumes {@link #isFinal(long)}.
+		        result may be undefined if not.
+		'''
+	
Index: geniuswebcore/geniusweb/protocol/session/SessionResult.py
===================================================================
--- geniuswebcore/geniusweb/protocol/session/SessionResult.py	(revision 94)
+++ geniuswebcore/geniusweb/protocol/session/SessionResult.py	(revision 95)
@@ -12,5 +12,6 @@
 	all the details, only the final outcome and other global notes.
 	'''
-	def __init__(self, participants : Dict[PartyId, PartyWithProfile],
+
+	def __init__(self, participants: Dict[PartyId, PartyWithProfile],
 			agreements:Agreements , penalties:Dict[PartyId, float] ,
 			error:Optional[Exception]):
@@ -19,6 +20,10 @@
 		                    be null. Some of them may have entered later of left
 		                    early. This list should contain them all.
-		@param agreements   the final Agreements.
-		@param penalties    the penalties in [0,1] for each participant.
+		@param agreements   the final Agreements. The key is the party ID, value
+		                    is the bid that the party agreed on. Only parties
+		                    that reached an agreement are in this list.
+		@param penalties    Key is the party ID, the value is the penalties in
+		                    [0,1] for that participant. A penalty only applies to
+		                    an agreement, not to a reservation bid.
 		@param error        a fatal error that terminated the session. Non-fatal
 		                    errors (warnings) are not to be reported. Null if no
@@ -34,5 +39,5 @@
 		self._error = error
 
-	def getParticipants(self) ->Dict[PartyId, PartyWithProfile] :
+	def getParticipants(self) -> Dict[PartyId, PartyWithProfile]:
 		'''
 		@return the map with for each {@link PartyId} the
@@ -43,5 +48,5 @@
 		return dict(self._participants)
 
-	def getAgreements(self) -> Agreements :
+	def getAgreements(self) -> Agreements:
 		'''
 		@return the final {@link Agreements} of the session. May be empty, not
@@ -50,5 +55,5 @@
 		return self._agreements;
 
-	def getPenalties(self ) -> Dict[PartyId, float] :
+	def getPenalties(self) -> Dict[PartyId, float]:
 		'''
 	 	@return Map of penalties,
@@ -56,5 +61,5 @@
 		return dict(self._penalties)
 
-	def getError(self) -> Optional[Exception] :
+	def getError(self) -> Optional[Exception]:
 		'''
 		@return a fatal error that terminated the session. Non-fatal errors
@@ -67,10 +72,10 @@
 		return self._error
 
-	def __repr__(self)->str:
+	def __repr__(self) -> str:
 		return "SessionResult[" + toStr(self._participants) + "," + str(self._agreements) + ","\
-				+ toStr(self._penalties) + "," + str(self._error) + "]"
+				+toStr(self._penalties) + "," + str(self._error) + "]"
 	
 	def __hash__(self):
-		return hash(( toTuple(self._participants ), toTuple(self._penalties ), self._agreements))
+		return hash((toTuple(self._participants), toTuple(self._penalties), self._agreements))
 
 	def __eq__(self, other):
Index: geniuswebcore/geniusweb/protocol/session/SessionState.py
===================================================================
--- geniuswebcore/geniusweb/protocol/session/SessionState.py	(revision 94)
+++ geniuswebcore/geniusweb/protocol/session/SessionState.py	(revision 95)
@@ -1,5 +1,4 @@
 from abc import abstractmethod
 from typing import List, Optional
-
 
 from geniusweb.actions.Action import Action
@@ -28,6 +27,7 @@
 	the protocol. As uaual, mark non-serializable fields as transient.
 	'''
+
 	@abstractmethod
-	def getSettings(self)->SessionSettings:
+	def getSettings(self) -> SessionSettings:
 		'''
 		@return the SessionSettings
@@ -35,5 +35,5 @@
 	
 	@abstractmethod
-	def getActions(self)->List[Action]: 
+	def getActions(self) -> List[Action]: 
 		'''
 		@return unmodifyable list of actions done so far, in the order in which
@@ -52,5 +52,5 @@
 	
 	@abstractmethod
-	def getAgreements(self)->Agreements :
+	def getAgreements(self) -> Agreements:
 		'''
 		@return the current standing agreements
@@ -58,9 +58,2 @@
 		'''
 	
-	@abstractmethod
-	def getResult(self)->Optional[SessionResult]:
-		'''
-		@return the {@link SessionResult} which is a short report of the final
-		        outcome. Assumes {@link #isFinal(long)}. result may be undefined
-		        if not.
-		'''
Index: geniuswebcore/geniusweb/protocol/session/learn/LearnState.py
===================================================================
--- geniuswebcore/geniusweb/protocol/session/learn/LearnState.py	(revision 94)
+++ geniuswebcore/geniusweb/protocol/session/learn/LearnState.py	(revision 95)
@@ -12,4 +12,5 @@
 from geniusweb.references.PartyWithProfile import PartyWithProfile
 
+
 class LearnState (DefaultSessionState["LearnState", "LearnSettings"]):
 	'''
@@ -19,6 +20,6 @@
 	def __init__(self, actions:List[Action] , conns:List[PartyId] ,
 			progress:Optional[Progress] , settings:LearnSettings ,
-			partyprofiles:Dict[PartyId, PartyWithProfile]={}, 
-			e:Optional[ProtocolException]=None ):
+			partyprofiles:Dict[PartyId, PartyWithProfile]={},
+			e:Optional[ProtocolException]=None):
 		'''
 		@param actions       the actions done by the parties
@@ -50,24 +51,24 @@
 
 	def With(self, actions:List[Action] , conns:List[PartyId],
-			progr:Optional[Progress] ,  settings:LearnSettings, 
-			partyprofiles:Dict[PartyId, PartyWithProfile] , 
-			e:Optional[ProtocolException] ) -> "LearnState" :
+			progr:Optional[Progress] , settings:LearnSettings,
+			partyprofiles:Dict[PartyId, PartyWithProfile] ,
+			e:Optional[ProtocolException]) -> "LearnState":
 		return LearnState(actions, conns, progr, settings, partyprofiles,
 				e)
 
-	def getAgreements(self)->Agreements :
+	def getAgreements(self) -> Agreements:
 		return Agreements()
 
-	def getResult(self)->SessionResult :
-		return SessionResult(self.getPartyProfiles(), self.getAgreements(),
-				{}, None)
+	def getResults(self) -> List[SessionResult]:
+		return [SessionResult(self.getPartyProfiles(), self.getAgreements(),
+				{}, None)]
 
-	def isFinal(self, currentTimeMs:int) ->bool:
+	def isFinal(self, currentTimeMs:int) -> bool:
 		done = self._getDoneLearning()
 		# if done is empty we're probably still starting up.
 		return super().isFinal(currentTimeMs)\
-				or (len(done)!=0 and set(self.getConnections()).issubset(done))
+				or (len(done) != 0 and set(self.getConnections()).issubset(done))
 
-	def WithException(self, e:ProtocolException) ->"LearnState" :
+	def WithException(self, e:ProtocolException) -> "LearnState":
 		'''
 		@param e the error that occured
@@ -77,5 +78,5 @@
 				self.getSettings(), self.getPartyProfiles(), e)
 
-	def checkAction(self, actor:PartyId , action:Action ) ->Optional[str]:
+	def checkAction(self, actor:PartyId , action:Action) -> Optional[str]:
 		'''
 		@param actor  the known real actor that did this action
@@ -92,5 +93,5 @@
 		return None
 
-	def _getDoneLearning(self)->Set[PartyId] :
+	def _getDoneLearning(self) -> Set[PartyId]:
 		'''
 		@return set of parties that reported they are done with learning.
Index: geniuswebcore/geniusweb/protocol/session/mopac/MOPACState.py
===================================================================
--- geniuswebcore/geniusweb/protocol/session/mopac/MOPACState.py	(revision 94)
+++ geniuswebcore/geniusweb/protocol/session/mopac/MOPACState.py	(revision 95)
@@ -56,5 +56,5 @@
 			progress:Optional[Progress] ,
 			settings:MOPACSettings,
-			partyprofiles:Dict[PartyId, PartyWithProfile] ): 
+			partyprofiles:Dict[PartyId, PartyWithProfile]): 
 		'''
 		@param phase         The Phase, or null if still initializing. Phase is
@@ -86,5 +86,5 @@
 		self._partyprofiles = partyprofiles
 
-	def initPhase(self,newprogress:Progress , now:int) -> "MOPACState" :
+	def initPhase(self, newprogress:Progress , now:int) -> "MOPACState":
 		'''
 		Sets the progress for this session and initial phase. Must be called
@@ -109,29 +109,29 @@
 				self._partyprofiles)
 
-	def getActions(self)->List[Action]:
+	def getActions(self) -> List[Action]:
 		return list(self._actions)
 
-	def getProgress(self)->Optional[Progress] :
+	def getProgress(self) -> Optional[Progress]:
 		return self._progress
 
-	def getAgreements(self)-> Agreements: 
+	def getAgreements(self) -> Agreements: 
 		return val(self._phase).getPartyStates().getAgreements();
 
-	def getSettings(self)->MOPACSettings :
+	def getSettings(self) -> MOPACSettings:
 		return self._settings
 
-	def getPartyProfiles(self)->Dict[PartyId, PartyWithProfile]:
+	def getPartyProfiles(self) -> Dict[PartyId, PartyWithProfile]:
 		return dict(self._partyprofiles)
 
-	def  isFinal(self, now:int)->bool:
+	def  isFinal(self, now:int) -> bool:
 		return self._phase != None and val(self._phase).isFinal(now) \
 			and not self.isNewPhasePossible(now)
 
-	def getResult(self)->SessionResult :
-		return SessionResult(self._partyprofiles, self.getAgreements(),
-				{}, None)
+	def getResults(self) -> List[SessionResult]:
+		return [SessionResult(self._partyprofiles, self.getAgreements(),
+				{}, None)]
 
 	@staticmethod
-	def  _getAvailablePhaseTime(aprogress:Progress , now:int) ->int: 
+	def  _getAvailablePhaseTime(aprogress:Progress , now:int) -> int: 
 		'''
 		@param progress the Progress that needs to be checked
@@ -140,8 +140,8 @@
 		        progress.
 		'''
-		return min(int(aprogress.getTerminationTime().timestamp()*1000) - now,
+		return min(int(aprogress.getTerminationTime().timestamp() * 1000) - now,
 				PHASE_MAXTIME)
 
-	def With(self, id:PartyId , partyprofile:PartyWithProfile ) -> "MOPACState" :
+	def With(self, id:PartyId , partyprofile:PartyWithProfile) -> "MOPACState":
 		'''
 		@param id           the new {@link PartyId}
@@ -157,8 +157,8 @@
 
 		newprofiles = dict(self._partyprofiles)
-		newprofiles[id]= partyprofile
-		return MOPACState(None, self._actions,self._progress, self._settings, newprofiles)
+		newprofiles[id] = partyprofile
+		return MOPACState(None, self._actions, self._progress, self._settings, newprofiles)
 	
-	def WithException(self, e:ProtocolException) ->"MOPACState" :
+	def WithException(self, e:ProtocolException) -> "MOPACState":
 		'''
 		@param e the {@link ProtocolException} that occured
@@ -166,8 +166,8 @@
 		        {@link #initPhase(Progress, long)} before using this
 		'''
-		return MOPACState(val(self._phase).WithException(e), self._actions, self._progress, 
-						self._settings,self._partyprofiles)
-
-	def nextPhase(self, now:int)->"MOPACState" :
+		return MOPACState(val(self._phase).WithException(e), self._actions, self._progress,
+						self._settings, self._partyprofiles)
+
+	def nextPhase(self, now:int) -> "MOPACState":
 		'''
 		Start the next phase. If new phase is OfferPhase, we increase progress.
@@ -178,12 +178,12 @@
 		@return new {@link MOPACState} with phase initialized for next phase.
 		'''
-		remainingNegoTime = int(val(self._progress).getTerminationTime().timestamp()*1000) - now
+		remainingNegoTime = int(val(self._progress).getTerminationTime().timestamp() * 1000) - now
 		newphase = val(self._phase).next(now, min(remainingNegoTime, PHASE_MAXTIME))
 
-		return MOPACState(newphase, self._actions, 
+		return MOPACState(newphase, self._actions,
 					MOPACState._increment(val(self._progress), val(self._phase)),
 				self.getSettings(), self._partyprofiles)
 
-	def isNewPhasePossible(self, now:int)->bool:
+	def isNewPhasePossible(self, now:int) -> bool:
 		'''
 		When this is called, all parties should have acted.
@@ -202,8 +202,8 @@
 						now) > PHASE_MINTIME
 
-	def getPhase(self)->Phase :
+	def getPhase(self) -> Phase:
 		return val(self._phase)
 
-	def WithAction(self, actor:PartyId,  action:Action, now:int)->"MOPACState" :
+	def WithAction(self, actor:PartyId, action:Action, now:int) -> "MOPACState":
 		'''
 		Check if action is allowed. Add action to the list of actions. Notice,
@@ -225,5 +225,5 @@
 
 	@staticmethod
-	def _increment(aprogress:Progress , aphase:Phase ) ->Progress :
+	def _increment(aprogress:Progress , aphase:Phase) -> Progress:
 		'''
 		@param aprogress the progress that might need to be advanced
@@ -232,14 +232,14 @@
 		        {@link OptIn}.
 		'''
-		if isinstance(aprogress,ProgressRounds) and isinstance(aphase,OptInPhase):
+		if isinstance(aprogress, ProgressRounds) and isinstance(aphase, OptInPhase):
 			return aprogress.advance()
 		return aprogress
 
-	def _getPowers(self)-> Dict[PartyId, int]:
+	def _getPowers(self) -> Dict[PartyId, int]:
 		'''
 		@return the power of all parties as set in their parameters, default =1.
 		    bad power values (non-integer, or <1) are ignored.
 		'''
-		map:Dict[PartyId,int] = {}
+		map:Dict[PartyId, int] = {}
 		for pid in self._partyprofiles:
 			if self._partyprofiles[pid].getParty().getParameters().containsKey("power"):
@@ -249,13 +249,13 @@
 					power = 1
 			else:
-				power=1
-			map[pid]=power
+				power = 1
+			map[pid] = power
 		return map
 
-	def __repr__(self)->str:
+	def __repr__(self) -> str:
 		return "MOPACState[" + str(self._phase) + "," + str(self._settings)\
-			+ "," + str(self._partyprofiles) + "," + str(self._progress) + "]"
-
-	def finishPhase(self)->"MOPACState" :
+			+"," + str(self._partyprofiles) + "," + str(self._progress) + "]"
+
+	def finishPhase(self) -> "MOPACState":
 		'''
 		@return a wrapped-up state, with all parties doen an action or kicked,
@@ -264,18 +264,18 @@
 		newphase = val(self._phase).finish()
 		newactions = list(self._actions)
-		newactions=newactions+ newphase.getPartyStates().getActions()
+		newactions = newactions + newphase.getPartyStates().getActions()
 		return MOPACState(newphase, newactions, self._progress, self._settings,
 				self._partyprofiles)
 
 	def __hash__(self):
-		return hash((tuple(self._actions), toTuple(self._partyprofiles), 
+		return hash((tuple(self._actions), toTuple(self._partyprofiles),
 					self._phase, self._progress, self._settings))
 	
 	def __eq__(self, other):
 		return isinstance(other, self.__class__) \
-			 and self._actions==other._actions\
-			 and self._partyprofiles==other._partyprofiles\
-			 and self._phase==other._phase\
-			 and self._progress==other._progress\
-			 and self._settings==other._settings
-
+			 and self._actions == other._actions\
+			 and self._partyprofiles == other._partyprofiles\
+			 and self._phase == other._phase\
+			 and self._progress == other._progress\
+			 and self._settings == other._settings
+
Index: geniuswebcore/geniusweb/protocol/session/saop/SAOPState.py
===================================================================
--- geniuswebcore/geniusweb/protocol/session/saop/SAOPState.py	(revision 94)
+++ geniuswebcore/geniusweb/protocol/session/saop/SAOPState.py	(revision 95)
@@ -18,5 +18,6 @@
 from geniusweb.references.PartyWithProfile import PartyWithProfile
 
-class SAOPState (DefaultSessionState[ "SAOPState","SAOPSettings"]):  
+
+class SAOPState (DefaultSessionState[ "SAOPState", "SAOPSettings"]): 
 	'''
 	Immutable.
@@ -25,6 +26,6 @@
 	def __init__(self, actions:List[Action] , connections:List[PartyId] ,
 			progress:Optional[Progress] , settings: SAOPSettings ,
-			partyprofiles:Dict[PartyId, PartyWithProfile]={}, 
-			error:Optional[ProtocolException]=None) :
+			partyprofiles:Dict[PartyId, PartyWithProfile]={},
+			error:Optional[ProtocolException]=None):
 		'''
 		
@@ -45,12 +46,11 @@
 	def With(self, actions:List[Action] , conns: List[PartyId],
 			progr:Optional[Progress] , settings: SAOPSettings,
-			partyprofiles:Dict[PartyId, PartyWithProfile] ,  e:Optional[ProtocolException]) -> "SAOPState" :
+			partyprofiles:Dict[PartyId, PartyWithProfile] , e:Optional[ProtocolException]) -> "SAOPState":
 		assert isinstance(actions, list)
-		#assert isinstance(settings, SAOPSettings)
+		# assert isinstance(settings, SAOPSettings)
 		assert isinstance(partyprofiles, dict)
 		return SAOPState(actions, conns, progr, settings, partyprofiles, e);
 
-
-	def getAgreements(self) ->Agreements :
+	def getAgreements(self) -> Agreements:
 		agree = Agreements()
 		acts = self.getActions()
@@ -64,11 +64,11 @@
 
 		# check that the last n-1 are accepts.
-		allaccept = all( [ (isinstance(act, Accept) and bid==act.getBid())\
-					for act in acts[-(nparticipants-1):]] )
+		allaccept = all([ (isinstance(act, Accept) and bid == act.getBid())\
+					for act in acts[-(nparticipants - 1):]])
 		if allaccept:
 			agree = Agreements({party: bid for party in  self._getParties()})
 		return agree
 
-	def _getParties(self)->List[PartyId] :
+	def _getParties(self) -> List[PartyId]:
 		'''
 		@return all currently connected parties.
@@ -76,14 +76,14 @@
 		return self.getConnections()
 
-	def isFinal(self,  currentTimeMs:int)->bool:
+	def isFinal(self, currentTimeMs:int) -> bool:
 		acts = self.getActions()
 		return super().isFinal(currentTimeMs) \
-				or self.getAgreements().getMap()!={} \
-				or (not acts==[] and isinstance(acts[- 1], EndNegotiation))
+				or self.getAgreements().getMap() != {} \
+				or (not acts == [] and isinstance(acts[-1], EndNegotiation))
 
-	def WithAction(self, actor:PartyId , action:Action ) -> "SAOPState":
+	def WithAction(self, actor:PartyId , action:Action) -> "SAOPState":
 		return super().WithAction(actor, action).WithProgress(self.advanceProgress())
 
-	def checkAction(self, actor:PartyId, action:Action ) -> Optional[str]:
+	def checkAction(self, actor:PartyId, action:Action) -> Optional[str]:
 		msg = super().checkAction(actor, action)
 		if msg:
@@ -101,7 +101,7 @@
 			if bid != action.getBid():
 				return "Party accepts a bid differing from the last offer ="\
-						+ str(bid) + ", action=" + str(action) + ")"
+						+str(bid) + ", action=" + str(action) + ")"
 			return None
-		elif isinstance(action,Offer):
+		elif isinstance(action, Offer):
 			return None
 		elif isinstance(action, EndNegotiation):
@@ -109,6 +109,5 @@
 		return "Action " + str(action) + " is not allowed in SAOP"
 
-
-	def _getLastBid(self)-> Optional[ Bid ]:
+	def _getLastBid(self) -> Optional[ Bid ]:
 		'''
 		Check up to nparticipants-1 steps back if there was an offer.
@@ -121,10 +120,10 @@
 		while n > len(acts) - nparticipants and n >= 0:
 			action = acts[n]
-			if isinstance(action ,Offer):
+			if isinstance(action , Offer):
 				return action.getBid()
-			n=n-1
+			n = n - 1
 		return None
 
-	def _getNextActor(self)->PartyId :
+	def _getNextActor(self) -> PartyId:
 		'''
 		@return the next actor in the current state. Assumes 1 action per actor
@@ -134,5 +133,5 @@
 		return self.getConnections()[len(self.getActions()) % len(self.getConnections())]
 
-	def advanceProgress(self)-> Progress :
+	def advanceProgress(self) -> Progress:
 		'''
 		@return new progress state
@@ -140,5 +139,5 @@
 		newprogress = self.getProgress()
 		assert newprogress
-		if isinstance(newprogress,ProgressRounds) and self._isLastActor():
+		if isinstance(newprogress, ProgressRounds) and self._isLastActor():
 			newprogress = newprogress.advance()
 		return newprogress
@@ -151,5 +150,5 @@
 		return len(self.getActions()) % nparticipants == nparticipants - 1;
 
-	def getResult(self) -> SessionResult:
-		return SessionResult(self.getPartyProfiles(), self.getAgreements(),
-				{}, self.getError())
+	def getResults(self) -> List[SessionResult]:
+		return [SessionResult(self.getPartyProfiles(), self.getAgreements(),
+				{}, self.getError())]
