source: src/main/webapp/newsession.xhtml@ 34

Last change on this file since 34 was 34, checked in by bart, 3 years ago

Reduced memory need of websockets.

File size: 23.5 KB
Line 
1<?xml version="1.0" encoding="UTF-8"?>
2<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
3<head>
4<title>Profiles and Domains list</title>
5<link rel="stylesheet" type="text/css" href="style.css" />
6</head>
7<body onload="init()">
8 <h1>Session</h1>
9
10 On this page you can configure the settings for running a new session
11 and start the session.
12
13 <br /> Protocol:
14 <select id="selectedprotocol" onchange="selectProtocol()">
15 <option value="SAOP">SAOP ( Stacked Alternating Offers
16 Protocol )</option>
17 <option value="MOPAC">MOPAC (Multiple Offers Partial
18 Consensus)</option>
19 <option value="MOPAC2">MOPAC2 (MOPAC but with values for each vote)</option>
20 <option value="AMOP">AMOP (Alternating Multiple Offers
21 Protocol)</option>
22 <option value="SHAOP">SHAOP (Stacked Human Alternating Offers
23 Protocol)</option>
24 <option value="Learn">Learn</option>
25
26 </select>
27
28 <div id="votingevaluator">
29 <br /> Voting Evaluator: <select id="selectedevaluator">
30 <option value="LargestAgreement">Largest Agreement</option>
31 <option value="LargestAgreementsLoop">Largest Agreements and Repeat</option>
32 </select>
33 </div>
34 <div id="votingevaluator2">
35 <br /> Voting Evaluator: <select id="selectedevaluator2">
36 <option value="LargestAgreementWithValue">Largest Agreement with Values</option>
37 </select>
38 </div>
39
40
41 <br /> Deadline:
42 <input type="number" id="deadlinevalue" name="deadline" min="1"
43 max="10000" value="10" />
44 <select id="deadlinetype">
45 <option value="ROUNDS">rounds</option>
46 <option value="TIME">seconds</option>
47 </select>
48
49 <div id="profserverselector">
50 <br /> Domain/Profile Server:
51 <input type="url" name="url" id="profilesserverurl"
52 value="localhost:8080/profilesserver-2.0.5"
53 pattern=".*:[0-9]+/profilesserver.*" size="30"
54 onchange="connectDomain()"> </input>
55 <br /> Domain:
56 <select id="domainselection" onchange="selectDomain()">
57 <!-- <option>Waiting for profiles server</option> -->
58 </select>
59 </div>
60
61 <br />
62 <br />
63
64 <div id="box" class="box">
65 <br /> <b>Participants</b> <br /> Parties Server: <input type="url"
66 name="url" id="partiesserverurl"
67 value="localhost:8080/partiesserver-2.0.5"
68 pattern=".*:[0-9]+/partiesserver.*" size="30"
69 onchange="connectParties()"> </input> <br /> <br /> <b>Party
70 settings</b> <br /> Party : <select id="partyselection">
71 </select> <br />
72
73 <div id="profileselector">
74 Profile: <select id="profileselection"></select> Filter: <input
75 type="text" id="filter" value="" maxlength="40" /> <br />
76 </div>
77 Parameters: {
78 <textarea id="parameters" rows="2" cols="70"
79 onchange="updateParameters()" value="" />
80 } <br /> <br />
81
82 <div id="cobsetting">
83 <input type="checkbox" id="advancedCobSettings"
84 onchange="advancedCobSet()"></input> Advanced COB settings<br />
85 <div id="advancedsettings" style="display: none">
86 <b>COB party settings</b> <br /> Party : <select
87 id="cobpartyselection">
88 </select> <br /> Profile: <select id="cobprofileselection"></select> Filter:
89 <input type="text" id="cobfilter" value="" maxlength="40" /> <br />
90 <!-- -->
91 Parameters: {
92 <textarea id="cobparameters" rows="2" cols="70"
93 onchange="updateCobParameters()" value="" />
94 } <br /> <br />
95 </div>
96 </div>
97
98 <button onclick="addParty()">Add</button>
99
100
101 <br /> <br /> <b>Selected Profiles, Parties for the session</b>
102 <table id="selectedpartiestable" width="100%">
103 <colgroup>
104 <col />
105 <col />
106 <col />
107 <col />
108 <col />
109 <col />
110 </colgroup>
111 <thead>
112 <tr>
113 <th align="center">Party</th>
114 <th align="center">Parameters</th>
115 <th align="center">Profile</th>
116
117 <th align="center">COB Party</th>
118 <th align="center">COB Parameters</th>
119 <th align="center">COB Profile</th>
120 </tr>
121 </thead>
122 <tbody id="partiesList">
123 </tbody>
124 </table>
125
126 </div>
127
128 <form>
129 <input id="startbutton" type="button" value="Start Session"
130 onclick="start()" />
131 </form>
132
133 <div id="started" style="visibility: hidden">
134 Your session started. Waiting for the results. <br />
135 </div>
136 <div id="results" style="visibility: hidden">
137 Session completed. <a href="" id="logref">view the log file</a> <br />
138 <a href="" id="plotref">render a utilities plot</a>.
139 </div>
140
141</body>
142
143<script type="application/javascript">
144
145
146
147
148
149
150
151
152
153
154
155 // FIXME quick and dirty code. No clean MVC
156
157
158 <![CDATA[
159 //"use strict";
160
161 var domainwebsocket = null;
162 var partieslistlistener=null;
163 // current setting of parameters
164 var parameters = {};
165
166 // currently known domains (and profiles) as coming from domainwebsocket.
167 // keys are domain names, values are list of profile names
168 var knowndomains={};
169
170
171 /**
172 List of created participants for the session. Each participant is a dictionary.
173 Each dict element contains keys
174 "party" and "profile", both containing a String containing
175 a valid IRI to the party resp. the profile to use.
176 The party should contain a IRI that gives a new instance of the required party.
177 The profile should contain an IRI that gives the profile contents.
178 */
179 var partyprofiles=[];
180
181 var cobpartyprofiles=[];
182
183 /** from http://fitzgeraldnick.com/2010/08/10/settimeout-patterns.html */
184
185 function getAdvancedCobSettings() {
186 return document.getElementById('advancedCobSettings').checked;
187 }
188
189 function advancedCobSet() {
190 document.getElementById('advancedsettings').style.display=(getAdvancedCobSettings()?'':'none');
191 }
192
193 function async (fn) {
194 setTimeout(fn, 1000);
195 }
196
197 function sometimeWhen (test, then) {
198 async(function () {
199 if ( test() ) {
200 then();
201 } else {
202 async(arguments.callee);
203 }
204 });
205 }
206
207 /**
208 Called when user changes the protocol */
209 function selectProtocol() {
210 var visible=getSelectedProtocol() == "SHAOP";
211
212 document.getElementById("cobsetting").style.display=(visible ? 'block': 'none');
213 var tbl = document.getElementById('selectedpartiestable');
214 tbl.getElementsByTagName('col')[3].style.visibility=(visible?'':'collapse');
215 tbl.getElementsByTagName('col')[4].style.visibility=(visible?'':'collapse');
216 tbl.getElementsByTagName('col')[5].style.visibility=(visible?'':'collapse');
217
218 var evaluatorvisible=getSelectedProtocol() == "MOPAC";
219 document.getElementById("votingevaluator").style.display=(evaluatorvisible ? 'block': 'none');
220
221 var evaluator2visible=getSelectedProtocol() == "MOPAC2";
222 document.getElementById("votingevaluator2").style.display=(evaluator2visible ? 'block': 'none');
223
224
225 var profileselectorvisible=!isUsingFakeProfile();
226 document.getElementById("profserverselector").style.display=(profileselectorvisible ? 'block': 'none');
227 document.getElementById("profileselector").style.display=(profileselectorvisible ? 'block': 'none');
228 if (getSelectedProtocol() == "Learn") {
229 params = {"persistentstate":createUUID(), "negotiationdata":[ createUUID() ] };
230 str=JSON.stringify(params);
231 // remove outer brackets from the text in the box
232 document.getElementById("parameters").value=str.substring(1, str.length-1);
233 updateParameters();
234 }
235 }
236
237 /**
238 @return true iff we need to use a fake profile.
239 */
240 function isUsingFakeProfile() {
241 return getSelectedProtocol() == "Learn";
242 }
243
244 function isUsingCobParty() {
245 return getSelectedProtocol() == "SHAOP";
246 }
247
248 /**
249 Refresh known domains using given profilesserver URL.
250 Called when user enters URL for domain server.
251 */
252 function connectDomain() {
253 if (domainwebsocket!=null) {
254 domainwebsocket.close();
255 domainwebsocket=null;
256 }
257 var url=new URL("http:"+document.getElementById("profilesserverurl").value);
258 // insert the liststream to the path
259 var target = "ws://"+url.host+url.pathname+"/websocket/liststream"+window.location.search+url.hash;
260 if ('WebSocket' in window) {
261 domainwebsocket = new WebSocket(target);
262 } else if ('MozWebSocket' in window) {
263 domainwebsocket = new MozWebSocket(target);
264 } else {
265 alert('WebSocket is not supported by this browser. Please use a newer browser');
266 return;
267 }
268 domainwebsocket.onopen = function () {
269 // whatever.
270 };
271 domainwebsocket.onmessage = function (event) {
272 updateDomainComboBox(JSON.parse(event.data));
273 };
274 domainwebsocket.onclose = function (event) {
275 alert('Info: Server closed connection. Code: ' + event.code +
276 (event.reason == "" ? "" : ", Reason: " + event.reason));
277 domainwebsocket=null;
278 updateDomainComboBox({});
279 };
280 }
281
282 /**
283 Sets a new knowndomains value and Updates the contents of the domain selector combobox.
284 @param the known domains, a map of the form {"jobs":["jobs1","jobs2"]}
285 where the keys are the names of the available domains nd the values a list of the available profiles in that domain.
286
287 */
288 function updateDomainComboBox(newdomains) {
289 knowndomains=newdomains
290 var combobox = document.getElementById("domainselection");
291 combobox.options.length=0;
292 for (var domain in knowndomains) {
293 var option = document.createElement('option');
294 option.text = option.value = domain;
295 combobox.add(option, 0);
296 }
297 selectDomain();
298 }
299
300 /**
301 Connects to partieslist service on partiesserver and
302 forwards reported parties into the updateParties() call.
303 */
304 class PartiesListWebsocket {
305 constructor(target) {
306 this.isopen=false
307 var that=this
308 if ('WebSocket' in window) {
309 this.partieswebsocket = new WebSocket(target);
310 } else if ('MozWebSocket' in window) {
311 this.partieswebsocket = new MozWebSocket(target);
312 } else {
313 alert('WebSocket is not supported by this browser. Please use a newer browser');
314 return;
315 }
316 this.partieswebsocket.onopen = function () {
317 console.log("new websocket conn made")
318 that.isopen=true
319 };
320 this.partieswebsocket.onmessage = function (event) {
321 console.log("new parties data came in")
322 updateParties(JSON.parse(event.data));
323 };
324 this.partieswebsocket.onclose = function (event) {
325 if (that.isopen) {
326 alert('Info: Server closed connection. Code: ' + event.code +
327 (event.reason == "" ? "" : ", Reason: " + event.reason));
328 that.isopen=false;
329 updateParties({});
330 }
331 };
332 }
333 close() {
334 if (this.isopen)
335 console.log("closing parties listener")
336 this.isopen=false;
337 this.partieswebsocket.close()
338 }
339 }
340
341 /**
342 Refresh known parties using given partiesserver URL.
343 Called when user enters URL for parties server.
344 */
345 function connectParties() {
346 if (partieslistlistener!=null) {
347 partieslistlistener.close();
348 }
349 var url=document.getElementById("partiesserverurl").value;
350 var target = "ws://"+url+"/available";
351 partieslistlistener = new PartiesListWebsocket(target)
352 }
353
354
355 /**
356 refresh table: copy all parties elements in there.
357 Typically parties is something like
358 [{"uri":"http:130.161.180.1:8080/partiesserver/run/randomparty-2.0.5",
359 "capabilities":{"protocols":["SAOP"]},
360 "description":"places random bids until it can accept an offer with utility >0.6",
361 "id":"randomparty-2.0.5",
362 "partyClass":"geniusweb.exampleparties.randomparty.RandomParty"},
363 ...]
364 */
365 function updateParties(parties) {
366 console.log("new parties set to "+parties)
367 updatePartiesCombobox(parties, document.getElementById("partyselection"),['SAOP','AMOP','SHAOP','MOPAC', 'MOPAC2']);
368 updatePartiesCombobox(parties, document.getElementById("cobpartyselection"),['COB']);
369 }
370
371 /**
372 @param parties a list of parties r(as received from the server)
373 @param combobox a combobox element to put the party URLs in
374 @param behaviours a list of behaviours for the parties. Only these are put in the combobox.
375 */
376 function updatePartiesCombobox(parties, combobox, behaviours) {
377 combobox.options.length=0;
378 for (var p in parties) {
379 var party = parties[p];
380 if (intersect(party.capabilities.behaviours, behaviours).length==0)
381 continue;
382 var option = document.createElement('option');
383 option.text = option.value = party.uri;
384 combobox.add(option, 0);
385 }
386
387 }
388
389 /**
390 @param a a list
391 @param b another list
392 @return intersection of a and b
393 */
394 function intersect(a, b) {
395 var t;
396 if (b.length > a.length) t = b, b = a, a = t; // indexOf to loop over shorter
397 return a.filter(function (e) {
398 return b.indexOf(e) > -1;
399 });
400 }
401
402
403 /**
404 updates parameters field to match the given text.
405 */
406 function updateParameters() {
407 var text="{"+document.getElementById("parameters").value+"}";
408 try {
409 parameters=JSON.parse(text);
410 } catch(e) {
411 alert("Parameters can not be parsed. "+e);
412 return;
413 }
414 }
415
416 /**
417 Called when the selected domain changes. Assumes knowndomains has been set.
418 Updates the available profiles in the profile combobox.
419 @param selection the name of the selected domain.
420 */
421 function selectDomain() {
422 // determined current selection
423 var domaincombobox = document.getElementById("domainselection");
424 if (domaincombobox.options.length==0) return; // fixme clean profiles options?
425 var domain = domaincombobox.options[domaincombobox.selectedIndex].value;
426
427 updateProfileComboBox(document.getElementById("profileselection"), knowndomains[domain]);
428 updateProfileComboBox(document.getElementById("cobprofileselection"), knowndomains[domain]);
429 }
430
431 function updateProfileComboBox(profilecombo, options) {
432 profilecombo.options.length=0;
433 for (var profile in options) {
434 var option = document.createElement('option');
435 option.text = option.value = options[profile];
436 profilecombo.add(option, 0);
437 }
438
439 }
440
441 /**
442 Called when user clicks "Add"
443 */
444 function addParty() {
445 addNormalParty();
446 if (isUsingCobParty()) {
447 addCobParty();
448 }
449 updatePartyProfileTable(); // what, MVC?
450 }
451
452 function addNormalParty() {
453 var partycombo = document.getElementById("partyselection");
454 var profilecombo = document.getElementById("profileselection");
455 var filteroptions = document.getElementById("filter").value;
456 if (filteroptions!="") {
457 filteroptions="?"+filteroptions;
458 }
459
460 var selectedprofile;
461 if (isUsingFakeProfile()) {
462 selectedprofile="not://valid";
463 } else {
464 if (partycombo.options.length==0) {
465 alert("Please set partier server and select a party");
466 return;
467 }
468 if (profilecombo.options.length==0) {
469 alert("Please set domain/profile server and select a domain and a profile");
470 return;
471 }
472 selectedprofile=profilecombo.options[profilecombo.selectedIndex].value +filteroptions;
473 }
474
475 var newpartyprof = {};
476 newpartyprof["party"]={"partyref":partycombo.options[partycombo.selectedIndex].value ,
477 "parameters":parameters };
478 newpartyprof["profile"]=selectedprofile;
479
480 partyprofiles.push(newpartyprof)
481 }
482
483
484 function addCobParty() {
485 // we assume a sensible default has been loaded into the combo and set,
486 // regardless it being invisible
487 var partycombo = document.getElementById("cobpartyselection");
488 if (partycombo.options.length==0) {
489 alert("Please set cpb partier server and select a party");
490 return;
491 }
492
493 var newpartyprof = {};
494 if (getAdvancedCobSettings()) {
495 var profilecombo = document.getElementById("cobprofileselection");
496 var filteroptions = document.getElementById("cobfilter").value;
497
498 if (profilecombo.options.length==0) {
499 alert("Please set a cob profile");
500 return;
501 }
502 if (filteroptions!="") {
503 filteroptions="?"+filteroptions;
504 }
505 newpartyprof["party"]={"partyref":partycombo.options[partycombo.selectedIndex].value ,
506 "parameters":parameters };
507 newpartyprof["profile"]=profilecombo.options[profilecombo.selectedIndex].value +filteroptions;
508 } else {
509 var profilecombo = document.getElementById("profileselection");
510 newpartyprof["party"]={"partyref":partycombo.options[partycombo.selectedIndex].value ,
511 "parameters":{} };
512 newpartyprof["profile"]=profilecombo.options[profilecombo.selectedIndex].value;
513 }
514 cobpartyprofiles.push(newpartyprof)
515 }
516
517
518 /** updates the party and profiles table, to match the #partyprofiles list. */
519 function updatePartyProfileTable() {
520 var table = document.getElementById("partiesList");
521 table.innerHTML = ""; // clear table
522 for ( var pp in partyprofiles) {
523 var row = table.insertRow(-1);
524 var cell1 = row.insertCell(-1);
525 var cell2 = row.insertCell(-1);
526 var cell3 = row.insertCell(-1);
527
528 cell1.innerHTML = partyprofiles[pp]["party"]["partyref"];
529 // help browser breaking too large strings
530 cell2.innerHTML = JSON.stringify(partyprofiles[pp]["party"]["parameters"]).replace(/,/g,", ");
531 cell2.setAttribute("style","overflow-wrap: anywhere;");
532 cell3.innerHTML = partyprofiles[pp]["profile"];
533
534 if (isUsingCobParty()) {
535 var cell4 = row.insertCell(-1);
536 var cell5 = row.insertCell(-1);
537 var cell6 = row.insertCell(-1);
538 cell4.innerHTML = cobpartyprofiles[pp]["party"]["partyref"];
539 cell5.innerHTML = JSON.stringify(cobpartyprofiles[pp]["party"]["parameters"]).replace(/,/g,", ");
540 cell5.setAttribute("style","overflow-wrap: anywhere;");
541 cell6.innerHTML = cobpartyprofiles[pp]["profile"];
542
543 }
544
545 }
546
547 }
548
549 var x=1;
550 /**
551 start the session as currently set on this page.
552 We need to send a SessionSettings object to the server, which typically looks like this
553 but is protocol dependent (currently we do SAOP)
554
555 {"SAOPSettings":
556 {"participants":[
557 {"party":{"partyref":"http://party1","parameters":{}},"profile":"ws://profile1"},
558 {"party":{"partyref",}"http://party2","parameters":{}},"profile":"ws://profile2"}],
559 "deadline":{"deadlinetime":{"durationms":100}}}}
560
561 participants are already in the global partyprofiles dictionary
562 */
563 function start() {
564 var minParties = getSelectedProtocol() == "Learn" ? 1: 2;
565 if (Object.keys(partyprofiles).length < minParties) {
566 alert("At least "+minParties+" parties are needed to run a "+getSelectedProtocol()+" session.");
567 return;
568 }
569
570 // see https://www.w3schools.com/xml/dom_httprequest.asp
571 document.getElementById("startbutton").disabled=true;
572 document.getElementById("started").setAttribute("style","");
573
574 var xmlHttp = new XMLHttpRequest();
575 xmlHttp.onreadystatechange = function() {
576 if (this.readyState == 4) {
577 if (this.status == 200) {
578 var logurl="log/"+this.responseText+".json";
579 document.getElementById("logref").href=logurl;
580 document.getElementById("plotref").href="plotlog.xhtml"+
581 combineQuery("?id="+this.responseText,window.location.search);
582
583 sometimeWhen(function() { return urlExists(logurl) },
584 function() { document.getElementById("results").setAttribute("style",""); });
585
586 }
587 else
588 alert("request failed:"+this.statusText);
589 }
590 }
591 xmlHttp.open("POST", "run", true);
592 xmlHttp.send(makeRequest());
593
594 }
595
596
597
598 /**
599 @param query1 a query string like &p=q (part of URL)
600 @param query2 another query string
601 @return the combined querystring of query1 and query2
602 */
603 function combineQuery(query1, query2) {
604 if (query1=="") return query2;
605 if (query2=="") return query1;
606 return query1+"&"+query2.substring(1);
607 }
608
609
610 /**
611 @return true iff the URL exists.
612 */
613 function urlExists(urlToFile) {
614 // Warning. Synchronous XMLHttpRequest on the main thread is
615 // deprecated because of its detrimental effects to the end user’s
616 // experience. For more help http://xhr.spec.whatwg.org/
617 var xhr = new XMLHttpRequest();
618 xhr.open('HEAD', urlToFile, false);
619 xhr.send();
620
621 return (xhr.status == "200")
622 }
623
624 function getSelectedProtocol() {
625 var protocolcombo = document.getElementById("selectedprotocol");
626 return protocolcombo.options[protocolcombo.selectedIndex].value;
627 }
628 /**
629 @return a json request package for the run server
630 */
631 function makeRequest() {
632 switch(getSelectedProtocol()) {
633 case "SHAOP":
634 return makeShaopRequest();
635 case"SAOP":
636 case "AMOP":
637 case "Learn":
638 return makeStdRequest(getSelectedProtocol()+"Settings");
639 case "MOPAC":
640 return makeMopacRequest();
641 case "MOPAC2":
642 return makeMopac2Request();
643 }
644 }
645
646 /**
647 @return a SAOP/AMOP request
648 The header contains 'SAOSettings' or 'AMOPSettings'
649 */
650 function makeStdRequest(header) {
651 return JSON.stringify({[header]: standardHeader() });
652 }
653
654 /**
655 * @ereturn MOPAC request. Almost standard but extra 'votingEvaluator'.
656 */
657 function makeMopacRequest() {
658 var extended = standardHeader();
659 var combo = document.getElementById("selectedevaluator");
660 var evaluator = combo.options[combo.selectedIndex].value;
661 extended['votingevaluator'] = { [evaluator]: {} };
662 return JSON.stringify({"MOPACSettings": extended });
663 }
664
665 /**
666 * @ereturn MOPAC2 request. Almost standard but extra 'votingEvaluator'.
667 */
668 function makeMopac2Request() {
669 var extended = standardHeader();
670 var combo = document.getElementById("selectedevaluator2");
671 var evaluator = combo.options[combo.selectedIndex].value;
672 extended['votingevaluator'] = { [evaluator]: {} };
673 return JSON.stringify({"MOPAC2Settings": extended });
674 }
675
676 /**
677 @return standard header with participants and deadline
678 */
679 function standardHeader() {
680 var deadline={};
681 var value = document.getElementById("deadlinevalue").value;
682 var dtypecombo = document.getElementById("deadlinetype");
683 if (dtypecombo.options[dtypecombo.selectedIndex].value=="TIME") {
684 deadline["DeadlineTime"] = { "durationms": 1000*value};
685 } else {
686 // ROUNDS
687 deadline["DeadlineRounds"] = {"rounds": value, "durationms":10000};
688 }
689 var parties=[];
690 for (let i=0; i< partyprofiles.length; i++) {
691 parties.push( {"TeamInfo":{"parties": [ partyprofiles[i] ] }} );
692 }
693 return { "participants": parties, "deadline":deadline }
694 }
695
696
697
698 /**
699 @return a SHAOP request
700 */
701 function makeShaopRequest() {
702 var deadline={};
703 var value = document.getElementById("deadlinevalue").value;
704 var dtypecombo = document.getElementById("deadlinetype");
705 if (dtypecombo.options[dtypecombo.selectedIndex].value=="TIME") {
706 deadline["DeadlineTime"] = { "durationms": 1000*value};
707 } else {
708 // ROUNDS
709 deadline["DeadlineRounds"] = {"rounds": value, "durationms":10000};
710 }
711
712 var parties=[];
713 for (let i=0; i< partyprofiles.length; i++) {
714 var team=[ partyprofiles[i] , cobpartyprofiles[i] ];
715 parties.push( {"TeamInfo":{"parties": team }} );
716 }
717 return JSON.stringify({"SHAOPSettings": { "participants": parties, "deadline":deadline }});
718 }
719
720 /**
721 @return a random UUID.
722 Note − This should not be used in production as GUID or UUID
723 generated by Math.Random() may not be unique.
724 */
725 function createUUID() {
726 return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
727 var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
728 return v.toString(16);
729 });
730 }
731
732
733 /**
734 Initialize the page after html is loaded.
735 */
736 function init() {
737 selectProtocol();
738 document.getElementById("partiesserverurl").value =window.location.hostname+":8080/partiesserver-2.0.5"
739 document.getElementById("profilesserverurl").value =window.location.hostname+":8080/profilesserver-2.0.5"
740 connectDomain();
741 connectParties();
742
743 }
744 ]]>
745
746
747
748
749
750
751
752
753
754</script>
755
756</html>
Note: See TracBrowser for help on using the repository browser.