Index: src/main/java/geniusweb/runserver/WebSocketProtToPartyConn.java
===================================================================
--- src/main/java/geniusweb/runserver/WebSocketProtToPartyConn.java	(revision 33)
+++ src/main/java/geniusweb/runserver/WebSocketProtToPartyConn.java	(revision 34)
@@ -54,4 +54,9 @@
 
 	/**
+	 * Buffers incoming text.
+	 */
+	private StringBuffer buffer = new StringBuffer();
+
+	/**
 	 * Constructor that uses default {@link Reporter}
 	 * 
@@ -82,5 +87,7 @@
 
 		container = ContainerProvider.getWebSocketContainer();
-		container.setDefaultMaxTextMessageBufferSize(200000);
+		// #50 disable: might cause large buffer. And why is this a good limit
+		// anyway
+		// container.setDefaultMaxTextMessageBufferSize(200000);
 
 		log.log(Level.INFO,
@@ -179,6 +186,7 @@
 	public void onOpen(Session session) {
 		log.log(Level.INFO, "Party is being connected: " + session);
-		session.setMaxTextMessageBufferSize(MAX_MESSAGE_SIZE);
-		session.setMaxBinaryMessageBufferSize(MAX_MESSAGE_SIZE);
+// #50 we now buffer partial messages
+//		session.setMaxTextMessageBufferSize(MAX_MESSAGE_SIZE);
+//		session.setMaxBinaryMessageBufferSize(MAX_MESSAGE_SIZE);
 		this.session = session;
 	}
@@ -201,13 +209,19 @@
 
 	@OnMessage
-	public void processMessage(String message) {
-		try {
-			Action act = Jackson.instance().readValue(message, Action.class);
-			notifyListeners(act);
-		} catch (IOException e) {
-			log.log(Level.WARNING,
-					"received bad message from client " + reference, e);
-			setError(e);
-			close();
+	public void processMessage(String message, boolean islast) {
+		// #50 avoid fixed (large) buffers
+		buffer.append(message);
+		if (islast) {
+			String msg = buffer.toString();
+			buffer = new StringBuffer();
+			try {
+				Action act = Jackson.instance().readValue(msg, Action.class);
+				notifyListeners(act);
+			} catch (IOException e) {
+				log.log(Level.WARNING,
+						"received bad message from client " + reference, e);
+				setError(e);
+				close();
+			}
 		}
 	}
Index: src/main/webapp/newsession.xhtml
===================================================================
--- src/main/webapp/newsession.xhtml	(revision 33)
+++ src/main/webapp/newsession.xhtml	(revision 34)
@@ -50,5 +50,5 @@
 	<br /> Domain/Profile Server:
 	<input type="url" name="url" id="profilesserverurl"
-		value="localhost:8080/profilesserver-2.0.4"
+		value="localhost:8080/profilesserver-2.0.5"
 		pattern=".*:[0-9]+/profilesserver.*" size="30"
 		onchange="connectDomain()"> </input>
@@ -65,5 +65,5 @@
 		<br /> <b>Participants</b> <br /> Parties Server: <input type="url"
 			name="url" id="partiesserverurl"
-			value="localhost:8080/partiesserver-2.0.4"
+			value="localhost:8080/partiesserver-2.0.5"
 			pattern=".*:[0-9]+/partiesserver.*" size="30"
 			onchange="connectParties()"> </input> <br /> <br /> <b>Party
@@ -356,8 +356,8 @@
 	 refresh table: copy all parties elements in there.
 	 Typically parties is something like
-	 [{"uri":"http:130.161.180.1:8080/partiesserver/run/randomparty-2.0.4",
+	 [{"uri":"http:130.161.180.1:8080/partiesserver/run/randomparty-2.0.5",
 		 "capabilities":{"protocols":["SAOP"]},
 		 "description":"places random bids until it can accept an offer with utility >0.6",
-		 "id":"randomparty-2.0.4",
+		 "id":"randomparty-2.0.5",
 		 "partyClass":"geniusweb.exampleparties.randomparty.RandomParty"},
 		 		 ...]
@@ -454,4 +454,7 @@
 		var profilecombo = document.getElementById("profileselection");
 		var filteroptions = document.getElementById("filter").value;
+		if (filteroptions!="") {
+			filteroptions="?"+filteroptions;
+		}
 		
 		var selectedprofile;
@@ -470,7 +473,4 @@
 		}
 		
-		if (filteroptions!="") {
-			filteroptions="?"+filteroptions;
-		}
 		var newpartyprof = {};
 		newpartyprof["party"]={"partyref":partycombo.options[partycombo.selectedIndex].value , 
@@ -704,8 +704,8 @@
 		var dtypecombo  = document.getElementById("deadlinetype");
 		if (dtypecombo.options[dtypecombo.selectedIndex].value=="TIME") {
-			deadline["deadlinetime"] = { "durationms": 1000*value};
+			deadline["DeadlineTime"] = { "durationms": 1000*value};
 		} else {
 			// ROUNDS
-			deadline["deadlinerounds"] = {"rounds": value, "durationms":10000};
+			deadline["DeadlineRounds"] = {"rounds": value, "durationms":10000};
 		}
 		
@@ -736,6 +736,6 @@
 	function init() {
 		selectProtocol();
-		document.getElementById("partiesserverurl").value =window.location.hostname+":8080/partiesserver-2.0.4"
-		document.getElementById("profilesserverurl").value =window.location.hostname+":8080/profilesserver-2.0.4"
+		document.getElementById("partiesserverurl").value =window.location.hostname+":8080/partiesserver-2.0.5"
+		document.getElementById("profilesserverurl").value =window.location.hostname+":8080/profilesserver-2.0.5"
 		connectDomain();
 		connectParties();
Index: src/main/webapp/newtournament.xhtml
===================================================================
--- src/main/webapp/newtournament.xhtml	(revision 33)
+++ src/main/webapp/newtournament.xhtml	(revision 34)
@@ -683,6 +683,6 @@
 	*/
 	function init() {
-		document.getElementById("partiesserverurl").value =window.location.hostname+":8080/partiesserver-2.0.4";
-		document.getElementById("profilesserverurl").value =window.location.hostname+":8080/profilesserver-2.0.4";
+		document.getElementById("partiesserverurl").value =window.location.hostname+":8080/partiesserver-2.0.5";
+		document.getElementById("profilesserverurl").value =window.location.hostname+":8080/profilesserver-2.0.5";
 
 		selectSessionProtocol();
Index: src/main/webapp/plotlog.xhtml
===================================================================
--- src/main/webapp/plotlog.xhtml	(revision 33)
+++ src/main/webapp/plotlog.xhtml	(revision 34)
@@ -128,5 +128,5 @@
         		var nr= json['partyNumbers'][partyid];
         		if ( (nr & 1 != 0)) continue; // skip COB parties
-        		var shaop=teams[nr/2]['shaop'];
+        		var shaop=teams[nr/2]['TeamInfo']['parties'][0];
         		var profile = withoutPartial(shaop['profile']); // hacky, remove complete query.
         		partyprofiles[partyid]=profile;
Index: src/test/java/geniusweb/runserver/EmbeddedTomcat.java
===================================================================
--- src/test/java/geniusweb/runserver/EmbeddedTomcat.java	(revision 34)
+++ src/test/java/geniusweb/runserver/EmbeddedTomcat.java	(revision 34)
@@ -0,0 +1,62 @@
+package geniusweb.runserver;
+
+import java.io.File;
+
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.startup.Tomcat;
+
+class EmbeddedTomcat {
+	private Tomcat tomcat = new Tomcat();
+
+	public void start() {
+		try {
+			// If I don't want to copy files around then the base directory must
+			// be '.'
+			String baseDir = ".";
+			tomcat.setPort(8080);
+			tomcat.setBaseDir(baseDir);
+			tomcat.getHost().setAppBase(baseDir);
+			tomcat.getHost().setDeployOnStartup(true);
+			tomcat.getHost().setAutoDeploy(true);
+			tomcat.start();
+		} catch (LifecycleException e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+	public void stop() {
+		try {
+			tomcat.stop();
+			tomcat.destroy();
+			// Tomcat creates a work folder where the temporary files are stored
+		} catch (LifecycleException e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+	/**
+	 * Deploys the webapp contained in this project
+	 * 
+	 * @param appName the name to use on the server
+	 */
+	public void deploy(String appName) {
+		deployWar(appName, new File("src/main/webapp"));
+	}
+
+	/**
+	 * Deploys the webapp in the given war
+	 * 
+	 * @param appName the name to use on the server
+	 * @param warfile the warfile to deploy. Should include ".war" extension.
+	 */
+	public void deployWar(String appName, File warfile) {
+		tomcat.addWebapp(tomcat.getHost(), "/" + appName,
+				warfile.getAbsolutePath());
+
+	}
+
+	public String getApplicationUrl(String appName) {
+		return String.format("http://%s:%d/%s", tomcat.getHost().getName(),
+				tomcat.getConnector().getLocalPort(), appName);
+	}
+}
Index: src/test/java/geniusweb/runserver/MaxLoadTest.java
===================================================================
--- src/test/java/geniusweb/runserver/MaxLoadTest.java	(revision 34)
+++ src/test/java/geniusweb/runserver/MaxLoadTest.java	(revision 34)
@@ -0,0 +1,189 @@
+package geniusweb.runserver;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.lang.management.ManagementFactory;
+import java.lang.management.OperatingSystemMXBean;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.ProtocolException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import geniusweb.deadline.Deadline;
+import geniusweb.deadline.DeadlineTime;
+import geniusweb.protocol.session.TeamInfo;
+import geniusweb.protocol.session.saop.SAOPSettings;
+import geniusweb.references.Parameters;
+import geniusweb.references.PartyRef;
+import geniusweb.references.PartyWithParameters;
+import geniusweb.references.PartyWithProfile;
+import geniusweb.references.ProfileRef;
+
+/**
+ * End to end test starts server, plus partyserver plus profilesserver, and then
+ * tries to launch large number of parties and keep them busy. Checks and
+ * reports the average CPU loads. Ensure that you have no other background tasks
+ * when you run this test, to avoid incorrect CPU measurements (we can't measure
+ * java-only CPU loads)
+ * 
+ * 
+ * <h2>Large tests</h2> Tomcat-embed seems very limited in heap space. Best way
+ * to test this with {@link #NUMBER_SESSIONS}>20 is to run all services on
+ * standard tomcat (not embed). To achieve this, disable the @Before and @After.
+ * Additionally, make sure that server.xml has maxThreads="4500" or some large
+ * number sufficient for your test.
+ */
+public class MaxLoadTest {
+	private static final int NUMBER_SESSIONS = 5;
+	private static final int INTER_LAUNCH_DELAY = 20;
+	private static final int PARTY_RESPONSETIME = 1;
+	// HACK can we get it from maven?
+	private static final String GENIUSWEB_VERSION = "2.0.5";
+	private static final ObjectMapper jackson = new ObjectMapper();
+
+	private static final String HARDLINER = "http://localhost:8080/partiesserver/run/hardliner-"
+			+ GENIUSWEB_VERSION;
+	/**
+	 * Test takes average load of last minute. It may take also a minute or two
+	 * to launch all sessions to start with. The average should be taken AFTER
+	 * all sessions were launched.
+	 */
+	private static final long TEST_TIME_MS = 3 * 60 * 1000;
+
+	private static final EmbeddedTomcat tomcat = new EmbeddedTomcat();
+	private static final Parameters parameters = new Parameters().with("delay",
+			PARTY_RESPONSETIME);
+	private static final String PROFILE1 = "ws://localhost:8080/profilesserver/websocket/get/7issues/7issues1";
+	private static final String PROFILE2 = "ws://localhost:8080/profilesserver/websocket/get/7issues/7issues2";
+	private static final Deadline deadline = new DeadlineTime(TEST_TIME_MS);
+
+	private final URL url;
+	private final byte[] startcommand;
+
+	public MaxLoadTest() throws MalformedURLException, JsonProcessingException,
+			URISyntaxException {
+		url = new URL("http://localhost:8080/runserver/run");
+		String startsession = jackson.writeValueAsString(getSettings());
+		startcommand = startsession.toString().getBytes(StandardCharsets.UTF_8);
+	}
+
+	/**
+	 * Start up embedded tomcat servers (all: parties-, profile- and run-server)
+	 * 
+	 * @throws InterruptedException
+	 * 
+	 * @throws Throwable
+	 */
+	@Before
+	public void before() throws InterruptedException {
+		tomcat.start();
+		tomcat.deploy("runserver");
+		tomcat.deployWar("profilesserver", new File(
+				"target/jars/profilesserver-" + GENIUSWEB_VERSION + ".war"));
+		tomcat.deployWar("partiesserver", new File(
+				"target/jars/partiesserver-" + GENIUSWEB_VERSION + ".war"));
+		System.out.println("waiting for server start");
+		Thread.sleep(1500);// HOW do this properly?
+		System.out.println("server started I hope");
+
+	}
+
+	@After
+	public void after() throws InterruptedException {
+		System.setSecurityManager(null);
+		tomcat.stop();
+		Thread.sleep(2000);
+	}
+
+	@Test
+	public void testRunOneSession()
+			throws URISyntaxException, IOException, InterruptedException {
+
+		for (int n = 0; n < NUMBER_SESSIONS; n++) {
+			startSession();
+			Thread.sleep(INTER_LAUNCH_DELAY);
+		}
+
+		System.out.println("Started session. Waiting termination");
+
+		// wait at least 1minute, becaues getLoadAver averages over 1 minute.
+		Thread.sleep(Math.max(TEST_TIME_MS + 100, 60 * 1000));
+		OperatingSystemMXBean operatingSystemMXBean = ManagementFactory
+				.getOperatingSystemMXBean();
+
+		System.out.println("average load in last minute was "
+				+ operatingSystemMXBean.getSystemLoadAverage());
+	}
+
+	/**
+	 * 
+	 * @return the response received from the startup request
+	 * @throws IOException
+	 * @throws ProtocolException
+	 * @throws IllegalStateException if party can not be launched.
+	 */
+	private void startSession() throws IOException, ProtocolException {
+		URLConnection con = url.openConnection();
+		HttpURLConnection http = (HttpURLConnection) con;
+		http.setRequestMethod("POST"); // PUT is another valid option
+		http.setDoOutput(true);
+
+		http.setFixedLengthStreamingMode(startcommand.length);
+		http.setRequestProperty("Content-Type",
+				"application/json; charset=UTF-8");
+		http.setUseCaches(false);
+		http.setDoOutput(true);
+		http.connect();
+		try (OutputStream os = http.getOutputStream()) {
+			os.write(startcommand);
+		}
+
+		InputStream is = http.getInputStream();
+		BufferedReader rd = new BufferedReader(new InputStreamReader(is));
+		String response = "";
+		String line;
+		while ((line = rd.readLine()) != null) {
+			response += line + "\r";
+		}
+		rd.close();
+		System.out.println("sent request. Response=" + response);
+		if (!(response.startsWith("SAOP")))
+			throw new IllegalStateException(
+					"Failed to start party:" + response);
+	}
+
+	private SAOPSettings getSettings() throws URISyntaxException {
+		PartyRef partyref = new PartyRef(HARDLINER);
+		PartyWithParameters party1 = new PartyWithParameters(partyref,
+				parameters);
+		PartyWithParameters party2 = new PartyWithParameters(partyref,
+				parameters);
+		PartyWithProfile partyprofile1 = new PartyWithProfile(party1,
+				new ProfileRef(PROFILE1));
+		PartyWithProfile partyprofile2 = new PartyWithProfile(party2,
+				new ProfileRef(PROFILE2));
+		TeamInfo team1 = new TeamInfo(Arrays.asList(partyprofile1));
+		TeamInfo team2 = new TeamInfo(Arrays.asList(partyprofile2));
+
+		List<TeamInfo> participants = Arrays.asList(team1, team2);
+		SAOPSettings settings = new SAOPSettings(participants, deadline);
+		return settings;
+	}
+
+}
