Index: src/main/java/geniusweb/runserver/RunNego.java
===================================================================
--- src/main/java/geniusweb/runserver/RunNego.java	(revision 7)
+++ src/main/java/geniusweb/runserver/RunNego.java	(revision 8)
@@ -60,4 +60,6 @@
 			response.sendError(HttpServletResponse.SC_BAD_REQUEST,
 					e.getMessage());
+			System.err.println("Run request failed " + reqstring);
+			e.printStackTrace(); // helpful for debugging run requests
 			return;
 		}
Index: src/main/java/geniusweb/runserver/RunningNego.java
===================================================================
--- src/main/java/geniusweb/runserver/RunningNego.java	(revision 7)
+++ src/main/java/geniusweb/runserver/RunningNego.java	(revision 8)
@@ -83,5 +83,5 @@
 			out.print(jackson.writeValueAsString(sessionState));
 			out.close();
-		} catch (IOException e) {
+		} catch (Throwable e) { // also catch outOfMem etc.
 			log.log(Level.SEVERE, "Failed to write log file for " + sessionid,
 					e);
Index: src/main/java/geniusweb/runserver/WebSocketProtToPartyConn.java
===================================================================
--- src/main/java/geniusweb/runserver/WebSocketProtToPartyConn.java	(revision 7)
+++ src/main/java/geniusweb/runserver/WebSocketProtToPartyConn.java	(revision 8)
@@ -46,4 +46,6 @@
 		implements ProtocolToPartyConn {
 	private final static ObjectMapper jackson = new ObjectMapper();
+	// 20MB seems reasonable limit?
+	private static final int MAX_MESSAGE_SIZE = 20 * 1024 * 1024;
 	private final Reporter log;
 
@@ -178,4 +180,6 @@
 	public void onOpen(Session session) {
 		log.log(Level.INFO, "Party is being connected: " + session);
+		session.setMaxTextMessageBufferSize(MAX_MESSAGE_SIZE);
+		session.setMaxBinaryMessageBufferSize(MAX_MESSAGE_SIZE);
 		this.session = session;
 	}
Index: src/main/webapp/newsession.xhtml
===================================================================
--- src/main/webapp/newsession.xhtml	(revision 7)
+++ src/main/webapp/newsession.xhtml	(revision 8)
@@ -13,6 +13,8 @@
 
 	<br /> Protocol:
-	<select>
-		<option value="SAOP">SAOP</option>
+	<select id="selectedprotocol" onchange="selectProtocol()">
+		<option value="SAOP">SAOP (stacked alternating offers)</option>
+		<option value="SHAOP">SHAOP (stacked human alternating
+			offers)</option>
 	</select>
 
@@ -21,6 +23,6 @@
 		max="10000" value="10" />
 	<select id="deadlinetype">
+		<option value="ROUNDS">rounds</option>
 		<option value="TIME">seconds</option>
-		<option value="ROUNDS">rounds</option>
 	</select>
 
@@ -43,9 +45,25 @@
 			value="localhost:8080/partiesserver-1.1.0"
 			pattern=".*:[0-9]+/partiesserver" size="30"
-			onchange="connectParties()"> </input> <br /> <br /> <b>Edit
-			next party</b> <br /> Party: <select id="partyselection">
-		</select> <br /> Profile: <select id="profileselection">
-		</select> <br /> Parameters: { <input type="text" id="parameters"
-			onchange="updateParameters()" value="" maxlength="100" /> }  <br /> <br />
+			onchange="connectParties()"> </input> <br /> <br /> <b>Party
+			settings</b> <br /> Party : <select id="partyselection">
+		</select> <br /> Profile: <select id="profileselection"></select> Filter: <input
+			type="text" id="filter" value="" maxlength="40" /> <br />
+		Parameters: { <input type="text" id="parameters"
+			onchange="updateParameters()" value="" maxlength="100" /> } <br />
+		<br />
+
+		<div id="cobsetting">
+  			<input type="checkbox" id="advancedCobSettings" onchange="advancedCobSet()" ></input>
+  			Advanced COB settings<br/>
+  			<div id="advancedsettings" style="display:none">
+				<b>COB party settings</b> <br /> Party : <select
+					id="cobpartyselection">
+				</select> <br /> Profile: <select id="cobprofileselection"></select>
+				Filter: <input type="text" id="cobfilter" value=""
+					maxlength="40" /> <br /> Parameters: { <input
+					type="text" id="cobparameters" onchange="updateCobParameters()"
+					value="" maxlength="100" /> } <br /> <br />
+			</div>
+		</div>
 
 		<button onclick="addParty()">Add</button>
@@ -53,14 +71,25 @@
 
 		<br /> <br /> <b>Selected Profiles, Parties for the session</b>
-		<table>
+		<table id="selectedpartiestable" width="100%">
+			<colgroup>
+				<col />
+				<col />
+				<col />
+				<col />
+				<col />
+				<col />
+			</colgroup>
 			<thead>
-				<th align="left" width='40%'>Party</th>
-				<th align="left" width='20%'>Parameters</th>
-				<th align="left" width='40%'>Profile</th>
+				<tr>
+					<th align="center">Party</th>
+					<th align="center">Parameters</th>
+					<th align="center">Profile</th>
+
+					<th align="center">COB Party</th>
+					<th align="center">COB Parameters</th>
+					<th align="center">COB Profile</th>
+				</tr>
 			</thead>
 			<tbody id="partiesList">
-				<tr id="partiesList">
-				</tr>
-
 			</tbody>
 		</table>
@@ -84,4 +113,7 @@
 
 <script type="application/javascript">
+	
+	
+	
 	
 	
@@ -114,7 +146,17 @@
 		*/
         var partyprofiles=[];
+        
+        var cobpartyprofiles=[];
 
 	/** from http://fitzgeraldnick.com/2010/08/10/settimeout-patterns.html */
     
+	function getAdvancedCobSettings() {
+		return document.getElementById('advancedCobSettings').checked;
+	}
+	
+	function advancedCobSet() {
+	    document.getElementById('advancedsettings').style.display=(getAdvancedCobSettings()?'':'none');
+	}
+	
     function async (fn) {
         setTimeout(fn, 1000);
@@ -131,5 +173,16 @@
     }
 
-        
+    /**
+    Called when user changes the protocol */
+    function selectProtocol() {
+    	var visible=getSelectedProtocol() == "SHAOP";
+		
+    	document.getElementById("cobsetting").style.display=(visible ? 'block': 'none');
+	    var tbl = document.getElementById('selectedpartiestable');
+	    tbl.getElementsByTagName('col')[3].style.visibility=(visible?'':'collapse');
+	    tbl.getElementsByTagName('col')[4].style.visibility=(visible?'':'collapse');
+	    tbl.getElementsByTagName('col')[5].style.visibility=(visible?'':'collapse');
+		
+    }   
         
 	/**
@@ -228,13 +281,39 @@
 	 */
 	function updateParties(parties) {
-		var combobox = document.getElementById("partyselection");
+		 updatePartiesCombobox(parties, document.getElementById("partyselection"),['SAOP','SHAOP']);
+		 updatePartiesCombobox(parties, document.getElementById("cobpartyselection"),['COB']);
+	}
+    
+    /**
+    @param parties a list of parties r(as received from the server)
+    @param combobox a combobox element to put the party URLs in
+    @param behaviours a list of behaviours for the parties. Only these are put in the combobox.
+    */
+    function updatePartiesCombobox(parties, combobox, behaviours) {
 		combobox.options.length=0;
-    	for (var party in parties) {
+    	for (var p in parties) {
+    		var party = parties[p];
+    		if (intersect(party.capabilities.behaviours, behaviours).length==0)  
+    			continue;
             var option = document.createElement('option');
-            option.text = option.value = parties[party].uri;
+            option.text = option.value = party.uri;
             combobox.add(option, 0);
     	}
-	}
-    
+
+    }
+
+    /**
+    @param a a list
+    @param b another list
+    @return intersection of a and b
+    */
+    function intersect(a, b) {
+        var t;
+        if (b.length > a.length) t = b, b = a, a = t; // indexOf to loop over shorter
+        return a.filter(function (e) {
+            return b.indexOf(e) > -1;
+        });
+    }
+
 
     /**
@@ -262,11 +341,16 @@
 		var domain = domaincombobox.options[domaincombobox.selectedIndex].value;
 		
-		var profilecombo = document.getElementById("profileselection");
+		updateProfileComboBox(document.getElementById("profileselection"), knowndomains[domain]);
+		updateProfileComboBox(document.getElementById("cobprofileselection"), knowndomains[domain]);
+	}
+	
+	function updateProfileComboBox(profilecombo, options) {
 		profilecombo.options.length=0;
-		for (var profile in knowndomains[domain]) {
+		for (var profile in options) {
             var option = document.createElement('option');
-            option.text = option.value = knowndomains[domain][profile];
+            option.text = option.value = options[profile];
             profilecombo.add(option, 0);
 		}
+
 	}
 	
@@ -275,6 +359,13 @@
 	*/
 	function addParty() {
+		addNormalParty();
+		addCobParty();
+		updatePartyProfileTable(); // what, MVC?
+	}
+	
+	function addNormalParty() {
 		var partycombo = document.getElementById("partyselection");
 		var profilecombo = document.getElementById("profileselection");
+		var filteroptions = document.getElementById("filter").value;
 		
 		if (partycombo.options.length==0) {
@@ -286,13 +377,50 @@
 			return;
 		}
+		
+		if (filteroptions!="") {
+			filteroptions="?"+filteroptions;
+		}
 		var newpartyprof = {};
-		
-		newpartyprof["party"]={"partyref":partycombo.options[partycombo.selectedIndex].value, 
+		newpartyprof["party"]={"partyref":partycombo.options[partycombo.selectedIndex].value , 
 				"parameters":parameters };
-		newpartyprof["profile"]=profilecombo.options[profilecombo.selectedIndex].value;
+		newpartyprof["profile"]=profilecombo.options[profilecombo.selectedIndex].value +filteroptions;
 		
 		partyprofiles.push(newpartyprof)
-		updatePartyProfileTable(); // what, MVC?
-	}
+	}
+	
+	
+	function addCobParty() {
+		// we assume a sensible default has been loaded into the combo and set,
+		// regardless it being invisible
+		var partycombo = document.getElementById("cobpartyselection");
+		if (partycombo.options.length==0) {
+			alert("Please set cpb partier server and select a party");
+			return;
+		}
+
+		var newpartyprof = {};
+		if (getAdvancedCobSettings()) {
+			var profilecombo = document.getElementById("cobprofileselection");
+			var filteroptions = document.getElementById("cobfilter").value;
+
+			if (profilecombo.options.length==0) {
+				alert("Please set a cob profile");
+				return;
+			}
+			if (filteroptions!="") {
+				filteroptions="?"+filteroptions;
+			}
+			newpartyprof["party"]={"partyref":partycombo.options[partycombo.selectedIndex].value , 
+					"parameters":parameters };
+			newpartyprof["profile"]=profilecombo.options[profilecombo.selectedIndex].value +filteroptions;
+		} else {
+			var profilecombo = document.getElementById("profileselection");
+			newpartyprof["party"]={"partyref":partycombo.options[partycombo.selectedIndex].value , 
+					"parameters":{} };
+			newpartyprof["profile"]=profilecombo.options[profilecombo.selectedIndex].value;
+		}
+		cobpartyprofiles.push(newpartyprof)
+	}
+
 	
 	/** updates the party and profiles table, to match the #partyprofiles list.	 	*/
@@ -305,7 +433,14 @@
 			var cell2 = row.insertCell(-1);
 			var cell3 = row.insertCell(-1);
+			var cell4 = row.insertCell(-1);
+			var cell5 = row.insertCell(-1);
+			var cell6 = row.insertCell(-1);
+			
 			cell1.innerHTML = partyprofiles[pp]["party"]["partyref"];
 			cell2.innerHTML = JSON.stringify(partyprofiles[pp]["party"]["parameters"]);
 			cell3.innerHTML = partyprofiles[pp]["profile"];
+			cell4.innerHTML = cobpartyprofiles[pp]["party"]["partyref"];
+			cell5.innerHTML = JSON.stringify(cobpartyprofiles[pp]["party"]["parameters"]);
+			cell6.innerHTML = cobpartyprofiles[pp]["profile"];
 		}
 
@@ -372,8 +507,24 @@
 	}
 	
+	function getSelectedProtocol() {
+		var protocolcombo = document.getElementById("selectedprotocol");
+		return protocolcombo.options[protocolcombo.selectedIndex].value;
+	}
 	/**
 	@return a json request package for the run server
 	*/
 	function makeRequest() {
+
+		if (getSelectedProtocol()=="SHAOP") {
+			return makeShaopRequest();
+		} else {
+			return makeSaopRequest();
+		} 
+	}
+	
+	/**
+	@return a SAOP request
+	*/
+	function makeSaopRequest() {
 		var deadline={};
 		var value = document.getElementById("deadlinevalue").value;
@@ -386,9 +537,32 @@
 		}
 		
-		
 		return JSON.stringify({"SAOPSettings": { "participants": partyprofiles, "deadline":deadline }});
-
-	}
-	
+	}
+
+	/**
+	@return a SHAOP request
+	*/
+	function makeShaopRequest() {
+		var deadline={};
+		var value = document.getElementById("deadlinevalue").value;
+		var dtypecombo  = document.getElementById("deadlinetype");
+		if (dtypecombo.options[dtypecombo.selectedIndex].value=="TIME") {
+			deadline["deadlinetime"] = { "durationms": 1000*value};
+		} else {
+			// ROUNDS
+			deadline["deadlinerounds"] = {"rounds": value, "durationms":10000};
+		}
+		
+		var parties=[];
+		for (let i=0; i< partyprofiles.length; i++) {
+			var group={};
+			group['shaop'] = partyprofiles[i];
+			group['cob'] = cobpartyprofiles[i];
+			
+			parties.push(group);
+		}
+		return JSON.stringify({"SHAOPSettings": { "participants": parties, "deadline":deadline }});
+	}
+
 	
 	/**
@@ -396,4 +570,5 @@
 	*/
 	function init() {
+		selectProtocol();
 		document.getElementById("partiesserverurl").value =window.location.hostname+":8080/partiesserver-1.1.0"
 		document.getElementById("profilesserverurl").value =window.location.hostname+":8080/profilesserver-1.1.0"
@@ -407,4 +582,7 @@
 
 
+
+
+
 </script>
 
Index: src/main/webapp/newtournament.xhtml
===================================================================
--- src/main/webapp/newtournament.xhtml	(revision 7)
+++ src/main/webapp/newtournament.xhtml	(revision 8)
@@ -30,11 +30,15 @@
 	<br />
 	<div id="box" class="box">
-		Session Protocol settings <br /> Session Protocol: <select>
+		Session Protocol settings <br /> Session Protocol: 
+		<select id="protocolselection">
 			<option value="SAOP">SAOP</option>
-		</select> <br /> Deadline: <input type="number" id="deadlinevalue"
+			<option value="SHAOP">SHAOP</option>
+		</select> 
+		
+		<br /> Deadline: <input type="number" id="deadlinevalue"
 			name="deadline" min="1" max="10000" value="10" /> <select
 			id="deadlinetype">
+			<option value="ROUNDS">rounds</option>
 			<option value="TIME">seconds</option>
-			<option value="ROUNDS">rounds</option>
 		</select>
 	</div>
@@ -52,5 +56,8 @@
 		Profile: <select id="profileselection">
 			<!-- <option>Waiting for partiesserver</option> -->
-		</select> <br /> <br />
+		</select> 
+		 Filter: <input type="text" id="filter" value="" maxlength="40" /> 
+		
+		<br /> <br />
 
 		<table id="profiles">
@@ -304,10 +311,15 @@
 	function addProfile() {
 		var profilecombo = document.getElementById("profileselection");
-		
+
 		if (profilecombo.options.length==0) {
 			alert("Please set domain/profile server and select a domain and a profile");
 			return;
 		}
-		profiles.push(profilecombo.options[profilecombo.selectedIndex].value)
+		var filteroptions = document.getElementById("filter").value;
+		if (filteroptions!="") {
+			filteroptions="?"+filteroptions;
+		}
+
+		profiles.push(profilecombo.options[profilecombo.selectedIndex].value + filteroptions)
 		updateProfileTable(); // what, MVC?
 	}
@@ -327,7 +339,6 @@
 	/**
 	start the tournament as currently set on this page.
-	We need to send a TournamentSettings object to the server, which typically looks like this
-	but is protocol dependent (currently we do SAOP)
-	
+	We need to send a TournamentSettings object to the server, which typically looks like this with SAOP
+	<code>
 	{"AllPermutationsSettings":{"parties":["party1","party2"],
 		"profiles":["profile1","profile2","profile3"],
@@ -335,6 +346,21 @@
 		"partiesPerSession":2,
 		"sessionsettings":{"SAOPSettings":{"participants":[],"deadline":{"deadlinetime":{"durationms":10}}}}}}
-	
+	</code>
 	participants are already in the global partyprofiles dictionary
+	
+	With SHAOP, it looks like this
+	<code>
+	{
+		"AllPermutationsSettings": {
+			"parties": [ { "partyref": "classpath:geniusweb.exampleparties.simpleshaop.ShaopParty", "parameters": { } },
+				{ "partyref": "classpath:geniusweb.exampleparties.randomparty.RandomParty",	"parameters": {	}}
+			],
+			"reuseParties": false,
+			"profiles": [ 	"prof1?partial=10", "prof2?partial=15"],
+			"partiesPerSession": 2,
+			"sessionsettings": { 	"SHAOPSettings": {
+					"participants": [ ], 
+					"deadline": { "deadlinerounds": {	"rounds": 10, "durationms": 10000	} } } } } }
+	</code>
 	*/
 	function start() {
@@ -380,7 +406,12 @@
 			deadline["deadlinerounds"] = {"rounds": value, "durationms": 10000};
 		}
-		
 		var reuseParties  = document.getElementById("reuseparties").checked;
-		var sessionSettings = {"SAOPSettings":{"participants":[],"deadline":deadline}};
+		
+		var protocolcombobox = document.getElementById("protocolselection");
+		var protocol = protocolcombobox.options[protocolcombobox.selectedIndex].value;
+		var header=protocol+"Settings";
+	
+		// create S(H)AOPSettings. [header] is a weird ECMA script workaround for javascript issue.
+		var sessionSettings = { [header]:{"participants":[],"deadline":deadline}};
 		return JSON.stringify({"AllPermutationsSettings":{"parties":parties,"profiles":profiles,"reuseParties":reuseParties,"partiesPerSession":2,"sessionsettings":sessionSettings}});
 	}
@@ -390,6 +421,6 @@
 	*/
 	function init() {
-		document.getElementById("partiesserverurl").value =window.location.hostname+":8080/partiesserver-1.1.0"
-		document.getElementById("profilesserverurl").value =window.location.hostname+":8080/profilesserver-1.1.0"
+		document.getElementById("partiesserverurl").value =window.location.hostname+":8080/partiesserver-1.1.0";
+		document.getElementById("profilesserverurl").value =window.location.hostname+":8080/profilesserver-1.1.0";
 
 
Index: src/main/webapp/style.css
===================================================================
--- src/main/webapp/style.css	(revision 7)
+++ src/main/webapp/style.css	(revision 8)
@@ -6,6 +6,5 @@
 table {
 	border: 1px solid black;
-	border-collapse: collapse;
-	border: 1px solid black;
+	#border-collapse: collapse;
 }
 
