Index: src/main/webapp/WEB-INF/web.xml
===================================================================
--- src/main/webapp/WEB-INF/web.xml	(revision 11)
+++ src/main/webapp/WEB-INF/web.xml	(revision 12)
@@ -5,4 +5,21 @@
 <web-app>
 	<display-name>GeniusWeb Run Server</display-name>
+
+	<filter>
+		<filter-name>CorsFilter</filter-name>
+		<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
+		<init-param>
+			<param-name>cors.allowed.origins</param-name>
+			<param-value>*</param-value>
+		</init-param>
+		<init-param>
+			<param-name>cors.exposed.headers</param-name>
+			<param-value>Access-Control-Allow-Origin</param-value>
+		</init-param>
+	</filter>
+	<filter-mapping>
+		<filter-name>CorsFilter</filter-name>
+		<url-pattern>/*</url-pattern>
+	</filter-mapping>
 
 	<servlet>
@@ -27,5 +44,5 @@
 		<servlet-class>geniusweb.runserver.RunNego</servlet-class>
 	</servlet>
-	
+
 
 	<servlet-mapping>
Index: src/main/webapp/newtournament.xhtml
===================================================================
--- src/main/webapp/newtournament.xhtml	(revision 11)
+++ src/main/webapp/newtournament.xhtml	(revision 12)
@@ -4,5 +4,4 @@
 <title>Profiles and Domains list</title>
 <link rel="stylesheet" type="text/css" href="style.css" />
-
 </head>
 <body onload="init()">
@@ -20,21 +19,19 @@
 	<br />
 	<br />
-	<input type="number" id="partiespersession" name="tentacles" min="2"
-		max="10" value="2" /> Number of parties in each session
-	<br />
-
-	<input type="checkbox" id="reuseparties" /> Pick parties with return
-	when creating sessions
+	<input type="number" id="teamspersession" name="tentacles" min="2"
+		max="10" value="2" /> Number of teams in each session
+	<br />
+
+	<input type="checkbox" id="reuseteams" /> Pick teams with return when
+	creating sessions
 	<br />
 
 	<br />
 	<div id="box" class="box">
-		Session Protocol settings <br /> Session Protocol: 
-		<select id="protocolselection">
+		Session Protocol settings <br /> Session Protocol: <select
+			id="protocolselection" onchange="selectProtocol()">
 			<option value="SAOP">SAOP</option>
 			<option value="SHAOP">SHAOP</option>
-		</select> 
-		
-		<br /> Deadline: <input type="number" id="deadlinevalue"
+		</select> <br /> Deadline: <input type="number" id="deadlinevalue"
 			name="deadline" min="1" max="10000" value="10" /> <select
 			id="deadlinetype">
@@ -46,5 +43,6 @@
 
 	<div id="box" class="box">
-		<br /> Domain/Profile Server: <input type="url" name="url"
+		<h3>Profiles</h3>
+		Domain/Profile Server: <input type="url" name="url"
 			id="profilesserverurl" value="localhost:8080/profilesserver-1.3.1"
 			pattern=".*:[0-9]+/profilesserver" size="30"
@@ -53,12 +51,15 @@
 			<!-- <option>Waiting for profiles server</option> -->
 		</select> <br /> <br />
-		<button onclick="addProfile()">Add</button>
-		Profile: <select id="profileselection">
-			<!-- <option>Waiting for partiesserver</option> -->
-		</select> 
-		 Filter: <input type="text" id="filter" value="" maxlength="40" /> 
-		
+		<!--  first selected profile -->
+		Profile: <select id="profileselection1">
+		</select> Filter: <input type="text" id="filter1" value="" maxlength="40" /> <br />
+		<!--  second selected profile -->
+		<div class="onlySHAOP">
+			COB: <select id="profileselection2">
+			</select> Filter: <input type="text" id="filter2" value="" maxlength="40" />
+			<br />
+		</div>
+		<button onclick="addProfiles()">Add</button>
 		<br /> <br />
-
 		<table id="profiles">
 			<thead>
@@ -75,14 +76,26 @@
 	<br />
 	<div id="box" class="box">
+		<h3>Teams</h3>
 		<br /> Parties Server: <input type="url" name="url"
 			id="partiesserverurl" value="localhost:8080/partiesserver-1.3.1"
 			pattern=".*:[0-9]+/partiesserver" size="30"
 			onchange="connectParties()"> </input> <br /> <br />
+		<!-- party  1 selection -->
 		Party: <select id="partyselection">
-			<!-- <option>Waiting for partiesserver</option> -->
-		</select> <br /> Parameters: { <input type="text" id="parameters"
-			onchange="updateParameters()" value="" maxlength="100" /> } <br />
-		<button onclick="addParty()">Add</button>
-			
+		</select> Parameters: { <input type="text" id="parameters"
+			onchange="getParameters('parameters')" value="" maxlength="100" /> }
+		<br />
+		<!-- party 2 selection -->
+		<div class="onlySHAOP">
+			COB: <select id="partyselection2">
+			</select> Parameters: { <input type="text" id="parameters2"
+				onchange="getParameters('parameters2')" value="" maxlength="100" />
+			}
+		</div>
+		<br />
+
+
+		<button onclick="addTeam()">Add</button>
+
 		<br /> <br />
 		<table>
@@ -90,7 +103,9 @@
 				<th align="left">Party</th>
 				<th align="left">Parameters</th>
+				<th align="left"><div class="onlySHAOP">Compare Bids Party</div></th>
+				<th align="left"><div class="onlySHAOP">Compare Bids Parameters</div></th>
 			</thead>
-			<tbody id="partiesList">
-				<tr id="partiesList">
+			<tbody id="teamList">
+				<tr id="FIXME REMOVE">
 				</tr>
 
@@ -106,6 +121,5 @@
 	<div id="started" style="visibility: hidden">
 		Your tournament started. Click <a href="" id="logref">here</a> to view
-		the log file. <br />
-		<a href="" id="plotref">show results table.</a>.
+		the log file. <br /> <a href="" id="plotref">show results table.</a>.
 	</div>
 
@@ -113,4 +127,12 @@
 
 <script type="application/javascript">
+	
+	
+	
+	
+	
+	
+	
+	
 	
 	
@@ -144,10 +166,37 @@
         var knowndomains={};
         
-        var parties=[];
+        var teamslist=[];
         var profiles=[]
-        // current setting of parameters
-        var parameters = {};
-
- 	
+
+ 	/**
+ 	called when user changes the protocol.
+ 	With SHAOP we show COB selectors and COB columns in the tables.
+    */
+    function selectProtocol() {
+    	const isShaop= "SHAOP"==document.getElementById("protocolselection").value;
+    	setStyleSheet('.onlySHAOP','{ display: '+(isShaop? '?':'none')+'; }')
+    }
+    
+    /**
+    Change style sheet to new value. Nothing happens if there is
+    no style sheet with given classname.
+    @param classname the name of the style definition, eg '.onlySHAOP'
+    @param style the new style for the class. eg  '{ max-width: 100px; }'
+    */
+    function setStyleSheet(classname, style) {
+    	for (var cssRulenr=0; cssRulenr< document.styleSheets.length; cssRulenr++) {
+    		var cssRule = document.styleSheets[cssRulenr];
+    		// there may be multple CSS definitions, check each.
+        	var rules = cssRule.cssRules;
+        	for (var rulenr=0;  rulenr<rules.length; rulenr++) {
+        		var rule = rules[rulenr];
+        		if ('selectorText' in rule && rule.selectorText==classname) {
+        			cssRule.deleteRule(rulenr);
+        			cssRule.insertRule(classname+ " "+style, rulenr);
+        		}
+        	}
+    	}
+    }
+        
 	/**
 	Refresh known domains using given profilesserver URL. 
@@ -233,29 +282,46 @@
     }
 
-	
+	/**
+	@param parties a new list of parties available on the parties server
+	*/
 	function updateParties(parties) {
-		var combobox = document.getElementById("partyselection");
+		updatePartyCombo(document.getElementById("partyselection"), parties, 'shaop');
+		updatePartyCombo(document.getElementById("partyselection2"), parties, 'comparebids');
+	}
+	
+	/**
+	put the available parties in the party comboboxes.
+	@param combobox a document <select> element 
+	@param parties a dict of party information coming from the partiesserver
+	@param select a string that may be a substring of the part names. 
+	@return the combobox value that contains 'select' as substring, or undefined
+	*/
+	function updatePartyCombo(combobox, parties, select) {
+		var selection=undefined;
 		combobox.options.length=0;
     	for (var party in parties) {
             var option = document.createElement('option');
             option.text = option.value = parties[party].uri;
+            if (option.text.includes(select) ) option.selected=true;
             combobox.add(option, 0);
     	}
+    	return selection;
 	}
     
 
-
+    
     /**
-    updates parameters field to match the given text.
+    @param elementname eg "parameters", the ID of the element in the <input> element 
+    @return the JSON parsed object, or {} if empty or parsing fails.
     */
-	function updateParameters() {
-		var text="{"+document.getElementById("parameters").value+"}";
+    function getParameters(elementname) {
+		var text="{"+document.getElementById(elementname).value+"}";
     	try {
-			parameters=JSON.parse(text);
+			return JSON.parse(text);
     	} catch(e) {
-    		alert("Parameters can not be parsed. "+e);
-    		return;
+    		alert("Parameters can not be parsed. Make sure you write correct JSON here."+e);
     	}
-	}
+		return {};
+    }
 
 	/**
@@ -269,19 +335,35 @@
 		if (domaincombobox.options.length==0) return; // fixme clean profiles options?
 		var domain = domaincombobox.options[domaincombobox.selectedIndex].value;
-		
-		var profilecombo = document.getElementById("profileselection");
+		updateProfiles(knowndomains[domain])
+	}
+	
+	function updateProfiles(profileslist) {
+		updateProfileCombo(document.getElementById("profileselection1"),profileslist);
+		updateProfileCombo(document.getElementById("profileselection2"),profileslist);
+	}
+	
+	/**
+	@param combobox the <select> element that should be udpated
+	@param profileslist the list of profile names to be put in the combbo
+	*/
+	function updateProfileCombo(profilecombo, profileslist) {
 		profilecombo.options.length=0;
-		for (var profile in knowndomains[domain]) {
+		for (var profile in profileslist) {
             var option = document.createElement('option');
-            option.text = option.value = knowndomains[domain][profile];
+            option.text = option.value = profileslist[profile];
             profilecombo.add(option, 0);
 		}
 	}
 	
+	
 	/**
 	Called when user clicks "Add" 
 	*/
-	function addParty() {
+	function addTeam() {
 		var partycombo = document.getElementById("partyselection");
+		var partycombo2 = document.getElementById("partyselection2");
+		var param = getParameters("parameters");
+		var param2 = getParameters("parameters2");
+		
 		
 		if (partycombo.options.length==0) {
@@ -289,38 +371,57 @@
 			return;
 		}
-		parties.push({"partyref":partycombo.options[partycombo.selectedIndex].value, "parameters":parameters})
-		updatePartyTable();
-	}
-	
-	/** updates the party table, to match the #partyprofiles list.	 	*/
-	function updatePartyTable() {
-		var table = document.getElementById("partiesList");
+		var team = [];
+		team.push({"partyref":partycombo.options[partycombo.selectedIndex].value, "parameters":param});
+		team.push({"partyref":partycombo2.options[partycombo2.selectedIndex].value, "parameters":param2});
+
+		teamslist.push(team);
+		updateTeamsTable();
+	}
+	
+	/** updates the teams table, to match the #partyprofiles list.	 	*/
+	function updateTeamsTable() {
+		var table = document.getElementById("teamList");
 		table.innerHTML = ""; // clear table
-		for ( var party in parties) {
+		for ( const team of teamslist) {
 			var row = table.insertRow(-1);
-			var cell1 = row.insertCell(-1);
-			var cell2 = row.insertCell(-1);
-			cell1.innerHTML = parties[party]["partyref"];
-			cell2.innerHTML = JSON.stringify(parties[party]["parameters"]);
-		}
-
-	}
-
-	/**
-	Called when user clicks "Add" to add a profile
-	*/
-	function addProfile() {
-		var profilecombo = document.getElementById("profileselection");
-
+			for (const col in team) {
+				const party = team[col]
+				var cell1 = row.insertCell(-1);
+				var cell2 = row.insertCell(-1);
+				cell1.innerHTML = party["partyref"];
+				cell2.innerHTML = JSON.stringify(party["parameters"]);
+				if (col>0) {
+					cell1.className = cell2.className = "onlySHAOP";
+				}
+
+			}
+		}
+		
+		selectProtocol(); // HACK we need to KEEP onlySHAOP elements hidden
+	}
+
+	/**
+	@param profilenr the profile nr, 1 for normal , 2 for cob profile
+	*/
+	function getProfile(profilenr) {
+		var profilecombo = document.getElementById("profileselection"+profilenr);
 		if (profilecombo.options.length==0) {
 			alert("Please set domain/profile server and select a domain and a profile");
-			return;
-		}
-		var filteroptions = document.getElementById("filter").value;
+			throw "blabla";
+		}
+		var filteroptions = document.getElementById("filter"+profilenr).value;
 		if (filteroptions!="") {
 			filteroptions="?"+filteroptions;
 		}
 
-		profiles.push(profilecombo.options[profilecombo.selectedIndex].value + filteroptions)
+		//return profilecombo.options[profilecombo.selectedIndex].value + filteroptions
+		return profilecombo.value + filteroptions
+	}
+	
+	/**
+	Called when user clicks "Add" to add a profile set
+	*/
+	function addProfiles() {
+		profiles.push([getProfile(1), getProfile(2)]);
 		updateProfileTable(); // what, MVC?
 	}
@@ -330,10 +431,14 @@
 		var table = document.getElementById("profilesList");
 		table.innerHTML = ""; // clear table
-		for ( var profile in profiles) {
+		for ( const profileset of profiles) {
 			var row = table.insertRow(-1);
-			var cell1 = row.insertCell(-1);
-			cell1.innerHTML = profiles[profile];
-		}
-
+			for (var col in profileset) {
+				var profile = profileset[col];
+				var cell1 = row.insertCell(-1);
+				cell1.innerHTML = profile;
+				if (col>0) cell1.className = "onlySHAOP"
+			}			
+		}
+		selectProtocol(); // HACK we need to KEEP onlySHAOP elements hidden
 	}
 	
@@ -366,13 +471,13 @@
 	*/
 	function start() {
-		var npersession = document.getElementById("partiespersession").value;
-		
-		if (parties.length < npersession || npersession <2) {
-			alert("At least "+npersession+" parties are needed.");
+		const npersession = document.getElementById("teamspersession").value;
+		
+		if (teamslist.length < npersession) {
+			alert("At least "+npersession+" teams are needed.");
 			return;
 		}
 		
 		if (profiles.length < npersession) {
-			alert("At least "+npersession+" profiles are needed.");
+			alert("At least "+npersession+" profilesets are needed.");
 			return;
 		}
@@ -396,10 +501,17 @@
 	
 	/**
-	@return a json request package containing a AllPermutationsSettings
+	@return a json request package containing a AllPermutationsSettings.
+	It assumes that global vars parties and sessionSettings have been set properly.
 	*/
 	function makeRequest() {
+		const npersession = document.getElementById("teamspersession").value;
+		const reuseTeams  = document.getElementById("reuseteams").checked;
+		const protocolcombobox = document.getElementById("protocolselection");
+		const protocol = protocolcombobox.options[protocolcombobox.selectedIndex].value;
+		const header=protocol+"Settings";
+
 		var deadline={};
-		var value = document.getElementById("deadlinevalue").value;
-		var dtypecombo  = document.getElementById("deadlinetype");
+		const value = document.getElementById("deadlinevalue").value;
+		const dtypecombo  = document.getElementById("deadlinetype");
 		if (dtypecombo.options[dtypecombo.selectedIndex].value=="TIME") {
 			deadline["deadlinetime"] = { "durationms": 1000*value};
@@ -408,13 +520,25 @@
 			deadline["deadlinerounds"] = {"rounds": value, "durationms": 10000};
 		}
-		var reuseParties  = document.getElementById("reuseparties").checked;
-		
-		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}});
+		const sessionSettings = { [header]:{"participants":[],"deadline":deadline}};
+		
+		var teamsFull = [];
+		for (const team of teamslist) {
+			if (protocol=="SAOP") // only first member of team is used.
+				teamsFull.push({"Team":[team[0]]});
+			else
+				teamsFull.push({"Team":team});
+		}
+		var profilesFull = [] ;
+		for (const profileset of profiles) {
+			if (protocol=="SAOP") // only first member of team is used.
+				profilesFull.push({"ProfileList":[profileset[0]]});
+			else
+				profilesFull.push({"ProfileList":profileset});
+		}
+		
+		return JSON.stringify({"AllPermutationsSettings":{"teams":teamsFull,"profileslists":profilesFull,
+			"reuseTeams":reuseTeams,"teamsPerSession":npersession,"sessionsettings":sessionSettings}});
 	}
 	
@@ -423,8 +547,8 @@
 	*/
 	function init() {
-		document.getElementById("partiesserverurl").value =window.location.hostname+":8080/partiesserver-1.3.1";
-		document.getElementById("profilesserverurl").value =window.location.hostname+":8080/profilesserver-1.3.1";
-
-
+		document.getElementById("partiesserverurl").value =window.location.hostname+":8080/partiesserver-1.4.0";
+		document.getElementById("profilesserverurl").value =window.location.hostname+":8080/profilesserver-1.4.0";
+
+		selectProtocol();
 		connectDomain();
 		connectParties();
@@ -438,4 +562,12 @@
 
 
+
+
+
+
+
+
+
+
 </script>
 
Index: src/main/webapp/style.css
===================================================================
--- src/main/webapp/style.css	(revision 11)
+++ src/main/webapp/style.css	(revision 12)
@@ -19,2 +19,6 @@
 	  border: 1px solid black;
 }
+
+/* Used for elements that are visible only if SHAOP protocol selected.
+This css is programmatically changed when protocol changes */
+.onlySHAOP { }
Index: src/main/webapp/utilstable.xhtml
===================================================================
--- src/main/webapp/utilstable.xhtml	(revision 11)
+++ src/main/webapp/utilstable.xhtml	(revision 12)
@@ -78,5 +78,5 @@
         Called when the page opens.
         */
-        function connect() {
+        function init() {
         	
         	var id=document.location.search;
@@ -124,5 +124,10 @@
         	}
         	
-        	getAllProfiles(json, json['toursettings']['AllPermutationsSettings']['profiles']);
+        	// collect all profiles from all profileslists
+        	var profiles= [];
+        	for (const profilelist of json['toursettings']['AllPermutationsSettings']['profileslists']) {
+        		profiles = profiles.concat(profilelist['ProfileList']); 
+        	}
+        	getAllProfiles(json, profiles);
         }
         
@@ -369,15 +374,4 @@
 
 
-
-
-</script>
-
-
-
-
-
-<script type="application/javascript">
-	
-	
 	
 	<![CDATA[
@@ -393,5 +387,5 @@
 			    noscripts[i].parentNode.removeChild(noscripts[i]);
 			}
-       		connect();
+       		init();
 
          }, false);
@@ -399,20 +393,4 @@
 
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 </script>
 
