Index: protocol/src/main/java/geniusweb/protocol/CurrentNegoState.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/CurrentNegoState.java	(revision 53)
+++ protocol/src/main/java/geniusweb/protocol/CurrentNegoState.java	(revision 1)
@@ -14,41 +14,6 @@
 	}
 
-	public CurrentNegoState(NegoState state, Long now) {
-		super(now);
-		this.state = state;
-	}
-
 	public NegoState getState() {
 		return state;
 	}
-
-	@Override
-	public String toString() {
-		return "CurrentNegoState[" + getTime() + "," + state + "]";
-	}
-
-	@Override
-	public int hashCode() {
-		final int prime = 31;
-		int result = super.hashCode();
-		result = prime * result + ((state == null) ? 0 : state.hashCode());
-		return result;
-	}
-
-	@Override
-	public boolean equals(Object obj) {
-		if (this == obj)
-			return true;
-		if (!super.equals(obj))
-			return false;
-		if (getClass() != obj.getClass())
-			return false;
-		CurrentNegoState other = (CurrentNegoState) obj;
-		if (state == null) {
-			if (other.state != null)
-				return false;
-		} else if (!state.equals(other.state))
-			return false;
-		return true;
-	}
 }
Index: protocol/src/main/java/geniusweb/protocol/NegoProtocol.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/NegoProtocol.java	(revision 53)
+++ protocol/src/main/java/geniusweb/protocol/NegoProtocol.java	(revision 1)
@@ -8,9 +8,9 @@
 
 import geniusweb.connection.ConnectionFactory;
-import geniusweb.deadline.Deadline;
 import geniusweb.events.CurrentState;
 import geniusweb.events.ProtocolEvent;
-import geniusweb.protocol.partyconnection.ProtocolToPartyConnFactory;
+import geniusweb.protocol.partyconnection.ConnectionWithPartyFactory;
 import geniusweb.protocol.session.SessionProtocol;
+import geniusweb.protocol.session.SessionSettings;
 import geniusweb.protocol.session.SessionState;
 import geniusweb.protocol.tournament.TournamentProtocol;
@@ -26,11 +26,16 @@
  * {@link #getDescription()}. A protocol reports the progress through its
  * {@link Listenable} interface. <br>
- * <h2>General information</h2>
+ * <p>
  * 
  * A protocol is mutable because the incoming connections cause state changes.
- * But it is recommended to push changing properties into the state so that the
- * complete state can be recovered and analysed.
+ * But it is recommended to push all changing properties into the state.
  * <p>
  * Because a protocol contains an internal state, it can be used only once.
+ * <p>
+ * The protocol also needs to keep an eye on the deadline and take appropriate
+ * actions when the deadline is reached. <br>
+ * <p>
+ * A protocol should emit a {@link SessionEnded} or {@link TournamentEnded}
+ * event when it is finished.
  * <p>
  * The protocol can emit a {@link CurrentState} event at any time. It should do
@@ -41,21 +46,10 @@
  * which it can resolve received {@link Reference}s. <br>
  * First call to instances <b>must be</b>
- * {@link #start(ProtocolToPartyConnFactory)}.
- * 
- * <h2>Ensure time deadline</h2>
- * 
- * The protocol also needs to keep an eye on the deadline and take appropriate
- * actions when the deadline is reached. <br>
- * <p>
- * All protocol implementations must ensure that the deadline is kept and that
- * the session ends at the agreed time {@link Deadline#getDuration()}. This is
- * to ensure that the negotiation ends and resources are freed up at or before
- * some known time.
+ * {@link #start(SessionSettings, ConnectionFactory)}.
  * 
  */
 @JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE, isGetterVisibility = Visibility.NONE)
 @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
-@JsonSubTypes({ @Type(value = SessionProtocol.class),
-		@Type(value = TournamentProtocol.class) })
+@JsonSubTypes({ @Type(value = SessionProtocol.class), @Type(value = TournamentProtocol.class) })
 
 public interface NegoProtocol extends Listenable<ProtocolEvent> {
@@ -70,22 +64,21 @@
 	 * <p>
 	 * 
-	 * All errors are to be handled through {@link SessionState#getResult()}
-	 * except for bugs that use {@link RuntimeException} like
-	 * {@link IllegalArgumentException}s. <br>
-	 * The protocol usually uses the incoming connections to keep running. It
-	 * does not need to run in a separate thread or so.
+	 * All errors are to be handled through {@link SessionState#getError()} except
+	 * for plain {@link IllegalArgumentException}s. <br>
+	 * The protocol usually uses the incoming connections to keep running. It does
+	 * not need to run in a separate thread or so.
 	 * 
 	 * 
-	 * @param connectionfactory the {@link ProtocolToPartyConnFactory} that
-	 *                          allows the protocol to connect with the
-	 *                          {@link Reference}s in the settings
+	 * @param connectionfactory the {@link ConnectionWithPartyFactory} that allows
+	 *                          the protocol to connect with the {@link Reference}s
+	 *                          in the settings
 	 */
-	void start(ProtocolToPartyConnFactory connectionfactory);
+	void start(ConnectionWithPartyFactory connectionfactory);
 
 	/**
 	 * 
-	 * @return a complete description of how this protocol behaves. Presented to
-	 *         the end users who should know negotiation basics but not all
-	 *         technical terms.
+	 * @return a complete description of how this protocol behaves. Presented to the
+	 *         end users who should know negotiation basics but not all technical
+	 *         terms.
 	 */
 	String getDescription();
@@ -93,6 +86,6 @@
 	/**
 	 * @return current state: the results of all sessions run so far and how to
-	 *         continue from that point. Changes over time as the session
-	 *         proceeds. Errors are also stored in the state.
+	 *         continue from that point. Changes over time as the session proceeds.
+	 *         Errors are also stored in the state.
 	 */
 	NegoState getState();
@@ -105,7 +98,6 @@
 
 	/**
-	 * Add a party after the protocol has started. Only some protocols can
-	 * handle this call. Usual protocols take the settings with their
-	 * constructor.
+	 * Add a party after the protocol has started. Only some protocols can handle
+	 * this call. Usual protocols take the settings with their constructor.
 	 * 
 	 * @param party the {@link PartyWithProfile} to be added.
Index: protocol/src/main/java/geniusweb/protocol/NegoSettings.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/NegoSettings.java	(revision 53)
+++ protocol/src/main/java/geniusweb/protocol/NegoSettings.java	(revision 1)
@@ -5,8 +5,10 @@
 import com.fasterxml.jackson.annotation.JsonSubTypes;
 import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
 
 import geniusweb.protocol.session.SessionSettings;
 import geniusweb.protocol.tournament.TournamentSettings;
+
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+
 import tudelft.utilities.logging.Reporter;
 
@@ -34,5 +36,5 @@
 	/**
 	 * @param logger the logger where the protocol can log events to.
-	 * @return an initialized and ready to use {@link NegoProtocol} that can
+	 * @return the an initialized and ready to use {@link NegoProtocol} that can
 	 *         handle this Negotiation.
 	 */
Index: protocol/src/main/java/geniusweb/protocol/NegoState.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/NegoState.java	(revision 53)
+++ protocol/src/main/java/geniusweb/protocol/NegoState.java	(revision 1)
@@ -1,5 +1,3 @@
 package geniusweb.protocol;
-
-import java.util.List;
 
 import com.fasterxml.jackson.annotation.JsonAutoDetect;
@@ -7,18 +5,13 @@
 import com.fasterxml.jackson.annotation.JsonSubTypes;
 import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
 
-import geniusweb.protocol.session.SessionResult;
 import geniusweb.protocol.session.SessionState;
 import geniusweb.protocol.tournament.TournamentState;
 
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+
 /**
- * The current state of the session/tournament. Must be (de)serializabl;e so
- * that it can be restarted if a crash occurs. Notice that this restart
- * functionality is not yet available.
- * <p>
- * In general the state contains all the information to control the flow of the
- * negotiation: who did what, are we finished, etc. This object may be stored to
- * record the final result as well
+ * The current state of the tournament. Must be serializabl;e so that it can be
+ * restarted if a crash occurs.
  */
 @JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE, isGetterVisibility = Visibility.NONE)
@@ -45,8 +38,7 @@
 	/**
 	 * 
-	 * @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.
+	 * @return a fatal error occured during the tournament. returns null if no
+	 *         errors occured.
 	 */
-	List<SessionResult> getResults();
+	ProtocolException getError();
 }
Index: protocol/src/main/java/geniusweb/protocol/ProtocolException.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/ProtocolException.java	(revision 53)
+++ protocol/src/main/java/geniusweb/protocol/ProtocolException.java	(revision 1)
@@ -2,40 +2,22 @@
 
 import geniusweb.actions.PartyId;
+import geniusweb.party.Party;
 import geniusweb.references.PartyRef;
 
 /**
- * thrown if a Party violates the protocols (that includes disconnecting).
+ * thrown if a {@link Party} violates the protocols (that includes
+ * disconnecting).
  */
 public class ProtocolException extends Exception {
-	private static final long serialVersionUID = 4618901784366523980L;
-	private PartyId party; // the failing party
+	private String party; // the failing party
 
 	/**
+	 * 
 	 * @param message the error message
 	 * @param party   offending party, either the {@link PartyId} or a
-	 *                {@link PartyRef}. In exceptional cases this can be null,
-	 *                eg if it can not be determined which party failed. Null
-	 *                should be avoided if possible at all.
+	 *                {@link PartyRef}
 	 */
-	public ProtocolException(String message, PartyId party) {
-		this(message, party, null);
-	}
-
-	/**
-	 * ProtocolException is special, in that it does not auto-fill the
-	 * stacktrace. This is needed because usually a ProtocolException is caused
-	 * by a party doing a bad action. Creating a stacktrace pointing to the
-	 * class reporting the protocol exception (usually, the protocol handler)
-	 * makes no sense as the protocol handler is doing the correct job there.
-	 * 
-	 * 
-	 * @param message the error message
-	 * @param party   offending {@link PartyId}. In exceptional cases this can
-	 *                be null, eg if it can not be determined which party
-	 *                failed. Null should be avoided if possible at all.
-	 * @param e       the cause of the error
-	 */
-	public ProtocolException(String message, PartyId party, Throwable e) {
-		super(party + ":" + message, e, true, false);
+	public ProtocolException(String message, String party) {
+		super(party + ":" + message);
 		this.party = party;
 	}
@@ -43,8 +25,19 @@
 	/**
 	 * 
-	 * @return offending party, either the {@link PartyId} or a
-	 *         {@link PartyRef}. In exceptional cases this can be null.
+	 * @param message the error message
+	 * @param party   offending party, either the {@link PartyId} or a
+	 *                {@link PartyRef}
+	 * @param e       the cause of the error
 	 */
-	public PartyId getParty() {
+	public ProtocolException(String message, String party, Throwable e) {
+		super(party + ":" + message, e);
+		this.party = party;
+	}
+
+	/**
+	 * 
+	 * @return offending party, either the {@link PartyId} or a {@link PartyRef}
+	 */
+	public String getParty() {
 		return party;
 	}
Index: protocol/src/main/java/geniusweb/protocol/SessionResult.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/SessionResult.java	(revision 1)
+++ protocol/src/main/java/geniusweb/protocol/SessionResult.java	(revision 1)
@@ -0,0 +1,135 @@
+package geniusweb.protocol;
+
+import java.util.Collections;
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+
+import geniusweb.issuevalue.Bid;
+import geniusweb.references.PartyWithProfile;
+
+/**
+ * All results collected from running a session. Normally this does not contain
+ * all the details, only the final outcome and other global notes.
+ */
+@JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)
+public class SessionResult {
+	private final List<PartyWithProfile> participants;
+	private final Bid agreement;
+
+	// add more type info so that jackson can deserialize the actual class
+	@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.WRAPPER_OBJECT)
+	private final Throwable error;
+
+	/**
+	 * 
+	 * @param participants the list oof {@link PartyWithProfile}, in the proper
+	 *                     order (this is relevant for the protocol etc). Should
+	 *                     never be null. Some of them may have entered later of
+	 *                     left early. This list should contain them all.
+	 * @param agreement    the final agreement {@link Bid} of the session. Null
+	 *                     if no agreement was reached.
+	 * @param error        a fatal error that terminated the session. Non-fatal
+	 *                     errors (warnings) are not to be reported. Null if no
+	 *                     fatal error occured (session ended following the
+	 *                     protocol). Normally, a fatal error results in no
+	 *                     agreement but there might be protocols that allow a
+	 *                     session to end with an error but stick with a already
+	 *                     reached agreement as well.
+	 */
+	@JsonCreator
+	public SessionResult(
+			@JsonProperty("participants") List<PartyWithProfile> participants,
+			@JsonProperty("agreement") Bid agreement,
+			@JsonProperty("error") Throwable error) {
+		this.participants = participants;
+		this.agreement = agreement;
+		this.error = error;
+	}
+
+	/**
+	 * 
+	 * @return the list oof {@link PartyWithProfile}, in the proper order (this
+	 *         is relevant for the protocol etc). Should never be null. Some of
+	 *         them may have entered later of left early. This list should
+	 *         contain them all.
+	 */
+	public List<PartyWithProfile> getParticipants() {
+		return Collections.unmodifiableList(participants);
+	}
+
+	/**
+	 * 8return the final agreement {@link Bid} of the session. Null if no
+	 * agreement was reached.
+	 */
+	public Bid getAgreement() {
+		return agreement;
+	};
+
+	/**
+	 * 
+	 * @return a fatal error that terminated the session. Non-fatal errors
+	 *         (warnings) are not to be reported. Null if no fatal error occured
+	 *         (session ended following the protocol). Normally, a fatal error
+	 *         results in no agreement but there might be protocols that allow a
+	 *         session to end with an error but stick with a already reached
+	 *         agreement as well.
+	 */
+	public Throwable getError() {
+		return error;
+	}
+
+	@Override
+	public String toString() {
+		return "SessionResult[" + participants + "," + agreement + "," + error
+				+ "]";
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result
+				+ ((agreement == null) ? 0 : agreement.hashCode());
+		result = prime * result + ((error == null) ? 0 : error.hashCode());
+		result = prime * result
+				+ ((participants == null) ? 0 : participants.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		SessionResult other = (SessionResult) obj;
+		if (agreement == null) {
+			if (other.agreement != null)
+				return false;
+		} else if (!agreement.equals(other.agreement))
+			return false;
+		if (error == null) {
+			if (other.error != null)
+				return false;
+		} else if (other.error == null)
+			return false;
+		else if (!error.toString().equals(other.error.toString()))
+			// HACK error does not have equals implemented!
+			// so we hacked in toString() here to work around it.
+			return false;
+		if (participants == null) {
+			if (other.participants != null)
+				return false;
+		} else if (!participants.equals(other.participants))
+			return false;
+		return true;
+	}
+
+}
Index: protocol/src/main/java/geniusweb/protocol/partyconnection/ConnectionWithParties.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/partyconnection/ConnectionWithParties.java	(revision 1)
+++ protocol/src/main/java/geniusweb/protocol/partyconnection/ConnectionWithParties.java	(revision 1)
@@ -0,0 +1,123 @@
+package geniusweb.protocol.partyconnection;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import geniusweb.actions.PartyId;
+import geniusweb.party.inform.Inform;
+
+/**
+ * Contains all parties with their connections. immutable
+ */
+public class ConnectionWithParties implements Iterable<ConnectionWithParty> {
+	private List<ConnectionWithParty> connections;
+
+	public ConnectionWithParties(List<ConnectionWithParty> connections) {
+		this.connections = connections;
+	}
+
+	/**
+	 * @param id the {@link PartyId} needed
+	 * @return a connection with that party, or null if no such connection.
+	 */
+	public ConnectionWithParty get(PartyId id) {
+		return connections.stream().filter(conn -> id.equals(conn.getParty()))
+				.findAny().orElse(null);
+	}
+
+	/**
+	 * 
+	 * @return true iff all parties have one connection only
+	 */
+	public boolean allunique() {
+		return getParties().size() == connections.size();
+	}
+
+	/**
+	 * 
+	 * @return list of parties currently in the connections.
+	 */
+	private List<PartyId> getParties() {
+		return connections.stream().map(conn -> conn.getParty()).distinct()
+				.collect(Collectors.toList());
+	}
+
+	/**
+	 * Broadcast info to all parties
+	 * 
+	 * @param info the {@link Inform} to broadcast
+	 */
+	public void broadcast(Inform info) throws IOException {
+		for (ConnectionWithParty conn : connections) {
+			conn.send(info);
+		}
+	}
+
+	/**
+	 * 
+	 * @return number of connections available
+	 */
+	public int size() {
+		return connections.size();
+	}
+
+	/**
+	 * @param i
+	 * @return the ith connection
+	 */
+	public ConnectionWithParty get(int i) {
+		return connections.get(i);
+	}
+
+	public Stream<ConnectionWithParty> stream() {
+		return connections.stream();
+	}
+
+	@Override
+	public Iterator<ConnectionWithParty> iterator() {
+		return connections.iterator();
+	}
+
+	public ConnectionWithParties with(ConnectionWithParty conn) {
+		List<ConnectionWithParty> newconnections = new LinkedList<>(
+				connections);
+		newconnections.add(conn);
+		return new ConnectionWithParties(newconnections);
+	}
+
+	@Override
+	public String toString() {
+		return "ConnectionWithParties" + connections;
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result
+				+ ((connections == null) ? 0 : connections.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		ConnectionWithParties other = (ConnectionWithParties) obj;
+		if (connections == null) {
+			if (other.connections != null)
+				return false;
+		} else if (!connections.equals(other.connections))
+			return false;
+		return true;
+	}
+
+}
Index: protocol/src/main/java/geniusweb/protocol/partyconnection/ConnectionWithParty.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/partyconnection/ConnectionWithParty.java	(revision 1)
+++ protocol/src/main/java/geniusweb/protocol/partyconnection/ConnectionWithParty.java	(revision 1)
@@ -0,0 +1,19 @@
+package geniusweb.protocol.partyconnection;
+
+import geniusweb.actions.Action;
+import geniusweb.actions.PartyId;
+import geniusweb.connection.Connection;
+import geniusweb.party.inform.Inform;
+
+/**
+ * Connection of the protocol with a party. Note, this is the opposite direction
+ * of a connection of the party with the protocol.
+ */
+public interface ConnectionWithParty extends Connection<Action, Inform> {
+
+	/**
+	 * 
+	 * @return the partyId of the party that this connects to
+	 */
+	PartyId getParty();
+}
Index: protocol/src/main/java/geniusweb/protocol/partyconnection/ConnectionWithPartyFactory.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/partyconnection/ConnectionWithPartyFactory.java	(revision 1)
+++ protocol/src/main/java/geniusweb/protocol/partyconnection/ConnectionWithPartyFactory.java	(revision 1)
@@ -0,0 +1,39 @@
+package geniusweb.protocol.partyconnection;
+
+import java.io.IOException;
+import java.util.List;
+
+import geniusweb.actions.Action;
+import geniusweb.connection.ConnectionFactory;
+import geniusweb.party.inform.Inform;
+import geniusweb.references.Reference;
+import tudelft.utilities.repository.NoResourcesNowException;
+
+/**
+ * An extended {@link ConnectionFactory} that store PartyIDs with the
+ * connections, making it possible to find back the appropriate connection given
+ * a PartyID. Also, it allows the connection factory to actually assign the
+ * PartyIDs.
+ *
+ */
+public interface ConnectionWithPartyFactory
+		extends ConnectionFactory<Action, Inform> {
+	@Override
+	public ConnectionWithParty connect(Reference reference)
+			throws IOException, NoResourcesNowException;
+
+	/**
+	 * Connects a set of References in one go, following a modified Banker's
+	 * algorthm.
+	 * 
+	 * @param references the list of references to connect with
+	 * @return a List of connections, one fore each Reference.
+	 * @throws IOException             if a connection is failing irrecoverably.
+	 * @throws NoResourcesNowException is there are insufficient resources now.
+	 *                                 This also includes a suggested moment to
+	 *                                 retry.
+	 */
+	List<ConnectionWithParty> connect(List<Reference> references)
+			throws IOException, NoResourcesNowException;
+
+}
Index: protocol/src/main/java/geniusweb/protocol/partyconnection/ProtocolToPartyConn.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/partyconnection/ProtocolToPartyConn.java	(revision 53)
+++ 	(revision )
@@ -1,19 +1,0 @@
-package geniusweb.protocol.partyconnection;
-
-import geniusweb.actions.Action;
-import geniusweb.actions.PartyId;
-import geniusweb.connection.ConnectionEnd;
-import geniusweb.inform.Inform;
-
-/**
- * Connection of the protocol with a party. Note, this is the opposite direction
- * of a connection of the party with the protocol.
- */
-public interface ProtocolToPartyConn extends ConnectionEnd<Action, Inform> {
-
-	/**
-	 * 
-	 * @return the partyId of the party that this connects to.
-	 */
-	PartyId getParty();
-}
Index: protocol/src/main/java/geniusweb/protocol/partyconnection/ProtocolToPartyConnFactory.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/partyconnection/ProtocolToPartyConnFactory.java	(revision 53)
+++ 	(revision )
@@ -1,52 +1,0 @@
-package geniusweb.protocol.partyconnection;
-
-import java.io.IOException;
-import java.util.List;
-
-import geniusweb.actions.Action;
-import geniusweb.connection.ConnectionFactory;
-import geniusweb.inform.Inform;
-import geniusweb.references.Reference;
-import tudelft.utilities.repository.NoResourcesNowException;
-
-/**
- * An extended {@link ConnectionFactory} that store PartyIDs with the
- * connections, making it possible to find back the appropriate connection given
- * a PartyID. Also, it allows the connection factory to actually assign the
- * PartyIDs.
- *
- */
-public interface ProtocolToPartyConnFactory
-		extends ConnectionFactory<Action, Inform> {
-	@Override
-	public ProtocolToPartyConn connect(Reference reference)
-			throws IOException, NoResourcesNowException;
-
-	/**
-	 * Connects a set of References in one go, following a modified Banker's
-	 * algorithm. Only succeeds if all requested connections can be made.
-	 * 
-	 * @param references the list of references to connect with
-	 * @return a List of connections, one fore each Reference. The URI Scheme
-	 *         deteremines how the connection to the party is created.
-	 *         Typically,
-	 *         <ul>
-	 *         <li>"classpath" assumes the file refers to an existing class on
-	 *         the classpath, directly to be instantiated.
-	 *         <li>"pythonpath" idem, but now the party is a python party.
-	 *         <li>"http" assumes the party is to be started on a partiesserver,
-	 *         where the partiesserver will convert the provided address to a
-	 *         specific party.
-	 *         </ul>
-	 *         It depends on the run system which of these protocols are
-	 *         actually supported, eg "pythonpath" is typically only supported
-	 *         for the python-based simplerunner.
-	 * @throws IOException             if a connection is failing irrecoverably.
-	 * @throws NoResourcesNowException is there are insufficient resources now.
-	 *                                 This exception includes a suggested
-	 *                                 moment to retry.
-	 */
-	List<ProtocolToPartyConn> connect(List<Reference> references)
-			throws IOException, NoResourcesNowException;
-
-}
Index: protocol/src/main/java/geniusweb/protocol/partyconnection/ProtocolToPartyConnections.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/partyconnection/ProtocolToPartyConnections.java	(revision 53)
+++ 	(revision )
@@ -1,138 +1,0 @@
-package geniusweb.protocol.partyconnection;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import geniusweb.actions.PartyId;
-import geniusweb.inform.Inform;
-
-/**
- * Contains all parties with their connections. immutable
- */
-public class ProtocolToPartyConnections
-		implements Iterable<ProtocolToPartyConn> {
-	private List<ProtocolToPartyConn> connections;
-
-	public ProtocolToPartyConnections(List<ProtocolToPartyConn> connections) {
-		this.connections = connections;
-	}
-
-	/**
-	 * @param id the {@link PartyId} needed
-	 * @return a connection with that party, or null if no such connection.
-	 */
-	public ProtocolToPartyConn get(PartyId id) {
-		return connections.stream().filter(conn -> id.equals(conn.getParty()))
-				.findAny().orElse(null);
-	}
-
-	/**
-	 * 
-	 * @return true iff all parties have one connection only
-	 */
-	public boolean allunique() {
-		return getParties().size() == connections.size();
-	}
-
-	/**
-	 * 
-	 * @return list of parties currently in the connections.
-	 */
-	private List<PartyId> getParties() {
-		return connections.stream().map(conn -> conn.getParty()).distinct()
-				.collect(Collectors.toList());
-	}
-
-	/**
-	 * Broadcast info to all parties. Notice that the broadcast immediately
-	 * aborts if an error occurs and remaining parties will not receive the
-	 * event. Therefore it is recommended to instead send to all parties
-	 * individually to ensure all parties are handled individually.
-	 * 
-	 * @param info the {@link Inform} to broadcast
-	 * @return a Map&lt;PartyId, IOException&gt; where possible exceptions for
-	 *         each party are stored. Normally a protocol would kick these
-	 *         parties.
-	 */
-	public Map<PartyId, IOException> broadcast(Inform info) {
-		Map<PartyId, IOException> exceptions = new HashMap<>();
-		for (ProtocolToPartyConn conn : connections) {
-			try {
-				conn.send(info);
-			} catch (IOException e) {
-				exceptions.put(conn.getParty(), e);
-			}
-		}
-		return exceptions;
-	}
-
-	/**
-	 * 
-	 * @return number of connections available
-	 */
-	public int size() {
-		return connections.size();
-	}
-
-	/**
-	 * @param i the connection number
-	 * @return the ith connection
-	 */
-	public ProtocolToPartyConn get(int i) {
-		return connections.get(i);
-	}
-
-	public Stream<ProtocolToPartyConn> stream() {
-		return connections.stream();
-	}
-
-	@Override
-	public Iterator<ProtocolToPartyConn> iterator() {
-		return connections.iterator();
-	}
-
-	public ProtocolToPartyConnections with(ProtocolToPartyConn conn) {
-		List<ProtocolToPartyConn> newconnections = new LinkedList<>(
-				connections);
-		newconnections.add(conn);
-		return new ProtocolToPartyConnections(newconnections);
-	}
-
-	@Override
-	public String toString() {
-		return "ConnectionWithParties" + connections;
-	}
-
-	@Override
-	public int hashCode() {
-		final int prime = 31;
-		int result = 1;
-		result = prime * result
-				+ ((connections == null) ? 0 : connections.hashCode());
-		return result;
-	}
-
-	@Override
-	public boolean equals(Object obj) {
-		if (this == obj)
-			return true;
-		if (obj == null)
-			return false;
-		if (getClass() != obj.getClass())
-			return false;
-		ProtocolToPartyConnections other = (ProtocolToPartyConnections) obj;
-		if (connections == null) {
-			if (other.connections != null)
-				return false;
-		} else if (!connections.equals(other.connections))
-			return false;
-		return true;
-	}
-
-}
Index: protocol/src/main/java/geniusweb/protocol/session/DefaultSessionState.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/DefaultSessionState.java	(revision 53)
+++ protocol/src/main/java/geniusweb/protocol/session/DefaultSessionState.java	(revision 1)
@@ -1,8 +1,5 @@
 package geniusweb.protocol.session;
 
-import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
@@ -13,29 +10,32 @@
 import geniusweb.progress.Progress;
 import geniusweb.protocol.ProtocolException;
+import geniusweb.protocol.partyconnection.ConnectionWithParties;
 import geniusweb.references.PartyWithProfile;
 
 /**
- * 
+ * The default current state of the session. immutable.
  */
-/**
- * 
- * The default current state of the session. immutable.
- * 
- * @param <P> the actual SessionState object
- * @param <S> the actual SessionSettings object
- */
-public abstract class DefaultSessionState<P extends DefaultSessionState<P, S>, S extends SessionSettings>
-		implements SessionState {
+public abstract class DefaultSessionState implements SessionState {
 	private final List<Action> actions;
 
-	private final List<PartyId> connections;
+	private final transient ConnectionWithParties connections;
 
 	private final Progress progress;
 
-	private final S settings;
+	private final SessionSettings settings;
 
 	private final ProtocolException error;
 
 	private final Map<PartyId, PartyWithProfile> partyprofiles;
+
+	// only for deserializer.
+	protected DefaultSessionState() {
+		actions = null;
+		connections = null;
+		progress = null;
+		settings = null;
+		partyprofiles = null;
+		error = null;
+	}
 
 	/**
@@ -57,66 +57,45 @@
 	 *                      {@link ProtocolException}s. All errors in our own
 	 *                      code are bugs (not ProtocolExceptions) and should
-	 *                      result in a throw and terminate the session.
-	 */
-	public DefaultSessionState(List<Action> actions, List<PartyId> conns,
-			Progress progr, S settings,
+	 *                      result in a throw.
+	 */
+	public DefaultSessionState(List<Action> actions,
+			ConnectionWithParties conns, Progress progr,
+			SessionSettings settings,
 			Map<PartyId, PartyWithProfile> partyprofiles, ProtocolException e) {
 		if (partyprofiles == null) {
-			this.partyprofiles = Collections.emptyMap();
+			partyprofiles = Collections.EMPTY_MAP;
+		}
+		if (conns == null) {
+			this.connections = new ConnectionWithParties(
+					Collections.EMPTY_LIST);
 		} else {
-			this.partyprofiles = new HashMap<>(partyprofiles);
-		}
-		if (conns == null) {
-			this.connections = Collections.emptyList();
-		} else {
-			this.connections = new LinkedList<>(conns);
+			this.connections = conns;
 		}
 		if (actions == null) {
 			this.actions = new LinkedList<>();
 		} else {
-			this.actions = new LinkedList<>(actions);
-		}
-
-		if (connections.size() != new HashSet<PartyId>(connections).size()) {
+			this.actions = actions;
+		}
+
+		if (!connections.allunique()) {
 			throw new IllegalArgumentException(
 					"There can not be multiple connections for a party:"
 							+ connections);
 		}
-		if (settings == null)
-			throw new IllegalArgumentException("Settings must be not null");
 		this.progress = progr;
 		this.settings = settings;
+		this.partyprofiles = partyprofiles;
 		this.error = e;
 	}
 
 	/**
-	 * Construct a new session state, where the DefaultSessionState changes
-	 * while the rest of the state remains unchanged. Notice the return type P.
-	 * 
-	 * @param actions1       the new {@link Action}s
-	 * @param conns          the new connected {@link PartyId}s
-	 * @param progress1      the new {@link Progress}
-	 * @param settings1      the new {@link SessionSettings}. Normally this is
-	 *                       constant during a session.
-	 * @param partyprofiles1 the new {@link PartyWithProfile}s for all parties.
-	 *                       Normally this remains constant during a session.
-	 * @param e              an error that occured that caused the session to
-	 *                       reach its terminated/final state. If an error does
-	 *                       not cause termination, only a warning should be
-	 *                       logged.
-	 * @return the new state of the derived sessionstate.
-	 */
-	abstract public P with(List<Action> actions1, List<PartyId> conns,
-			Progress progress1, S settings1,
-			Map<PartyId, PartyWithProfile> partyprofiles1, ProtocolException e);
-
-	/**
 	 * @return existing connections.
 	 */
-	public List<PartyId> getConnections() {
-		return Collections.unmodifiableList(connections);
-	}
-
-	/**
+	public ConnectionWithParties getConnections() {
+		return connections;
+	}
+
+	/**
+	 * @return
 	 * @return map with {@link PartyWithProfile} for the parties. May be an
 	 *         incomplete map, as more parties with their profiles may be set
@@ -124,5 +103,5 @@
 	 */
 	public Map<PartyId, PartyWithProfile> getPartyProfiles() {
-		return Collections.unmodifiableMap(partyprofiles);
+		return partyprofiles;
 	}
 
@@ -142,5 +121,5 @@
 
 	@Override
-	public S getSettings() {
+	public SessionSettings getSettings() {
 		return settings;
 	}
@@ -152,4 +131,5 @@
 	}
 
+	@Override
 	public ProtocolException getError() {
 		return error;
@@ -159,86 +139,6 @@
 	public String toString() {
 		return this.getClass().getSimpleName() + "[" + actions + ","
-				+ connections + "," + progress + "," + settings + "," + error;
-	}
-
-	public P withDeadlineReached() {
-		return with(actions, connections, progress, settings, partyprofiles,
-				error);
-	}
-
-	public P withoutParty(PartyId party) {
-		List<PartyId> newconn = new ArrayList<>(connections);
-		newconn.remove(party);
-		return with(actions, newconn, progress, settings, partyprofiles, error);
-	}
-
-	/**
-	 * 
-	 * @param e the error that occured
-	 * @return a new state with the error set/updated.
-	 */
-	public P with(ProtocolException e) {
-		return with(actions, connections, progress, settings, partyprofiles, e);
-	}
-
-	public P with(PartyId connection, PartyWithProfile partyprofile) {
-		List<PartyId> newconns = new ArrayList<>(getConnections());
-		newconns.add(connection);
-		Map<PartyId, PartyWithProfile> newprofiles = new HashMap<>(
-				getPartyProfiles());
-		newprofiles.put(connection, partyprofile);
-		return with(getActions(), newconns, getProgress(), getSettings(),
-				newprofiles, null);
-	}
-
-	/**
-	 * Sets the new progress for this session.
-	 * 
-	 * @param newprogress the new progress
-	 * @return new SAOPState with the progress set to new value
-	 */
-	public P with(Progress newprogress) {
-		if (newprogress == null) {
-			throw new IllegalArgumentException("newprogress must be not null");
-		}
-		return with(actions, connections, newprogress, settings, partyprofiles,
-				error);
-	}
-
-	/**
-	 * @param actor  the actor that did this action. Can be used to check if
-	 *               action is valid. NOTICE caller has to make sure the current
-	 *               state is not final.
-	 * @param action the action that was proposed by actor.
-	 * @return new SAOPState with the action added as last action.
-	 */
-
-	public P with(PartyId actor, Action action) {
-		String msg = checkAction(actor, action);
-		if (msg != null)
-			throw new IllegalArgumentException(msg);
-
-		List<Action> newactions = new LinkedList<>(getActions());
-		newactions.add(action);
-		return with(newactions, connections, progress, settings, partyprofiles,
-				error);
-	}
-
-	/**
-	 * 
-	 * @param actor  the known real actor that did this action
-	 * @param action an {@link Action}
-	 * @return null if action seems ok, or message explaining why not.
-	 */
-	public String checkAction(PartyId actor, Action action) {
-		if (actor == null) { // this is a bug
-			return "actor must not be null";
-		}
-		if (action == null) {
-			return "action is null";
-		}
-		if (!actor.equals(action.getActor()))
-			return "act contains wrong credentials: " + action;
-		return null;
+				+ connections + "," + progress + "," + settings + "," + error
+				+ "]";
 	}
 
Index: protocol/src/main/java/geniusweb/protocol/session/SessionResult.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/SessionResult.java	(revision 53)
+++ 	(revision )
@@ -1,154 +1,0 @@
-package geniusweb.protocol.session;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import com.fasterxml.jackson.annotation.JsonAutoDetect;
-import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-
-import geniusweb.actions.PartyId;
-import geniusweb.inform.Agreements;
-import geniusweb.references.PartyWithProfile;
-
-/**
- * All results collected from running a session. Normally this does not contain
- * all the details, only the final outcome and other global notes.
- */
-@JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)
-public class SessionResult {
-	private final Map<PartyId, PartyWithProfile> participants;
-	private final Agreements agreements;
-	private final Map<PartyId, Double> penalties;
-
-	// add more type info so that jackson can deserialize the actual class
-	@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.WRAPPER_OBJECT)
-	private final Throwable error;
-
-	/**
-	 * 
-	 * @param participants the list oof {@link PartyWithProfile}. Should never
-	 *                     be null. Some of them may have entered later of left
-	 *                     early. This list should contain them all.
-	 * @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
-	 *                     fatal error occured (session ended following the
-	 *                     protocol). Normally, a fatal error results in no
-	 *                     agreement but there might be protocols that allow a
-	 *                     session to end with an error but stick with a already
-	 *                     reached agreement as well.
-	 */
-	@JsonCreator
-	public SessionResult(
-			@JsonProperty("participants") Map<PartyId, PartyWithProfile> participants,
-			@JsonProperty("agreements") Agreements agreements,
-			@JsonProperty("penalties") Map<PartyId, Double> penalties,
-			@JsonProperty("error") Throwable error) {
-		this.participants = new HashMap<>(participants);
-		this.agreements = agreements;
-		this.penalties = new HashMap<>(penalties);
-		this.error = error;
-	}
-
-	/**
-	 * 
-	 * @return the map with for each {@link PartyId} the
-	 *         {@link PartyWithProfile}. Should never be null. Some of them may
-	 *         have entered later of left early. This list should contain them
-	 *         all.
-	 */
-	public Map<PartyId, PartyWithProfile> getParticipants() {
-		return Collections.unmodifiableMap(participants);
-	}
-
-	/**
-	 * @return the final {@link Agreements} of the session. May be empty, not
-	 *         null
-	 */
-	public Agreements getAgreements() {
-		return agreements;
-	};
-
-	/**
-	 * 
-	 * @return Map of penalties,
-	 */
-	public Map<PartyId, Double> getPenalties() {
-		return Collections.unmodifiableMap(penalties);
-	}
-
-	/**
-	 * 
-	 * @return a fatal error that terminated the session. Non-fatal errors
-	 *         (warnings) are not to be reported. Null if no fatal error occured
-	 *         (session ended following the protocol). Normally, a fatal error
-	 *         results in no agreement but there might be protocols that allow a
-	 *         session to end with an error but stick with a already reached
-	 *         agreement as well.
-	 */
-	public Throwable getError() {
-		return error;
-	}
-
-	@Override
-	public String toString() {
-		return "SessionResult[" + participants + "," + agreements + ","
-				+ penalties + "," + error + "]";
-	}
-
-	@Override
-	public int hashCode() {
-		final int prime = 31;
-		int result = 1;
-		result = prime * result
-				+ ((agreements == null) ? 0 : agreements.hashCode());
-		result = prime * result + ((error == null) ? 0 : error.hashCode());
-		result = prime * result
-				+ ((participants == null) ? 0 : participants.hashCode());
-		result = prime * result
-				+ ((penalties == null) ? 0 : penalties.hashCode());
-		return result;
-	}
-
-	@Override
-	public boolean equals(Object obj) {
-		if (this == obj)
-			return true;
-		if (obj == null)
-			return false;
-		if (getClass() != obj.getClass())
-			return false;
-		SessionResult other = (SessionResult) obj;
-		if (agreements == null) {
-			if (other.agreements != null)
-				return false;
-		} else if (!agreements.equals(other.agreements))
-			return false;
-		if (error == null) {
-			if (other.error != null)
-				return false;
-		} else if (!error.equals(other.error))
-			return false;
-		if (participants == null) {
-			if (other.participants != null)
-				return false;
-		} else if (!participants.equals(other.participants))
-			return false;
-		if (penalties == null) {
-			if (other.penalties != null)
-				return false;
-		} else if (!penalties.equals(other.penalties))
-			return false;
-		return true;
-	}
-
-}
Index: protocol/src/main/java/geniusweb/protocol/session/SessionSettings.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/SessionSettings.java	(revision 53)
+++ protocol/src/main/java/geniusweb/protocol/session/SessionSettings.java	(revision 1)
@@ -6,10 +6,5 @@
 
 import geniusweb.protocol.NegoSettings;
-import geniusweb.protocol.session.amop.AMOPSettings;
-import geniusweb.protocol.session.learn.LearnSettings;
-import geniusweb.protocol.session.mopac.MOPACSettings;
-import geniusweb.protocol.session.mopac2.MOPAC2Settings;
 import geniusweb.protocol.session.saop.SAOPSettings;
-import geniusweb.protocol.session.shaop.SHAOPSettings;
 import geniusweb.references.PartyWithProfile;
 import tudelft.utilities.logging.Reporter;
@@ -18,51 +13,31 @@
  * interface for settings for session protocols. Immutable.
  */
-@JsonSubTypes({ @JsonSubTypes.Type(value = SAOPSettings.class),
-		@JsonSubTypes.Type(value = SHAOPSettings.class),
-		@JsonSubTypes.Type(value = AMOPSettings.class),
-		@JsonSubTypes.Type(value = MOPACSettings.class),
-		@JsonSubTypes.Type(value = MOPAC2Settings.class),
-		@JsonSubTypes.Type(value = LearnSettings.class) })
+@JsonSubTypes({ @JsonSubTypes.Type(value = SAOPSettings.class) })
+
 public interface SessionSettings extends NegoSettings {
 
 	/**
-	 * Get the {@link TeamInfo}s.
+	 * Get participants
 	 * 
 	 * @return list of {@link PartyWithProfile} items.
 	 */
-	List<TeamInfo> getTeams();
+	public List<PartyWithProfile> getParticipants();
 
 	/**
-	 * @return the size of each {@link TeamInfo}. Usually 1 (SAOP etc) or
-	 *         sometimes 2 (SHAOP). Used eg by tournament runner to determine
-	 *         proper team construction.
-	 */
-	Integer getTeamSize();
-
-	/**
-	 * Allows modification of SessionSettings to include a party. This is needed
-	 * for tournament auto-configuration of sessions.
+	 * Allows modification of SessionSettings to include a party. This is needed for
+	 * tournament auto-configuration of sessions.
 	 * 
-	 * @param partyprofteam the {@link TeamInfo} to be added
+	 * @param partyprof the party with profile to be added
 	 * @return new modified SessionSettings object
 	 */
-	SessionSettings with(TeamInfo partyprofteam);
-
-	/**
-	 * 
-	 * @return all parties from all teams, as a flattened ordered list. The
-	 *         order : start with all parties from team 1, then all from team 2,
-	 *         etc. The specific order of the parties from a team depends on the
-	 *         protocol.
-	 */
-	List<PartyWithProfile> getAllParties();
+	public SessionSettings with(PartyWithProfile partyprof);
 
 	/**
 	 * @param logger the logger where the protocol can log events to.
-	 * @return the an initialized and ready to use {@link SessionProtocol} that
-	 *         can handle this Negotiation.
+	 * @return the an initialized and ready to use {@link SessionProtocol} that can
+	 *         handle this Negotiation.
 	 */
 	@Override
-	SessionProtocol getProtocol(Reporter logger);
+	public SessionProtocol getProtocol(Reporter logger);
 
 }
Index: protocol/src/main/java/geniusweb/protocol/session/SessionState.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/SessionState.java	(revision 53)
+++ protocol/src/main/java/geniusweb/protocol/session/SessionState.java	(revision 1)
@@ -6,12 +6,8 @@
 
 import geniusweb.actions.Action;
-import geniusweb.inform.Agreements;
+import geniusweb.issuevalue.Bid;
 import geniusweb.progress.Progress;
 import geniusweb.protocol.NegoState;
-import geniusweb.protocol.session.amop.AMOPState;
-import geniusweb.protocol.session.learn.LearnState;
-import geniusweb.protocol.session.mopac.MOPACState;
 import geniusweb.protocol.session.saop.SAOPState;
-import geniusweb.protocol.session.shaop.SHAOPState;
 
 /**
@@ -19,9 +15,15 @@
  * and the parties currently connected. <br>
  * The state checks if transitions (Actions from the party) are following the
- * protocol, and thus implement most of the protocol . <br>
+ * protocol, and thus implement most of the protocol . See
+ * {@link #with(geniusweb.actions.PartyId, Action)}. <br>
+ * 
+ * Use {@link #with(geniusweb.actions.PartyId, Action)} and
+ * {@link #with(geniusweb.actions.PartyId, tudelft.utilities.connection.Connection)}
+ * to create a new state <br>
+ * 
  * 
  * If protocol errors occur, these should be stored in the state and the state
- * should become {@link #isFinal(long)}. Throwing should happen only in case of
- * a bug.<br>
+ * should become {@link #isFinal()}. Throwing should happen only in case of a
+ * bug.<br>
  * 
  * Implementations should be immutable (to ensure thread safety, testability
@@ -31,9 +33,6 @@
  * the protocol. As uaual, mark non-serializable fields as transient.
  */
-@JsonSubTypes({ @JsonSubTypes.Type(value = SAOPState.class),
-		@JsonSubTypes.Type(value = SHAOPState.class),
-		@JsonSubTypes.Type(value = AMOPState.class),
-		@JsonSubTypes.Type(value = MOPACState.class),
-		@JsonSubTypes.Type(value = LearnState.class) })
+@JsonSubTypes({ @JsonSubTypes.Type(value = SAOPState.class) })
+
 public interface SessionState extends NegoState {
 
@@ -44,6 +43,5 @@
 	 * 
 	 * @return unmodifyable list of actions done so far, in the order in which
-	 *         they arrived. List of list allows implementations to add some
-	 *         extra structure to the actions, eg one list per phase
+	 *         they arrived.
 	 */
 	List<Action> getActions();
@@ -60,8 +58,8 @@
 	/**
 	 * 
-	 * @return the current standing {@link Agreements}. An agreement does not
-	 *         necessarily mean {@link #isFinal(long)}.
+	 * @return the current standing agreement, or null if there is no agreement
+	 *         at this point. An agreement does not necessarily mean
+	 *         {@link #isFinal()}.
 	 */
-	Agreements getAgreements();
-
+	Bid getAgreement();
 }
Index: protocol/src/main/java/geniusweb/protocol/session/TeamInfo.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/TeamInfo.java	(revision 53)
+++ 	(revision )
@@ -1,116 +1,0 @@
-package geniusweb.protocol.session;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import com.fasterxml.jackson.annotation.JsonAutoDetect;
-import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-
-import geniusweb.protocol.tournament.Team;
-import geniusweb.references.Parameters;
-import geniusweb.references.PartyWithParameters;
-import geniusweb.references.PartyWithProfile;
-import geniusweb.references.ProfileRef;
-
-/**
- * Contains a functional team, eg in SHAOP a team would be a SHAOP together with
- * his COB partner. In SAOP this is just a SAOP party.
- */
-@JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)
-@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
-public class TeamInfo {
-
-	private final List<PartyWithProfile> parties;
-
-	/**
-	 * Convenient constructor if team is only 1 party and profile
-	 * 
-	 * @param party   the {@link PartyWithParameters}
-	 * @param profile the ProfileRef to be used by party
-	 */
-	public TeamInfo(PartyWithParameters party, ProfileRef profile) {
-		this(Arrays.asList(new PartyWithProfile(party, profile)));
-	}
-
-	@JsonCreator
-	public TeamInfo(@JsonProperty("teams") List<PartyWithProfile> teams) {
-		this.parties = teams;
-	}
-
-	/**
-	 * 
-	 * @return the list of all parties involved, which is the parties in all
-	 *         teams combined.
-	 */
-	public List<PartyWithProfile> getParties() {
-		return Collections.unmodifiableList(parties);
-	}
-
-	/**
-	 * 
-	 * @return the number of parties in the team.
-	 */
-	public Integer getSize() {
-		return parties.size();
-	}
-
-	@Override
-	public String toString() {
-		return "TeamInfo[" + parties + "]";
-	}
-
-	@Override
-	public int hashCode() {
-		final int prime = 31;
-		int result = 1;
-		result = prime * result + ((parties == null) ? 0 : parties.hashCode());
-		return result;
-	}
-
-	@Override
-	public boolean equals(Object obj) {
-		if (this == obj)
-			return true;
-		if (obj == null)
-			return false;
-		if (getClass() != obj.getClass())
-			return false;
-		TeamInfo other = (TeamInfo) obj;
-		if (parties == null) {
-			if (other.parties != null)
-				return false;
-		} else if (!parties.equals(other.parties))
-			return false;
-		return true;
-	}
-
-	/**
-	 * @param parameters a set of {@link Parameters} to be merged with the
-	 *                   existing parameters of the first team member.
-	 * @return updated TeamInfo
-	 */
-	public TeamInfo with(Parameters parameters) {
-		List<PartyWithProfile> updatedparties = new ArrayList<>(parties);
-		PartyWithProfile party1 = updatedparties.get(0);
-		Parameters newparams1 = party1.getParty().getParameters()
-				.with(parameters);
-		PartyWithProfile party1update = new PartyWithProfile(
-				party1.getParty().with(newparams1), party1.getProfile());
-		updatedparties.set(0, party1update);
-		return new TeamInfo(updatedparties);
-	}
-
-	/**
-	 * @return the Team, without the profiles
-	 */
-	public Team getTeam() {
-		return new Team(parties.stream().map(pwithp -> pwithp.getParty())
-				.collect(Collectors.toList()));
-	}
-}
Index: protocol/src/main/java/geniusweb/protocol/session/saop/SAOP.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/saop/SAOP.java	(revision 53)
+++ protocol/src/main/java/geniusweb/protocol/session/saop/SAOP.java	(revision 1)
@@ -2,7 +2,4 @@
 
 import java.io.IOException;
-import java.sql.Date;
-import java.text.SimpleDateFormat;
-import java.util.Collections;
 import java.util.List;
 import java.util.Timer;
@@ -16,19 +13,17 @@
 import geniusweb.deadline.Deadline;
 import geniusweb.events.ProtocolEvent;
-import geniusweb.inform.ActionDone;
-import geniusweb.inform.Finished;
-import geniusweb.inform.Inform;
-import geniusweb.inform.Settings;
-import geniusweb.inform.YourTurn;
+import geniusweb.party.inform.ActionDone;
+import geniusweb.party.inform.Finished;
+import geniusweb.party.inform.Inform;
+import geniusweb.party.inform.Settings;
+import geniusweb.party.inform.YourTurn;
 import geniusweb.progress.ProgressFactory;
 import geniusweb.protocol.CurrentNegoState;
 import geniusweb.protocol.ProtocolException;
-import geniusweb.protocol.partyconnection.ProtocolToPartyConn;
-import geniusweb.protocol.partyconnection.ProtocolToPartyConnFactory;
-import geniusweb.protocol.partyconnection.ProtocolToPartyConnections;
+import geniusweb.protocol.partyconnection.ConnectionWithParty;
+import geniusweb.protocol.partyconnection.ConnectionWithPartyFactory;
 import geniusweb.protocol.session.SessionProtocol;
 import geniusweb.protocol.session.SessionSettings;
 import geniusweb.protocol.session.SessionState;
-import geniusweb.references.Parameters;
 import geniusweb.references.PartyWithProfile;
 import geniusweb.references.ProfileRef;
@@ -40,11 +35,11 @@
 
 /**
- * The protocol runs as follows
+ * 
+ * All parties are first sent the {@link SessionSettings}. Only parties
+ * specified initially in the settings do participate.
  * <ol>
- * <li>The protocol tries to start all parties. If not all parties start, the
+ * The protocol tries to start all parties. If not all parties start, the
  * parties are freed up and another attempt is done to start all parties some
  * time later.
- * <li>All parties are sent the {@link SessionSettings}. Only parties specified
- * initially in the settings do participate.
  * <li>The session deadline clock now starts ticking.
  * <li>All parties are sent their settings.
@@ -63,24 +58,25 @@
  * the protocol.
  * <p>
- * Thread safe: all entry points are synchronized.
+ * Threadsafe: all entrypoints are synhronized.
  */
 public class SAOP extends DefaultListenable<ProtocolEvent>
 		implements SessionProtocol {
-	public static final int TIME_MARGIN = 20;// ms extra delay after deadline
-	public static final int MINDURATION = 100;
-	public static final int MIN_SLEEP_TIME = 1000;
-	public static final int MAX_SLEEP_TIME = 60000;
+	private static final int TIME_MARGIN = 20;// ms extra delay after deadline
+	private static final int MINDURATION = 100;
+	private static final int MIN_SLEEP_TIME = 1000;
+	private static final int MAX_SLEEP_TIME = 60000;
 	private static final ProtocolRef SAOP = new ProtocolRef("SAOP");
 	private final Reporter log;
 
-	// these 4 variables are why protocols are so complex.
 	private SAOPState state = null; // mutable!
 	private volatile AtomicBoolean isFinishedInfoSent = new AtomicBoolean(
 			false);
 	private volatile Timer deadlinetimer = null;
-	private volatile ProtocolToPartyConnections conns;
-
-	public SAOP(SAOPState state, Reporter logger,
-			ProtocolToPartyConnections connects) {
+
+	/**
+	 * 
+	 * @param state normally the initial state coming from SAOPSettings
+	 */
+	public SAOP(SAOPState state, Reporter logger) {
 		if (state == null) {
 			throw new NullPointerException("state must be not null");
@@ -92,20 +88,9 @@
 		this.log = logger;
 		this.state = state;
-		this.conns = connects;
-	}
-
-	/**
-	 * 
-	 * @param state  normally the initial state coming from SAOPSettings
-	 * @param logger the Reporter to log to
-	 */
-	public SAOP(SAOPState state, Reporter logger) {
-		this(state, logger,
-				new ProtocolToPartyConnections(Collections.emptyList()));
 	}
 
 	@Override
 	public synchronized void start(
-			ProtocolToPartyConnFactory connectionfactory) {
+			ConnectionWithPartyFactory connectionfactory) {
 
 		try {
@@ -114,5 +99,5 @@
 			setupParties();
 			nextTurn();
-		} catch (Throwable e) {
+		} catch (ProtocolException | IOException | InterruptedException e) {
 			handleError("Failed to start up session", null, e);
 		}
@@ -163,12 +148,11 @@
 	 */
 	protected synchronized void connect(
-			ProtocolToPartyConnFactory connectionfactory)
+			ConnectionWithPartyFactory connectionfactory)
 			throws InterruptedException, IOException {
 		List<PartyWithProfile> participants = state.getSettings()
-				.getAllParties();
+				.getParticipants();
 		List<Reference> parties = participants.stream()
-				.map(parti -> (parti.getParty().getPartyRef()))
-				.collect(Collectors.toList());
-		List<ProtocolToPartyConn> connections = null;
+				.map(parti -> (parti.getParty())).collect(Collectors.toList());
+		List<ConnectionWithParty> connections = null;
 		log.log(Level.INFO, "SAOP connect " + parties);
 		while (connections == null) {
@@ -186,9 +170,5 @@
 		}
 		for (int i = 0; i < participants.size(); i++) {
-			// now we bookkeep the connections ourselves,
-			// and update the state to keep in sync.
-			conns = conns.with(connections.get(i));
-			setState(this.state.with(connections.get(i).getParty(),
-					participants.get(i)));
+			setState(this.state.with(connections.get(i), participants.get(i)));
 		}
 	}
@@ -210,6 +190,4 @@
 							"BUG. Deadline timer has triggered but state is not final");
 				}
-				log.log(Level.INFO,
-						"SAOP deadline reached. Terminating session.");
 				finish();
 			}
@@ -218,8 +196,4 @@
 		// early
 		deadlinetimer.schedule(task, deadline.getDuration() + TIME_MARGIN);
-		log.log(Level.INFO, "SAOP deadline set to "
-				+ new SimpleDateFormat("yyyy/MM/dd HH:mm:ss")
-						.format(new Date(System.currentTimeMillis()
-								+ deadline.getDuration() + TIME_MARGIN)));
 	}
 
@@ -234,14 +208,14 @@
 	 */
 	protected synchronized void setupParties() throws ProtocolException {
-		for (ProtocolToPartyConn conn : conns) {
+		for (ConnectionWithParty conn : state.getConnections()) {
 			conn.addListener(action -> actionRequest(conn, action));
 		}
 
-		for (ProtocolToPartyConn connection : conns) {
+		for (ConnectionWithParty connection : state.getConnections()) {
 			try {
 				sendSettings(connection);
 			} catch (IOException e) {
 				throw new ProtocolException("Failed to initialize",
-						connection.getParty(), e);
+						connection.getParty().getName(), e);
 			}
 		}
@@ -255,10 +229,8 @@
 	 * @throws IOException if party got disconnected
 	 */
-	private synchronized void sendSettings(ProtocolToPartyConn connection)
+	private synchronized void sendSettings(ConnectionWithParty connection)
 			throws IOException {
 		PartyId partyid = connection.getParty();
 		ProfileRef profile = state.getPartyProfiles().get(partyid).getProfile();
-		Parameters params = state.getPartyProfiles().get(partyid).getParty()
-				.getParameters();
 		if (profile == null) {
 			throw new IllegalArgumentException(
@@ -266,5 +238,5 @@
 		}
 		connection.send(new Settings(connection.getParty(), profile, getRef(),
-				state.getProgress(), params));
+				state.getProgress()));
 	}
 
@@ -273,17 +245,12 @@
 	 * Synchronized so that we always handle only 1 action at a time.
 	 * 
-	 * @param partyconn the connection on which the action came in.
+	 * @param partyconn the connection on which the action came in
 	 * @param action    the {@link Action} taken by some party
 	 */
 	protected synchronized void actionRequest(
-			final ProtocolToPartyConn partyconn, final Action action) {
+			final ConnectionWithParty partyconn, final Action action) {
 		if (action == null) {
-			Throwable err = partyconn.getError();
-			if (err == null) {
-				err = new ProtocolException("Party sent a null action",
-						partyconn.getParty());
-			}
-			handleError(partyconn + "Protocol error", partyconn.getParty(),
-					err);
+			handleError("Received null from " + partyconn + ". Closing session",
+					partyconn.getParty().getName(), null);
 			return;
 		}
@@ -292,16 +259,14 @@
 			if (!partyconn.getParty().equals(state.getNextActor())) {
 				// party does not have the turn.
-				throw new ProtocolException(
-						"Party acts without having the turn",
-						partyconn.getParty());
+				throw new ProtocolException(" act without having the turn",
+						partyconn.getParty().getName());
 			}
-			// FIXME? this ignores possible broadcast errors
-			conns.broadcast(new ActionDone(action));
+			state.getConnections().broadcast(new ActionDone(action));
 			setState(state.with(partyconn.getParty(), action));
 			if (!state.isFinal(System.currentTimeMillis()))
 				nextTurn();
-		} catch (Throwable e) {
+		} catch (Exception e) {
 			handleError("failed to handle action " + action,
-					partyconn.getParty(), e);
+					partyconn.getParty().getName(), e);
 		}
 
@@ -313,10 +278,10 @@
 	 * @throws IOException
 	 */
-	synchronized void nextTurn() {
+	private synchronized void nextTurn() {
 		PartyId party = state.getNextActor();
 		try {
-			conns.get(party).send(new YourTurn());
+			state.getConnections().get(party).send(new YourTurn());
 		} catch (IOException e) {
-			handleError("failed to send YourTurn", party, e);
+			handleError("failed to send YourTurn", party.getName(), e);
 		}
 	}
@@ -326,20 +291,14 @@
 	 * 
 	 * @param message The message to attach to the error
-	 * @param party   the party where the error occured. Can be null in
-	 *                exceptional cases.
+	 * @param party   the party where the error occured
 	 * @param e       the exception that occured.
 	 */
 	private synchronized void handleError(final String message,
-			final PartyId party, final Throwable e) {
+			final String party, final Exception e) {
 		if (e instanceof ProtocolException) {
 			setState(state.with((ProtocolException) e));
-
 		} else {
 			setState(state.with(new ProtocolException(message, party, e)));
 		}
-		if (party != null)
-			setState(state.withoutParty(party));
-		log.log(Level.WARNING, "SAOP protocol intercepted error due to party "
-				+ party + ":" + message, e);
 	}
 
@@ -374,12 +333,12 @@
 		if (!isFinishedInfoSent.compareAndSet(false, true))
 			return;
-		Inform finished = new Finished(state.getAgreements());
-		for (ProtocolToPartyConn conn : conns) {
+		Inform finished = new Finished(state.getAgreement());
+		for (ConnectionWithParty conn : state.getConnections()) {
 			sendFinish(conn, finished);
 		}
-		notifyListeners(new CurrentNegoState(state));
-	}
-
-	private void sendFinish(ProtocolToPartyConn connection, Inform finished) {
+		notifyChange(new CurrentNegoState(state));
+	}
+
+	private void sendFinish(ConnectionWithParty connection, Inform finished) {
 		try {
 			connection.send(finished);
Index: protocol/src/main/java/geniusweb/protocol/session/saop/SAOPSettings.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/saop/SAOPSettings.java	(revision 53)
+++ protocol/src/main/java/geniusweb/protocol/session/saop/SAOPSettings.java	(revision 1)
@@ -4,5 +4,4 @@
 import java.util.LinkedList;
 import java.util.List;
-import java.util.stream.Collectors;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
@@ -12,10 +11,9 @@
 import geniusweb.protocol.session.SessionProtocol;
 import geniusweb.protocol.session.SessionSettings;
-import geniusweb.protocol.session.TeamInfo;
 import geniusweb.references.PartyWithProfile;
 import tudelft.utilities.logging.Reporter;
 
 public class SAOPSettings implements SessionSettings {
-	private final List<TeamInfo> participants;
+	private final List<PartyWithProfile> participants;
 	private final Deadline deadline;
 
@@ -26,9 +24,9 @@
 	 *                     protocol. But SAOP can be initialized with less, for
 	 *                     use in TournamentSettings.
-	 * @param deadline     the deadline of the negotiation
+	 * @param deadline
 	 */
 	@JsonCreator
 	public SAOPSettings(
-			@JsonProperty("participants") List<TeamInfo> participants,
+			@JsonProperty("participants") List<PartyWithProfile> participants,
 			@JsonProperty("deadline") Deadline deadline) {
 		this.participants = participants;
@@ -53,5 +51,5 @@
 
 	@Override
-	public List<TeamInfo> getTeams() {
+	public List<PartyWithProfile> getParticipants() {
 		return Collections.unmodifiableList(participants);
 	}
@@ -62,16 +60,4 @@
 	public Deadline getDeadline() {
 		return deadline;
-	}
-
-	@Override
-	public List<PartyWithProfile> getAllParties() {
-		return participants.stream()
-				.map(particip -> particip.getParties().get(0))
-				.collect(Collectors.toList());
-	}
-
-	@Override
-	public Integer getTeamSize() {
-		return 1;
 	}
 
@@ -115,10 +101,7 @@
 
 	@Override
-	public SessionSettings with(TeamInfo team) {
-		if (team.getSize() != 1)
-			throw new IllegalArgumentException(
-					"Team must be size 1 but found " + team);
-		List<TeamInfo> newparts = new LinkedList<>(participants);
-		newparts.add(team);
+	public SessionSettings with(PartyWithProfile party) {
+		List<PartyWithProfile> newparts = new LinkedList<>(participants);
+		newparts.add(party);
 		return new SAOPSettings(newparts, deadline);
 	}
Index: protocol/src/main/java/geniusweb/protocol/session/saop/SAOPState.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/session/saop/SAOPState.java	(revision 53)
+++ protocol/src/main/java/geniusweb/protocol/session/saop/SAOPState.java	(revision 1)
@@ -1,12 +1,9 @@
 package geniusweb.protocol.session.saop;
 
-import java.util.Arrays;
 import java.util.Collections;
-import java.util.HashSet;
+import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
 
 import geniusweb.actions.Accept;
@@ -15,11 +12,12 @@
 import geniusweb.actions.Offer;
 import geniusweb.actions.PartyId;
-import geniusweb.inform.Agreements;
 import geniusweb.issuevalue.Bid;
 import geniusweb.progress.Progress;
 import geniusweb.progress.ProgressRounds;
 import geniusweb.protocol.ProtocolException;
+import geniusweb.protocol.partyconnection.ConnectionWithParties;
+import geniusweb.protocol.partyconnection.ConnectionWithParty;
 import geniusweb.protocol.session.DefaultSessionState;
-import geniusweb.protocol.session.SessionResult;
+import geniusweb.protocol.session.SessionSettings;
 import geniusweb.references.PartyWithProfile;
 
@@ -27,59 +25,120 @@
  * Immutable.
  */
-public class SAOPState extends DefaultSessionState<SAOPState, SAOPSettings> {
-
-	/**
-	 * 
-	 * @param actions       the actions done by the parties
-	 * @param connections   the existing party connections. If null, default
+public class SAOPState extends DefaultSessionState {
+
+	/**
+	 * 
+	 * @param actions
+	 * @param conns         the existing party connections. we assume ownership
+	 *                      of this so it should not be modified although
+	 *                      connections may of course break. If null, default
 	 *                      empty list is used. Can be less than 2 parties in
-	 *                      the first phases of the setup or after parties
-	 *                      disconnected.
+	 *                      the first phases of the setup.
 	 * @param progress      the {@link Progress} line. can be null
 	 * @param settings      the {@link SAOPSettings}
 	 * @param partyprofiles map with the {@link PartyWithProfile} for connected
 	 *                      parties. null is equivalent to an empty map.
-	 * @param error         the {@link ProtocolException}, or null if none
+	 * @param e             the {@link ProtocolException}, or null if none
 	 *                      occurred.
 	 */
-	@JsonCreator
-	public SAOPState(@JsonProperty("actions") List<Action> actions,
-			@JsonProperty("connections") List<PartyId> connections,
-			@JsonProperty("progress") Progress progress,
-			@JsonProperty("settings") SAOPSettings settings,
-			@JsonProperty("partyprofiles") Map<PartyId, PartyWithProfile> partyprofiles,
-			@JsonProperty("error") ProtocolException error) {
-		super(actions, connections, progress, settings, partyprofiles, error);
+	public SAOPState(List<Action> actions, ConnectionWithParties conns,
+			Progress progress, SessionSettings settings,
+			Map<PartyId, PartyWithProfile> partyprofiles, ProtocolException e) {
+		super(actions, conns, progress, settings, partyprofiles, e);
+	}
+
+	/**
+	 * Creates the initial state from the given settings and progress=null
+	 * 
+	 * @param settings the {@link SAOPSettings}
+	 */
+	public SAOPState(SAOPSettings settings) {
+		this(Collections.emptyList(),
+				new ConnectionWithParties(Collections.emptyList()), null,
+				settings, null, null);
+
+	}
+
+	/**
+	 * @param actor         the actor that did this action. Can be used to check
+	 *                      if action is valid. NOTICE caller has to make sure
+	 *                      the current state is not final.
+	 * @param action        the action that was proposed by actor.
+	 * @param currentTimeMs the current time in ms since 1970, see
+	 *                      {@link System#currentTimeMillis()}
+	 * @return new SessionState with the action added as last action.
+	 */
+	public SAOPState with(PartyId actor, Action action) {
+		try {
+			return with1(actor, action);
+		} catch (ProtocolException e) {
+			List<Action> newactions = new LinkedList<>(getActions());
+			newactions.add(action);
+			return new SAOPState(newactions, getConnections(), getProgress(),
+					getSettings(), getPartyProfiles(), e);
+		}
+	}
+
+	/**
+	 * 
+	 * @param connection   the new {@link ConnectionWithParty}
+	 * @param partyprofile the {@link PartyWithProfile} that is associated with
+	 *                     this state
+	 * @return new SessionState with the new connection added. This call ignores
+	 *         the progress (does not check isFinal) because SAOP uses this
+	 *         during the setup where the deadline is not yet relevant. The
+	 *         connection should be informed about the partyprofile but the
+	 *         state currently indicate if that already happened or not.
+	 */
+	public SAOPState with(ConnectionWithParty connection,
+			PartyWithProfile partyprofile) {
+		// Only called from the SAOP initialization phase.
+		ConnectionWithParties newconns = getConnections().with(connection);
+		Map<PartyId, PartyWithProfile> newprofiles = new HashMap<>(
+				getPartyProfiles());
+		newprofiles.put(connection.getParty(), partyprofile);
+		return new SAOPState(getActions(), newconns, getProgress(),
+				getSettings(), newprofiles, null);
+	}
+
+	/**
+	 * 
+	 * @param e             the error that occured
+	 * @param currentTimeMs the current time in ms since 1970, see
+	 *                      {@link System#currentTimeMillis()}
+	 * @return a new state with the error set.
+	 */
+	public SAOPState with(ProtocolException e) {
+		return new SAOPState(getActions(), getConnections(), getProgress(),
+				getSettings(), getPartyProfiles(), e);
+	}
+
+	/**
+	 * Sets the progress for this session. Can be set only if progress=null.
+	 * 
+	 * @param newprogress the new progress
+	 * @return new SAOPState with the progress set
+	 */
+	public SAOPState with(Progress newprogress) {
+		if (newprogress == null) {
+			throw new IllegalArgumentException("newprogress must be not null");
+		}
+		if (getProgress() != null) {
+			return this;
+		}
+		return new SAOPState(getActions(), getConnections(), newprogress,
+				getSettings(), getPartyProfiles(), getError());
 	}
 
 	@Override
-	public SAOPState with(List<Action> actions, List<PartyId> conns,
-			Progress progr, SAOPSettings settings,
-			Map<PartyId, PartyWithProfile> partyprofiles, ProtocolException e) {
-		return new SAOPState(actions, conns, progr, settings, partyprofiles, e);
-	}
-
-	/**
-	 * Creates the initial state from the given settings and progress=null
-	 * 
-	 * @param settings the {@link SAOPSettings}
-	 */
-	public SAOPState(SAOPSettings settings) {
-		this(Collections.emptyList(), Collections.emptyList(), null, settings,
-				null, null);
-
-	}
-
-	@Override
-	public Agreements getAgreements() {
-		Agreements agree = new Agreements();
+	public Bid getAgreement() {
 		List<Action> acts = getActions();
 		int nparticipants = getConnections().size();
 		if (nparticipants < 2 || acts.size() < nparticipants) {
-			return agree;
+			return null;
 		}
 		Action offer = acts.get(acts.size() - nparticipants);
 		if (!(offer instanceof Offer))
-			return agree;
+			return null;
 		Bid bid = ((Offer) offer).getBid();
 
@@ -88,16 +147,5 @@
 				.allMatch(act -> act instanceof Accept
 						&& bid.equals(((Accept) act).getBid()));
-		if (allaccept)
-			agree = agree
-					.with(new Agreements(bid, new HashSet<>(getParties())));
-		return agree;
-	}
-
-	/**
-	 * 
-	 * @return all currently connected parties.
-	 */
-	public List<PartyId> getParties() {
-		return getConnections();
+		return allaccept ? bid : null;
 	}
 
@@ -105,39 +153,12 @@
 	public boolean isFinal(long currentTimeMs) {
 		List<Action> acts = getActions();
-		return super.isFinal(currentTimeMs)
-				|| !getAgreements().getMap().isEmpty() || (!acts.isEmpty()
+		return super.isFinal(currentTimeMs) || getAgreement() != null
+				|| (!acts.isEmpty()
 						&& acts.get(acts.size() - 1) instanceof EndNegotiation);
 	}
 
 	@Override
-	public SAOPState with(PartyId actor, Action action) {
-		return super.with(actor, action).with(advanceProgress());
-	}
-
-	@Override
-	public String checkAction(PartyId actor, Action action) {
-		String msg = super.checkAction(actor, action);
-		if (msg != null)
-			return msg;
-
-		if (!actor.equals(getNextActor()))
-			return "Party does not have the turn ";
-
-		// check protocol is followed for specific actions
-		if (action instanceof Accept) {
-			Bid bid = getLastBid();
-			if (bid == null)
-				return "Accept without a recent offer";
-
-			if (!bid.equals(((Accept) action).getBid()))
-				return "Party accepts a bid differing from the last offer ="
-						+ bid + ", action=" + action + ")";
-			return null;
-		} else if (action instanceof Offer) {
-			return null;
-		} else if (action instanceof EndNegotiation) {
-			return null;
-		}
-		return "Action " + action + " is not allowed in SAOP";
+	public SAOPSettings getSettings() {
+		return (SAOPSettings) super.getSettings();
 	}
 
@@ -161,19 +182,70 @@
 	}
 
+	private SAOPState with1(PartyId actor, Action action)
+			throws ProtocolException {
+
+		if (actor == null) { // this is a bug
+			throw new IllegalArgumentException("actor must not be null");
+		}
+		if (!actor.equals(getNextActor())) {
+			throw new ProtocolException("actor does not have the turn ",
+					actor.getName());
+
+		}
+		if (action == null) {
+			throw new ProtocolException("action is null", actor.getName());
+		}
+		if (!actor.equals(action.getActor())) {
+			throw new ProtocolException(
+					"act contains wrong credentials: " + action,
+					actor.getName());
+		}
+
+		// check protocol is followed for specific actions
+		if (action instanceof Accept) {
+			Bid bid = getLastBid();
+			if (bid == null) {
+				throw new ProtocolException("Accept without a recent offer",
+						actor.getName());
+			}
+			if (!bid.equals(((Accept) action).getBid())) {
+				throw new ProtocolException(
+						"Accepts a bid that was not offered (last offer =" + bid
+								+ ", action=" + action + ")",
+						actor.getName());
+			}
+		} else if (action instanceof Offer) {
+			// offer is always fine. We don't check if bid is actually in domain
+			// or complete etc. We would need domain for that
+		} else if (action instanceof EndNegotiation) {
+			// just act, we will get into the final state then.
+		} else {
+			throw new ProtocolException(
+					"Action " + action + " is not allowed in SAOP",
+					actor.getName());
+		}
+
+		List<Action> newactions = new LinkedList<>(getActions());
+		newactions.add(action);
+		return new SAOPState(newactions, getConnections(), advanceProgress(),
+				getSettings(), getPartyProfiles(), null);
+	}
+
 	/**
 	 * 
 	 * @return the next actor in the current state. Assumes 1 action per actor
-	 *         every time. NOTE if party disconnects this would jump wildly but
-	 *         nego stops then anyway
+	 *         every time.
 	 */
 	protected PartyId getNextActor() {
 		return getConnections()
-				.get(getActions().size() % getConnections().size());
-	}
-
-	/**
+				.get(getActions().size() % getConnections().size()).getParty();
+	}
+
+	/**
+	 * 
+	 * @param progress
 	 * @return new progress state
 	 */
-	public Progress advanceProgress() {
+	private Progress advanceProgress() {
 		Progress newprogress = getProgress();
 		if (newprogress instanceof ProgressRounds && isLastActor()) {
@@ -191,9 +263,3 @@
 	}
 
-	@Override
-	public List<SessionResult> getResults() {
-		return Arrays.asList(new SessionResult(getPartyProfiles(),
-				getAgreements(), Collections.emptyMap(), getError()));
-	}
-
 }
Index: protocol/src/main/java/geniusweb/protocol/tournament/ProfileList.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/tournament/ProfileList.java	(revision 53)
+++ 	(revision )
@@ -1,68 +1,0 @@
-package geniusweb.protocol.tournament;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import com.fasterxml.jackson.annotation.JsonAutoDetect;
-import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import com.fasterxml.jackson.annotation.JsonValue;
-
-import geniusweb.references.ProfileRef;
-
-/**
- * Contains a list of profiles, one for each {@link Team} member.
- */
-@JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE, isGetterVisibility = Visibility.NONE)
-@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
-public class ProfileList {
-	@JsonValue
-	private final List<ProfileRef> profiles; // field to ensure immutability
-
-	/**
-	 * 
-	 * @param ps a list of {@link ProfileRef}s. The length and order is
-	 *           important as each will be matched with the {@link Team} member
-	 *           at the same index.
-	 */
-	@JsonCreator
-	public ProfileList(List<ProfileRef> ps) {
-		this.profiles = new ArrayList<>(ps);
-	}
-
-	public List<ProfileRef> getProfiles() {
-		return Collections.unmodifiableList(profiles);
-	}
-
-	@Override
-	public int hashCode() {
-		final int prime = 31;
-		int result = 1;
-		result = prime * result
-				+ ((profiles == null) ? 0 : profiles.hashCode());
-		return result;
-	}
-
-	@Override
-	public boolean equals(Object obj) {
-		if (this == obj)
-			return true;
-		if (obj == null)
-			return false;
-		if (getClass() != obj.getClass())
-			return false;
-		ProfileList other = (ProfileList) obj;
-		if (profiles == null) {
-			if (other.profiles != null)
-				return false;
-		} else if (!profiles.equals(other.profiles))
-			return false;
-		return true;
-	}
-
-	public String toString() {
-		return profiles.toString();
-	}
-}
Index: protocol/src/main/java/geniusweb/protocol/tournament/Team.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/tournament/Team.java	(revision 53)
+++ 	(revision )
@@ -1,74 +1,0 @@
-package geniusweb.protocol.tournament;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import com.fasterxml.jackson.annotation.JsonAutoDetect;
-import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import com.fasterxml.jackson.annotation.JsonValue;
-
-import geniusweb.references.PartyWithParameters;
-
-/**
- * A team is a group of parties, each with their own parameters. Each will be
- * coupled to a {@link ProfileList} in the generation phase of the protocol
- *
- */
-@JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE, isGetterVisibility = Visibility.NONE)
-@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
-public class Team {
-	@JsonValue
-	private final List<PartyWithParameters> parties; // ensure immutability
-
-	/**
-	 * 
-	 * @param ps a list of {@link PartyWithParameters}. Each party is always
-	 *           associated with the given parameters. The order of them is
-	 *           important as it will be matched with the order in the
-	 *           {@link ProfileList}.
-	 */
-	@JsonCreator
-	public Team(List<PartyWithParameters> ps) {
-		this.parties = new ArrayList<PartyWithParameters>(ps);
-	}
-
-	/**
-	 * 
-	 * @return list of all team {@link PartyWithParameters}.
-	 */
-	public List<PartyWithParameters> getParties() {
-		return Collections.unmodifiableList(parties);
-	}
-
-	@Override
-	public int hashCode() {
-		final int prime = 31;
-		int result = 1;
-		result = prime * result + ((parties == null) ? 0 : parties.hashCode());
-		return result;
-	}
-
-	@Override
-	public boolean equals(Object obj) {
-		if (this == obj)
-			return true;
-		if (obj == null)
-			return false;
-		if (getClass() != obj.getClass())
-			return false;
-		Team other = (Team) obj;
-		if (parties == null) {
-			if (other.parties != null)
-				return false;
-		} else if (!parties.equals(other.parties))
-			return false;
-		return true;
-	}
-
-	public String toString() {
-		return parties.toString();
-	}
-}
Index: protocol/src/main/java/geniusweb/protocol/tournament/TournamentSettings.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/tournament/TournamentSettings.java	(revision 53)
+++ protocol/src/main/java/geniusweb/protocol/tournament/TournamentSettings.java	(revision 1)
@@ -5,5 +5,4 @@
 import geniusweb.protocol.NegoSettings;
 import geniusweb.protocol.tournament.allpermutations.AllPermutationsSettings;
-import geniusweb.protocol.tournament.allpermutationslearn.AllPermutationsLearnSettings;
 import tudelft.utilities.logging.Reporter;
 
@@ -11,6 +10,5 @@
  * Interface for tournament settings
  */
-@JsonSubTypes({ @JsonSubTypes.Type(value = AllPermutationsSettings.class),
-		@JsonSubTypes.Type(value = AllPermutationsLearnSettings.class) })
+@JsonSubTypes({ @JsonSubTypes.Type(value = AllPermutationsSettings.class) })
 public interface TournamentSettings extends NegoSettings {
 	@Override
Index: protocol/src/main/java/geniusweb/protocol/tournament/TournamentState.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/tournament/TournamentState.java	(revision 53)
+++ protocol/src/main/java/geniusweb/protocol/tournament/TournamentState.java	(revision 1)
@@ -3,20 +3,12 @@
 import com.fasterxml.jackson.annotation.JsonAutoDetect;
 import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
-import com.fasterxml.jackson.annotation.JsonSubTypes;
-import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
 
 import geniusweb.protocol.NegoState;
-import geniusweb.protocol.tournament.allpermutations.AllPermutationsState;
-import geniusweb.protocol.tournament.allpermutationslearn.AllPermutationsLearnState;
 
 /**
- * The current state of the tournament. Must be implement Json serialization so
- * that it can be used to log the state. State must contain all information to
- * determine the relevant info of the negotiation. It may also be used to
- * restart the nego if a crash occurs.
+ * The current state of the tournament. Must be serializabl;e so that it can be
+ * restarted if a crash occurs.
  */
 @JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)
-@JsonSubTypes({ @Type(value = AllPermutationsState.class),
-		@Type(value = AllPermutationsLearnState.class) })
 public interface TournamentState extends NegoState {
 
Index: protocol/src/main/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsProtocol.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsProtocol.java	(revision 53)
+++ protocol/src/main/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsProtocol.java	(revision 1)
@@ -1,5 +1,4 @@
 package geniusweb.protocol.tournament.allpermutations;
 
-import java.util.List;
 import java.util.logging.Level;
 
@@ -7,7 +6,7 @@
 import geniusweb.events.TournamentStarted;
 import geniusweb.protocol.CurrentNegoState;
-import geniusweb.protocol.partyconnection.ProtocolToPartyConnFactory;
+import geniusweb.protocol.SessionResult;
+import geniusweb.protocol.partyconnection.ConnectionWithPartyFactory;
 import geniusweb.protocol.session.SessionProtocol;
-import geniusweb.protocol.session.SessionResult;
 import geniusweb.protocol.session.SessionSettings;
 import geniusweb.protocol.session.SessionState;
@@ -30,10 +29,10 @@
 	private final transient Reporter log;
 
-	private ProtocolToPartyConnFactory connectionFactory; // FINAL
+	private ConnectionWithPartyFactory connectionFactory; // FINAL
 	private AllPermutationsState state; // MUTABLE
 
 	/**
 	 * 
-	 * @param state  the {@link AllPermutationsState}
+	 * @param state
 	 * @param logger used for all logging, about the tournament, and the created
 	 *               the session and protocols.
@@ -46,7 +45,7 @@
 
 	@Override
-	public void start(ProtocolToPartyConnFactory connectionfactory) {
+	public void start(ConnectionWithPartyFactory connectionfactory) {
 		this.connectionFactory = connectionfactory;
-		notifyListeners(new TournamentStarted(state.getSize().longValue()));
+		notifyChange(new TournamentStarted(state.getSize().longValue()));
 		startNextSession();
 	}
@@ -82,7 +81,9 @@
 			long now = System.currentTimeMillis();
 			if (sessionstate.isFinal(now)) {
-				List<SessionResult> results = sessionstate.getResults();
-				state = state.with(results);
-				notifyListeners(new CurrentNegoState(state));
+				SessionResult result = new SessionResult(
+						sessionstate.getSettings().getParticipants(),
+						sessionstate.getAgreement(), sessionstate.getError());
+				state = state.with(result);
+				notifyChange(new CurrentNegoState(state));
 				if (!state.isFinal(now)) {
 					startNextSession();
Index: protocol/src/main/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsSettings.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsSettings.java	(revision 53)
+++ protocol/src/main/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsSettings.java	(revision 1)
@@ -1,9 +1,6 @@
 package geniusweb.protocol.tournament.allpermutations;
 
-import java.math.BigInteger;
 import java.util.Collections;
-import java.util.LinkedList;
 import java.util.List;
-import java.util.function.BiFunction;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
@@ -11,15 +8,11 @@
 
 import geniusweb.protocol.session.SessionSettings;
-import geniusweb.protocol.session.TeamInfo;
-import geniusweb.protocol.session.saop.SAOPSettings;
-import geniusweb.protocol.session.shaop.SHAOPSettings;
-import geniusweb.protocol.tournament.ProfileList;
-import geniusweb.protocol.tournament.Team;
 import geniusweb.protocol.tournament.TournamentProtocol;
 import geniusweb.protocol.tournament.TournamentSettings;
-import geniusweb.references.PartyWithParameters;
+import geniusweb.references.PartyRef;
 import geniusweb.references.PartyWithProfile;
 import geniusweb.references.ProfileRef;
 import tudelft.utilities.immutablelist.FixedList;
+import tudelft.utilities.immutablelist.Function2;
 import tudelft.utilities.immutablelist.ImmutableList;
 import tudelft.utilities.immutablelist.MapList;
@@ -29,5 +22,4 @@
 import tudelft.utilities.immutablelist.PermutationsWithReturn;
 import tudelft.utilities.immutablelist.PermutationsWithoutReturn;
-import tudelft.utilities.immutablelist.Repeat;
 import tudelft.utilities.immutablelist.Tuple;
 import tudelft.utilities.immutablelist.Tuples;
@@ -37,97 +29,51 @@
  * Takes a number of parties and profiles and makes all permutations of them
  * with the given number of parties and profiles. All profiles must be in the
- * same domain.
- * <p>
- * All sessions are based on the given {@link SessionSettings} (can be
- * {@link SAOPSettings} or {@link SHAOPSettings}). The parties for each
- * tournament session are added to this basic sessionsettings. sessionsettings
- * contains basically all the normal run-sessionsettings. This is used as a
- * "template" for all sessions of the tournament. You can put any use any
- * session setting here, and each session will be run according to the protocol
- * you select here.
- * 
- * The participants list usually is empty. The AllPermutationsProtocol adds the
- * the required parties to this list. So if you provide a non-empty list here,
- * then these parties would be present in every session in the tournament.
- * <p>
- * If the tournament is used with a SHAOP sessionsettings, the first member of
- * each team is assumed to be the SHAOP party, the second the COB party. To
- * match this, the first element of the ProfileList will have to be a partial
- * profile to fit the needs of the SHAOP party. The second profile will have to
- * be a normal profile, to fit the needs of the COB party. Note that you can
- * generate a partial profile using the <code>partial=N</code> option of the
- * profiles server.
+ * same domain. All sessions are based on the given sessionsettings (can be any
+ * session protocol). The parties for each tournament session are added to this
+ * basic sessionsettings.
+ *
  */
 public class AllPermutationsSettings implements TournamentSettings {
-
-	protected final List<Team> teams;
-	protected final List<ProfileList> profileslists;
-	protected final boolean reuseTeams;
-	protected final int teamsPerSession;
-	protected final SessionSettings sessionsettings;
-	protected final int numberTournaments;
-	private final transient ImmutableList<SessionSettings> perms; // cache
-
-	/**
-	 * 
-	 * @param teams           a list of {@link Team}s. Must contain at least
-	 *                        {@link #teamsPerSession} elements. The
-	 *                        {@link #teamsPerSession} must match the protocol:
-	 *                        (SAOP:1, SHAOP:2)
-	 * @param reuseTeams      if true, we use PermutationsWithReturn, if false
-	 *                        we use PermutationsWithoutReturn to create the
-	 *                        teams.
-	 * @param plists          list of available {@link ProfileList}s to be
-	 *                        permutated over the teams. Each
-	 *                        {@link ProfileList} must contain
-	 *                        {@link #teamsPerSession} elements.
-	 * @param teamsPerSession number of parties per session, must be at least 2.
-	 * @param sesettings      The generic {@link SessionSettings}.
-	 *                        {@link SessionSettings#with(TeamInfo)} will be
-	 *                        used to add the required {@link TeamInfo}s
-	 * @param nTournaments    the number of times the tournament should be run.
+	private final List<PartyRef> parties;
+	private final List<ProfileRef> profiles;
+	private final boolean reuseParties;
+	private final int partiesPerSession;
+	private final SessionSettings sessionsettings;
+
+	/**
+	 * 
+	 * @param parties           a list of {@link PartyRef}s. Must contain at
+	 *                          least <partiesPerSession> elements.
+	 * @param reuseParties      if true, we use PermutationsWithReturn, if false
+	 *                          we use PermutationsWithoutReturn to create the
+	 *                          parties.
+	 * @param profiles
+	 * @param partiesPerSession number of parties per session, must be at least
+	 *                          2.
+	 * @param sesettings        The generic {@link SessionSetting}.
+	 *                          {@link SessionSettings#with(PartyWithProfile)}
+	 *                          will be used to add the required
+	 *                          {@link PartyWithProfile}s
 	 */
 	@JsonCreator
-	public AllPermutationsSettings(@JsonProperty("teams") List<Team> teams,
-			@JsonProperty("profileslists") List<ProfileList> plists,
-			@JsonProperty("reuseTeams") boolean reuseTeams,
-			@JsonProperty("teamsPerSession") int teamsPerSession,
-			@JsonProperty("sessionsettings") SessionSettings sesettings,
-			@JsonProperty("numberTournaments") int nTournaments) {
-		if (teamsPerSession < 2)
-			throw new IllegalArgumentException("teamsPerSession must be >=2");
-		if (teams == null || teams.size() < teamsPerSession)
-			throw new IllegalArgumentException("teams must contain at least "
-					+ teamsPerSession + " teams");
-		if (plists == null || plists.size() < 2)
-			throw new IllegalArgumentException(
-					"profileslist must contain at least " + teamsPerSession
-							+ " ProfileList's");
-		if (nTournaments <= 0)
-			throw new IllegalArgumentException("nTournaments must be >0");
-		int teamsize = sesettings.getTeamSize();
-
-		for (Team team : teams) {
-			if (team.getParties().size() != teamsize) {
-				throw new IllegalArgumentException("All teams should have size "
-						+ teamsize + " but found " + team.getParties().size());
-			}
-		}
-		for (ProfileList profile : plists) {
-			if (profile.getProfiles().size() != teamsize) {
-				throw new IllegalArgumentException(
-						"All profiles should have size equal to the team size "
-								+ teamsize + " but found "
-								+ profile.getProfiles().size());
-			}
-		}
-		this.teamsPerSession = teamsPerSession;
-		this.reuseTeams = reuseTeams;
-		this.teams = teams;
-		this.profileslists = plists;
+	public AllPermutationsSettings(
+			@JsonProperty("parties") List<PartyRef> parties,
+			@JsonProperty("reuseParties") boolean reuseParties,
+			@JsonProperty("profiles") List<ProfileRef> profiles,
+			@JsonProperty("partiesPerSession") int partiesPerSession,
+			@JsonProperty("sessionsettings") SessionSettings sesettings) {
+		if (partiesPerSession < 2)
+			throw new IllegalArgumentException("partiesPerSession must be >=2");
+		if (parties == null || parties.size() < partiesPerSession)
+			throw new IllegalArgumentException("parties must contain at least "
+					+ partiesPerSession + " PartyRefs");
+		if (profiles == null || profiles.size() < 2)
+			throw new IllegalArgumentException("profiles must contain at least "
+					+ partiesPerSession + " ProfileRefs");
+		this.partiesPerSession = partiesPerSession;
+		this.reuseParties = reuseParties;
+		this.parties = parties;
+		this.profiles = profiles;
 		this.sessionsettings = sesettings;
-		this.numberTournaments = nTournaments;
-
-		this.perms = permutations1();
 	}
 
@@ -138,40 +84,22 @@
 	}
 
-	/**
-	 * 
-	 * @return number of times the entire tournament is repeated, &gt;0
-	 */
-	public int getNrTournaments() {
-		return this.numberTournaments;
-	}
-
 	@Override
 	public TournamentProtocol getProtocol(Reporter logger) {
 		AllPermutationsState state = new AllPermutationsState(this,
-				Collections.emptyList());
+				permutations(), Collections.emptyList());
 		return new AllPermutationsProtocol(state, logger);
 	}
 
 	/**
-	 * @return All {@link SessionSettings} for the tournament, in the correct
-	 *         order.
+	 * @return {@link ImmutableList} containing all {@link SessionSettings} for
+	 *         all Sessions in the correct order.
 	 */
 	public ImmutableList<SessionSettings> permutations() {
-		return perms;
-	}
-
-	/**
-	 * @return list of all {@link SessionSettings} for this tournament
-	 */
-	private ImmutableList<SessionSettings> permutations1() {
-		ImmutableList<ImmutableList<TeamInfo>> partylistlist;
-		ImmutableList<Team> partieslist = new FixedList<Team>(teams);
-		ImmutableList<ProfileList> profileslist = new FixedList<ProfileList>(
-				profileslists);
-		partylistlist = getParticipantsOneTournament(partieslist, profileslist,
-				teamsPerSession, reuseTeams);
-		partylistlist = new Repeat<ImmutableList<TeamInfo>>(partylistlist,
-				BigInteger.valueOf(numberTournaments), true);
-
+		ImmutableList<ImmutableList<PartyWithProfile>> partylistlist;
+		ImmutableList<PartyRef> partieslist = new FixedList<PartyRef>(parties);
+		ImmutableList<ProfileRef> profileslist = new FixedList<ProfileRef>(
+				profiles);
+		partylistlist = getParticipants(partieslist, profileslist,
+				partiesPerSession, reuseParties);
 		return new MapList<>(partyproflist -> createSetting(partyproflist),
 				partylistlist);
@@ -180,11 +108,7 @@
 	@Override
 	public String toString() {
-		return "AllPermutationsSettings[" + contentString() + "]";
-	}
-
-	protected String contentString() {
-		return teams + "," + reuseTeams + "," + profileslists + ","
-				+ teamsPerSession + "," + sessionsettings + ","
-				+ numberTournaments;
+		return "AllPermutationsSettings[" + parties + "," + reuseParties + ","
+				+ profiles + "," + partiesPerSession + "," + sessionsettings
+				+ "]";
 	}
 
@@ -193,12 +117,11 @@
 		final int prime = 31;
 		int result = 1;
-		result = prime * result + numberTournaments;
+		result = prime * result + ((parties == null) ? 0 : parties.hashCode());
+		result = prime * result + partiesPerSession;
 		result = prime * result
-				+ ((profileslists == null) ? 0 : profileslists.hashCode());
-		result = prime * result + (reuseTeams ? 1231 : 1237);
+				+ ((profiles == null) ? 0 : profiles.hashCode());
+		result = prime * result + (reuseParties ? 1231 : 1237);
 		result = prime * result
 				+ ((sessionsettings == null) ? 0 : sessionsettings.hashCode());
-		result = prime * result + ((teams == null) ? 0 : teams.hashCode());
-		result = prime * result + teamsPerSession;
 		return result;
 	}
@@ -213,12 +136,17 @@
 			return false;
 		AllPermutationsSettings other = (AllPermutationsSettings) obj;
-		if (numberTournaments != other.numberTournaments)
-			return false;
-		if (profileslists == null) {
-			if (other.profileslists != null)
+		if (parties == null) {
+			if (other.parties != null)
 				return false;
-		} else if (!profileslists.equals(other.profileslists))
-			return false;
-		if (reuseTeams != other.reuseTeams)
+		} else if (!parties.equals(other.parties))
+			return false;
+		if (partiesPerSession != other.partiesPerSession)
+			return false;
+		if (profiles == null) {
+			if (other.profiles != null)
+				return false;
+		} else if (!profiles.equals(other.profiles))
+			return false;
+		if (reuseParties != other.reuseParties)
 			return false;
 		if (sessionsettings == null) {
@@ -227,11 +155,4 @@
 		} else if (!sessionsettings.equals(other.sessionsettings))
 			return false;
-		if (teams == null) {
-			if (other.teams != null)
-				return false;
-		} else if (!teams.equals(other.teams))
-			return false;
-		if (teamsPerSession != other.teamsPerSession)
-			return false;
 		return true;
 	}
@@ -242,8 +163,8 @@
 	 * @return {@link SessionSettings}
 	 */
-	protected SessionSettings createSetting(
-			ImmutableList<TeamInfo> partyproflist) {
+	private SessionSettings createSetting(
+			ImmutableList<PartyWithProfile> partyproflist) {
 		SessionSettings settings = sessionsettings;
-		for (TeamInfo partyprof : partyproflist) {
+		for (PartyWithProfile partyprof : partyproflist) {
 			settings = settings.with(partyprof);
 		}
@@ -253,18 +174,18 @@
 	/**
 	 * 
-	 * @param parties              the parties in the tournament
-	 * @param profiles             the profiles in the tournament
-	 * @param n                    number of items to draw. Assumed &ge;1.
+	 * @param parties
+	 * @param profiles
+	 * @param n                    number of items to draw. Assumed >= 1.
 	 * @param drawPartyWithPutback if parties can be drawn multiple times
 	 * @return list of sessionsets where each sessionset contains settings for a
-	 *         session: a list with {@link TeamInfo}s. The sessionsets are made
-	 *         by making all combinations of parties and profiles. Profiles are
-	 *         drawn with replace.
-	 */
-	protected ImmutableList<ImmutableList<TeamInfo>> getParticipantsOneTournament(
-			ImmutableList<Team> parties, ImmutableList<ProfileList> profiles,
+	 *         session: a list with {@link PartyWithProfile}s. The sessionsets
+	 *         are made by making all combinations of parties and profiles.
+	 *         Profiles are drawn with replace.
+	 */
+	private ImmutableList<ImmutableList<PartyWithProfile>> getParticipants(
+			ImmutableList<PartyRef> parties, ImmutableList<ProfileRef> profiles,
 			int n, boolean drawPartyWithPutback) {
 
-		Permutations<Team> partiesPermutations;
+		Permutations<PartyRef> partiesPermutations;
 		if (drawPartyWithPutback) {
 			partiesPermutations = new PermutationsWithReturn<>(parties, n);
@@ -273,46 +194,34 @@
 		}
 
-		Permutations<ProfileList> profilesPermutations = new PermutationsOrderedWithoutReturn<>(
+		Permutations<ProfileRef> profilesPermutations = new PermutationsOrderedWithoutReturn<>(
 				profiles, n);
 
-		// each tuple contains session info: a list of Team and a list of
-		// ProfileList.
-		Tuples<ImmutableList<Team>, ImmutableList<ProfileList>> tuples = new Tuples<>(
+		// each tuple contains sesion info: a list of partyref and a list of
+		// profileref's.
+		Tuples<ImmutableList<PartyRef>, ImmutableList<ProfileRef>> tuples = new Tuples<>(
 				partiesPermutations, profilesPermutations);
 
-		return new MapList<Tuple<ImmutableList<Team>, ImmutableList<ProfileList>>, ImmutableList<TeamInfo>>(
-				tuple -> teamlist(tuple), tuples);
-	}
-
-	/**
-	 * 
-	 * @param tuple a tuple with (1) ImmutableList<Team> (2)
-	 *              ImmutableList<Profiles>
-	 * @return list of TeamOfPartiesAndProfiles, each picked from the two lists
-	 *         in order.
-	 */
-	private ImmutableList<TeamInfo> teamlist(
-			Tuple<ImmutableList<Team>, ImmutableList<ProfileList>> tuple) {
-		BiFunction<Team, ProfileList, TeamInfo> makeparty = new BiFunction<Team, ProfileList, TeamInfo>() {
+		return new MapList<Tuple<ImmutableList<PartyRef>, ImmutableList<ProfileRef>>, ImmutableList<PartyWithProfile>>(
+				tuple -> partyprofilelist(tuple), tuples);
+	}
+
+	/**
+	 * 
+	 * @param tuple a tuple with (1) ImmutableList<PartyRef> (2)
+	 *              ImmutableList<ProfileRef>
+	 * @return list of PartyWithProfile, each picked from the two lists in
+	 *         order.
+	 */
+	private ImmutableList<PartyWithProfile> partyprofilelist(
+			Tuple<ImmutableList<PartyRef>, ImmutableList<ProfileRef>> tuple) {
+		Function2<PartyRef, ProfileRef, PartyWithProfile> //
+		makeparty = new Function2<PartyRef, ProfileRef, PartyWithProfile>() {
 			@Override
-			public TeamInfo apply(Team team, ProfileList profilelist) {
-				List<PartyWithParameters> parties = team.getParties();
-				List<ProfileRef> profiles = profilelist.getProfiles();
-				if (parties.size() != profiles.size())
-					throw new IllegalArgumentException(
-							"Parties and profiles list must match, but found "
-									+ team + " and " + profilelist);
-
-				List<PartyWithProfile> theteams = new LinkedList<>();
-				for (int n = 0; n < parties.size(); n++) {
-					theteams.add(new PartyWithProfile(parties.get(n),
-							profiles.get(n)));
-				}
-				return new TeamInfo(theteams);
+			public PartyWithProfile apply(PartyRef party, ProfileRef profile) {
+				return new PartyWithProfile(party, profile);
 			}
-
 		};
-		return new MapThreadList<TeamInfo, Team, ProfileList>(makeparty,
-				tuple.get1(), tuple.get2());
+		return new MapThreadList<PartyWithProfile, PartyRef, ProfileRef>(
+				makeparty, tuple.get1(), tuple.get2());
 	}
 
Index: protocol/src/main/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsState.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsState.java	(revision 53)
+++ protocol/src/main/java/geniusweb/protocol/tournament/allpermutations/AllPermutationsState.java	(revision 1)
@@ -5,10 +5,9 @@
 import java.util.List;
 
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-import geniusweb.protocol.session.SessionResult;
+import geniusweb.protocol.ProtocolException;
+import geniusweb.protocol.SessionResult;
 import geniusweb.protocol.session.SessionSettings;
 import geniusweb.protocol.tournament.TournamentState;
+import tudelft.utilities.immutablelist.ImmutableList;
 
 /**
@@ -17,13 +16,14 @@
 public class AllPermutationsState implements TournamentState {
 
-	protected final AllPermutationsSettings toursettings; // original settings
+	private final AllPermutationsSettings toursettings; // original settings
+	private final ImmutableList<SessionSettings> sessionsettings;
 	// limited to MAX_INT elements. But we need to store results anyway
-	protected final List<SessionResult> results;
+	private final List<SessionResult> results;
 
-	@JsonCreator
-	public AllPermutationsState(
-			@JsonProperty("toursettings") AllPermutationsSettings toursettings,
-			@JsonProperty("results") List<SessionResult> results) {
+	public AllPermutationsState(AllPermutationsSettings toursettings,
+			ImmutableList<SessionSettings> settings,
+			List<SessionResult> results) {
 		this.toursettings = toursettings;
+		this.sessionsettings = settings;
 		this.results = results;
 	}
@@ -35,5 +35,5 @@
 	@Override
 	public boolean isFinal(long currentTimeMs) {
-		return toursettings.permutations().size().intValue() == results.size();
+		return sessionsettings.size().intValue() == results.size();
 	}
 
@@ -44,6 +44,5 @@
 		if (isFinal(0l))
 			return null;
-		return toursettings.permutations()
-				.get(BigInteger.valueOf(results.size()));
+		return sessionsettings.get(BigInteger.valueOf(results.size()));
 	}
 
@@ -55,13 +54,18 @@
 	 *                                  matching the expected participants
 	 */
-	public AllPermutationsState with(List<SessionResult> res) {
-		// FIXME do we really need this? Why is this not working?
-		// if (!new HashSet<PartyWithProfile>(getNextSettings().getAllParties())
-		// .equals(result.getParticipants().values())) {
-		// throw new IllegalArgumentException("Inconsistent session result");
-		// }
+	public AllPermutationsState with(SessionResult result) {
+		if (!getNextSettings().getParticipants()
+				.equals(result.getParticipants())) {
+			throw new IllegalArgumentException("Inconsistent session result");
+		}
 		ArrayList<SessionResult> newresults = new ArrayList<>(results);
-		newresults.addAll(res);
-		return new AllPermutationsState(toursettings, newresults);
+		newresults.add(result);
+		return new AllPermutationsState(toursettings, sessionsettings,
+				newresults);
+	}
+
+	@Override
+	public ProtocolException getError() {
+		return null;
 	}
 
@@ -71,5 +75,5 @@
 	 */
 	public BigInteger getSize() {
-		return toursettings.permutations().size();
+		return sessionsettings.size();
 	}
 
Index: protocol/src/test/java/geniusweb/protocol/CurrentNegoStateTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/CurrentNegoStateTest.java	(revision 53)
+++ 	(revision )
@@ -1,50 +1,0 @@
-package geniusweb.protocol;
-
-import static org.mockito.Mockito.mock;
-
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-
-import geniusweb.actions.Action;
-import geniusweb.actions.PartyId;
-import geniusweb.progress.Progress;
-import geniusweb.progress.ProgressTime;
-import geniusweb.protocol.session.saop.SAOPSettings;
-import geniusweb.protocol.session.saop.SAOPState;
-import tudelft.utilities.junit.GeneralTests;
-
-public class CurrentNegoStateTest extends GeneralTests<CurrentNegoState> {
-	private PartyId party1 = new PartyId("party1");
-	private PartyId party2 = new PartyId("party2");
-	private List<Action> actions1 = new LinkedList<>();
-
-	private List<PartyId> connections = Arrays.asList(party1);
-	private List<PartyId> connections2 = Arrays.asList(party1, party2);
-
-	private Progress progresstime = mock(ProgressTime.class);
-	private SAOPSettings settings = mock(SAOPSettings.class);
-
-	SAOPState saop1 = new SAOPState(actions1, connections2, progresstime,
-			settings, null, null);
-	SAOPState saop2 = new SAOPState(actions1, connections, progresstime,
-			settings, null, null);
-
-	CurrentNegoState state1 = new CurrentNegoState(saop1);
-	CurrentNegoState state1a = new CurrentNegoState(saop1);
-	CurrentNegoState state2 = new CurrentNegoState(saop2);
-
-	@Override
-	public List<List<CurrentNegoState>> getGeneralTestData() {
-		return Arrays.asList(Arrays.asList(state1, state1a),
-				Arrays.asList(state2));
-	}
-
-	@Override
-	public List<String> getGeneralTestStrings() {
-		return Arrays.asList(
-				"CurrentNegoState.*SAOPState.*party1.*party2.*ProgressTime.*SAOPSettings.*",
-				"CurrentNegoState.*SAOPState.*party1.*ProgressTime.*SAOPSettings.*");
-	}
-
-}
Index: protocol/src/test/java/geniusweb/protocol/ProtocolExceptionTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/ProtocolExceptionTest.java	(revision 53)
+++ 	(revision )
@@ -1,54 +1,0 @@
-package geniusweb.protocol;
-
-import static org.junit.Assert.assertEquals;
-
-import java.io.IOException;
-
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.util.ObjectBuffer;
-
-import geniusweb.actions.PartyId;
-
-public class ProtocolExceptionTest {
-	private ObjectBuffer jackson = new ObjectBuffer();
-	private Exception exception;
-	private String asString1 = "{\"cause\":null,\"stackTrace\":[],\"party\":\"party1\",\"message\":\"party1:test\",\"suppressed\":[],\"localizedMessage\":\"party1:test\"}";
-
-	@Before
-	public void before() {
-		try {
-			throw new ProtocolException("test", new PartyId("party1"));
-			// int x = 1 / 0;
-		} catch (Exception e) {
-			this.exception = e;
-			System.out.println(e);
-		}
-	}
-
-	@Test
-	public void testSerialize() throws JsonProcessingException {
-
-		ObjectMapper jackson = new ObjectMapper();
-		System.out.println(jackson.writeValueAsString(exception));
-		// disabled check , does not work either in Java8 or in Java16 because
-		// field order seems swapped
-//		assertEquals(asString1, jackson.writeValueAsString(exception));
-
-	}
-
-	// ProtocolExceptions can not be deserialized now
-	@Ignore
-	@Test
-	public void testDeserialize() throws IOException {
-
-		ObjectMapper jackson = new ObjectMapper();
-		Exception read = jackson.readValue(asString1, ProtocolException.class);
-		assertEquals(exception, read);
-	}
-
-}
Index: protocol/src/test/java/geniusweb/protocol/session/ConnectionWithPartiesTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/ConnectionWithPartiesTest.java	(revision 53)
+++ protocol/src/test/java/geniusweb/protocol/session/ConnectionWithPartiesTest.java	(revision 1)
@@ -14,29 +14,29 @@
 
 import geniusweb.actions.PartyId;
-import geniusweb.protocol.partyconnection.ProtocolToPartyConnections;
-import geniusweb.protocol.partyconnection.ProtocolToPartyConn;
+import geniusweb.protocol.partyconnection.ConnectionWithParties;
+import geniusweb.protocol.partyconnection.ConnectionWithParty;
 import tudelft.utilities.junit.GeneralTests;
 
 public class ConnectionWithPartiesTest
-		extends GeneralTests<ProtocolToPartyConnections> {
+		extends GeneralTests<ConnectionWithParties> {
 	PartyId party1 = new PartyId("party1");
 	PartyId party2 = new PartyId("party2");
 	PartyId party3 = new PartyId("party3");
 
-	private ProtocolToPartyConn con1 = mock(ProtocolToPartyConn.class);
-	private ProtocolToPartyConn con2 = mock(ProtocolToPartyConn.class);
-	private ProtocolToPartyConn con3 = mock(ProtocolToPartyConn.class);
+	private ConnectionWithParty con1 = mock(ConnectionWithParty.class);
+	private ConnectionWithParty con2 = mock(ConnectionWithParty.class);
+	private ConnectionWithParty con3 = mock(ConnectionWithParty.class);
 
-	private ProtocolToPartyConnections conns1 = new ProtocolToPartyConnections(
+	private ConnectionWithParties conns1 = new ConnectionWithParties(
 			Arrays.asList(con1, con2));
-	private ProtocolToPartyConnections conns1a = new ProtocolToPartyConnections(
+	private ConnectionWithParties conns1a = new ConnectionWithParties(
 			Arrays.asList(con1, con2));
-	private ProtocolToPartyConnections conns2 = new ProtocolToPartyConnections(
+	private ConnectionWithParties conns2 = new ConnectionWithParties(
 			Arrays.asList(con1, con3));
-	private ProtocolToPartyConnections conns3 = new ProtocolToPartyConnections(
+	private ConnectionWithParties conns3 = new ConnectionWithParties(
 			Arrays.asList(con2, con1));
-	private ProtocolToPartyConnections conns4 = new ProtocolToPartyConnections(
+	private ConnectionWithParties conns4 = new ConnectionWithParties(
 			Arrays.asList(con2, con1, con3));
-	private ProtocolToPartyConnections conns5 = new ProtocolToPartyConnections(
+	private ConnectionWithParties conns5 = new ConnectionWithParties(
 			Arrays.asList(con2, con1, con3, con1));
 
@@ -54,5 +54,5 @@
 
 	@Override
-	public List<List<ProtocolToPartyConnections>> getGeneralTestData() {
+	public List<List<ConnectionWithParties>> getGeneralTestData() {
 		return Arrays.asList(Arrays.asList(conns1, conns1a),
 				Arrays.asList(conns2), Arrays.asList(conns3),
@@ -98,5 +98,5 @@
 	@Test
 	public void withPartyTest() {
-		ProtocolToPartyConnections conns = conns3.with(con3);
+		ConnectionWithParties conns = conns3.with(con3);
 		assertEquals(2, conns3.size());
 		assertEquals(3, conns.size());
Index: protocol/src/test/java/geniusweb/protocol/session/DefaultSessionStateTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/DefaultSessionStateTest.java	(revision 1)
+++ protocol/src/test/java/geniusweb/protocol/session/DefaultSessionStateTest.java	(revision 1)
@@ -0,0 +1,137 @@
+package geniusweb.protocol.session;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import geniusweb.actions.Action;
+import geniusweb.actions.EndNegotiation;
+import geniusweb.actions.PartyId;
+import geniusweb.deadline.DeadlineTime;
+import geniusweb.issuevalue.Bid;
+import geniusweb.progress.Progress;
+import geniusweb.progress.ProgressTime;
+import geniusweb.protocol.ProtocolException;
+import geniusweb.protocol.partyconnection.ConnectionWithParties;
+import geniusweb.protocol.session.DefaultSessionState;
+import geniusweb.protocol.session.SessionSettings;
+import geniusweb.protocol.session.saop.SAOPSettings;
+import geniusweb.references.PartyRef;
+import geniusweb.references.PartyWithProfile;
+import geniusweb.references.ProfileRef;
+import tudelft.utilities.junit.GeneralTests;
+
+public class DefaultSessionStateTest extends GeneralTests<DefaultSessionState> {
+	private final ObjectMapper jackson = new ObjectMapper();
+	private DefaultSessionState1 state1, state1a, stateA, stateE, stateF;
+	private String state1string = "{\"DefaultSessionState1\":{\"actions\":[],\"progress\":{\"time\":{\"duration\":1000,\"start\":1000}},\"settings\":{\"SAOPSettings\":{\"participants\":[{\"party\":\"party1\",\"profile\":\"profile1\"},{\"party\":\"party2\",\"profile\":\"profile2\"}],\"deadline\":{\"deadlinetime\":{\"durationms\":1000}}}},\"error\":null,\"partyprofiles\":{\"party1\":{\"party\":\"party1\",\"profile\":\"profile1\"}}}}";
+	private ProgressTime progr;
+	private final Date start = new Date(1000l);
+
+	@Before
+	public void before() throws URISyntaxException {
+		List<Action> actions = new LinkedList<>();
+		PartyId party1 = new PartyId("party1");
+		actions.add(new EndNegotiation(party1));
+		ConnectionWithParties conns = new ConnectionWithParties(
+				Collections.EMPTY_LIST);
+		DeadlineTime deadline = new DeadlineTime(1000);
+		progr = new ProgressTime(deadline.getDuration(), start);
+		PartyRef party1ref = new PartyRef("party1");
+		ProfileRef profile1 = new ProfileRef("profile1");
+		PartyRef party2ref = new PartyRef("party2");
+		ProfileRef profile2 = new ProfileRef("profile2");
+		List<PartyWithProfile> participants = Arrays.asList(
+				new PartyWithProfile(party1ref, profile1),
+				new PartyWithProfile(party2ref, profile2));
+		SessionSettings settings = new SAOPSettings(participants, deadline);
+		ProtocolException e = new ProtocolException("test protocol error",
+				party1.getName());
+		HashMap<PartyId, PartyWithProfile> partyprofiles = new HashMap<PartyId, PartyWithProfile>();
+		partyprofiles.put(party1, new PartyWithProfile(party1ref, profile1));
+		state1 = new DefaultSessionState1(Collections.EMPTY_LIST, null, progr,
+				settings, partyprofiles, null);
+		state1a = new DefaultSessionState1(Collections.EMPTY_LIST, null, progr,
+				settings, partyprofiles, null);
+
+		stateA = new DefaultSessionState1(actions, conns, progr, settings,
+				partyprofiles, null);
+
+		stateE = new DefaultSessionState1(Collections.EMPTY_LIST, conns, progr,
+				settings, partyprofiles, e);
+		stateF = new DefaultSessionState1(Collections.EMPTY_LIST, conns, progr,
+				settings, null, e);
+
+	}
+
+	@Override
+	public List<List<DefaultSessionState>> getGeneralTestData() {
+
+		return Arrays.asList(Arrays.asList(state1, state1a),
+				Arrays.asList(stateA), Arrays.asList(stateE),
+				Arrays.asList(stateF));
+	}
+
+	@Override
+	public List<String> getGeneralTestStrings() {
+		return Arrays.asList(
+				"DefaultSessionState1.*\\[\\].*ProgressTime.*1000ms.*SAOPSettings.*party1.*party2.*,null]",
+				"DefaultSessionState1.*\\[.*EndNegotiation.*party1.*\\].*,.*,ProgressTime.*1000ms.*SAOPSettings.*party1.*party2.*,null]",
+				"DefaultSessionState1.*\\[\\],.*,ProgressTime.*1000ms.*,SAOPSettings.*party1.*party2.*,.*ProtocolException: party1:test protocol error.*",
+				"DefaultSessionState1.*\\[\\],.*,ProgressTime.*1000ms.*,SAOPSettings.*party1.*party2.*,.*ProtocolException: party1:test protocol error.*");
+	}
+
+	@Test
+	public void serializeTest() throws JsonProcessingException {
+		System.out.println(jackson.writeValueAsString(state1));
+		assertEquals(state1string, jackson.writeValueAsString(state1));
+	}
+
+	@Test
+	public void deserializeTest() throws IOException {
+		// note, we don't use DefaultSessionState because we can't add the
+		// annotation nor tell jackson dynamically about the test class.
+		DefaultSessionState state = jackson.readValue(state1string,
+				DefaultSessionState1.class);
+		// compare fields, as sessionended is a derived/new inner class
+		assertEquals(progr, state.getProgress());
+	}
+}
+
+/**
+ * We need to implement a few things because we can not instantiate an abstract
+ * class.
+ */
+class DefaultSessionState1 extends DefaultSessionState {
+
+	private DefaultSessionState1() {
+		super();
+	}
+
+	public DefaultSessionState1(List<Action> actions,
+			ConnectionWithParties conns, Progress progr,
+			SessionSettings settings,
+			Map<PartyId, PartyWithProfile> partyprofiles, ProtocolException e) {
+		super(actions, conns, progr, settings, partyprofiles, e);
+	}
+
+	@Override
+	public Bid getAgreement() {
+		return null;
+	}
+
+}
Index: protocol/src/test/java/geniusweb/protocol/session/SessionResultTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/SessionResultTest.java	(revision 53)
+++ protocol/src/test/java/geniusweb/protocol/session/SessionResultTest.java	(revision 1)
@@ -7,5 +7,4 @@
 import java.util.Arrays;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -17,12 +16,9 @@
 import com.fasterxml.jackson.databind.ObjectMapper;
 
-import geniusweb.actions.PartyId;
-import geniusweb.inform.Agreements;
 import geniusweb.issuevalue.Bid;
 import geniusweb.issuevalue.DiscreteValue;
 import geniusweb.issuevalue.Value;
-import geniusweb.references.Parameters;
+import geniusweb.protocol.SessionResult;
 import geniusweb.references.PartyRef;
-import geniusweb.references.PartyWithParameters;
 import geniusweb.references.PartyWithProfile;
 import geniusweb.references.ProfileRef;
@@ -34,39 +30,27 @@
 
 	private final String ISSUE1 = "issue1";
+	// private final String errorstring =
+	// "\"error\":{\"java.lang.RuntimeException\":{\"cause\":null,\"stackTrace\":[{\"methodName\":\"<init>\",\"fileName\":\"SessionResultTest.java\",\"lineNumber\":29,\"className\":\"events.SessionResultTest\",\"nativeMethod\":false},{\"methodName\":\"newInstance0\",\"fileName\":\"NativeConstructorAccessorImpl.java\",\"lineNumber\":-2,\"className\":\"sun.reflect.NativeConstructorAccessorImpl\",\"nativeMethod\":true},{\"methodName\":\"newInstance\",\"fileName\":\"NativeConstructorAccessorImpl.java\",\"lineNumber\":62,\"className\":\"sun.reflect.NativeConstructorAccessorImpl\",\"nativeMethod\":false},{\"methodName\":\"newInstance\",\"fileName\":\"DelegatingConstructorAccessorImpl.java\",\"lineNumber\":45,\"className\":\"sun.reflect.DelegatingConstructorAccessorImpl\",\"nativeMethod\":false},{\"methodName\":\"newInstance\",\"fileName\":\"Constructor.java\",\"lineNumber\":423,\"className\":\"java.lang.reflect.Constructor\",\"nativeMethod\":false},{\"methodName\":\"createTest\",\"fileName\":\"BlockJUnit4ClassRunner.java\",\"lineNumber\":217,\"className\":\"org.junit.runners.BlockJUnit4ClassRunner\",\"nativeMethod\":false},{\"methodName\":\"runReflectiveCall\",\"fileName\":\"BlockJUnit4ClassRunner.java\",\"lineNumber\":266,\"className\":\"org.junit.runners.BlockJUnit4ClassRunner$1\",\"nativeMethod\":false},{\"methodName\":\"run\",\"fileName\":\"ReflectiveCallable.java\",\"lineNumber\":12,\"className\":\"org.junit.internal.runners.model.ReflectiveCallable\",\"nativeMethod\":false},{\"methodName\":\"methodBlock\",\"fileName\":\"BlockJUnit4ClassRunner.java\",\"lineNumber\":263,\"className\":\"org.junit.runners.BlockJUnit4ClassRunner\",\"nativeMethod\":false},{\"methodName\":\"runChild\",\"fileName\":\"BlockJUnit4ClassRunner.java\",\"lineNumber\":78,\"className\":\"org.junit.runners.BlockJUnit4ClassRunner\",\"nativeMethod\":false},{\"methodName\":\"runChild\",\"fileName\":\"BlockJUnit4ClassRunner.java\",\"lineNumber\":57,\"className\":\"org.junit.runners.BlockJUnit4ClassRunner\",\"nativeMethod\":false},{\"methodName\":\"run\",\"fileName\":\"ParentRunner.java\",\"lineNumber\":290,\"className\":\"org.junit.runners.ParentRunner$3\",\"nativeMethod\":false},{\"methodName\":\"schedule\",\"fileName\":\"ParentRunner.java\",\"lineNumber\":71,\"className\":\"org.junit.runners.ParentRunner$1\",\"nativeMethod\":false},{\"methodName\":\"runChildren\",\"fileName\":\"ParentRunner.java\",\"lineNumber\":288,\"className\":\"org.junit.runners.ParentRunner\",\"nativeMethod\":false},{\"methodName\":\"access$000\",\"fileName\":\"ParentRunner.java\",\"lineNumber\":58,\"className\":\"org.junit.runners.ParentRunner\",\"nativeMethod\":false},{\"methodName\":\"evaluate\",\"fileName\":\"ParentRunner.java\",\"lineNumber\":268,\"className\":\"org.junit.runners.ParentRunner$2\",\"nativeMethod\":false},{\"methodName\":\"run\",\"fileName\":\"ParentRunner.java\",\"lineNumber\":363,\"className\":\"org.junit.runners.ParentRunner\",\"nativeMethod\":false},{\"methodName\":\"run\",\"fileName\":\"JUnit4TestReference.java\",\"lineNumber\":86,\"className\":\"org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference\",\"nativeMethod\":false},{\"methodName\":\"run\",\"fileName\":\"TestExecution.java\",\"lineNumber\":38,\"className\":\"org.eclipse.jdt.internal.junit.runner.TestExecution\",\"nativeMethod\":false},{\"methodName\":\"runTests\",\"fileName\":\"RemoteTestRunner.java\",\"lineNumber\":538,\"className\":\"org.eclipse.jdt.internal.junit.runner.RemoteTestRunner\",\"nativeMethod\":false},{\"methodName\":\"runTests\",\"fileName\":\"RemoteTestRunner.java\",\"lineNumber\":760,\"className\":\"org.eclipse.jdt.internal.junit.runner.RemoteTestRunner\",\"nativeMethod\":false},{\"methodName\":\"run\",\"fileName\":\"RemoteTestRunner.java\",\"lineNumber\":460,\"className\":\"org.eclipse.jdt.internal.junit.runner.RemoteTestRunner\",\"nativeMethod\":false},{\"methodName\":\"main\",\"fileName\":\"RemoteTestRunner.java\",\"lineNumber\":206,\"className\":\"org.eclipse.jdt.internal.junit.runner.RemoteTestRunner\",\"nativeMethod\":false}],\"message\":\"test\",\"localizedMessage\":\"test\",\"suppressed\":[]}}";
 	private SessionResult result1, result1a, result2, result3, result4;
-	private String jsonstring = "{\"participants\":{\"party2\":{\"party\":{\"partyref\":\"party2\",\"parameters\":{}},\"profile\":\"profile2\"},\"party1\":{\"party\":{\"partyref\":\"party1\",\"parameters\":{}},\"profile\":\"profile1\"}},\"agreements\":{\"party2\":{\"issuevalues\":{\"issue1\":\"a\"}},\"party1\":{\"issuevalues\":{\"issue1\":\"a\"}}},\"penalties\":{\"party2\":0.0,\"party1\":0.0},\"error\":null}";
-	private Map<PartyId, Double> nopenalties = new HashMap<>();
-	private Map<PartyId, Double> penalties = new HashMap<>();
-
-	private PartyId PARTY1 = new PartyId("party1");
-	private PartyId PARTY2 = new PartyId("party2");
-	private PartyId PARTY3 = new PartyId("party3");
+	private String errorstring; // created dynamically: eclipse and maven
+								// generate different stacktrace.
+	private String jsonstring;
 
 	@Before
 	public void before() throws URISyntaxException, JsonProcessingException {
-		penalties.put(PARTY1, 0.1d);
-		penalties.put(PARTY2, 0.2d);
-		nopenalties.put(PARTY1, 0d);
-		nopenalties.put(PARTY2, 0d);
+		errorstring = "\"error\":{\"java.lang.RuntimeException\":"
+				+ jackson.writeValueAsString(error) + "}";
+		System.out.println(errorstring);
+		jsonstring = "{\"participants\":[{\"party\":\"party1\",\"profile\":\"profile1\"},{\"party\":\"party2\",\"profile\":\"profile2\"}],\"agreement\":{\"issuevalues\":{\"issue1\":\"a\"}},"
+				+ errorstring + "}";
 
-		String errorstring = "\"error\":{\"java.lang.RuntimeException\":"
-				+ jackson.writeValueAsString(error) + "}";
-		// System.out.println(errorstring);
-
-		PartyWithParameters party1 = new PartyWithParameters(
-				new PartyRef("party1"), new Parameters());
-		PartyWithParameters party2 = new PartyWithParameters(
-				new PartyRef("party2"), new Parameters());
-
-		PartyWithProfile partyprofile1 = new PartyWithProfile(party1,
-				new ProfileRef("profile1"));
-		PartyWithProfile partyprofile2 = new PartyWithProfile(party2,
-				new ProfileRef("profile2"));
+		PartyWithProfile partyprofile1 = new PartyWithProfile(
+				new PartyRef("party1"), new ProfileRef("profile1"));
+		PartyWithProfile partyprofile2 = new PartyWithProfile(
+				new PartyRef("party2"), new ProfileRef("profile2"));
 
 		Map<String, Value> issuevalues1 = new HashMap<>();
 		issuevalues1.put(ISSUE1, new DiscreteValue("a"));
 		Bid bid1 = new Bid(issuevalues1);
-		Agreements agreement1 = new Agreements().with(new Agreements(bid1,
-				new HashSet<>(Arrays.asList(PARTY1, PARTY2))));
 
 		// different order but that shouldn't matter
@@ -74,24 +58,15 @@
 		issuevalues2.put(ISSUE1, new DiscreteValue("b"));
 		Bid bid2 = new Bid(issuevalues2);
-		Agreements agreement2 = new Agreements().with(new Agreements(bid2,
-				new HashSet<>(Arrays.asList(PARTY1, PARTY3))));
 
-		Map<PartyId, PartyWithProfile> partiesmap = new HashMap<>();
-		partiesmap.put(PARTY1, partyprofile1);
-		partiesmap.put(PARTY2, partyprofile2);
-
-		Map<PartyId, PartyWithProfile> partiesmap2 = new HashMap<>();
-		partiesmap2.put(PARTY1, partyprofile2);
-		partiesmap2.put(PARTY3, partyprofile1);
-
-		result1 = new SessionResult(partiesmap, agreement1, nopenalties, null);
-		result1a = new SessionResult(partiesmap, agreement1, nopenalties, null);
-		result2 = new SessionResult(partiesmap, agreement2, nopenalties, null);
-		result3 = new SessionResult(partiesmap2, agreement1, nopenalties, null);
-		result4 = new SessionResult(partiesmap2, agreement1, penalties, null);
-
-		// IGNORE ERROR for now, it fails somewhere deep in maven suddenly.
-		// result4 = new SessionResult(Arrays.asList(partyprofile1,
-		// partyprofile2), bid1, error);
+		result1 = new SessionResult(Arrays.asList(partyprofile1, partyprofile2),
+				bid1, error);
+		result1a = new SessionResult(
+				Arrays.asList(partyprofile1, partyprofile2), bid1, error);
+		result2 = new SessionResult(Arrays.asList(partyprofile1, partyprofile2),
+				bid2, error);
+		result3 = new SessionResult(Arrays.asList(partyprofile2, partyprofile1),
+				bid2, error);
+		result4 = new SessionResult(Arrays.asList(partyprofile1, partyprofile2),
+				bid1, null);
 	}
 
@@ -106,10 +81,8 @@
 	public List<String> getGeneralTestStrings() {
 		return Arrays.asList(
-				"SessionResult.*party2.*profile2.*,.*party1.*profile1.*Agreements.*Bid.*issue1=\"a\".*0\\.0.*0\\.0.*null.*",
-				"SessionResult.*party2.*profile2.*,.*party1.*profile1.*Agreements.*Bid.*issue1=\"b\".*0\\.0.*0\\.0.*null.*",
-				"SessionResult.*party1.*profile2.*,.*party3.*profile1.*Agreements.*Bid.*issue1=\"a\".*0\\.0.*0\\.0.*null.*",
-				"SessionResult.*party1.*profile2.*,.*party3.*profile1.*Agreements.*Bid.*issue1=\"a\".*party2.*0\\.2.*party1.*0\\.1.*null.*"
-
-		);
+				"SessionResult.*party1.*profile1.*,.*party2.*profile2.*Bid.*issue1=\"a\".*java.lang.RuntimeException.*test.*",
+				"SessionResult.*party1.*profile1.*,.*party2.*profile2.*Bid.*issue1=\"b\".*java.lang.RuntimeException.*test.*",
+				"SessionResult.*party2.*profile2.*,.*party1.*profile1.*Bid.*issue1=\"b\".*java.lang.RuntimeException.*test.*",
+				"SessionResult.*party1.*profile1.*,.*party2.*profile2.*Bid.*issue1=\"a\".*null.*");
 	}
 
Index: protocol/src/test/java/geniusweb/protocol/session/TeamInfoTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/TeamInfoTest.java	(revision 53)
+++ 	(revision )
@@ -1,73 +1,0 @@
-package geniusweb.protocol.session;
-
-import static org.junit.Assert.assertEquals;
-
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import geniusweb.references.Parameters;
-import geniusweb.references.PartyRef;
-import geniusweb.references.PartyWithParameters;
-import geniusweb.references.ProfileRef;
-import tudelft.utilities.junit.GeneralTests;
-
-public class TeamInfoTest extends GeneralTests<TeamInfo> {
-
-	private TeamInfo team1 = new TeamInfo(Collections.emptyList());
-	private TeamInfo team1a = new TeamInfo(Collections.emptyList());
-	private PartyRef partyref;
-	private Parameters parameters = new Parameters();;
-	private ProfileRef profileref;
-	private TeamInfo team2, team2a;
-	private String asString1 = "{\"TeamInfo\":{\"parties\":[{\"party\":{\"partyref\":\"party1\",\"parameters\":{}},\"profile\":\"profile1\"}]}}";
-
-	@Before
-	public void before() throws URISyntaxException {
-		partyref = new PartyRef("party1");
-		profileref = new ProfileRef("profile1");
-		team2 = new TeamInfo(new PartyWithParameters(partyref, parameters),
-				profileref);
-		team2a = new TeamInfo(new PartyWithParameters(partyref, parameters),
-				profileref);
-
-	}
-
-	@Override
-	public List<List<TeamInfo>> getGeneralTestData() {
-		return Arrays.asList(Arrays.asList(team1, team1a),
-				Arrays.asList(team2, team2a));
-	}
-
-	@Override
-	public List<String> getGeneralTestStrings() {
-		return Arrays.asList("TeamInfo.\\[\\].",
-				"TeamInfo.\\[PartyWithProfile.*party1.*profile1.*\\].*");
-	}
-
-	@Test
-	public void testSerialize() throws JsonProcessingException {
-
-		ObjectMapper jackson = new ObjectMapper();
-		System.out.println(jackson.writeValueAsString(team2));
-		assertEquals(asString1, jackson.writeValueAsString(team2));
-
-	}
-
-	@Test
-	public void testDeserialize() throws IOException {
-
-		ObjectMapper jackson = new ObjectMapper();
-		TeamInfo read = jackson.readValue(asString1, TeamInfo.class);
-		assertEquals(team2, read);
-	}
-
-}
Index: protocol/src/test/java/geniusweb/protocol/session/saop/SAOPSettingsTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/saop/SAOPSettingsTest.java	(revision 53)
+++ protocol/src/test/java/geniusweb/protocol/session/saop/SAOPSettingsTest.java	(revision 1)
@@ -20,8 +20,7 @@
 import geniusweb.deadline.DeadlineTime;
 import geniusweb.protocol.session.SessionSettings;
-import geniusweb.protocol.session.TeamInfo;
-import geniusweb.references.Parameters;
+import geniusweb.protocol.session.saop.SAOPSettings;
 import geniusweb.references.PartyRef;
-import geniusweb.references.PartyWithParameters;
+import geniusweb.references.PartyWithProfile;
 import geniusweb.references.ProfileRef;
 import tudelft.utilities.junit.GeneralTests;
@@ -30,11 +29,11 @@
 public class SAOPSettingsTest extends GeneralTests<SAOPSettings> {
 
-	private TeamInfo partyprof1 = mock(TeamInfo.class);
-	private TeamInfo partyprof2 = mock(TeamInfo.class);
-	private TeamInfo partyprof3 = mock(TeamInfo.class);
-	private List<TeamInfo> participants2 = Arrays.asList(partyprof1,
+	private PartyWithProfile partyprof1 = mock(PartyWithProfile.class);
+	private PartyWithProfile partyprof2 = mock(PartyWithProfile.class);
+	private PartyWithProfile partyprof3 = mock(PartyWithProfile.class);
+	private List<PartyWithProfile> participants2 = Arrays.asList(partyprof1,
 			partyprof2);
-	private List<TeamInfo> participants3 = Arrays.asList(partyprof1, partyprof2,
-			partyprof3);
+	private List<PartyWithProfile> participants3 = Arrays.asList(partyprof1,
+			partyprof2, partyprof3);
 
 	private DeadlineTime deadline = mock(DeadlineTime.class);
@@ -47,5 +46,5 @@
 
 	private SAOPSettings sersettings;
-	private final String serialized = "{\"SAOPSettings\":{\"participants\":[{\"TeamInfo\":{\"parties\":[{\"party\":{\"partyref\":\"http://party1\",\"parameters\":{}},\"profile\":\"http://profile1\"}]}},{\"TeamInfo\":{\"parties\":[{\"party\":{\"partyref\":\"http://party2\",\"parameters\":{}},\"profile\":\"http://profile2\"}]}}],\"deadline\":{\"DeadlineTime\":{\"durationms\":100}}}}";
+	private final String serialized = "{\"SAOPSettings\":{\"participants\":[{\"party\":\"http://party1\",\"profile\":\"http://profile1\"},{\"party\":\"http://party2\",\"profile\":\"http://profile2\"}],\"deadline\":{\"deadlinetime\":{\"durationms\":100}}}}";
 
 	@Before
@@ -55,8 +54,4 @@
 		when(deadline2.toString()).thenReturn("deadline2");
 
-		when(partyprof1.getSize()).thenReturn(1);
-		when(partyprof2.getSize()).thenReturn(1);
-		when(partyprof3.getSize()).thenReturn(1);
-
 		when(partyprof1.toString()).thenReturn("party and profile 1");
 		when(partyprof2.toString()).thenReturn("party and profile 2");
@@ -65,13 +60,13 @@
 		// SERIALIZABLE version with REAL objects. Still no workaround for
 		// this...
-		PartyWithParameters party1 = new PartyWithParameters(
-				new PartyRef("http://party1"), new Parameters());
+		PartyRef party1 = new PartyRef("http://party1");
 		ProfileRef profile1 = new ProfileRef("http://profile1");
-		PartyWithParameters party2 = new PartyWithParameters(
-				new PartyRef("http://party2"), new Parameters());
+		PartyRef party2 = new PartyRef("http://party2");
 		ProfileRef profile2 = new ProfileRef("http://profile2");
-		TeamInfo partywithprof1 = new TeamInfo(party1, profile1);
-		TeamInfo partywithprof2 = new TeamInfo(party2, profile2);
-		List<TeamInfo> participants = Arrays.asList(partywithprof1,
+		PartyWithProfile partywithprof1 = new PartyWithProfile(party1,
+				profile1);
+		PartyWithProfile partywithprof2 = new PartyWithProfile(party2,
+				profile2);
+		List<PartyWithProfile> participants = Arrays.asList(partywithprof1,
 				partywithprof2);
 
@@ -143,5 +138,5 @@
 		SAOPSettings saop = new SAOPSettings(participants2, deadline);
 		SessionSettings saop2 = saop.with(partyprof3);
-		assertEquals(3, saop2.getTeams().size());
+		assertEquals(3, saop2.getParticipants().size());
 	}
 
Index: protocol/src/test/java/geniusweb/protocol/session/saop/SAOPStateTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/saop/SAOPStateTest.java	(revision 53)
+++ protocol/src/test/java/geniusweb/protocol/session/saop/SAOPStateTest.java	(revision 1)
@@ -9,6 +9,4 @@
 import static org.mockito.Mockito.when;
 
-import java.io.IOException;
-import java.net.URISyntaxException;
 import java.util.Arrays;
 import java.util.Date;
@@ -18,7 +16,4 @@
 import org.junit.Before;
 import org.junit.Test;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
 
 import geniusweb.actions.Accept;
@@ -27,19 +22,12 @@
 import geniusweb.actions.Offer;
 import geniusweb.actions.PartyId;
-import geniusweb.deadline.Deadline;
-import geniusweb.deadline.DeadlineTime;
 import geniusweb.issuevalue.Bid;
 import geniusweb.progress.Progress;
 import geniusweb.progress.ProgressRounds;
 import geniusweb.progress.ProgressTime;
-import geniusweb.protocol.NegoState;
 import geniusweb.protocol.ProtocolException;
-import geniusweb.protocol.partyconnection.ProtocolToPartyConn;
-import geniusweb.protocol.session.TeamInfo;
-import geniusweb.references.Parameters;
-import geniusweb.references.PartyRef;
-import geniusweb.references.PartyWithParameters;
-import geniusweb.references.PartyWithProfile;
-import geniusweb.references.ProfileRef;
+import geniusweb.protocol.partyconnection.ConnectionWithParties;
+import geniusweb.protocol.partyconnection.ConnectionWithParty;
+import geniusweb.protocol.session.SessionSettings;
 import tudelft.utilities.junit.GeneralTests;
 
@@ -50,21 +38,24 @@
 	private PartyId party2 = new PartyId("party2");
 	private PartyId party3 = new PartyId("party3");
-	private List<Action> actions1 = new LinkedList<>();
+	private List<Action> actions = new LinkedList<>();
 	private Action action = mock(Action.class);
 	private List<Action> actions2 = Arrays.asList(action);
 
-	private ProtocolToPartyConn party1conn = mock(ProtocolToPartyConn.class);
-	private ProtocolToPartyConn party2conn = mock(ProtocolToPartyConn.class);
-	private ProtocolToPartyConn party3conn = mock(ProtocolToPartyConn.class);
-
-	private List<PartyId> connections = Arrays.asList(party1, party2);
-	private List<PartyId> connections2 = Arrays.asList(party1, party3);
-	private List<PartyId> connections3 = Arrays.asList(party1, party2, party3);
+	private ConnectionWithParty party1conn = mock(ConnectionWithParty.class);
+	private ConnectionWithParty party2conn = mock(ConnectionWithParty.class);
+	private ConnectionWithParty party3conn = mock(ConnectionWithParty.class);
+
+	private ConnectionWithParties connections = new ConnectionWithParties(
+			Arrays.asList(party1conn, party2conn));
+	private ConnectionWithParties connections2 = new ConnectionWithParties(
+			Arrays.asList(party1conn, party3conn));
+	private ConnectionWithParties connections3 = new ConnectionWithParties(
+			Arrays.asList(party1conn, party2conn, party3conn));
 
 	private Progress progresstime = mock(ProgressTime.class);
 	private ProgressRounds progressrounds = mock(ProgressRounds.class);
 	private ProgressRounds progressrounds1 = mock(ProgressRounds.class);
-	private SAOPSettings settings = mock(SAOPSettings.class);
-	private SAOPState state, state1, state1a, state2, state3, state4;
+	private SessionSettings settings = mock(SAOPSettings.class);
+	private SAOPState state1, state1a, state2, state3, state4;
 
 	private Bid bid1 = mock(Bid.class);
@@ -76,10 +67,6 @@
 	private EndNegotiation endNegotiation1 = new EndNegotiation(party1);
 
-	private final ObjectMapper jackson = new ObjectMapper();
-
-	private String serialized = "{\"SAOPState\":{\"actions\":[],\"connections\":[\"party1\",\"party2\"],\"progress\":{\"ProgressTime\":{\"duration\":1000000,\"start\":2000000}},\"settings\":{\"SAOPSettings\":{\"participants\":[{\"TeamInfo\":{\"parties\":[{\"party\":{\"partyref\":\"party1ref\",\"parameters\":{}},\"profile\":\"prof1\"}]}}],\"deadline\":{\"DeadlineTime\":{\"durationms\":123000}}}},\"partyprofiles\":{},\"error\":null}}";
-
 	@Before
-	public void before() throws URISyntaxException {
+	public void before() {
 		when(party1conn.getParty()).thenReturn(party1);
 		when(party2conn.getParty()).thenReturn(party2);
@@ -96,26 +83,14 @@
 		when(progressrounds.advance()).thenReturn(progressrounds1);
 
-		state1 = new SAOPState(actions1, connections, progresstime, settings,
-				null, null);
-		state1a = new SAOPState(actions1, connections, progresstime, settings,
+		state1 = new SAOPState(actions, connections, progresstime, settings,
+				null, null);
+		state1a = new SAOPState(actions, connections, progresstime, settings,
 				null, null);
 		state2 = new SAOPState(actions2, connections, progresstime, settings,
 				null, null);
-		state3 = new SAOPState(actions1, connections2, progresstime, settings,
-				null, null);
-		state4 = new SAOPState(actions1, connections, progressrounds, settings,
-				null, null);
-
-		List<PartyId> conns = Arrays.asList(party1, party2);
-		PartyWithParameters pwithp = new PartyWithParameters(
-				new PartyRef("party1ref"), new Parameters());
-		List<PartyWithProfile> teams = Arrays
-				.asList(new PartyWithProfile(pwithp, new ProfileRef("prof1")));
-		List<TeamInfo> participants = Arrays.asList(new TeamInfo(teams));
-		Deadline deadline = new DeadlineTime(123000);
-		SAOPSettings setts = new SAOPSettings(participants, deadline);
-		state = new SAOPState(actions1, conns,
-				new ProgressTime(1000000l, new Date(2000000l)), setts, null,
-				null);
+		state3 = new SAOPState(actions, connections2, progresstime, settings,
+				null, null);
+		state4 = new SAOPState(actions, connections, progressrounds, settings,
+				null, null);
 
 	}
@@ -131,19 +106,19 @@
 	public List<String> getGeneralTestStrings() {
 		return Arrays.asList(
-				"SAOPState.*\\[\\].*party1.*party2.*ProgressTime.*",
-				"SAOPState.*\\[act1\\].*party1.*party2.*ProgressTime.*",
-				"SAOPState.*party1.*party3.*ProgressTime.*",
-				"SAOPState.*party1.*party2.*ProgressRounds.*");
+				"SAOPState.*\\[\\].*ConnectionWithParties.*conn1.*conn2.*ProgressTime.*",
+				"SAOPState.*\\[act1\\].*ConnectionWithParties.*conn1.*conn2.*ProgressTime.*",
+				"SAOPState.*ConnectionWithParties.*conn1.*conn3.*ProgressTime.*",
+				"SAOPState.*ConnectionWithParties.*conn1.*conn2.*ProgressRounds.*");
 	}
 
 	@Test
 	public void constructWith0Connection() {
-		new SAOPState(actions1, Arrays.asList(), progresstime, settings, null,
-				null);
+		new SAOPState(actions, new ConnectionWithParties(Arrays.asList()),
+				progresstime, settings, null, null);
 	}
 
 	@Test
 	public void constructWithNullConnection() {
-		SAOPState state = new SAOPState(actions1, null, progresstime, settings,
+		SAOPState state = new SAOPState(actions, null, progresstime, settings,
 				null, null);
 		assertEquals(0, state.getConnections().size());
@@ -157,6 +132,7 @@
 	@Test
 	public void testNextActor2() {
-		List<PartyId> conns = Arrays.asList(party2, party3);
-		SAOPState state = new SAOPState(actions1, conns, progresstime, settings,
+		ConnectionWithParties conns = new ConnectionWithParties(
+				Arrays.asList(party2conn, party3conn));
+		SAOPState state = new SAOPState(actions, conns, progresstime, settings,
 				null, null);
 		assertEquals(party2, state.getNextActor());
@@ -182,5 +158,5 @@
 	public void isFinalTest() {
 		assertFalse(state1.isFinal(NOW));
-		SAOPState state = new SAOPState(actions1, connections, progresstime,
+		SAOPState state = new SAOPState(actions, connections, progresstime,
 				settings, null, mock(ProtocolException.class));
 		assertTrue(state.isFinal(NOW));
@@ -200,5 +176,5 @@
 		SAOPState state = new SAOPState(actions, connections3, progressrounds,
 				settings, null, null);
-		assertTrue(state.getAgreements().getMap().isEmpty());
+		assertNull(state.getAgreement());
 	}
 
@@ -208,5 +184,5 @@
 		SAOPState state = new SAOPState(actions, connections3, progressrounds,
 				settings, null, null);
-		assertTrue(state.getAgreements().getMap().isEmpty());
+		assertNull(state.getAgreement());
 	}
 
@@ -216,5 +192,5 @@
 		SAOPState state = new SAOPState(actions, connections3, progressrounds,
 				settings, null, null);
-		assertTrue(state.getAgreements().getMap().isEmpty());
+		assertNull(state.getAgreement());
 	}
 
@@ -224,5 +200,5 @@
 		SAOPState state = new SAOPState(actions, connections3, progressrounds,
 				settings, null, null);
-		assertEquals(bid1, state.getAgreements().getMap().get(party1));
+		assertEquals(bid1, state.getAgreement());
 		assertTrue(state.isFinal(NOW));
 	}
@@ -233,5 +209,5 @@
 		SAOPState state = new SAOPState(actions, connections3, progressrounds,
 				settings, null, null);
-		assertTrue(state.getAgreements().getMap().isEmpty());
+		assertEquals(null, state.getAgreement());
 	}
 
@@ -241,16 +217,30 @@
 		SAOPState state = new SAOPState(actions, connections3, progressrounds,
 				settings, null, null);
-		assertTrue(state.getAgreements().getMap().isEmpty());
-	}
-
-	@Test(expected = IllegalArgumentException.class)
+		assertEquals(null, state.getAgreement());
+	}
+
+	@Test
+	public void withWrongActionTest() {
+		// wrong because action has actor null which does not match party1
+		SAOPState state = state1.with(party1, action);
+		assertEquals(1, state.getActions().size());
+		assertEquals(action, state.getActions().get(0));
+		assertTrue(state.isFinal(NOW));
+		assertEquals(
+				"geniusweb.protocol.ProtocolException: party1:act contains wrong credentials: act1",
+				state.getError().toString());
+	}
+
+	@Test
 	public void withActionTest() {
 		when(action.getActor()).thenReturn(party1);
-		state1.with(party1, action);
+		SAOPState state = state1.with(party1, action);
+		assertEquals(1, state.getActions().size());
+		assertEquals(action, state.getActions().get(0));
 	}
 
 	@Test
 	public void withConnectionTest() {
-		SAOPState state = state1.with(party3, (PartyWithProfile) null);
+		SAOPState state = state1.with(party3conn, null);
 		assertEquals(3, state.getConnections().size());
 	}
@@ -261,5 +251,5 @@
 		SAOPState state = new SAOPState(actions, connections3, progressrounds,
 				settings, null, null);
-		assertTrue(state.getAgreements().getMap().isEmpty());
+		assertEquals(null, state.getAgreement());
 		assertEquals(null, state.getError());
 		assertTrue(state.isFinal(NOW));
@@ -269,18 +259,21 @@
 	@Test
 	public void isProtocolErrorFinal() {
-		SAOPState state = new SAOPState(actions1, connections3, progressrounds,
-				settings, null,
-				new ProtocolException("test error", new PartyId("test")));
+		SAOPState state = new SAOPState(actions, connections3, progressrounds,
+				settings, null, new ProtocolException("test error", "test"));
 		assertTrue(state.isFinal(NOW));
 		assertNotNull(state.getError());
 	}
 
-	@Test(expected = IllegalArgumentException.class)
+	@Test
 	public void RefuseImmediateAccept() {
 		Accept nullaccept = new Accept(party1, null);
-		state1.with(party1, nullaccept);
-	}
-
-	@Test(expected = IllegalArgumentException.class)
+		SAOPState state = state1.with(party1, nullaccept);
+		assertTrue(state.isFinal(NOW));
+		assertEquals(
+				"geniusweb.protocol.ProtocolException: party1:Accept without a recent offer",
+				state.getError().toString());
+	}
+
+	@Test
 	public void RefuseNotMyTurn() {
 		List<Action> actions = Arrays.asList(offer1);
@@ -288,8 +281,12 @@
 				settings, null, null);
 
-		state.with(party1, offer1);
-	}
-
-	@Test(expected = IllegalArgumentException.class)
+		state = state.with(party1, offer1);
+		assertTrue(state.isFinal(NOW));
+		assertEquals(
+				"geniusweb.protocol.ProtocolException: party1:actor does not have the turn ",
+				state.getError().toString());
+	}
+
+	@Test
 	public void RefuseNullAccept() {
 		List<Action> actions = Arrays.asList(offer1);
@@ -300,7 +297,9 @@
 		state = state.with(party2, nullaccept);
 		assertTrue(state.isFinal(NOW));
-	}
-
-	@Test(expected = IllegalArgumentException.class)
+		assertTrue(state.getError().toString()
+				.matches(".*party2.*Accepts a bid that was not offered.*"));
+	}
+
+	@Test
 	public void RefuseNullAction() {
 		List<Action> actions = Arrays.asList(offer1);
@@ -308,5 +307,8 @@
 				settings, null, null);
 
-		state = state.with(party2, (Action) null);
+		state = state.with(party2, null);
+		assertEquals(
+				"geniusweb.protocol.ProtocolException: party2:action is null",
+				state.getError().toString());
 	}
 
@@ -321,5 +323,5 @@
 		assertTrue(state.isFinal(NOW));
 		assertNull(state.getError());
-		assertEquals(bid1, state.getAgreements().getMap().get(party1));
+		assertEquals(bid1, state.getAgreement());
 
 	}
@@ -337,23 +339,6 @@
 		assertTrue(state.isFinal(NOW));
 		assertNull(state.getError());
-		assertEquals(bid2, state.getAgreements().getMap().get(party1));
-
-	}
-
-	@Test
-	public void testDeserialize() throws IOException {
-		NegoState obj = jackson.readValue(serialized, NegoState.class);
-		System.out.println(obj);
-		assertEquals(state, obj);
-	}
-
-	@Test
-	public void testSerialize()
-			throws JsonProcessingException, URISyntaxException {
-
-		String string = jackson.writeValueAsString(state);
-		System.out.println(string);
-		assertEquals(serialized, string);
-	}
-
+		assertEquals(bid2, state.getAgreement());
+
+	}
 }
Index: protocol/src/test/java/geniusweb/protocol/session/saop/SAOPTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/saop/SAOPTest.java	(revision 53)
+++ protocol/src/test/java/geniusweb/protocol/session/saop/SAOPTest.java	(revision 1)
@@ -3,8 +3,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isA;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
@@ -17,5 +16,4 @@
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
@@ -23,9 +21,9 @@
 import java.util.Map;
 
-import org.junit.Before;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 
 import geniusweb.actions.Accept;
+import geniusweb.actions.Action;
 import geniusweb.actions.EndNegotiation;
 import geniusweb.actions.Offer;
@@ -35,18 +33,17 @@
 import geniusweb.events.CurrentState;
 import geniusweb.events.ProtocolEvent;
-import geniusweb.inform.ActionDone;
-import geniusweb.inform.Agreements;
-import geniusweb.inform.Finished;
-import geniusweb.inform.Settings;
-import geniusweb.inform.YourTurn;
+import geniusweb.party.inform.Finished;
+import geniusweb.party.inform.Inform;
+import geniusweb.party.inform.Settings;
+import geniusweb.party.inform.YourTurn;
 import geniusweb.progress.Progress;
 import geniusweb.protocol.ProtocolException;
-import geniusweb.protocol.partyconnection.ProtocolToPartyConn;
-import geniusweb.protocol.partyconnection.ProtocolToPartyConnFactory;
-import geniusweb.protocol.partyconnection.ProtocolToPartyConnections;
-import geniusweb.protocol.session.TeamInfo;
-import geniusweb.references.Parameters;
+import geniusweb.protocol.partyconnection.ConnectionWithParties;
+import geniusweb.protocol.partyconnection.ConnectionWithParty;
+import geniusweb.protocol.partyconnection.ConnectionWithPartyFactory;
+import geniusweb.protocol.session.saop.SAOP;
+import geniusweb.protocol.session.saop.SAOPSettings;
+import geniusweb.protocol.session.saop.SAOPState;
 import geniusweb.references.PartyRef;
-import geniusweb.references.PartyWithParameters;
 import geniusweb.references.PartyWithProfile;
 import geniusweb.references.ProfileRef;
@@ -66,5 +63,4 @@
  */
 public class SAOPTest {
-
 	private final SAOPState state = mock(SAOPState.class),
 			connectedstate = mock(SAOPState.class),
@@ -72,6 +68,5 @@
 			finalstate = mock(SAOPState.class);
 
-	private static final long DEADLINE = 1000l;
-	private ProtocolRef SAOPPROTOCOL;
+	private final ProtocolRef SAOP;
 	private static final PartyId PARTY2ID = new PartyId("party2");
 	private static final PartyId PARTY1ID = new PartyId("party1");
@@ -79,65 +74,44 @@
 	private final PartyRef party2ref = mock(PartyRef.class);
 	private final SAOPSettings settings = mock(SAOPSettings.class);
-	private final TeamInfo team1 = mock(TeamInfo.class);
-	private final TeamInfo team2 = mock(TeamInfo.class);
+	private final PartyWithProfile party1 = mock(PartyWithProfile.class);
+	private final PartyWithProfile party2 = mock(PartyWithProfile.class);
 	private SAOP saop;
-	private ProtocolToPartyConnFactory factory;
-	private List<ProtocolToPartyConn> connections;
-	private ProtocolToPartyConn conn1 = mock(ProtocolToPartyConn.class),
-			conn2 = mock(ProtocolToPartyConn.class);
-	private Map<PartyId, TeamInfo> partyprofiles;
+	private ConnectionWithPartyFactory factory;
+	private List connections;
+	private ConnectionWithParty conn1 = mock(ConnectionWithParty.class),
+			conn2 = mock(ConnectionWithParty.class);
+	private Map<PartyId, PartyWithProfile> partyprofiles;
 	private Progress progress = mock(Progress.class);
 	private ProfileRef profile1;
 	private ProfileRef profile2;
-	private ProtocolToPartyConnections connectionswithparties;// = new
-																// ProtocolTmock(
-																// ProtocolToPartyConnections.class);;
+	private ConnectionWithParties connectionswithparties = mock(
+			ConnectionWithParties.class);;
 	@SuppressWarnings("unchecked")
 	private final Listener<ProtocolEvent> testlistener = mock(Listener.class);
-	private final Parameters parameters = new Parameters();
-
-//	private final long NOW = 1000;
-	private final PartyWithParameters partywithparam1 = new PartyWithParameters(
-			party1ref, parameters);
-	private final PartyWithParameters partywithparam2 = new PartyWithParameters(
-			party2ref, parameters);
+
+	private final long NOW = 1000;
 
 	private final Deadline deadlinetime = mock(DeadlineTime.class);
 
-	private Map<PartyId, PartyWithProfile> pwpmap;
-
-	@Before
-	public void before()
+	public SAOPTest()
 			throws URISyntaxException, IOException, NoResourcesNowException {
-		SAOPPROTOCOL = new ProtocolRef("SAOP");
-
-		profile1 = mock(ProfileRef.class);
-		profile2 = mock(ProfileRef.class);
-
-		PartyWithProfile pwp1 = new PartyWithProfile(partywithparam1, profile1);
-		PartyWithProfile pwp2 = new PartyWithProfile(partywithparam2, profile2);
-		when(team1.getParties()).thenReturn(Arrays.asList(pwp1));
-		when(team2.getParties()).thenReturn(Arrays.asList(pwp2));
+		SAOP = new ProtocolRef("SAOP");
+		when(party1.getParty()).thenReturn(party1ref);
+		when(party2.getParty()).thenReturn(party2ref);
 
 		partyprofiles = new HashMap<>();
-		partyprofiles.put(PARTY1ID, team1);
-		partyprofiles.put(PARTY2ID, team2);
-
-		pwpmap = new HashMap<>();
-		pwpmap.put(PARTY1ID, pwp1);
-		pwpmap.put(PARTY2ID, pwp2);
-
-		when(deadlinetime.getDuration()).thenReturn(DEADLINE);
-
-		List<TeamInfo> teams = new ArrayList<>();
-		teams.add(team1);
-		teams.add(team2);
-		when(settings.getTeams()).thenReturn(teams);
-		when(settings.getAllParties()).thenReturn(Arrays.asList(pwp1, pwp2));
+		partyprofiles.put(PARTY1ID, party1);
+		partyprofiles.put(PARTY2ID, party2);
+
+		when(deadlinetime.getDuration()).thenReturn(1000l);
+
+		List<PartyWithProfile> participants = new ArrayList<>();
+		participants.add(party1);
+		participants.add(party2);
+		when(settings.getParticipants()).thenReturn(participants);
 		when(settings.getDeadline()).thenReturn(deadlinetime);
 
-		factory = mock(ProtocolToPartyConnFactory.class);
-		// connections = mock(List.class);
-		connections = Arrays.asList(conn1, conn2);
+		factory = mock(ConnectionWithPartyFactory.class);
+		connections = mock(List.class);
 		when(factory.connect(any(List.class))).thenReturn(connections);
 
@@ -147,30 +121,25 @@
 		when(conn2.getParty()).thenReturn(PARTY2ID);
 
-		mockState(connectedstate, "connected state", true);
-		mockState(state, "running state", true);
-		mockState(finalstate, "final state", true);
+		profile1 = mock(ProfileRef.class);
+		when(party1.getProfile()).thenReturn(profile1);
+		profile2 = mock(ProfileRef.class);
+		when(party2.getProfile()).thenReturn(profile2);
+
+		mockState(connectedstate, "connected state");
+		mockState(state, "initial state");
+		mockState(finalstate, "final state");
 		when(finalstate.isFinal(anyLong())).thenReturn(true);
-		mockState(failstate, "fail state", true);
+		mockState(failstate, "fail state");
 		when(failstate.isFinal(anyLong())).thenReturn(true);
 
-		connectionswithparties = new ProtocolToPartyConnections(
-				Arrays.asList(conn1, conn2));
-
-//		when(connectionswithparties.get(eq(PARTY1ID))).thenReturn(conn1);
-//		when(connectionswithparties.get(eq(PARTY2ID))).thenReturn(conn2);
+		when(connectionswithparties.get(eq(PARTY1ID))).thenReturn(conn1);
+		when(connectionswithparties.get(eq(PARTY2ID))).thenReturn(conn2);
 		// HACK thenReturn twice, so that 2nd call to iterator() returns new
 		// iterator instead of the old one
-//		when(connectionswithparties.iterator())
-//				.thenReturn(Arrays.asList(conn1, conn2).iterator())
-//				.thenReturn(Arrays.asList(conn1, conn2).iterator());
-		Map<PartyId, PartyWithProfile> profilesmap = new HashMap<>();
-		profilesmap.put(PARTY1ID, pwp1);
-		profilesmap.put(PARTY2ID, pwp2);
-		when(state.getPartyProfiles()).thenReturn(profilesmap);
-
-		saop = new SAOP(state, new ReportToLogger("test"),
-				connectionswithparties);
+		when(connectionswithparties.iterator())
+				.thenReturn(Arrays.asList(conn1, conn2).iterator())
+				.thenReturn(Arrays.asList(conn1, conn2).iterator());
+		saop = new SAOP(state, new ReportToLogger("test"));
 		saop.addListener(testlistener);
-
 	}
 
@@ -179,20 +148,13 @@
 	 * 
 	 * @param state  the state to mock (must be already
-	 * @param asText short name for the state, for debugging
-	 * @param bool   true if parties are connected
+	 * @param asText
 	 */
-	private void mockState(SAOPState state, String asText,
-			boolean isConnected) {
+	private void mockState(SAOPState state, String asText) {
 		when(state.getSettings()).thenReturn(settings);
-		if (isConnected) {
-			when(state.getConnections())
-					.thenReturn(Arrays.asList(PARTY1ID, PARTY2ID));
-		} else {
-			when(state.getConnections()).thenReturn(Collections.emptyList());
-		}
-
+		when(state.getConnections()).thenReturn(connectionswithparties);
+		when(state.getPartyProfiles()).thenReturn(partyprofiles);
 		when(state.getProgress()).thenReturn(progress);
-		when(state.with(any(PartyId.class), any(PartyWithProfile.class)))
-				.thenReturn(connectedstate);
+		when(state.with(any(ConnectionWithParty.class),
+				any(PartyWithProfile.class))).thenReturn(connectedstate);
 		when(state.getNextActor()).thenReturn(PARTY1ID);
 		when(state.with(any(PartyId.class), any(EndNegotiation.class)))
@@ -203,6 +165,4 @@
 		when(state.toString()).thenReturn(asText);
 		when(state.with(any(ProtocolException.class))).thenReturn(failstate);
-		when(state.getAgreements()).thenReturn(mock(Agreements.class));
-		when(state.getPartyProfiles()).thenReturn(pwpmap);
 	}
 
@@ -215,5 +175,5 @@
 		when(set.getDeadline()).thenReturn(dl);
 		when(dl.getDuration()).thenReturn(1000l);
-		new SAOP(state1, new ReportToLogger("test"), connectionswithparties);
+		new SAOP(state1, new ReportToLogger("test"));
 		verify(state1, times(0)).with(any(ProtocolException.class));
 		verify(testlistener, times(0)).notifyChange(any(CurrentState.class));
@@ -272,11 +232,11 @@
 				.forClass(Settings.class);
 		verify(conn1).send(actualsettings.capture());
-		assertEquals(new Settings(PARTY1ID, profile1, SAOPPROTOCOL, progress,
-				parameters), actualsettings.getValue());
+		assertEquals(new Settings(PARTY1ID, profile1, SAOP, progress),
+				actualsettings.getValue());
 
 		verify(conn2, times(1)).send(any(Settings.class));
 		verify(conn2).send(actualsettings.capture());
-		assertEquals(new Settings(PARTY2ID, profile2, SAOPPROTOCOL, progress,
-				parameters), actualsettings.getValue());
+		assertEquals(new Settings(PARTY2ID, profile2, SAOP, progress),
+				actualsettings.getValue());
 		verify(state, times(0)).with(any(ProtocolException.class));
 		verify(testlistener, times(0)).notifyChange(any(CurrentState.class));
@@ -286,4 +246,5 @@
 	@Test
 	public void testActionRequestWrongActor() {
+
 		saop.actionRequest(conn2, mock(EndNegotiation.class));
 
@@ -293,7 +254,23 @@
 
 	@Test
-	public void testActionRequest() throws IOException, ProtocolException {
-		saop.nextTurn();
-
+	public void testActionRequest() throws IOException {
+		when(state.getNextActor()).thenReturn(PARTY1ID);
+		when(state.with(any(PartyId.class), any(Action.class)))
+				.thenReturn(state);
+
+		saop.actionRequest(conn1, mock(EndNegotiation.class));
+
+		verify(state, times(0)).with(any(ProtocolException.class));
+		verify(state, times(1)).with(eq(PARTY1ID), any(EndNegotiation.class));
+		verify(connectionswithparties, times(1)).broadcast(any(Inform.class));
+
+		// state.getNextActor() is frozen to PARTY1 by our mocking
+		verify(conn1, times(1)).send(any(YourTurn.class));
+		verify(conn2, times(0)).send(any(YourTurn.class));
+		verify(testlistener, times(0)).notifyChange(any(CurrentState.class));
+	}
+
+	@Test
+	public void testFinalActionRequest() throws IOException {
 		when(state.getNextActor()).thenReturn(PARTY1ID);
 		when(state.with(any(PartyId.class), any(EndNegotiation.class)))
@@ -303,35 +280,10 @@
 
 		verify(state, times(0)).with(any(ProtocolException.class));
-		verify(state, times(1)).with(eq(PARTY1ID), isA((EndNegotiation.class)));
-		// verify broadcast
-		verify(conn1, times(1)).send(isA(ActionDone.class));
-		verify(conn2, times(1)).send(isA(ActionDone.class));
-
-		// state.getNextActor() is frozen to PARTY1 by our mocking
-		verify(conn1, times(1)).send(isA(YourTurn.class));
-		verify(conn2, times(0)).send(isA(YourTurn.class));
-		// listener should be informed about final state.
+		verify(state, times(1)).with(eq(PARTY1ID), any(EndNegotiation.class));
+		verify(connectionswithparties, times(1)).broadcast(any(Finished.class));
 		verify(testlistener, times(1)).notifyChange(any(CurrentState.class));
-	}
-
-	@Test
-	public void testFinalActionRequest() throws IOException, ProtocolException {
-		when(state.getNextActor()).thenReturn(PARTY1ID);
-		when(state.with(any(PartyId.class), any(EndNegotiation.class)))
-				.thenReturn(finalstate);
-		// when(finalstate.getAgreements()).thenReturn(mock(Agreements.class));
-
-		saop.nextTurn(); // ensure we send YourTurn to party1.
-		saop.actionRequest(conn1, mock(EndNegotiation.class));
-
-		verify(state, times(0)).with(any(ProtocolException.class));
-		verify(state, times(1)).with(eq(PARTY1ID), any(EndNegotiation.class));
-		// verify broadcast
-		verify(conn1, times(1)).send(isA(Finished.class));
-		verify(conn2, times(1)).send(isA(Finished.class));
-		verify(testlistener, times(1)).notifyChange(any(CurrentState.class));
-
-		verify(conn1, times(1)).send(isA(YourTurn.class));
-		verify(conn2, times(0)).send(isA(YourTurn.class));
+
+		verify(conn1, times(1)).send(any(YourTurn.class));
+		verify(conn2, times(1)).send(any(YourTurn.class));
 	}
 
@@ -345,7 +297,5 @@
 		doThrow(new IOException("fail sending yourturn")).when(conn1)
 				.send(any(YourTurn.class));
-		// CHECK is the state really final after an exception?
-		when(state.with(any(ProtocolException.class))).thenReturn(finalstate);
-		// when(state.getAgreements()).thenReturn(mock(Agreements.class));
+
 		saop.actionRequest(conn1, mock(Accept.class));
 
@@ -358,5 +308,4 @@
 		doThrow(new IOException("fail sending yourturn")).when(conn1)
 				.send(any(YourTurn.class));
-		// when(failstate.getAgreements()).thenReturn(mock(Agreements.class));
 		// not turn of conn2.
 		saop.actionRequest(conn2, mock(EndNegotiation.class));
@@ -368,7 +317,5 @@
 	@Test
 	public void testActionInFinalState() throws IOException {
-		saop = new SAOP(finalstate, new ReportToLogger("test"),
-				connectionswithparties);
-		// when(finalstate.getAgreements()).thenReturn(mock(Agreements.class));
+		saop = new SAOP(finalstate, new ReportToLogger("test"));
 
 		saop.actionRequest(conn1, mock(Offer.class));
@@ -387,20 +334,3 @@
 		saop.addParticipant(null);
 	}
-
-	@Test
-	public void testDeadlineTimer() throws InterruptedException, IOException {
-		SAOPState unconnectedstate = mock(SAOPState.class);
-		mockState(unconnectedstate, "unconnected state", false);
-		SAOP saopempty = new SAOP(unconnectedstate, new ReportToLogger("test"),
-				new ProtocolToPartyConnections(Collections.emptyList()));
-		saopempty.addListener(testlistener);
-
-		saopempty.start(factory);
-		verify(testlistener, times(0)).notifyChange(any(CurrentState.class));
-		verify(conn1, times(1)).send(isA(YourTurn.class));
-		Thread.sleep(DEADLINE + SAOP.TIME_MARGIN + 100);
-		verify(testlistener, times(1)).notifyChange(any(CurrentState.class));
-		verify(conn1, times(1)).send(isA(Finished.class));
-	}
-
 }
Index: protocol/src/test/java/geniusweb/protocol/session/saop/SaopPartyWithProfileTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/session/saop/SaopPartyWithProfileTest.java	(revision 53)
+++ 	(revision )
@@ -1,107 +1,0 @@
-package geniusweb.protocol.session.saop;
-
-import static org.junit.Assert.assertEquals;
-
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Arrays;
-import java.util.List;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.fasterxml.jackson.core.JsonParseException;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonMappingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import geniusweb.protocol.session.TeamInfo;
-import geniusweb.references.Parameters;
-import geniusweb.references.PartyRef;
-import geniusweb.references.PartyWithParameters;
-import geniusweb.references.ProfileRef;
-import tudelft.utilities.junit.GeneralTests;
-
-public class SaopPartyWithProfileTest extends GeneralTests<TeamInfo> {
-
-	private PartyRef party1, party1a, party2, party3;
-	private ProfileRef profile1, profile2;
-	private TeamInfo partyprof1, partyprof1a, partyprof2, partyprof3,
-			partyprof4;
-	private final String serialized = "{\"TeamInfo\":{\"parties\":[{\"party\":{\"partyref\":\"ws:party1\",\"parameters\":{}},\"profile\":\"ws:profile1\"}]}}";
-
-	@Before
-	public void before() throws URISyntaxException {
-		party1 = new PartyRef(new URI("ws:party1"));
-		party1a = new PartyRef(new URI("ws:party1"));
-		party2 = new PartyRef(new URI("ws:party2"));
-		party3 = new PartyRef(new URI("http:party3"));
-
-		profile1 = new ProfileRef(new URI("ws:profile1"));
-		profile2 = new ProfileRef(new URI("ws:profile2"));
-
-		Parameters settings1 = new Parameters();
-		Parameters settings2 = new Parameters().with("a", 1);
-
-		PartyWithParameters party1withparams1 = new PartyWithParameters(party1,
-				settings1);
-		PartyWithParameters party1withparams2 = new PartyWithParameters(party1,
-				settings2);
-		PartyWithParameters party2withparams1 = new PartyWithParameters(party2,
-				settings1);
-
-		partyprof1 = new TeamInfo(party1withparams1, profile1);
-		partyprof1a = new TeamInfo(party1withparams1, profile1);
-		partyprof2 = new TeamInfo(party2withparams1, profile1);
-		partyprof3 = new TeamInfo(party1withparams1, profile2);
-		partyprof4 = new TeamInfo(party1withparams2, profile1);
-
-	}
-
-	@Override
-	public List<List<TeamInfo>> getGeneralTestData() {
-		return Arrays.asList(Arrays.asList(partyprof1, partyprof1a),
-				Arrays.asList(partyprof2), Arrays.asList(partyprof3),
-				Arrays.asList(partyprof4));
-	}
-
-	@Override
-	public List<String> getGeneralTestStrings() {
-		return Arrays.asList(
-				"TeamInfo.*PartyWithProfile.PartyRef.ws:party1.,ProfileRef.ws:profile1.*",
-				"TeamInfo.*PartyWithProfile.PartyRef.ws:party2.,ProfileRef.ws:profile1.*",
-				"TeamInfo.*PartyWithProfile.PartyRef.ws:party1.,ProfileRef.ws:profile2.*",
-				"TeamInfo.*PartyWithProfile.PartyRef.ws:party1.\\{a=1\\},ProfileRef.ws:profile1.*");
-	}
-
-	@Test
-	public void smokeTest() throws URISyntaxException {
-	}
-
-	@Test(expected = IllegalArgumentException.class)
-	public void nullTest() throws URISyntaxException {
-		new TeamInfo((PartyWithParameters) null, (ProfileRef) null);
-	}
-
-	@Test
-	public void testSerialize() throws JsonProcessingException {
-		ObjectMapper jackson = new ObjectMapper();
-
-		String json = jackson.writeValueAsString(partyprof1);
-		System.out.println(json);
-		assertEquals(serialized, json);
-	}
-
-	@Test
-	public void testDeserialize()
-			throws JsonParseException, JsonMappingException, IOException {
-		ObjectMapper jackson = new ObjectMapper();
-		// always used as part of bigger class, do not include class name
-		// and therfore can not serialize as TeamOfPartiesAndProfiles
-		TeamInfo p = jackson.readValue(serialized, TeamInfo.class);
-		System.out.println(p);
-		assertEquals(partyprof1, p);
-	}
-
-}
Index: protocol/src/test/java/geniusweb/protocol/tournament/AllPermutationsProtocolTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/tournament/AllPermutationsProtocolTest.java	(revision 1)
+++ protocol/src/test/java/geniusweb/protocol/tournament/AllPermutationsProtocolTest.java	(revision 1)
@@ -0,0 +1,181 @@
+package geniusweb.protocol.tournament;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.math.BigInteger;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import geniusweb.events.ProtocolEvent;
+import geniusweb.issuevalue.Bid;
+import geniusweb.protocol.CurrentNegoState;
+import geniusweb.protocol.NegoState;
+import geniusweb.protocol.SessionResult;
+import geniusweb.protocol.partyconnection.ConnectionWithPartyFactory;
+import geniusweb.protocol.session.SessionProtocol;
+import geniusweb.protocol.session.SessionSettings;
+import geniusweb.protocol.session.SessionState;
+import geniusweb.protocol.tournament.allpermutations.AllPermutationsProtocol;
+import geniusweb.protocol.tournament.allpermutations.AllPermutationsState;
+import geniusweb.references.PartyWithProfile;
+import geniusweb.references.ProtocolRef;
+import tudelft.utilities.listener.Listener;
+import tudelft.utilities.logging.ReportToLogger;
+
+public class AllPermutationsProtocolTest {
+
+	private final AllPermutationsState state = mock(AllPermutationsState.class),
+			newstate = mock(AllPermutationsState.class);
+	private final ReportToLogger log = new ReportToLogger("test");
+	private final AllPermutationsProtocol app = new AllPermutationsProtocol(
+			state, log);
+	private final ConnectionWithPartyFactory factory = mock(
+			ConnectionWithPartyFactory.class);
+	private final SessionSettings settings = mock(SessionSettings.class);
+	private final SessionState finalsessionstate = mock(SessionState.class);
+	private Bid agreement = mock(Bid.class);
+	private final long NOW = 1000;
+
+	@Before
+	public void before() {
+		when(state.getSize()).thenReturn(BigInteger.ZERO);
+		when(finalsessionstate.isFinal(anyLong())).thenReturn(true);
+		when(finalsessionstate.getSettings()).thenReturn(settings);
+		when(finalsessionstate.getAgreement()).thenReturn(agreement);
+		when(state.with(any())).thenReturn(newstate);
+	}
+
+	@Test
+	public void smokeTest() {
+	}
+
+	@Test
+	public void startTestNoSessions() {
+		AllPermutationsProtocol app = new AllPermutationsProtocol(state, log);
+		app.start(factory);
+
+	}
+
+	@Test
+	public void getDescrTest() {
+		assertNotNull(app.getDescription());
+	}
+
+	@Test
+	public void getStateTest() {
+		assertEquals(state, app.getState());
+	}
+
+	@Test
+	public void getRefTest() {
+		assertEquals("APP", app.getRef().getURI().toString());
+	}
+
+	@Test
+	public void runOneSessionTest() throws InterruptedException {
+		MockSessionProtocol sessionprotocol = startSession();
+		sessionprotocol.getListener();
+	}
+
+	@Test
+	public void runOneSessionAndUnhandledEvent() throws InterruptedException {
+		MockSessionProtocol sessionprotocol = startSession();
+		sessionprotocol.getListener().notifyChange(mock(ProtocolEvent.class));
+		verify(state, times(0)).with(any());
+	}
+
+	/**
+	 * Check that a started session correctly handles a session event.
+	 */
+	@Test
+	public void CurrentNegoStateEventTest() throws InterruptedException {
+		MockSessionProtocol sessionprotocol = startSession();
+
+		CurrentNegoState evt = mock(CurrentNegoState.class);
+		when(evt.getState()).thenReturn(finalsessionstate);
+		sessionprotocol.getListener().notifyChange(evt);
+
+		ArgumentCaptor<SessionResult> argument = ArgumentCaptor
+				.forClass(SessionResult.class);
+		verify(state, times(1)).with(argument.capture());
+		assertEquals(agreement, argument.getValue().getAgreement());
+		assertNull(argument.getValue().getError());
+	}
+
+	private MockSessionProtocol startSession() throws InterruptedException {
+		SessionSettings setting = mock(SessionSettings.class);
+		MockSessionProtocol sessionprotocol = new MockSessionProtocol();
+		when(setting.getProtocol(log)).thenReturn(sessionprotocol);
+		when(state.getNextSettings()).thenReturn(setting);
+
+		app.start(factory);
+		Thread.sleep(500); // allow app to start session
+		// this call should return fine, and have listener registered to our
+		// protocol. app now waits for a notification
+		return sessionprotocol;
+	}
+
+}
+
+/**
+ * 
+ * The protocol needs to record the listners, we need a listener to trigger
+ * further protocol actions. Mockito can't handle this, we mneed our own mock...
+ *
+ */
+class MockSessionProtocol implements SessionProtocol {
+	private final List<Listener<ProtocolEvent>> listeners = new LinkedList<>();
+
+	@Override
+	public void start(ConnectionWithPartyFactory connectionfactory) {
+
+	}
+
+	@Override
+	public String getDescription() {
+		return null;
+	}
+
+	@Override
+	public NegoState getState() {
+		return null;
+	}
+
+	@Override
+	public ProtocolRef getRef() {
+		return null;
+	}
+
+	@Override
+	public void addParticipant(PartyWithProfile party) {
+	}
+
+	@Override
+	public void addListener(Listener<ProtocolEvent> l) {
+		listeners.add(l);
+	}
+
+	@Override
+	public void removeListener(Listener<ProtocolEvent> l) {
+	}
+
+	public Listener<ProtocolEvent> getListener() {
+		if (listeners.size() != 1) {
+			throw new IllegalStateException("Not having exactly 1 listener");
+		}
+		return listeners.get(0);
+	}
+
+}
Index: protocol/src/test/java/geniusweb/protocol/tournament/AllPermutationsSettingsTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/tournament/AllPermutationsSettingsTest.java	(revision 1)
+++ protocol/src/test/java/geniusweb/protocol/tournament/AllPermutationsSettingsTest.java	(revision 1)
@@ -0,0 +1,173 @@
+package geniusweb.protocol.tournament;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import geniusweb.deadline.DeadlineTime;
+import geniusweb.protocol.session.saop.SAOPSettings;
+import geniusweb.protocol.tournament.TournamentSettings;
+import geniusweb.protocol.tournament.allpermutations.AllPermutationsSettings;
+import geniusweb.references.PartyRef;
+import geniusweb.references.ProfileRef;
+import tudelft.utilities.junit.GeneralTests;
+import tudelft.utilities.logging.ReportToLogger;
+
+public class AllPermutationsSettingsTest
+		extends GeneralTests<AllPermutationsSettings> {
+
+	private final ObjectMapper jackson = new ObjectMapper();
+
+	private final String serialized = "{\"AllPermutationsSettings\":{"
+			+ "\"parties\":[\"party1\",\"party2\"]," + "\"reuseParties\":false,"
+			+ "\"profiles\":[\"profile1\",\"profile2\",\"profile3\"],"
+			+ "\"partiesPerSession\":2,"
+			+ "\"sessionsettings\":{\"SAOPSettings\":{\"participants\":[],\"deadline\":{\"deadlinetime\":{\"durationms\":10000}}}}}}";
+
+	private AllPermutationsSettings settings, settings1a, settings2, settings3,
+			settings4;
+
+	private SAOPSettings saopsettings;
+
+	private ProfileRef profile1, profile2, profile3;
+
+	private List<PartyRef> parties;
+
+	@Before
+	public void before() throws URISyntaxException {
+		PartyRef partyref1 = new PartyRef("party1");
+		PartyRef partyref2 = new PartyRef("party2");
+		PartyRef partyref3 = new PartyRef("party3");
+
+		parties = Arrays.asList(partyref1, partyref2);
+		DeadlineTime deadline = new DeadlineTime(10000);
+
+		saopsettings = new SAOPSettings(Collections.emptyList(), deadline);
+
+		profile1 = new ProfileRef("profile1");
+		profile2 = new ProfileRef("profile2");
+		profile3 = new ProfileRef("profile3");
+
+		List<ProfileRef> profiles = Arrays.asList(profile1, profile2, profile3);
+
+		settings = new AllPermutationsSettings(parties, false, profiles, 2,
+				saopsettings);
+
+		settings1a = new AllPermutationsSettings(parties, false, profiles, 2,
+				saopsettings);
+
+		settings2 = new AllPermutationsSettings(
+				Arrays.asList(partyref1, partyref2, partyref3), false, profiles,
+				2, saopsettings);
+
+		settings3 = new AllPermutationsSettings(parties, true, profiles, 2,
+				saopsettings);
+
+		settings4 = new AllPermutationsSettings(parties, false,
+				Arrays.asList(profile1, profile2, profile3, profile1), 2,
+				saopsettings);
+
+	}
+
+	@Override
+	public List<List<AllPermutationsSettings>> getGeneralTestData() {
+		return Arrays.asList(Arrays.asList(settings, settings1a),
+				Arrays.asList(settings2), Arrays.asList(settings3),
+				Arrays.asList(settings4));
+	}
+
+	@Override
+	public List<String> getGeneralTestStrings() {
+		return Arrays.asList(
+				"AllPermutationsSettings.*party1.*party2.*,false,.*profile1.*profile2.*profile3.*,2,SAOPSettings.*",
+				"AllPermutationsSettings.*party1.*party2.*party3.*,false,.*profile1.*profile2.*profile3.*,2,SAOPSettings.*",
+				"AllPermutationsSettings.*party1.*party2.*,true,.*profile1.*profile2.*profile3.*,2,SAOPSettings.*",
+				"AllPermutationsSettings.*party1.*party2.*,false,.*profile1.*profile2.*profile3.*profile1.*,2,SAOPSettings.*");
+	}
+
+	@Test
+	public void getProtocolTest() {
+		assertEquals("APP", settings.getProtocol(new ReportToLogger("test"))
+				.getRef().getURI().toString());
+	}
+
+	@Test
+	public void testDeserialize() throws IOException {
+		TournamentSettings obj = jackson.readValue(serialized,
+				TournamentSettings.class);
+		System.out.println(obj);
+		assertEquals(settings, obj);
+	}
+
+	@Test
+	public void testSerialize()
+			throws JsonProcessingException, URISyntaxException {
+
+		String string = jackson.writeValueAsString(settings);
+		System.out.println(string);
+		assertEquals(serialized, string);
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testNullParties() {
+		new AllPermutationsSettings(null, true,
+				Arrays.asList(profile1, profile2, profile3, profile1), 2,
+				saopsettings);
+
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testNoParties() {
+		new AllPermutationsSettings(Collections.emptyList(), true,
+				Arrays.asList(profile1, profile2, profile3, profile1), 2,
+				saopsettings);
+
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testNullProfiles() {
+		new AllPermutationsSettings(parties, true, null, 2, saopsettings);
+
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testInsufficientProfiles() {
+		new AllPermutationsSettings(parties, true,
+				Arrays.asList(profile1, profile2, profile3, profile1), 4,
+				saopsettings);
+
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testNullSessionSettings() {
+		new AllPermutationsSettings(parties, true,
+				Arrays.asList(profile1, profile2, profile3, profile1), 4, null);
+
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testOnePartyPerSession() {
+		new AllPermutationsSettings(parties, true,
+				Arrays.asList(profile1, profile2, profile3, profile1), 1,
+				saopsettings);
+
+	}
+
+	@Test
+	public void getMaxRuntimeTest() {
+		assertEquals(BigInteger.valueOf(6), settings.permutations().size());
+		assertEquals((Double) (6d * 12), settings.getMaxRunTime());
+	}
+
+}
Index: protocol/src/test/java/geniusweb/protocol/tournament/AllPermutationsStateTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/tournament/AllPermutationsStateTest.java	(revision 1)
+++ protocol/src/test/java/geniusweb/protocol/tournament/AllPermutationsStateTest.java	(revision 1)
@@ -0,0 +1,96 @@
+package geniusweb.protocol.tournament;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+
+import geniusweb.protocol.SessionResult;
+import geniusweb.protocol.session.SessionSettings;
+import geniusweb.protocol.tournament.allpermutations.AllPermutationsSettings;
+import geniusweb.protocol.tournament.allpermutations.AllPermutationsState;
+import geniusweb.references.PartyWithProfile;
+import tudelft.utilities.immutablelist.ImmutableList;
+
+public class AllPermutationsStateTest {
+
+	private final AllPermutationsSettings toursettings = mock(
+			AllPermutationsSettings.class);;
+	@SuppressWarnings("unchecked")
+	private final List<SessionResult> results = mock(List.class);
+	@SuppressWarnings("unchecked")
+	private final ImmutableList<SessionSettings> settings = mock(
+			ImmutableList.class);
+	private final AllPermutationsState state = new AllPermutationsState(
+			toursettings, settings, results);
+	private final SessionSettings session7settings = mock(
+			SessionSettings.class);
+	private final long NOW = 1000;
+
+	@SuppressWarnings("unchecked")
+	private final List<PartyWithProfile> participants = mock(List.class);
+
+	@Test
+	public void getResultsTest() {
+		assertEquals(results, state.getResults());
+	}
+
+	@Test
+	public void isFinalTestFalse() {
+		when(settings.size()).thenReturn(BigInteger.TEN);
+		when(results.size()).thenReturn(11);
+		assertFalse(state.isFinal(NOW));
+	}
+
+	@Test
+	public void isFinalTestTrue() {
+		when(settings.size()).thenReturn(BigInteger.TEN);
+		when(results.size()).thenReturn(10);
+		assertTrue(state.isFinal(NOW));
+	}
+
+	@Test
+	public void getNextSetting() {
+		prepareNextSettings();
+		assertEquals(session7settings, state.getNextSettings());
+	}
+
+	private void prepareNextSettings() {
+		when(results.size()).thenReturn(7); // result 0..6
+		when(settings.size()).thenReturn(BigInteger.TEN);
+		when(session7settings.getParticipants()).thenReturn(participants);
+		when(settings.get(BigInteger.valueOf(7))).thenReturn(session7settings);
+
+	}
+
+	@Test
+	public void withTest() {
+		prepareNextSettings();
+		ArrayList<SessionResult> results1 = new ArrayList<>();
+		for (int n = 0; n < 7; n++) {
+			results1.add(mock(SessionResult.class));
+		}
+		// use state with "real" results... to allow array copy in with
+		AllPermutationsState state = new AllPermutationsState(toursettings,
+				settings, results1);
+
+		when(settings.size()).thenReturn(BigInteger.TEN);
+		when(settings.get(BigInteger.valueOf(7))).thenReturn(session7settings);
+
+		SessionResult result = mock(SessionResult.class);
+		when(result.getParticipants()).thenReturn(participants);
+		AllPermutationsState state1 = state.with(result);
+
+		assertEquals(null, state1.getError());
+		assertEquals(8, state1.getResults().size());
+		assertEquals(toursettings, state1.getSettings());
+
+	}
+}
Index: protocol/src/test/java/geniusweb/protocol/tournament/TeamTest.java
===================================================================
--- protocol/src/test/java/geniusweb/protocol/tournament/TeamTest.java	(revision 53)
+++ 	(revision )
@@ -1,51 +1,0 @@
-package geniusweb.protocol.tournament;
-
-import static org.junit.Assert.assertEquals;
-
-import java.net.URISyntaxException;
-import java.util.Arrays;
-import java.util.List;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import geniusweb.references.Parameters;
-import geniusweb.references.PartyRef;
-import geniusweb.references.PartyWithParameters;
-import tudelft.utilities.junit.GeneralTests;
-
-public class TeamTest extends GeneralTests<Team> {
-
-	private Team team1, team1a, team2;
-	private PartyWithParameters pwithp1, pwithp2;
-
-	@Before
-	public void before() throws URISyntaxException {
-		PartyRef partyref1 = new PartyRef("party1");
-		PartyRef partyref2 = new PartyRef("party2");
-		Parameters params1 = new Parameters().with("a", 1);
-		pwithp1 = new PartyWithParameters(partyref1, params1);
-		pwithp2 = new PartyWithParameters(partyref2, params1);
-		team1 = new Team(Arrays.asList(pwithp1));
-		team1a = new Team(Arrays.asList(pwithp1));
-		team2 = new Team(Arrays.asList(pwithp2));
-	}
-
-	@Override
-	public List<List<Team>> getGeneralTestData() {
-		return Arrays.asList(Arrays.asList(team1, team1a),
-				Arrays.asList(team2));
-	}
-
-	@Override
-	public List<String> getGeneralTestStrings() {
-		return Arrays.asList(".PartyRef.party1..a=1..",
-				".PartyRef.party2..a=1..");
-	}
-
-	@Test
-	public void testGet() {
-		assertEquals(Arrays.asList(pwithp1), team1.getParties());
-	}
-
-}
