source: src/main/webapp/utilstable.xhtml@ 12

Last change on this file since 12 was 12, checked in by bart, 5 years ago

Release 1.4.0

File size: 11.7 KB
RevLine 
[9]1<?xml version="1.0" encoding="UTF-8"?>
2<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
3<head>
4<title>Show tournament results table</title>
5<link rel="stylesheet" type="text/css" href="style.css" />
6<script src="Chart.min_2.8.0.js"></script>
7</head>
8<style>
9canvas {
10 -moz-user-select: none;
11 -webkit-user-select: none;
12 -ms-user-select: none;
13}
14</style>
15<body>
16 <div class="noscript">
17 <h2 style="color: #ff0000">Seems your browser doesn't support
18 Javascript! Websockets rely on Javascript being enabled. Please
19 enable Javascript and reload this page!</h2>
20 </div>
21 <h1 id="header">Tournament results</h1>
22
23 Progress:
24 <div id="progress">Waiting for log file name</div>
25 <br />
26
27 <table id="outcomes">
28 <thead>
29 <tr>
30 <th align="center">run nr</th>
31 <th align="center">accepted bid</th>
32 <th align="center">party utilities</th>
33 </tr>
34 </thead>
35 <tbody id="outcomeslist">
36 <!-- one row for each session run added by script -->
37 </tbody>
38
39 </table>
40
41
42</body>
43
44<!-- Script to get/update the table using the query given in the URL. -->
45<script type="application/javascript">
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 <![CDATA[
66 "use strict";
67
68
69
70 var ws = null;
71 var SHAOP=false;
72 /* dict with key=profile URL and value = the downloaded (json) profile */
73 var profiles = {};
74
75 <!-- Most functions are reactive programming written out-->
76
77 /**
78 Called when the page opens.
79 */
[12]80 function init() {
[9]81
82 var id=document.location.search;
83 id = location.search.split('?')[1]
84 if (id==undefined) return;
85
86 // load the log file with given id
87 document.getElementById('header').innerHTML="Tournament results table of "+id;
88
89 var url = "log/"+id+".json";
90 setStatus("Downloading file "+url);
91 var request=new XMLHttpRequest();
92 request.responseType = 'text';
93 request.open('Get', url)
94 request.onload=function() {
95 if (request.status!=200) {
96 setStatus("Failed to fetch "+url+":" +request.status+" "+request.statusText)
97 return;
98 }
99 processLogFile(JSON.parse(request.response));
100 }
101 request.send();
102 }
103
104
105 /**
106 Figure out the protocol contents and parse accordingly.
107 */
108 function processLogFile(json) {
109 if (json['AllPermutationsState']!=undefined) {
110 processAPP(json['AllPermutationsState']);
111 } else {
112 setStatus("Unknown log file contents "+Object.keys(json));
113 }
114 }
115
116 /**
117 Handle AllPermutationsState protocol result.
118 */
119 function processAPP(json) {
120 setStatus("processing the log file");
121
122 if (json['toursettings']['AllPermutationsSettings']['sessionsettings']['SHAOPSettings']!=undefined) {
123 SHAOP=true;
124 }
125
[12]126 // collect all profiles from all profileslists
127 var profiles= [];
128 for (const profilelist of json['toursettings']['AllPermutationsSettings']['profileslists']) {
129 profiles = profiles.concat(profilelist['ProfileList']);
130 }
131 getAllProfiles(json, profiles);
[9]132 }
133
134 /**
135 Step 1, get all profiles. Repeats recursiuvely till profileurls is empty.
136 Note just calling the function again without recurse would be better.
137 Problem is that we call this after we got the profile to ensure we
138 have all profiles at the end.
139 @param profileurls the list of profile urls that need to be fetched.
140 @param profiles a dictionary of profiles . Key is profileurl, value the profile. Should
141 be initially {}
142 returns only after all profiles have been fetched.
143 */
144 function getAllProfiles(json, profileurls) {
145 for (var n in profileurls) {
146 getProfile(profileurls[n], function() {fillRows(json)} );
147 }
148 }
149
150 /**
151 This function returns immediately and will add the profile to the profiles dictionary some time later.
152 @param callwhendone function is called (without arguments) when profiles contains no pending anymore
153 */
154 function getProfile(profileurl, callwhendone) {
155 profiles[profileurl]='pending';
156
157 var profileurl1 = profileurl; // idem but possibly without query
158 if (SHAOP) {
159 profileurl1 = profileurl1.split('?',1)[0]; // hacky, remove complete query.
160 }
161
162 setStatus("fetching profile "+profileurl1);
163 var ws;
164 if ('WebSocket' in window) {
165 ws = new WebSocket(profileurl1);
166 } else if ('MozWebSocket' in window) {
167 ws = new MozWebSocket(profileurl1);
168 } else {
169 setStatus('Fatal: WebSocket is not supported by this browser. Please use a newer browser');
170 return;
171 }
172 ws.onmessage = function (event) {
173 ws.close();
174 var profile = JSON.parse(event.data);
175 if (profile['LinearAdditiveUtilitySpace']==undefined) {
176 setStatus('Fatal: profile '+uri+" does not contain a LinearAdditiveUtilitySpace.");
177 return;
178 }
179
180 profiles[profileurl]=profile['LinearAdditiveUtilitySpace'];
181
182 checkAllProfiles(callwhendone);
183 };
184 ws.onerror=function(event) {
185 ws.close();
186 setStatus('Error fetching profile '+uri+':'+event);
187 }
188 }
189
190 /**
191 Check if there are still pending profiles. If not, callwhendone().
192 */
193 function checkAllProfiles(callwhendone) {
194 for (var key in profiles) {
195 if (profiles[key] == 'pending') return;
196 }
197 callwhendone();
198 }
199
200 /**
201 Step 2, fill the table with util values
202 @param profiles a dictionary of profiles . Key is profileurl, value the profile. Should
203 be initially {}
204 */
205 function fillRows(json)
206 {
207 setStatus("Computing utilities");
208 var table = document.getElementById("outcomeslist");
209 table.innerHTML="";
210 var results = json['results'];
211
212 for (var nr in results) {
213 var result = results[nr];
214 var row = table.insertRow(-1); //-1 = end
215 fillRow(row, nr, results[nr]);
216 }
217 setStatus("done");
218 }
219
220
221
222
223 /**
224 @param row the table row object in the document
225 @param nr the row number
226 @param result a single json result from the APP results section.
227 Contains participants, agreement and error
228 */
229 function fillRow(row, nr, result) {
230 row.insertCell(0).innerHTML = nr;
231
232 if (result['error']!=null) {
233 row.insertCell(-1).innerHTML="session failed with error";
234 return;
235 }
236
237 var agreedbid = result['agreement'];
238 row.insertCell(-1).innerHTML = (agreedbid==null?"none":JSON.stringify(agreedbid['issuevalues']));
239 if (agreedbid==null) agreedbid = {};
240 else agreedbid = agreedbid['issuevalues'];
241
242 // fill in the columns. If SHAOP, only the even parties
243 var stepsize = SHAOP? 2:1;
244 for (var n=0; n<result['participants'].length; n=n+stepsize) {
245 var party = result['participants'][n]
246 var profile =party['profile'];
247 // make short name for readability
248 var partyname = party['party']['partyref'];
249 partyname = partyname.split('/');
250 partyname = partyname[partyname.length-1];
251 addUtilityCell(row.insertCell(-1), agreedbid, partyname, profile);
252 }
253 }
254
255 /**
256 @param cell the table cell to put the result in
257 @param agreedbid the bid that was agreed on
258 @param partyname the short name of the party
259 @param profileurl the profile url to use for the evaluation of the bid
260 @param bid the accepted bid, not null.
261 */
262 function addUtilityCell(cell, agreedbid, partyname, profileurl) {
263 if (Object.keys(agreedbid).lengt==0) {
264 cell.innerHTML = "0 :"+partyname;
265 return;
266 }
267 var util = utility(profiles[profileurl],agreedbid);
268 cell.innerHTML = Math.round(util*1000000)/1000000 +" :"+partyname;
269
270 }
271
272
273
274
275 /**
276 @json the log file contents
277 @param partyprofiles a dict with key=party id and value a the (linear additive) profile
278 */
279 function computeUtils(json, partyprofiles) {
280
281 setStatus("Computing utilities.")
282 var utilities={};
283 for (var party in partyprofiles) {
284 utilities[party]=[];
285 }
286 var actions = json['actions'];
287 for (var action in actions) {
288 var offer = actions[action];
289 if (offer['offer']==undefined)
290 continue;
291 var issueutilities = offer['offer']['bid']['issuevalues']
292 for (var party in partyprofiles) {
293 utilities[party].push(utility(partyprofiles[party],issueutilities));
294 }
295 }
296 return utilities;
297
298
299 }
300
301
302
303 /******************* Private support funcs****************/
304
305 /**
306 Set the progress/status text
307 */
308 function setStatus(text) {
309 document.getElementById('progress').innerHTML=text;
310 }
311
312 /*
313 @param sessions a list of IDs (Strings).
314 */
315 function update(sessions) {
316 var table = document.getElementById("sessionsTable");
317 table.innerHTML="";
318 for(var session of sessions) {
319 var row = table.insertRow(-1); //-1 = end
320 row.insertCell(0).innerHTML = session;
321 }
322
323 }
324
325
326
327
328 /**
329 Compute utilityes
330 @param linadditive the linear additive utility space
331 @param issueValues the bid containing dict with values for the issues
332 @return utility of issueValues
333 */
334 function utility(profile, issueValues) {
335 var util=0;
336 var weights = profile['issueWeights'];
337
338 for (var issue in issueValues) {
339 util = util + weights[issue] * evaluate(profile['issueUtilities'][issue], issueValues[issue] );
340 }
341 return util;
342 }
343
344 /**
345 Bit hacky, javascript version of evaluator of utility space.
346 Would be much nicer if we could use java here
347 */
348 function evaluate (utilfunc, value) {
349 if (utilfunc == undefined) {
350 return 0;
351 }
352 if (utilfunc['numberutils']!=undefined) {
353 // it's numeric issue. Compute
354 var minval = utilfunc['numberutils']['lowValue'];
355 var minutil = utilfunc['numberutils']['lowUtility'];
356 var maxval = utilfunc['numberutils']['highValue'];
357 var maxutil = utilfunc['numberutils']['highUtility'];
358
359 var alfa = (value-minval) / (maxval - minval) ;
360 alfa = Math.max(Math.min(alfa, 1),0);
361 return alfa * maxutil + (1-alfa) * minutil;
362 }
363 if (utilfunc['discreteutils']!=undefined) {
364 // it's discrete issue. Compute
365 return utilfunc['discreteutils']['valueUtilities'][value];
366 }
367 setStatus("Unknown utility function type "+Object.keys(utilfunc));
368
369 }
370
371
372 ]]>
373
374
375
376
377 <![CDATA[
378 "use strict";
379 /*
380 This is called when the window DOM is loaded. window.onload runs BEFORE the window is loaded
381 and therefore is too early to remove the noscript message.
382 */
383 document.addEventListener("DOMContentLoaded", function() {
384 // Remove elements with "noscript" class - <noscript> is not allowed in XHTML
385 var noscripts = document.getElementsByClassName("noscript");
386 for (var i = 0; i < noscripts.length; i++) {
387 noscripts[i].parentNode.removeChild(noscripts[i]);
388 }
[12]389 init();
[9]390
391 }, false);
392 ]]>
393
394
395</script>
396
397
398</html>
Note: See TracBrowser for help on using the repository browser.