Index: protocol/src/main/java/geniusweb/protocol/CurrentNegoState.java
===================================================================
--- protocol/src/main/java/geniusweb/protocol/CurrentNegoState.java	(revision 52)
+++ 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 52)
+++ 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 52)
+++ 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 52)
+++ 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 52)
+++ 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 52)
+++ 	(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 52)
+++ 	(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 52)
+++ 	(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 52)
+++ 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 52)
+++ 	(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 52)
+++ 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 52)
+++ 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 52)
+++ 	(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 52)
+++ 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 52)
+++ 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 52)
+++ 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 52)
+++ 	(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 52)
+++ 	(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 52)
+++ 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 52)
+++ 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 52)
+++ 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 52)
+++ 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 52)
+++ 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();
 	}
 
