//LAPTlite Copyright 2003 UCL London WC1E 6BT (cusplap@ucl.ac.uk)
//13/7/03 added SHOWALL option (default false): always shows conditional comments and doesn't display 'ex'.
//13/7/03 put helpconf and helptips into separate window, not interrupting flow.
// 6/8/03 made RANDSEQ, RANDSEL set -ve if set at start: then stick without reset.
//11/8/03 'selection' only shown when bad or text to show, format of index, colour of f/b
//25/10/03 act when invalid numbers entered, continue correctly in index, E() after S().
//12/11/03 RANDOPT added but not implemented.
//14//11/03 added CQ.explanx for E() after C()
//17/11 removed IDENT, INST (unused)
//20/11  Need to check im, suppl for : and use DIR iff not
//11/12 REPEATS=no. of times to repeat Qs in a section, set with SET()
//21/12 RET() same as SET() but retrospective
//PROG for sys images  DIR for imgs and menu.htm FINI=URL to override menu.htm
//23/12 implemented for multiple SET() and RET() fns, using arrays
//2/2/06 corrected longstanding bug adding MRQN=0 to displayTXT & TF that made display after response wrong if following skip of a MRQ or MCQ  
var blankFrame=""; // try out for NS 6.2 

//Settable Modes & Parameters
var USECONF=1; //USECONF -1(neg mark),0,1(conf)
var Z=new Array(); MCQSEQ=new Array(); EMQSEQ=new Array(); RANDSEQ=RANDSEL=MCQRAND=EMQRAND=QLAST=0; SHOWALL=false; 
 
//current status info
var PROG,SYS,DIR,FNAME,EXID,FINI,COURSE,HEAD,LOCAL=false,VLE,SKIPCHK, EMAILADD,QueryString; 
var CS, CQ, MRQN=0, MRQOPEN=0, TXT,TXT2="",STARTTIME, CONF=-1,TOLERANCE=1, CSENS=0, CINC=0, QN=-1, SN=-1, NSEQ=-1;
var LASTCF=2, SUBD=true, DEF="", INFO=0, LASTSUP="", MROWS=6, PRECISION=4, FB=1;
var QSEQ=new Array(), QTXT, STARTED=0, SCREEN, reparr=new Array(), resp, STRIP=0, REPEATS=0;
var COMTAG=""; REPLY = new Object(); REPLY.text=REPLY.model=REPLY.mark=REPLY.conf="";
//accumulated data
var TOTAL=TOTFIRST=0, TOTALCH=TOTALCHFIRST=0., NRESP=0, NFIRST=0, NVIEW=0, NCORR=0;
var NS=new Array(), NC=new Array(), COMMENTS = new Array();
var CHANCE=0.5, SCORES, CUMSC=0;
var popUpsBlocked = true;

//submission data 
var USR,IDR,VLE,REC,MAX,QTYPE=1; 
var STATUS=TOPIC=-1, SUBSELECT, NDONE=0,DONETXT;
//INST="test"; STATUS=1;
//var SUBSITES = new Array("http://www.ucl.ac.uk/lapt/laptlite/submit/sub1.php", "http://www.ucl.ac.uk/lapt/web/sub2.php");
var SUBSITES = new Array("http://www.ucl.ac.uk/lapt/web/sub1.php", "http://www.ucl.ac.uk/lapt/web/sub2.php");
var SUBCOM = "http://www.ucl.ac.uk/lapt/web/comment.php"; 
var SUBNAMES =new Array ("UCL Normal","UCL Test","original");
var EMAILDEF="cusplap@ucl.ac.uk";

//fixed data from exercise file
var SECTIONS=new Array(), QUESTIONS, TITLETXT="";
var TNQ=TNQQ=0, TNS=0; // Total No. Q's, Sections with Qs in file 

//constants
//var SUPWIN; // =self.open("","supwin","width=600,height=400,resizable=yes"); SUPWIN.close();
var N=100; T="T", F="F", REPEAT="REPEAT", MCQ="MCQ", MRQ="MRQ";
var Ma="1",Mb="2",Mc="3",Md="4",Me="5",Mf="6",Mg="7";
var Mh="8",Mi="9",Mj="10",Mk="11",Ml="12",Mm="13",Mn="14",Mo="15",Mp="16";
var Mq="17",Mr="18",Ms="19",Mt="20",Mu="21",Mv="22",Mw="23",Mx="24";
var TRUE=true, FALSE=false;
var RIGHT="<FONT color=green ><b>&radic;</b></FONT>"; // FACE='Wingdings'   &thorn;
var WRONG="<FONT color=red ><b>X</b></FONT>";  // FACE='Wingdings' &yacute;
var BLANK="&nbsp;&nbsp;";
var BUTT="<input type=button value="; 
//var CMATRIX = [ 0, 0 , -2 , -6 , 0,  0, 1 , 2 , 3 , 0]; //conf info, 4,8 not used currently
//var CMATRIX = [[ 0,0,-2,-6,0,0,1,2,3,0],[0,0,-1,-4,0,0,1,2,3,0]], matrix=0;
var CMATRIX = [[ 0,0,-2,-6,0,0,1,2,3,0],[0,0,-2,-6,0,0,1,2,3,0]], matrix=0; //temp override matrix setting
var OKBOX = BUTT+"'No Reply' name=conf onclick='parent.respond(0);'> &nbsp; &nbsp;";
  OKBOX += "<b> Make your selection (if any), then click OK: &nbsp;&nbsp;</b></small> "; // Level
  OKBOX += BUTT+"' OK ' name=conf onclick='parent.respond(-1);'> &nbsp; &nbsp;";
var CBOX = BUTT+"'No Reply' name=conf onclick='parent.respond(0);'></small>";
  CBOX += "<b> Certainty: &nbsp;&nbsp;</b><small> "; // Level
  CBOX += BUTT+"'C=1 (low)' name=conf onclick='parent.respond(1);'> &nbsp; &nbsp;";
  CBOX += BUTT+"'C=2 (mid)' name=conf onclick='parent.respond(2);'> &nbsp; &nbsp;";
  CBOX += BUTT+"'C=3 (high)' name=conf onclick='parent.respond(3);'></small>";
var NCBOX =BUTT+"'No Reply' name=conf onclick='parent.respond(0);'> &nbsp; (";
var NEGBOX=NCBOX + "-ve marking)"; NCBOX += "simple marking)";
  TXT="&nbsp;&nbsp;" +BUTT+"'Enter' name=conf onclick='parent.respond(4);'></small>";
  NCBOX += TXT; NEGBOX +=TXT; TXT="";
var B_START = BUTT+"'Start' name=foc onclick='parent.showsection(0);'> ";  
// var B_CONT = BUTT+"'Continue' name=foc2 onclick='--parent.NSEQ;parent.nextq();'> ";  
var B_CONT = BUTT+"'Continue' name=foc2 onclick='parent.reshowq();'> ";  
var B_NEXTQ = BUTT+"'Next Question' onclick='if(parent.SCREEN==\"i\") parent.reshowq(); else parent.nextq();'> ";  
var B_NEXTQ = BUTT+"'Next Question' onclick='parent.nextq();'> ";  
var B_NEXTQL = BUTT+"'Proceed to the Next Question' name=foc onclick='parent.nextq();'> ";  
var B_NEXTS = BUTT+"'Next Section' name=foc onclick='parent.nexts();'> ";  
var B_INDEX = BUTT+"'Index' onclick='parent.sectionindex();'> ";  
var B_HELP  = BUTT+"'CBM Help' onclick='parent.helpconf();'> ";
//var B_TIPS  = <a href=helptips.htm target="_blank"><button value='Tips'>Problems/Tips</button></a> ";
var B_TIPS  = BUTT+"'Problems' onclick='parent.helptips();'> ";
//var B_QUIT=B_EXIT="<a href='' onclick='parent.finish"; //alert(parent.finish); 
var B_QUIT=B_EXIT="<img onclick='parent.finish"; 
//  B_QUIT+="(0); return false;' src="+ PROG +"lplfin.gif alt='Click this to FINISH. Please do NOT close the Window directly.'"+b+" > &nbsp; "; //
//  B_EXIT+="(1); return false;' src="+ PROG +"lplexit.gif alt='Click this to EXIT and return to the menu. Please do NOT close the Window directly.'"+b+" > &nbsp; ";

var B_EXPL="<a href='' onclick='alert(\"Explanation may be conditional on your making a reply\"); return false;'><small>ex</small></a>";
//var B_BACK  = BUTT+"'Back (Previous File)' onclick='parent.finish(1);'> "; //'parent.finish();' 'history.back();'
var B_COMM  = BUTT+"'View / Make Comments' onclick='parent.getcomment(0); '> ";
var B_VCOM  = BUTT+"'View Comments' onclick='parent.vcomments(); '> ";
var B_REV  = BUTT+"'Revise' onclick='opener.userinfo(3); '> ";

var B_ADDCOMM  = BUTT+"'Add Extra Info/Comment' onclick='opener.proceed(2);'> "; 
//var B_RESULTS = BUTT+"'Submit' onclick='parent.proceed(4);'> "; //'parent.resultform(true);'
var B_RESULTS = BUTT+"'Submit' onclick='parent.finish(0); return false;'> "; //'parent.resultform(true);'
var B_SAVE = BUTT+"'(Save)' onclick='alert(\"If you use Netscape, you may save your results and comments on your computer. Click somewhere within the main frame containing the results, and then click File - Save Frame As.. and choose a folder and a file name for your results.";
B_SAVE += " These will be saved as a .HTM file.  You can review them later by clicking on this file in Explorer. With a network connection, you may submit the results at that stage. Do be careful to select the MAIN frame on your screen first (by clicking inside it) otherwise you will not save the right thing.\");' > ";

var STATUSArray=new Array("none","1","2","3","p/g","GCSE","AS/A","School staff","Univ. staff","Other");
var TOPICArray=new Array("none","Medicine","Biol.Sci.","Physical Sci.","Maths/Comp","Social/Envt. Sci","Arts/Humanities");


//var C_RAND = "<input type='checkbox' name='random' CHECKED onClick='parent.setRAND();'>";
//opener.COMWIN.close()
var T_tf=new Object(); T_tf.display = displayTF; T_tf.answer=answerTF; T_tf.respond=respondTF; T_tf.type='tf';
var T_mcq=new Object(); T_mcq.display=displayMCQ; T_mcq.answer=answerM; T_mcq.respond=respondMCQ; T_mcq.type='mult';
var T_text=new Object(); T_text.display=displayTXT; T_text.answer=answerTXT; T_text.respond=respondTXT; T_text.type='text';
var set=new Array(), COMWIN,RESWIN,USERWIN,SUPWIN,HLPWIN,APPLETWIN;
function SET(t) { set[set.length]=new Function(t); } 
function RET(t) { if(DEF=="S") x=CS.set; else x=CQ.set; x[x.length]=new Function(t); } 
function implement(set) { nset=set.length; if(nset>0) for(i=0;i<nset;++i) { set[i](); } } //alert("nset="+nset+ " i="+i);
//function RET(t) { ret=new Function(t); if(DEF=="S") CS.set=ret; if(DEF=="Q") CQ.set=ret; } 

function helpsave() {  // How make it not show original window instead of reswin??  RESWIN.focus();
  alert("If you use Netscape, you may save your results and comments on your computer. Click somewhere within the main frame containing the results, and then click 'File' - 'Save Frame As..') and choose a folder and a file name for your results. These will be saved as a .HTM file.  You can review them later by clicking on this file in Explorer. With a network connection, you may submit the results at that stage. Do be careful to select the MAIN frame on your screen first (by clicking inside it) otherwise you will not save the right thing."); }

//Object definitions
function Question(type,text) { this.text = text; this.ans = new Array(); this.set=set;
  this.mcq = new Array(); this.mfb = new Array(); for(f in type) this[f] = type[f]; }  //25
function Section() { this.mcq = new Array(); this.mfb = new Array();  }
function Response() { this.val = 0; this.explan = ''; } // this.correct = ''; 
function defaults() {
  if(MROWS>0) MROWS=6; //MROWS defaults to 6 at S() unless set -ve
  if(QLAST>0) QLAST=0;
  if(PRECISION>0) PRECISION=4;
  if(REPEATS>0) REPEATS=0;
  if(RANDSEQ>0) RANDSEQ=0; //RANDSEQ +ve: will only last for S() -ve will survive
  if(MCQRAND>0) MCQRAND=0; //MCQRAND +ve: will only last for S() -ve will survive
  if(EMQRAND>0) EMQRAND=0; //EMQRAND +ve: will only last for S() -ve will survive
  if(RANDSEL>0) RANDSEL=0; } //RANDSEL +ve: will only last for S() -ve will survive
function log10(x) {return Math.log(x)*Math.LOG10E;}

function load(path) { // run at start, then commands created by exercise
//alert("Ignore this");
  var i,j,f="",ldr,ldf="",t="",b="HSPACE=0 VSPACE=3 align=LEFT"; for(i=0;i<5;++i) NS[i]=NC[i]=0; // ORDER=0 
//alert("Prior:\r\nPROG="+PROG +"\r\nDIR=" +DIR +"\r\nFINI=" +FINI +"\r\nFNAME=" +FNAME +"\r\nEXID=" +EXID +"\r\nSYS=" +SYS +"\r\nUSR=" +USR +"\r\nIDR=" +IDR);
//alert(String(document.location)+"\n\rPlease ignore this box and press OK");
  url=String(document.location);
  QueryString=url.substring(url.indexOf('?'),5000);
  url=url.split('?'); 
  j=url[0].lastIndexOf('/'); if(j>=0) {ldr=url[0].substring(0,j+1); ldf=url[0].substring(j+1,1000);} //loader dir

  if((ldf.indexOf('run.htm')<0)&&(ldf.indexOf('runn.htm')<0)&&(ldf.indexOf('author.php')<0))
   alert("NB This mode of using US-CBA is only for test, and may lead to problems."); 
  t=navigator.userAgent;
  if(t.indexOf('Mac')>-1) {
    if(t.indexOf('Safari')<0) alert("On a MAC with MSIE, you may need to click 'Refresh' or press APPLE+R to show the exercise. If anyone has an idea why, or how to avoid this, please contact cusplap@ucl.ac.uk!\n\r"+"OS="+t); }

  if(ldr.substring(0,4)=='file') LOCAL=true;
  if(url[1]) {j=url[1].lastIndexOf('/'); f=url[1].substring(j+1,1000); if(j>=0) t=url[1].substring(0,j+1);} //?string
  else f=ldf;
  if(DIR) {j=DIR.lastIndexOf(':'); if(j<0) DIR=ldr+DIR;}
  else DIR=ldr+t; j=DIR.lastIndexOf('/'); if(j<DIR.length-1) DIR=DIR+'/';
  if(FNAME) ; else FNAME=f; j=FNAME.indexOf('ex='); if(j>=0) FNAME=FNAME.substring(j+3,1000); //remove 'ex='
  j=FNAME.indexOf('.'); if(j>0) FNAME=FNAME.substring(0,j); 
  if(EXID) ; else EXID=FNAME;
  if(SUBSELECT>0) ; else SUBSELECT=0; 
  if(SKIPCHK) ; else SKIPCHK=0; 
  if(COURSE) ; else COURSE=''; 
  if(HEAD) ; else HEAD=''; 
  if(REC) ; else REC=0; 
  if(MAX) ; else MAX=0; //NB MAX>0 is NVIEW at which to terminate
  if(FINI) ; else FINI=DIR +'menu.htm';
  if(SYS) ; else PROG='http://www.ucl.ac.uk/lapt/laptlite/sys/'; 
  if(USR) ; else USR=""; //default username
  if(IDR) ; else IDR=""; //default identifier
  if(PROG) ; else PROG=ldr+SYS; //used for img files associated with prog,
  if(VLE) {SUBSELECT=1;} // if(new_frame) new_frame.focus();}
  j=PROG.lastIndexOf('/'); if(j>=0) PROG=PROG.substring(0,j); //remove any /filename
  PROG+='/'; //ensure ends with /
  for(;;) {  //up one dir for each /../ 
    j=PROG.indexOf('/../'); if(j<0) break; t=PROG.substring(j+4,1000); PROG=PROG.substring(0,j); 
    j=PROG.lastIndexOf('/'); PROG=PROG.substring(0,j+1) + t; }
  for(;;) {  //remove /./
    j=PROG.indexOf('/./'); if(j<0) break; PROG=PROG.substring(0,j+1)+PROG.substring(j+3,1000); }
// alert("Please click OK and ignore this test box! \r\n\r\nPost:\r\nPROG="+PROG +"\r\nDIR=" +DIR +"\r\nFINI=" +FINI +"\r\nFNAME=" +FNAME +"\r\nEXID=" +EXID +"\r\nSYS=" +SYS +"\r\nUSR=" +USR +"\r\nIDR=" +IDR);
//  B_QUIT+="(0); return false;'><img src="+ PROG +"lplfin.gif alt='Click this to FINISH. Please do NOT close the Window directly.'"+b+" ></a> &nbsp; "; //
//  B_EXIT+="(1); return false;'><img src="+ PROG +"lplexit.gif alt='Click this to EXIT and return to the menu. Please do NOT close the Window directly.'"+b+" ></a> &nbsp; ";
  B_QUIT+="(0); return false;' src="+ PROG +"lplfin.gif alt='Click this to FINISH. Please do NOT close the Window directly.'"+b+" > &nbsp; "; //
  B_EXIT+="(1); return false;' src="+ PROG +"lplexit.gif alt='Click this to EXIT and return to the menu. Please do NOT close the Window directly.'"+b+" > &nbsp; ";

  if(RANDSEL>0) RANDSEL=-RANDSEL; if(RANDSEQ>0) RANDSEQ=-RANDSEQ;
  if(MCQRAND>0) MCQRAND=-MCQRAND; if(EMQRAND>0) EMQRAND=-EMQRAND; if(QLAST>0) QLAST=-QLAST; 
  if(REPEATS>0) REPEATS=-REPEATS; if(MROWS>0) MROWS=-MROWS; if(PRECISION>0) PRECISION=-PRECISION;
  SN=0; 
  if(SECTIONS.length<1) {
    alert("The requested exercise ["+DIR+FNAME+".js] does not exist, or is not accessible, or has errors. If using Netscape, Mozilla or Firefox, you may be able to identify errors by typing javascript: in the URL box."); self.close(); }

/*  var test=window.open('','','width=1,height=1,left=0,top=0,scrollbars=no');
  if(test) {popUpsBlocked = false; test.close();}
  if(popUpsBlocked) {
    alert("You appear to have popups blocked.\n\r LAPT requires that you always allow popups from ucl.ac.uk\n\rIf your browser is blocking popups, look under 'Tools' on its menu."); 
    }
  sectionindex(); }
*/
//alert(SKIPCHK);

SKIPCHK=1; //added 3/1/06

  if(SKIPCHK&1) {sectionindex();}
  else {
    helpconf();
    if(!HLPWIN) {
      alert("You appear to have popups blocked. LAPT needs these.\n\r You must always allow popups from ucl.ac.uk\n\n\rNB You may have more than one popup blocker running.\n\rIf it is your browser that is blocking popups, you may need to use 'Tools' or 'Options' on its menu. If it is separate security software that is blocking popups, please turn off the popop or 'adware' blocker."); 
      d = self.display.document; d.close(); 
      d.write("If a popup warning is visible here from your browser,<br>");
      d.write("follow its instructions always to allow popups from *.ucl.ac.uk<br>");
      d.write("or www.ucl.ac.uk . <br>");
      d.write("If you have a Google Bar, close this window and allow popups on it.");
      d.close(); 
      alert("** IMPORTANT **\n\rYour computer system is blocking the opening of new windows under program control from ucl.ac.uk (popups). YOU MUST CURE THIS to have full LAPT functionality. TEST SCORES (for example, on WebCT) may be lost if you don't solve the problem. If you cannot cure it, email cusplap@ucl.ac.uk with full details of your computer, your browser (including version) and any extra security software you have installed (e.g. Norton, Google ToolBar, etc.).");
//      document.location="http://www.ucl.ac.uk/lapt/web/recerr.php?"+QueryString+ "?s=1"; //repeat without popup chk 
      document.location="http://www.ucl.ac.uk/lapt/web/recerr.php"+QueryString+ "?s=1"; //repeat without popup chk 
      }
    else {sectionindex(); HLPWIN.focus();} }
  } 

function focentry() { //set focus on text box if one is included
  var i, f=self.display.document.qform.entry, n=f.length;
  if(f.type=="text") f.focus();
  for(i=0;i<n;++i) if(f[i].type=="text") f[i].focus(); }  
 
function foc() { var f = self.display.document.qform.foc; 
//alert("foc2="+ self.display.document.qform.foc.value);
  if(f.focus != null) f.focus(); }
 
function focconf() { 
  if(LASTCF<1) return false; 
  var f = self.display.document.qform.conf[LASTCF]; //.nextql; 
  if (f.focus != null) f.focus(); return false; }

function sectionindex() { 
  SCREEN="i";
  tscore();  // 105
  var i, d = self.display.document; d.close(); //self.display.
  var t=""; // ="<h2>";
  if(SUBD) t+=B_EXIT; else t+=B_QUIT;
  t+=" <big><b>US-CBA Index";

  if(STARTED==0) {STARTED=1; SN=0; CS=SECTIONS[0]; }
  if(TITLETXT!="") t+=(" [ " + TITLETXT + " ]"); t+="<br></b>";

  if(EMAILADD) t+="&nbsp; Comments on this exercise: enter below or email to <b><a href=mailto:" +EMAILADD+ "?Subject=LAPT-lite_" +EXID+ ">" +EMAILADD+ "</a></b>";

  t+="</big><br clear='left'>"; // t+="</h2>";
  var a,b=0,c=0; for(i=0;i<SECTIONS.length;++i) { //count correct sections, errors
    a=chkscores(SECTIONS[i]); if(a>0) ++c; if(a<0) ++b; }
  t+="<form name=qform>" + TNQ;
  if(TNQQ>0) t+="(+"+TNQQ+" subsid.)";
  t+=" question/s in " + TNS + " section/s. "; 
  t+= ("&nbsp;&nbsp; <i>Click on a link to choose a section, or click ");
  t+= B_START; if((SN>0)||(QN>=0)) t+= " or " + B_CONT; 
//alert(SN+"|"+QN);
  t+= "<br>Uncompleted sections ("+(TNS-c-b)+"); ";
  if(FB) t+= "<font color=green>Green: sections all correct at first attempt ("+c+"); </font> ";
  if(FB) t+= "<font color=red>Red: sections with error(s) at first attempt ("+b+").</font></i><ul>";
  else t+= "<font color=red>Red: completed sections ("+b+").</font></i><ul>";

  if((MAX)&&(NVIEW>=MAX)) t+="<p>"+addend();
  t+="</form>";

  d.write(t); self.display.onload = foc; foc(); 
  for (i=0 ; i < SECTIONS.length ; ++i ) {d.write (sectindexline(i) + "<br>" );}
  d.write ( "</ul>"); d.close(); 
  foc(); }

function sectindexline(ind ) {  
  var c, s=SECTIONS[ind], n=100, m=s.title.length; // n=length of title + header to show
  if(m<1) m=n; else m=n-m; if(m<0) m=0;   
  var t = "<small><a href='' onClick=\"parent.showsection(" + ind + ");return false\">";
  if (s.questions.length>0 || s.isSect) {
    c=chkscores(s);
    t+="Sect. " + s.qseq + " (" + s.questions.length + " Q's)</a>: "; 
    if(c>0) t+="<font color=green>"; 
    else if(c<0) t+="<font color=red>"; else t+="<font color=black>"; }
  else t += "Information</a><font color=blue>: ";
  t+="<b>"+(striptag(s.title,n) + " </b>&nbsp; " + striptag(s.header,m) + " ... </small></font>");
//alert(t);
  return t; }

function chkscores(sect) { //returns -1 if errors, 1 if all correct, 0 otherwise //xxz
  var i, n=sect.questions.length; 
  if(n==0) return 0;
  var sc=sect.scores; allok=1; 
  if(FB) for(i=0;i<n;++i) {if((sc[i]==0)||(sc[i]==5)) allok=0; else if(sc[i]<5) return(-1);}
  else {for(i=0;i<n;++i) if((sc[i]==0)||(sc[i]==5)) allok=0; allok=-allok;} 
  return(allok); }

function reshowq() { // res=0 -> allow answer, res!=0 -> display explan
  var i,t,x=""; CQ=QUESTIONS[QN]; SCREEN="q"; tscore(); if(!CQ) return;
  if(!STARTTIME) STARTTIME=new Date();
  d=self.display.document; d.close(); 
  d.write(getimage(resp)); wsecthead(d);   // CS.write(d); 
  if(CS.mcq[0]) x=CS.xtxt; else x=CQ.xtxt; //extra text to write later
  tq="<b><i><font color='#00007f'>Qu. "+(NSEQ+1) + ":</b></i>&nbsp;&nbsp;"+ repZ(CQ.text) + "</font><br>"; 
  if(USECONF>0) t= "<form name=qform onsubmit='return parent.focconf();'>"; //Response form
  else t= "<form name=qform onsubmit='parent.respond(4); return false;'><table border>";
  if(SN&1) t+="<table border bgcolor='#cFcFFF'>"; else t+="<table border bgcolor='#cFFFcF'>";
 
  if(resp==0) { CONF=-1; t+="<tr><td>"+ CQ.display() + "</td>" + "<tr><td>"; //if(resp == 0)
    if(USECONF>0) {if(MRQOPEN==1) t+=OKBOX; else t+= CBOX;} 
    else if(USECONF<0) t+=NEGBOX; else t+=NCBOX; t+= "</td></table>"; }
  else t+="<tr><td>"+ resp.display + "</td><tr>" + resp.mark + "</table>";
  if(x) t+=x+"<br>";
  if(QLAST) t+="<p>" + tq; else t=tq+t; 
  d.write(t);
//alert("MRQN="+MRQN);
  if(resp!=0) { SCREEN="e"; t="";
    if(MRQN==0) t+= "<b><i><font color=blue>Model Answer: </i></b>" + stripquotes(repZ(resp.model)) + "</font><br>";
    if(resp.explan && (resp.explan!='undefined')) {t+="<font color=green>" + repZ(resp.explan) + "</font>";} 
    if((MAX)&&(NVIEW>=MAX)) t+=addend();
    d.write(t+"</form>");

    if(MRQN==0) {self.display.onload = foc; foc();} } //doesn't set focus to LASTCF xxx
  else {
    if((SHOWALL==false)&&(CQ.expunc || CQ.expcor|| CQ.expinc)) d.write(B_EXPL); 
    self.display.onload = focentry; focentry(); }  // set focus
//alert("OK");
  t=getsuppl(1); d.write(t); d.close(); } 

function randomise(n,sel,seq) {
  var h,i,j=n,k,ar=new Array(n),r=Math.abs(sel); 
  for(i=0;i<n;++i) ar[i]=i; 
  if(r>1) for(i=j=0;j<n;i+=r,++j) {      //make subset 1 of each sel (RANDSEL)
    k=i+Math.floor(Math.random()*r); if(k<n) ar[j]=k; else {ar[j]=-1; break;} } //j is new length
  if(seq!=0) for(h=j;h-->0;) {
    i=Math.floor(Math.random()*h); k=ar[h]; ar[h]=ar[i]; ar[i]=k; } //shuffle the subset
  return ar; }

function addend() { 
  t="<br><big><b>FINISHED!!</b> You've done the set number of Qs: " +MAX;
  t+=" &nbsp; &nbsp; You must click &nbsp; "+ B_RESULTS ;
  t+="&nbsp; to record your score.</big>"; 
  return t; }

function reachedmax() { 
  SCREEN="f"; tscore();  // 105
  var d = self.display.document; d.close(); //self.display.
  var t=""; 
  if(SUBD) t+=B_EXIT; else t+=B_QUIT; t+=" <big><b>";
  if(TITLETXT!="") t+=" &nbsp; &nbsp; &nbsp; Exercise: " + TITLETXT + "<br><br>"; 
  t+="<br clear='left'>";
  t+=" You have finished the set maximum number of Qs for this exercise ( " +MAX+" attempted).<p>";
  t+="Please click on &nbsp; &nbsp; &nbsp; &nbsp; "+ B_RESULTS ;
  t+="&nbsp; to record your score <p>"; 
  if(EMAILADD) t+="&nbsp; Comments on this exercise: enter below or email to <b><a href=mailto:" +EMAILADD+ "?Subject=LAPT-lite_" +EXID+ ">" +EMAILADD+ "</a></b>";
  t+="</big></b><p>";
  d.write(t); self.display.onload = foc; foc(); 
  d.close(); }

function nextq() {
//  if((MAX)&&(NVIEW>=MAX)) {alert("Finished: "+MAX+" Qs attempted"); finish(0); return;} //quit when viewed MAX number 
  if((MAX)&&(NVIEW>=MAX)) { reachedmax(); } //quit when viewed MAX number 
  var done=false; if((SN==-1)&&(QN<0)) {nexts(); return;} //start
  if(QN<0) {showsection(SN); QN=0;} //added 13/7/03 with QN=0 in showsection
  else {  //aded else 27/10/04
    REPLY.text=REPLY.model=REPLY.mark=REPLY.conf=""; MRQOPEN=0; CUMSC=0;
    ++NSEQ; done=(NSEQ>=CS.questions.length); // if(MRQN==0) 
    QN=QSEQ[NSEQ]; if(QN<0) done=true; 
    if(done) { 
      if((REPEATS==0) && !CS.repeat) {
        if(CS.explan) {sectexpl(); return;} // alert(CS.explan);
        nexts(); return; }
      else {--REPEATS; NSEQ=0; QSEQ=randomise(CS.questions.length,RANDSEL,RANDSEQ); QN=QSEQ[NSEQ];} } //reshuffles
    if(QUESTIONS.length>0) implement(QUESTIONS[QN].set); resp=0; 
    rand=MCQRAND; src=QUESTIONS[QN]; 
    if(src.mcq[0]==null) {src=CS;rand=0;} m=src.mcq; n=m.length;
    if(n>1) MCQSEQ=randomise(n,0,rand); //only randomise MCQ opts in Q xxx
    reshowq(); } }

function nexts() {
  ++SN;   
  if(SN==SECTIONS.length) { SN=0; CS=SECTIONS[0]; QN=-1; alert("End of file, Returning to Index"); sectionindex();}
//  if(SN==SECTIONS.length) {SN=0; CS=SECTIONS[0]; QN=-1; sectionindex(); finish(0);} // alert("End of file, Finished"); 
  else showsection(SN); }

function sectexpl() {  
  var t="<big>",nq=CS.questions.length, d;
  tscore(); d=self.display.document; d.close(); 
  if(SUBD) t+=B_EXIT; else t+=B_QUIT; 
  t+="<b><i>Sect. " + CS.qseq + " (" + nq + " question/s) </i> &nbsp;&nbsp;";
  t+= CS.title + "</b></big><br clear='left'> "+ CS.header+"<p>"; 
  t+=getsuppl(1) + "<b><u><FONT color=green>Explanation for this Section:</u></b><br>" + CS.explan;
  t+= ("</font><form name=qform><br>" + B_NEXTS + "</form>");   
  d.write(getimage(2)); d.write(t); d.close(); 
  self.display.onload = foc; foc(); }

function showsection(n) {
  var k,t; SN = n; CS = SECTIONS[n]; MRQN=0;
  defaults(); implement(CS.set); //!=null //CS.set(); 23/12 if(CS.set.length>0) 
  QUESTIONS = CS.questions; QN=0; k=CS.questions.length; SCORES=CS.scores;
//alert(CS.mcq.length); EMQRAND=1;
  n=CS.mcq.length; if(n>0) EMQSEQ=randomise(n,0,EMQRAND);
//alert(EMQSEQ);
  if(k>0) {QSEQ=randomise(k,RANDSEL,RANDSEQ); NSEQ=-1; nextq();}  
  else { tscore(); d=self.display.document; d.close(); 
    d.write(getimage(0)); wsecthead(d); // CS.write(d); 
    t=("<form name=qform>" + B_NEXTS + "</form>");
    d.write(t);
    self.display.onload = foc; foc();
    t=getsuppl(1); 
//alert(t);
    d.write(t); 
    d.close(); } } 

function respond(conf) { //done when nr/C pressed conf=0-3 0=NR, 4=NC -1=intermed MRQ,0
//alert("X="+res.model);
  var str, mark, i, entry=display.document.qform.entry;
//alert(CS.scores[QN]+"|"+CUMSC);
  if(REC>99) ++NVIEW; else if(CS.scores[QN]==0 && CUMSC==0) ++NVIEW; 
//alert(NVIEW);
  SUBD=false; 
  if(conf==0) {entry.value="";} //cancel any entered reply
  else if(USECONF<1) conf=4;
  CONF=conf;
  if(conf==-1) {MRQOPEN=2; reshowq(); return;} //OK for MRQ
  MRQNwas=MRQN;
  var res=CQ.respond(entry);
  if((res.val==-1)&&(conf>0)) {alert("Enter a valid reply."); MRQN=MRQNwas; reshowq(); return;}  
  REPLY.text=res.text; REPLY.model=res.model; REPLY.conf=CONF=LASTCF=conf; 
  var corr =(res.val==1?1:0); 
  if(USECONF>0) mark=CMATRIX[matrix][5*corr + parseInt(conf)];
  else if(USECONF<0) mark=2*corr-1; else mark=corr; REPLY.mark=mark;
  var sc=SECTIONS[SN].scores[QN]; if(sc==0) { NFIRST+=1; TOTFIRST+=mark; TOTALCHFIRST+=CHANCE;//only stores first attempts
    if(corr==1) sc=5+conf; else sc=5-conf;
    if((MRQN>0)&&(MRQN<900)) CUMSC+=(sc*Math.pow(10,MRQN));
    else SECTIONS[SN].scores[QN]=CUMSC+sc; }
  TOTAL += mark; NRESP+=1; NS[conf]+=1; NCORR +=corr; NC[conf]+=corr; TOTALCH+=CHANCE;
  tscore(); 
  if(res.explan == null) res.explan = CQ.explan; 
  res.mark = markline(corr, mark,conf);  
  if(FB) {resp=res; reshowq();} else nextq(); } 

function markline(corr,mark,conf) { var t= "<td><b>&nbsp;"; //<tr>
  if(conf==0) t+= "[NO REPLY]"; 
   else t+= (corr==1 ? "<font color=green>"+RIGHT : "<font color=red>"+WRONG); 
//   else t+= (corr==1 ? RIGHT : WRONG); 
  t+= ("&nbsp; Mark = " + mark + "&nbsp;&nbsp;"); 
  if((conf>0)&&(conf<4)) t+="(conf=" + conf + " ) "; t+="</font>";
//alert("MRQOPEN="+MRQOPEN+ " MRQN="+MRQN);
  if(MRQN==0) t+= ("&nbsp; &nbsp;" + B_NEXTQL ); else t+= ("&nbsp; &nbsp;" + CBOX );
//  t+= ("&nbsp; &nbsp;" + B_NEXTQL + "</td>"); 
  return t+"</td>"; } //<br>

function unifscore(p) { return ((p>0.8)? 9*p-6:(p>0.667)? 2*(2*p-1):p)/3; }

var SCACC=SCCH=SCK=SCCBS=SCPOW=SCMAX=0;

function tscore() { //shows footer frame with score & buttons
  var c,k,d,p,n,t;
//  if(SN&1) t="<body bgcolor='#8F8FFF'>"; else t="<body bgcolor='#8FFF8F'>"; 
  t= "<form name=qform>"; if(SUBD) t+=B_EXIT; else t+=B_QUIT; 
//alert(" NRESP="+NRESP+ " NFIRST="+NFIRST+ " TOTAL="+TOTAL+" TOTALCH="+TOTALCH+ " TOTALCHFIRST="+TOTALCHFIRST+ " NCORR="+NCORR); 
  t+="<small>("+EXID+") <b>TOTALS:</b> ";
//  ts="Marks="+TOTAL+ " Q's done = " + NFIRST;
//  if(NRESP>NFIRST) ts+="[+"+(NRESP-NFIRST)+"]";
  if(NRESP==NFIRST)ts="Q's done="+NRESP+", Marks="+TOTAL;
  else ts="Q's done="+NFIRST+"[+"+(NRESP-NFIRST)+" repeats], Marks="+TOTFIRST+ "[+"+(TOTAL-TOTFIRST)+"]";
  if(NRESP >0) { SCMAX=3*NRESP; SCCH=Math.round(100.*TOTALCH/NRESP);
    SCACC=Math.round(100.*NCORR/NRESP); SCPOW=0.4*(1+TOTALCH/(1.0*NRESP));
    SCK=Math.round(100.*(NCORR-TOTALCH)/(NRESP-TOTALCH)); if(SCK<0) SCK=0; 
    SCCBS=((1.0*TOTAL)-TOTALCH)/((3.*NRESP)-TOTALCH); if(SCCBS<0) SCCBS=0.; else SCCBS=Math.pow(SCCBS,SCPOW); SCCBS=Math.round(100.*SCCBS); 
    ts+= (" (" +SCACC+ "% correct, %A="+SCK+"%");
    if(USECONF>0) ts+=", CBS=" + SCCBS + "% "; 
    ts+=" : <a href='' onClick=\" parent.helpscore(); return false\"><b>see explanation</b></a> "; ts+=")"; } 
  if(FB) t+=ts; else t+=" (not shown) ";
  if(STARTTIME) t+= " [T="+ Math.round((new Date()-STARTTIME)/6000)/10 +" min]"; 
  t+= " <b> &nbsp; &copy; UCL 2.2.06</b> ";
  if(EMAILADD) t+= " <b>Queries:</b> <a href=mailto:" +EMAILADD+ "?Subject=Lapt-lite_" +EXID+ ">" +EMAILADD+ "</a>";
  t+= "<br> &nbsp;";
  if(SCREEN=='i') t+=B_CONT; else t+=B_NEXTQ; 
  t+= B_NEXTS + B_INDEX; 
  t+=B_COMM + B_RESULTS + B_HELP + B_TIPS + "</small></form>"; //+ "SUBD=" +SUBD
//  t+=B_COMM + B_VCOM + B_RESULTS + B_HELP + B_TIPS + "</small></form>"; //+ "SUBD=" +SUBD
  d=self.feedback.document; 
  d.write(t); d.close(); }

function getmultvalue(barray) { var i; 
  var s; for(i=0 ; i<barray.length ; ++i) {
    if(barray[i].checked) return barray[i].value; s=barray[i].value;
    if(s!=null) {if(s.search(/^[tyvoj]/i)==0) return 1; if(s.search(/^[fn]/i)==0) return 0;} }   return -1; }

function wsecthead(d) { 
  t="<font face='Arial'><font size='+0'><big>";
  nq=CS.questions.length;
  if(SUBD) t+=B_EXIT; else t+=B_QUIT; 
  if(nq>0||CS.isSect>0) {
    if(SN&1) t+="<font color='blue'>"; else t+="<font color='green'>";
    t+="<b><i>Sect. " + CS.qseq + " (" + nq + " question/s) </i> &nbsp;&nbsp;"; }
  else t+="<font><b><i>Information (Sect." +CS.qseq +") : </i> &nbsp;&nbsp;";
  t+= (CS.title + "</b></big><br clear='left'> "+ repZ(CS.header)); 
//  if(nq==0) t+= ("<form name=qform><br>" + B_NEXTS + "</form></font></font></font>"); //self.display.onload = foc;
  if(nq==0) t+="<br></font></font></font>"; else t+="<p>";
  d.write(t); 
//  if(nq==0) {self.display.onload = foc; foc();} }
  }

function getimage(expl) { //expl=object: Q expl, expl=2: Sectexpl  
  var im=""; 
  if(expl==2) {im=CS.Eimage; if(!im) im=CS.image;} 
  else {
    if(!CS.questions.length) im=CS.image;
    else {if(expl&& (MRQN<1)) im=CQ.Eimage; if(!im) im=CQ.image;}
    if(!im) im=CS.image; }
  im=repZ(im); 
  im=tidytxt(im); 
  im=im.toLowerCase(); if(im.search(/\/p/)>0) im="";
  if(!im || im==="/c") return "";
  return "<img src=" + DIR + im + " alt='[GRAPHIC!!]' HSPACE=10 VSPACE=5 BORDER=0 align=RIGHT >"; } 

//alert("opening SUPWIN");
//alert(dumpProps(SUPWIN,"supwin"));  
//alert(!SUPWIN);
//alert(dumpProps(SUPWIN,"supwin"));  
//alert("opening SUPWIN");
// \n\r"+ "SUPWIN.location="+SUPWIN.location + "SUPWIN.closed="+SUPWIN.closed + "SUPWIN.location="+SUPWIN.location);
//alert("url="+url + " \n\rlastsup="+LASTSUP + " \n\rsupwin=" +SUPWIN+ "\n\r.location=" +SUPWIN);

function getsuppl(focus) { var t, url="", name="";
//alert(focus);
  if(!CS.questions.length) {url=CS.suppl; name=CS.supplname;}
  else {
    if((SCREEN=="e") && (MRQN<1)) {url=CQ.Esuppl;  name=CQ.Esupplname;} 
    if(!url) {url=CQ.suppl; name=CQ.supplname;} }
  if(!url) {url=CS.suppl; name=CS.supplname;}
  if(!url) {if(SUPWIN && (!SUPWIN.closed)) SUPWIN.close(); return("");}
  url=repZ(url); url=tidytxt(url);
  if(!SUPWIN || SUPWIN.closed) { LASTSUP="";
    SUPWIN=fchkopen("","suppl","width=600,height=400,top=300,left=400,menubar=no,scrollbars=yes,resizable=yes"); }
  j=url.indexOf('www.'); if(j==0) url="http://"+url; 
  j=url.indexOf(':'); if(j<0) url=DIR+url; 
  if(LASTSUP!=url) {
    LASTSUP=url; SUPWIN.location.href=url; SUPWIN.focus(); }
  if(focus) SUPWIN.focus();
  t="<br><a href='"+LASTSUP+"' onClick='parent.getsuppl(1); return false;'>Supplementary material (click here to bring to front): "+ name;
  t+="</a>"; return(t); } 

function dumpProps(obj,obj_name) {
  var result = "", i ="";
  for (i in obj) result += obj_name +"."+ i +" = "+ obj[i].value +"\n";
  return result; }

function adddir(text) { if(!text) return('');  //added 20/7/04
  text1=text.toLowerCase(); // dir1=toLowerCase(DIR);
  if(text1.indexOf('<img')>-1) { 
    for(i=1000;--i;text1=text1.substring(0,j)) { 
      j=text1.lastIndexOf('src='); if(j<0) break;
      k=j+4; c=text1.charAt(k); if((c=="'")||(c=='\"')||(c==' ')) ++k;
      h=text1.indexOf("http:",k); if(h==k) continue;
      h=text1.indexOf("file:",k); if(h==k) continue;

      h=text1.indexOf("www",k); if(h==k) continue;
      h=text.indexOf(DIR,k); if(h==k) continue;
      text=text.substring(0,k)+DIR+text.substring(k); }
    text1=text.toLowerCase(); }
  if(text1.indexOf('<a ')>-1) { 
    for(i=1000;--i;text1=text1.substring(0,j)) { 
      j=text1.lastIndexOf('href='); if(j<0) break;
      text=text.substring(0,j)+"target='_blank' "+text.substring(j);
      k=j+5; c=text1.charAt(k); if((c=="'")||(c=='\"')||(c==' ')) ++k; k2=k+16;
      h=text1.indexOf("http:",k); if(h==k) continue;
      h=text1.indexOf("file:",k); if(h==k) continue;
      h=text1.indexOf("www",k); if(h==k) continue;
      h=text1.indexOf("blank",k); if(h==k) continue;
      h=text.indexOf(DIR,k2); if(h==k2) continue;
      c=text1.charAt(k);  if((c=="'")||(c=='\"')||(c=='#')) continue;
      text=text.substring(0,k2)+DIR+text.substring(k2); } }
  return(text); }
 
//Functions appearing in exercise script

function TITLE(text) { TITLETXT = text; } 
function EMAIL(text) { EMAILADD = text; } 

function S(text) {  //format S(<"title",> "header"); <image(URL);> 3rd arg to S can be increment of SN for #/
  //If 2 text fields, shows first bold. Single or second text field shown normal.
  //image is shown with each Q unless Q has its own image
  var i=0,j; DEF="S"; STRIP=0;
  CS =  new Section(); SECTIONS[SECTIONS.length] = CS; CS.mcq = new Array(); 
  CS.questions = new Array(); QUESTIONS = CS.questions; CS.isSect=0;
  CS.scores = new Array(); SCORES = CS.scores; CS.isSect=0; //xxz
  CS.qseq=TNS+1; //Info qseq is as for next qs
  CS.repeat=(text=="REPEAT"); if(CS.repeat)++i;
  if(arguments.length>i+2) {j=arguments[i+2]; if(j>0) {TNS+=j; CS.isSect=j;} } //inc TNS
  CS.title = arguments[i]; CS.header = arguments[i+1]; 
  if(CS.header==null) {CS.header=CS.title; CS.title='';}
  CS.header=adddir(CS.header);
//alert(CS.header);
  CS.cf = new Array(); CS.ok = new Array(); //? .ok not used XXX
  CS.set=set; set=new Array; } //null;

function SX(text) {  //format S("text"); add text as new line to S() header
//  if(CS.title=="") {CS.title=CS.header; CS.header="";} 
  if(CS.header!="") CS.header+=" <br>";
  CS.header+=text; }

function Q(text) { // T or F or MCQ in either first or 2nd field signifies TF or MCQ
  if(!CS) {alert("no S()"); S("untitled");}
  var i=1,n=QUESTIONS.length, val=-1, type=T_text, args=new Array(); MRQN=0; DEF="Q";
  if(arguments.length>1) { //check special fields indicating Q-type
    if(arguments[1]==T) val=1; if(arguments[1]==F) val=0; 
    if(val>-1) {i=2; type=T_tf;} 
    else { if(arguments[0]==T) val=1; if(arguments[0]==F) val=0; 
      if(val>-1) {i=2; text=arguments[1]; type=T_tf;} }
    if(arguments[1]==MCQ) {i=2; type=T_mcq; MRQN=1;} 
    if(text==MCQ) {i=2; text=arguments[1]; type=T_mcq; MRQN=1;} 
    else if(text==MRQ) { i=3; 
      MRQN=arguments[1]; if(MRQN==0) MRQN=1000; else TNQQ+=(MRQN-1); //Q(MRQ,0,..) sets so MRQN > no. of answers
      text=arguments[2]; type=T_mcq;} }

  text=adddir(text);
  CQ = new Question(type,text ); QUESTIONS[n] = CQ; CS.ok[n]=-2; SCORES[n]=0; //xxz
  if(CS.qseq==TNS+1) ++TNS; // qseq is seq no. for sects with Q (total=TNS)
  if(val>-1) {args[0]=val; answerTF(args);}  
  x=arguments[i]; CQ.explan=(x)?adddir(x):''; x=arguments[++i]; CQ.expcor=(x)?adddir(x):''; x=arguments[++i]; CQ.expinc=(x)?x:'';
  CQ.mrqn=MRQN;
  CQ.set=set; set=new Array; CQ.suppl=CQ.Esuppl=CQ.image=CQ.Eimage=""; ++TNQ; }  //null 23/12

function IMG(url) { 
  if(DEF=="") {alert("Ignore "+url); return;}
  if(DEF=="S") CS.image=url; else if(DEF=="Q") CQ.image=url; 
  else if(CS.questions.length==0) CS.Eimage=url; else CQ.Eimage=url; }

function SUPPL(url) { var t=""; 
  if(arguments.length>1) t=arguments[1];
  if(DEF=="S") {CS.suppl=url; CS.supplname=t;}
  else if(DEF=="Q") {CQ.suppl=url; CQ.supplname=t;} 
  else {CQ.Esuppl=url; CQ.Esupplname=t;} }

/* function A() { //correct answer definition
  Args=new Array(); Args[0]=1; var i; 
  if(DEF!="A" && isNaN(arguments[0])) arguments[0]="'"+stripquotes(arguments[0])+"'"; //model text answer in quotes
  DEF="A"; for(i=0;i<arguments.length;++i) Args[i+1]=arguments[i]; CQ.answer(Args); } 
*/

function A() { //correct answer definition
  Args=new Array(); Args[0]=1; var i;
  arguments[0]=tidytxt(String(arguments[0])); //strip lead & trail quotes
//alert(arguments[0] + "|" + arguments[0].indexOf(" ")); 
  if(DEF!="A") {                   //put multiple string model answers in quotes
    if(arguments[0].indexOf(" ")>-1) arguments[0]="'"+stripquotes(arguments[0])+"'"; } 
  DEF="A"; for(i=0;i<arguments.length;++i) Args[i+1]=arguments[i]; CQ.answer(Args); } 


function I() { //incorrect answer
  Args=new Array(); Args[0]=0; var i; 
  for(i=0;i<arguments.length;++i) Args[i+1]=arguments[i]; CQ.answer(Args); } 

function C(text) { //sets explan text conditional on a reply: or on +, - answers if 2 args
  if(arguments.length>1) {
    CQ.expcor=adddir(arguments[0]); CQ.expinc=adddir(arguments[1]); CQ.expunc=""; }
  else {
    CQ.expunc=adddir(arguments[0]); CQ.expcor=CQ.expinc="";} DEF="C"; }  
  
function E(text) { //replaces any uncond explan text set in Q() with arg[0]; additional args ignored
  if(CS.questions.length==0) CS.explan=adddir(arguments[0]); 
  else if(DEF=="C") CQ.explanx=adddir(arguments[0]); else CQ.explan=adddir(arguments[0]); DEF="E";}  

function ES(text) {CS.explan=adddir(arguments[0]);} //sets (or replaces) explan text shown at completion of section
   
function CT(tt, tf) { // [for TF Qs] sets exps cond on answers T or F 
//alert(CQ.ans[0]);
  var i=0,j=1; if(CQ.ans[0].corr==0) {i=1; j=0;} // added .corr 26/2/05
  CQ.expcor=adddir(arguments[i]); CQ.expinc=adddir(arguments[j]); }  

function M(t) { // defines MCQ or MRQ options for S or Q
  var i, n=arguments.length, tar, m; 
  if (QUESTIONS.length == 0) { tar = CS; } else {tar = CQ;} 
  m=tar.mcq.length; for(i=0;i<n;++i) tar.mcq[m+i]=adddir(arguments[i]); }

function MFB(t) { // defines FB for MCQ choices when incorrectly selected, (mainly for S)
  var i, n=arguments.length, tar, m; 
  if (QUESTIONS.length == 0) { tar = CS; } else {tar = CQ;} 
  m=tar.mfb.length; for(i=0;i<n;++i) tar.mfb[m+i]=adddir(arguments[i]); }

function MC(t) { // defines MCQ options & FB for S or Q one at a time
  if(QUESTIONS.length==0) tar=CS; else tar=CQ; 
  m=tar.mcq.length; tar.mcq[m]=t; if(arguments[1]) tar.mfb[m]=adddir(arguments[1]); }

var U=E; // MQ=MCQ;  //backwards compatibility

function X(text) { // defines extra text to show below MCQ options
  var tar; if (QUESTIONS.length == 0) { tar = CS; } else {tar = CQ;} 
  tar.xtxt=adddir(text); }

// T/F Q's  
// format Q("question text",T|F[,"expl1"]) or Q(T|F,"question text"[,"expl1"]) 
// optional C("explunc") or C("explcor","explinc") shown if reply given
// or CT("expl_if reply=T,"expl_if reply=F") 
// <IMG(url);>  // replaces (for this Q) any IMG() following S() and is shown with Q and with f/b.

function displayTF() { // (replied,correct)
  var i,b1=b0=0,a=arguments[1],n=arguments.length,t,s="",s2="", r=arguments[0]; matrix=0; MRQN=0;
  if(n==0) {
    t= radio("TRUE (or YES)",1,false) + "<br>"+ radio("FALSE (or NO)",0,false); 
    t+=" &nbsp;&nbsp;&nbsp;<input type=text name=entry size=2 ><br>"; return t; }
  if((n>1)&&(a=arguments[1],a>-1)) {b1=a; b0=1-a;} //which bold
  t="&nbsp;"; if(r==1) {if(a==1) t+=RIGHT; else t+=WRONG;} else t+=BLANK; t+="&nbsp;&nbsp;";
  if(b1==1) t+="<u><b><font color=blue>"; t+="TRUE (or YES)"; if(b1==1) t+="</font></u></b>"; 
  t+="<br>&nbsp;"; if(r==0) {if(a==0) t+=RIGHT; else t+=WRONG;} else t+=BLANK; t+="&nbsp;&nbsp;";
  if(b0==1) t+="<u><b><font color=blue>"; t+="FALSE (or NO)"; if(b0==1) t+="</font></u></b>"; 
  return t; }
 
function respondTF(entry) {
  var i, a=CQ.ans, r=new Response(), rep, t=addline(CQ.explan,""); CHANCE=0.5;
//alert(t);
  if(entry.value=="") rep=-1; else rep=getmultvalue(entry);
  r.model=a[0].text; r.val=-1; r.text=rep;  // rep is S's reply, 1=T,0=F or -1 for nr
  r.display= displayTF(rep,a[0].corr);
  if(rep>-1) {if(rep==a[0].corr) r.val=1; else r.val=0;} 
  r.explan=addexp(t,r.val); 
//alert(r.explan);
  if(CQ.explanx) r.explan=addline(CQ.explanx,t); return r; }

function answerTF(Args) { // (val,..) - done by Q() for tf; any subseq A()overrides its effect 
  var a=new Object(), corr=Args[0]; CQ.ans[0]=a; a.val=1;
  a.corr=corr; if(corr==1) a.text="TRUE"; else a.text="FALSE";
//alert(CQ.ans[0]); 
  if(Args[2]) {CQ.expcor=Args[1]; CQ.expinc=Args[2];}
  else CQ.expunc=Args[1]; }

//Specific to MCQs  
// format Q("question text",MCQ[,"expl1"]) Q(MCQ,"question text"[,"expl1"])  
// followed by M() containing set of MCQ text options (up to 24)
// followed by one A(Mx[,"expl2"]) with the correct answers (alphabetic seq) 
// and any number of I(Mx,"expl2") with expl text for incorrect replies
// If M() occurs after S(), before any Q(), then this contains the options 
// and then Q format can be just Q("question text"[,"expl1"])  
// optional MFB() following M() contains an equal-sized set of expl texts for incorrect replies
// optional X() after M() contains S() text to be shown below the M() option table
// optional C() & IMG() as for TF Qs

function displayMCQ() { // [replied, correct]
  var i,j,t="",s,s2,m,mj,re=arguments.length, ok=false, n, cols=1, rep, rows=Math.abs(MROWS);  
  var src=CQ; if(src.mcq[0]==null) {src=CS; seq=EMQSEQ;} else seq=MCQSEQ; m=src.mcq;
  matrix=1; if(m[0]==null) {alert("Bad MCQ"); return "";} 
  n=m.length; if(n>0) CHANCE=1./n; else CHANCE=0.; //no. of opts
  if((re==0)||(MRQOPEN>0)) { MRQN=CQ.mrqn; if((MRQN>=n)&&(MRQOPEN==0)) MRQOPEN=1; 
    if(MRQOPEN<2) for(i=0;i<n;++i) reparr[i]=-1;
    if(MRQN==1) t="<b>Choose <u>one</u> of the following:</b><br>";
    else if(MRQOPEN==1) t="<b>Tick <u>ALL</u> the appropriate boxes (if any), and then click OK:</b><br>"; 
    else if(MRQOPEN==2) t="<b>Enter certainty that your <u>entire</u> selection is <u>exactly</u> correct (or change it first):</b><br>"; 
    else t="<b><u>One at a time</u>, make <u>"+MRQN+"</u> choices, entering certainty each time:</b><br>";
    }
  else if(MRQN>0) t="<b>Choose <u>"+MRQN+" more</u>, entering certainty each time:</b><br>"; 
  t+="<table>";
  cols=1+Math.floor(n/rows); k=rows*cols;
  for(i=0;i<k;++i) { 
    j=rows*(i%cols);  if(j==0) t = t + "<tr>"; j+=Math.floor(i/cols); 
    if(j<n) { jact=seq[j]; mj=repZ(m[jact]); //added repZ 9/12/03
      if(re>0) {rep=reparr[jact]; if(MRQN==0) ok=chkarr(jact,arguments[1]); else ok=false; }
      t+= "<td>&nbsp;";
      if(rep==1) t+="&nbsp;"+RIGHT+"&nbsp;&nbsp;"; else if(rep==0) t+="&nbsp;"+WRONG+"&nbsp;&nbsp;"; 
      else if(MRQN==0) t+="&nbsp;"+BLANK+"&nbsp;&nbsp;";
      else if(MRQOPEN==0) t+="<input type=radio name=entry value=" + jact + "> "; //onclick='parent.chkinfo();' 
      else { t+="<input type=checkbox onclick='parent.chkopen();'";
         if(reparr[jact]>-1) t+="checked "; t+=" name=entry value=" + jact + "> "; }
      if(ok) t+= "<u><b>" + mj + "</b></u>"; else  t+= mj;
      t+= "</td>"; } }
//alert(t);
  t+="</table>";   return t; } 

function chkopen() { 
  var i,j, entry=display.document.qform.entry;
  for(i=0 ; i<entry.length ; ++i) { j=entry[i].value;
    if(entry[i].checked) reparr[j]=0; else reparr[j]=-1; } }
//alert("reparr0=" + reparr[0]);
//  chkinfo(); } 

function respondMCQ(entry) { 
  var i,j,ta='',tb,nrep=ok=0, a=CQ.ans, ai, r=new Response(), rep, t=""; var corarr=new Array();
  var src = CQ; if (src.mcq[0]==null) src=CS; //alert("respMCQ"+MRQOPEN);
  if(MRQOPEN) { MRQOPEN=-1; MRQN=0; 
    for(i=0;i<reparr.length;++i) if(reparr[i]==0) { ++nrep;
      if(src.mfb[i]) t+="<br><i>Your selection:</i> "+src.mcq[i]+src.mfb[i]; }      
    ok=nrep; } //ok=nrep=n(replies) 
  else { 
    if(entry.value=="") rep=-1; else rep=getmultvalue(entry);
    if(rep<0) {r.val=-1; if((MRQN>1)&&(CONF<1)) {NRESP+=(MRQN-1);} MRQN=0;} //no reply in MRQ
    else {r.val=0; MRQN-=1;} } 
  for(i=0; i<a.length; i++) { 
    ai=a[i]; ansr=stripquotes(repZ(ai.text)); //repz added 5/4/04
    if(ai.val==1) { j=ansr-1; //A(i) -> j=i-1  
//alert(j);
//alert(Int(repZ(ai.text)));
      if(j<0) {r.model="none would be correct"; break;}  
          //NB no check that there aren't also correct answers specified A(0).  
      r.model=src.mcq[j]; corarr[corarr.length]=j; //corarr contains inds of + answers
      if(MRQOPEN<0) { if(reparr[j]==0) {reparr[j]=1; --ok;} //ok is n(replies not corr)
        --nrep; } }       // nrep is n(replies) - n(corr answers)//xxx21.8.03  NB no cond'l explans 
//    if(rep==(ai.text-1)) {
    if(rep==(ansr-1)) {
      r.val=ai.val; tb=ai.explan; } } //explicit explan for bad answer 
  if(MRQOPEN<0) {if((ok==0)&&(nrep==0)) r.val=1; else r.val=0;}
  else {
    if(rep>-1) reparr[rep]=r.val;
    tb=addline(src.mfb[rep],tb);
//    if((rep>-1)&&((r.val==0)||(tb!=""))) { //shows mfb + and - and selection even if no mfb XX chgd 18/9/05 
    if((rep>-1)&&((r.val==0)||(CQ.explan==''))) { //shows mfb + and - and selection even if no mfb
      if(r.val==0) ta="<b><i>Your Selection</b></i> ["+src.mcq[rep]+"] ";
      if(tb!='') t=addline("<table border><tr><td>"+ta,t) +tb+"</td></table>";
      } }
  if(corarr.length>1) r.model="see above"; //no model answer for multiple A's 
  if(MRQN==0) if(CQ.explan) t=CQ.explan+t; // t=addline(CQ.explan,t);
  r.display=displayMCQ(reparr,corarr);
  r.text=src.mcq[rep]; r.explan=addexp(t,r.val); 
  if(CQ.explanx) r.explan=addline(CQ.explanx,r.explan); return r; }

function answerM(Args) { //(val,text,..)
  var t="", a = new Object(); addanswer(a); 
  a.val = Args[0]; a.text = Args[1]; a.explan=Args[2]; }

//Specific to TEXT, NUM, Quantity Qs  
// format Q("question text",[,"expl1"])
// followed by A("deftext=model answer text"[,"expl2"])
// and then any number of A("deftext"[,"expl2"]) with correct answers
// and any number of I("deftext","expl2") with expl text for incorrect replies
// deftext can be "{n} [proto_text]" or "{n1 n2} [proto_text]" or "proto_text"
// if no proto_text then reply must be n+/- TOLERANCE% or within {n1 n2} without units
// if numeric followed by proto_text, then units must conform to proto_text
// proto_text is any number of space-delimited strings [`][<|>]txt 
// where txt may be a non-white char string or a phrase delimited by '..' 
// wildcards ? (matches any char) and * (matches anything, ignoring any further chars in the proto string
// optional C() & IMG() as for TF Qs

function displayTXT(t) { var value = ""; matrix=1; MRQN=0;
  if(t != null) value = " value=\"" + t + "\" ";
  return "<b>Reply:</b> &nbsp;" + "<input type=text name=entry" + value + " size=30 >"; } //<br>

function respondTXT(entry) { //line 399
  var i,ok,n,t,t2,a=CQ.ans, ai, reply, r=new Response(), rtxt,tc,pars; 
  r.text=entry.value; reply=tidytxt(entry.value); CHANCE=0.;
  r.display = displayTXT(reply); tc='';  r.explan=repZ(CQ.explan); // removed tc xxx6.1.04
  ai=numdef(repZ(a[0].text));  //xyz
  if(isNaN(ai.min)) r.model=ai.text; //text, not num model answer 
  else {                             //num model answer
    if(isNaN(ai.num)) {r.model=toprec(ai.min,PRECISION,4,0) + " to "+toprec(ai.max,PRECISION,4,0) + " " +ai.text;}  // if explicit range
    else r.model = toprec(ai.num,PRECISION,4,0) + " " +ai.text+ " (tolerance: &plusmn;" + TOLERANCE + "%)"; } //tolerance range
  if(reply=="") {r.val=-1; return r;}  //require non-blank reply before conf
  for(i=0,r.val=0; i<a.length; ++i ) { //check reply against each answer line
    ai=numdef(repZ(a[i].text)); ok=true; t=rtxt=reply; 
    if(a[i].strip&1) rtxt=tidytxt(rtxt,1); //strip wh space
    if(!isNaN(ai.min)) { ok=false;           // num proto 
      pars=parsenum(rtxt); n=pars.num; rtxt=pars.unit; //rtxt=reply unit
// alert("rtxt="+rtxt);
      if(isNaN(n)) { alert("Your answer should begin with a valid number."); r.val=-1; return r;}
      t2=tidytxt(String(n) + " " + rtxt); 
      if(!(t2===reply)) t=reply + " &rarr; " + t2;  //revise display of reply to show intepr of n
      r.display = displayTXT(t);
      ok=ai.comp(n); }
//alert(ok+" "+rtxt+"|"+ai.text);
//    if(ok) {ok=checktxt(rtxt,stripquotes(ai.text)); // stripquotes removed 12/2/05 with chg to A() XXX
    if(ok) {ok=checktxt(rtxt,ai.text);
    if(ok) break;} }  //301
//alert(ok);
  if(ok) { r.val=a[i].val; 
    if(a[i].explan!='') tc="<FONT color=blue>"+repZ(a[i].explan)+"</FONT><br>"; }
//alert(tc+"|"+a[i].explan);
//    tc=addline(repZ(a[i].explan),tc); tc+="</FONT><br>"; }
  tc+=repZ(CQ.explan); 
  r.explan=addexp(tc,r.val); 
  if(CQ.explanx) r.explan=addline(CQ.explanx,r.explan); 
//alert(r.explan);
  return r; }

//XXX    if((i==0)&&(isNaN(ai.num))) ai.text="'"+ai.text+"'"; 
//alert("ai.min ="+ai.min+" rtxt="+rtxt+" ai.text="+ai.text);
//alert("strip="+a[i].strip+" reply="+reply+" rtxt="+rtxt+" i="+i+" ai.text="+ai.text);
//alert("NUM "+ai.min+ "~" + ai.max);
//alert("ok="+ok);
//alert("rtxt="+rtxt+" ai,text="+ai.text);
//alert("ok2="+ok);

function answerTXT(Args) {  // (val, text, ...) 
  var a = new Object(), strip=STRIP, n=2; a.val = Args[0]; 
//  if(Args[2]==1) {strip=1; n=3;} a.text=tidytxt(Args[1],strip); a.explan = Args[n]; a.strip=strip;   
  if(Args[2]==1) {strip=1; ++n;} //deprecated
  else if(Args[3]) {c=Args[3]; strip=c&1;} //added 7/1/04 
  a.text=tidytxt(Args[1],strip); if(Args[n]) a.explan=Args[n]; else a.explan=''; a.strip=strip;   
  addanswer(a); }

function numdef(t) {
  var c,pars1,pars2,n,n1,n2,e,a = new Object(); //n added 8/8
//alert("t="+t);
//  if(t.charAt(0)!="{") {a.text=t; return a;}  //non-numeric line //XXX a.min=""; added 29/7
  c=t.charAt(0);
  if(!((c=="{")||((c=="'")&&(t.charAt(1)=="{")))) {a.text=t; return a;}  //non-numeric line 
  n=t.length; if(c=="'") {c=2; n--;} else c=1; TXT=t.substring(c,n); 
//  if(c=='{') c=1; else c=2; TXT=t.substring(c,1000); 
  pars1=parsenum(getTXTstr());
  n1=pars1.num; //1st string
//alert("n1="+n1);
  if(isNaN(n1)) {alert("Bad numeric answer line: " + t);  return a;} //invalid num
  pars2=parsenum(TXT); n2=pars2.num; // parse rest 
//alert("n2="+n2);
  if(isNaN(n2)) {e = Math.abs(n1 * TOLERANCE/100); n=n1; n1=n-e; n2=n+e; a.text=TXT;} //single num only
  else a.text=pars2.unit; 
  a.num=n; a.min=n1; a.max=n2; a.comp = comprange; 
//alert(a.min+"|"+a.num+"|"+a.max+"|"+a.text+"|"); //+a.comp);
  return a; }

function checktxt(reply,line) { var u; TXT=line; //check reply vs proto line 
  if(line=="") return (reply=="");  //blank line must be matched by blank reply
  for(j=1000;j--;) { //multiple prototypes on a line
    u=getTXTstr(); if(u=="") break;
    if((u=="*")||check1(reply,u)) return true; }  // u==* added 21/8/03
  return false; }

function check1(reply,proto) { //check match reply text vs single proto 
  var k, b, p=prot2reg(proto), r=reply, i="i", t;   //p is stripped of [`<>
  if((CINC==0)&&(proto.indexOf(" ")<0)) { // proto not a phrase: only use 1st string of reply for exact match
    if(k=r.indexOf(" "), k>-1) r=r.substring(0,k); } 
  if(CSENS==1) i="";  //  if(CINC<2) { var r1=new RegExp(p,i); k=r.search(r1); 
  if(CINC<2) { 
//alert(r+"|"+p+"|i="+i);
    k=r.search(new RegExp(p,i));   
//alert("CINC="+CINC+" CSENS="+CSENS+" proto="+proto+" r="+r+" p="+p+" k="+k); 
//alert("k="+k+" proto="+proto+" r="+r+" p="+p+" k="+k); 
    if(CINC==1) b=(k>-1);  //reply contains re
    else { b=(k==0); 
     if(b && (p.charAt(p.length-1)!="+")) b=(p.length==prot2reg(r).length); } } //XXXp2r(r) added 29/7 
  else {
    r=prot2reg(r);  //var r2=new RegExp(r,i); k=p.search(r2);
    k=p.search(new RegExp(r,i));
    b=(k>-1);} //prot contains reply
  return b; }

function parsenum(text) { //xxx doesnt leave units after single num 
  var i,j,k,c,t="",t2,r=new Object(),p=new Array();  //p=text index of t equiv
  for(i=0,j=0;i<text.length;++i) {
    c=text.charAt(i); if((c!=",")&&(c!=" ")) {  //delete space & , 
      if((c=="*")||(c=="X")) c="x"; // multiply -> x
      p[j++]=i; t+=c; } } 
  t=t.replace(/[eE]([-\+\.0-9])/,function (str,p1) {return "|"+p1;}); //valid Ex format
  j=t.search(/x10\^/); if(j>=0) {
    t=t.replace(/x10\^/,"|"); for(k=j;k<t.length;++k) p[k]=p[k+3]; } //correct for deletion  
  j=t.search(/10\^/); if(j==0) t=t.replace(/10\^/,"1.|"); //added 30/9/03 for simple 10^x
  j=t.search(/[a-zA-Z]/); 
  if(j<0) {j=1000; r.unit="";} else r.unit=text.substring(p[j],1000);
  t=t.substring(0,j); 
  if(t.search(/\|.*\./)>=0) { //added 25/10/03
    alert("Only integer powers are allowed when entering a numerical answer"); t="x"; } 
  if(t.search(/.*\^/)>=0) { //added 25/10/03
    alert("In numerical answers, the ^ symbol is only allowed for entering integer powers of 10 (e.g. 3.2x10^-6)");  t="x"; } 
  t=t.replace(/\|/,"E"); t=t.replace(/\{/,""); t=t.replace(/\}/,""); //remove  { }
  r.num=parseFloat(t); 
  return r; }

function arrtoprec(arr) {return arr;} // XXX needs writing

function repZ(text) {
  var c,i,j,k,t=text; 
  if(t==null || !isNaN(t)) return text;
  for(i=0;i<100;++i) { // NB iterates for Z[Z[.]] OK
    t=String(t);
    j=t.search(/Z\[.\]/); 
    if(j>-1) t=t.substring(0,j) + toprec(parseFloat(Z[t.charAt(j+2)]),PRECISION,4,0) + t.substring(j+4,1000);
    else { j=t.search(/Z\[..\]/); 
      if(j<0) break;
//alert("Hi1!"+j+"|"+t+"|"+t.substring(j+2,j+4)+"|");
      if(t.charAt(j+2)=='Z') {
//        t=t.substring(0,j); if(t.charAt(j+3)=='1') t=t.substring(0,j) + ZZ1 + t.substring(j+5,1000);
//        else if(t.charAt(j+3)=='2') t=t.substring(0,j) + ZZ2 + t.substring(j+5,1000); else break; }
        if(t.charAt(j+3)=='1') t=t.substring(0,j) + ZZ1 + t.substring(j+5,1000);
        else if(t.charAt(j+3)=='2') t=t.substring(0,j) + ZZ2 + t.substring(j+5,1000); else break; }
      else t=t.substring(0,j) + toprec(parseFloat(Z[t.substring(j+2,j+4)]),PRECISION,4,0) + t.substring(j+5,1000);
//alert("Hi2!"+text+"\n\r"+t);
      } } 
  return t; }

function prot2reg(text) { var i, t=text, cont=1; CINC=0, CSENS=0;
  for(;cont;) { cont=0; 
    if(t.charAt(0)=="[") {CSENS=0;cont=1;t=strip1(t);}
    if(t.charAt(0)=="`") {CSENS=1;cont=1;t=strip1(t);}
    if(t.charAt(0)==">") {CINC=1;cont=1;t=strip1(t);} 
    if(t.charAt(0)=="<") {CINC=2;cont=1;t=strip1(t);}
    if(cont==0) break; }
  t=t.replace(/([\\\^\$\+\.\(\)\|\[\]\{\}])/g,function (str,p1) {return "\\"+p1;}); // make these literals: \^$+.()|[]{}
  if(i=t.indexOf("*"), i>-1) {if(i==0) t=".+"; else t=t.substring(0,i)+ "+";} //wild * 
  t=t.replace(/\?/g,"."); //single char wildcard ? -> . 
  return t; }

function stripquotes(t) {
// alert(t); 
  if(!t || !isNaN(t)) return(t); var t1=t.replace(/^'+/,""); t1=t1.replace(/'+$/,""); 
  if((t1.charAt(0)=="[")||(t1.charAt(0)=="`")) t1=strip1(t1);
  return(t1); } // xxx from t="" 8/8/03

function strip1(t) {return t.substring(1,1000);} 

function comprange( v ) { return(v >= this.min) &&(v <= this.max); }
  
function tidytxt(text) { var t=text; //remove multiple, leading & trailing spaces if args[1]&1 remove all
  if(!t) return ""; t=String(t);
  if(arguments[1]&1) t=t.replace(/ /g,""); //strip all spaces
  t=t.replace(/ +/g," "); 
  t=t.replace(/^ /g,"");
  t=t.replace(/ $/,""); 
  t=t.replace(/mm Hg/ig,"mmHg"); //specific processing
  return t; }

function striptag(text,maxlen) { //strips up to 100 <..>, terminating at maxlen or lone < or >
  var i,m,n,t=text; if(maxlen<1) return(""); 
  for(i=100;--i;) { m=t.indexOf("<"); n=t.indexOf(">"); if(m==-1) break; //369
    if(n>m) t=t.substring(0,m) + t.substring(n+1,10000); 
    else {if(n<0) t=t.substring(0,m); else t=t.substring(0,n);} }
  for(;;) {m=t.indexOf(">"); if(m<0) break; t=t.replace(">","");}
  return t.substring(0,maxlen); }

function addanswer(a) { CQ.ans[CQ.ans.length] = a; } 
 
function addexp(t,val) { var t1=t;    //add explans only shown after reply //13/7 added SHOWALL
  if(SHOWALL) { t1=addline(CQ.expunc,t); 
    if(!(CQ.expcor==="")) t1=addline("[+]: "+CQ.expcor,t1);
    if(!(CQ.expinc==="")) t1=addline("[-]: "+CQ.expinc,t1); }
  else if(val>-1){ t1=addline(CQ.expunc,t);  
    if(val==1) t1=addline(CQ.expcor,t1); else t1=addline(CQ.expinc,t1); } 
  return t1; } 

function addline(t,t0) { // return t0 followed by t
  if((t=='undefined')||(t==null)) t='';   
  if((t0=='undefined')||(t0==null)||(t0==='')) return t;
  if(t==='') return t0; else return t0 + "<br>"+t; }

function getTXTstr() { //get 1st str or '...' in TXT & leave remainder 
  var i,j,k,t; for(i=1000;i--;) {  //strip lead sps
    if(TXT.charAt(0)==" ") TXT=TXT.substring(1,1000); else break; }
  if(TXT=="") return ""; 
  i=TXT.indexOf(" "); if(i<0) {t=TXT; TXT="";} //last str in TXT
  else { // >1 string
    t=TXT.substring(0,i); //t is first str, TXT includes this still
    if(j=t.indexOf("'"), j>-1) { // " in t
      if(k=TXT.substring(i+1,1000).indexOf("'"), k<0) k=1000; //unmatched ", take to end
      i=i+k+1; t=TXT.substring(0,i); }
    TXT=TXT.substring(i+1,1000); }
//var re=new RegExp("'"); t=t.replace(re,""); return t; }
  t=t.replace(new RegExp("'"),""); return t; }

function cleantxt(t0) { var t; if(t0==null) return ""; //replace " with ', , with ;
  t0=String(t0);  if(!t0) return(""); if(t0=="") return("");
//alert("clean="+t0+'Ý');
  t=t0.replace(/\"/g , "'"); t=t.replace(/,/g , ";");
  return t; }

function finish(q) { //currently ignores q (diff between Finish & Exit) //sub made auto 20/1/04
//alert("Hi4 finish " + SUBD ); 
  if(!SUBD) proceed(3);
// alert("Hi! finish" + SUBD + " " + FINI); 
  if(SUBD) {if(FINI.toUpperCase()=='CLOSE') {self.close();} //alert("closing"); 
  else {document.location=FINI;} } // "alert(not closing");
  return; } 

function cvtdate(date) {
  var i=date.getDate() + 100*(date.getMonth()+1)+ 10000*date.getFullYear(); 
  var j=date.getMinutes() + 100*date.getHours();
  j+= Math.round((1000*date.getSeconds()+date.getMilliseconds())/600)/100; //chgd to fract of minute
  return i+", "+j; }

function selrand(n1) { 
  var sep=1,n,n2,n4,r,ex,e=1.E-6,i; //default exclusion range +/- 1e-6
  if(arguments.length<2) return n1; else n2=arguments[1]; 
  if(arguments.length>2) sep=Math.abs(arguments[2]); 
  if(arguments.length>3) ex=arguments[3]; 
  if(arguments.length>4) e=Math.abs(arguments[4]); 
  if(n2<n1) {n=n2; n2=n1; n1=n;} n=n2-n1;  if(n==0) return n1; 
  if(sep!=0) n=1+Math.floor(n/sep);
  for(i=1000;--i;) { 
    r=Math.random(); if(sep==0) r=n1+r*n; else r=n1+sep*Math.floor(n*r);
    if(isNaN(ex)) break; if((r<ex-e)||(r>ex+e)) break; } 
  return r; }
//  return parseFloat(toprec(r,3)); } //XX should restore??

function radio(text , val ) { 
  var sel="", n="entry"; 
  if(arguments[2]) sel=" CHECKED "; if(arguments.length>3) n=arguments[3];
  return "<input type=radio name=" + n + " value=" + val + sel + "> " + text; } //onclick='parent.chkinfo();' 

function radioc(text , val ) { 
  var sel="", n="entry"; 
  if(arguments[2]) sel=" CHECKED "; if(arguments.length>3) n=arguments[3];
  return "<input type=radio name=" + n + " value=" + val + sel + "> " + text; } //onclick='opener.chkinfo();' 

function chkarr(j,arr) {
  var i,n=arr.length; for(i=0;i<n;++i) if(j==arr[i]) return(true); return(false); } 

function toprec(n,p,e,full) { 
//no., precision, threshold for E format: n>=10^e or n<10^-e,full precision: include trailing zeroes (e.g. 3.000, 0.0300)
  p=Math.abs(p);  
  var i,j,k=1,neg=(n<0)?"-":"",t=""; if(isNaN(n)) return n; n=Math.abs(n); if(n==0) return '0'; //n>=0
  for(i=1;i<p;++i) k*=10; //k=10^(p-1) NOT USED
  for(i=0;;++i) {if(n>=1) break; n*=10;} 
  if(i==0) {for(;;--i) {if(n<1) break; n/=10;} n*=10; ++i;} //mult by 10^i so n in {1,10}
  if(p>1) for(j=1;j<p;++j) n*=10; i=i+p-1; j=p-i-1; // i gives n in {k,10k}
  n=Math.round(n); t=n.toString(); // t is text for rounded n*10^i (p chars)
  // j is posn of . rel to std form x.y
  if(Math.abs(j)>e) return neg+t.charAt(0)+'.'+t.substring(1,p)+'E'+j; //use E format if >e from x.y
  if(i<0) for(;i<0;++i) t+='0'; if(i==0) return neg+t; //return 12340
  if(full==0) for(;i>0;--i,--p) {  //strip trail zeroes
    if(t.charAt(t.length-1)=='0') t=t.substring(0,t.length-1); else break; }  
  if(i==0) return neg+t; // return 1234
  if(i<p) return neg+t.substring(0,p-i)+'.'+t.substring(p-i,p); //return 123.4
  for(j=0;j<i-p;++j) t='0'+t; return neg+'0.'+t; } //return 0.001234

function userinfo(info) { INFO=info;
  if(!USERWIN || USERWIN.closed) USERWIN=fchkopen("","user"," width=800,height=400,resizable=yes");
  USERWIN.focus(); var d=USERWIN.document; d.close(); 
  var i,x,t="<title>LAPT User</title><h3>Please enter USER information to submit results and see Analysis :</h3>";    // 
//  [<a href='' onClick='self.close();return false'>close</a>]";
  t+="<i>The rows marked by asterisks are required for submission of results and comments.</i>";
  d.write(t); d.bgColor='#D0FFD0 ';
//alert(d.bgColor); 
  d.write("<form name=iform >");  
  d.write("<table border><tr><td colspan=2><b>*Institution (e.g. ucl or ucl.ac.uk): </b><input type=text size=50 name=inst value=\"",IDR,"\"> &nbsp;&nbsp;&nbsp;","</td>"); //B_ADDCOMM,
  d.write("<tr><td><b>Status/Year: &nbsp;</b></td><td><small>","(Univ): "); 
  for(i=1;i<STATUSArray.length;++i) d.write(radioc(STATUSArray[i] + " &nbsp;&nbsp;",i,STATUS==(i),"status"));
  d.write("</small></td><tr><td><b>Main Interest: &nbsp;</b></td><td><small>"); 
  for(i=1;i<TOPICArray.length;++i) d.write(radioc(TOPICArray[i] + " &nbsp;&nbsp;",i,TOPIC==(i),"subj"));
  d.write("</small></td><tr><td colspan=2><b>");
  d.write("Name / ID (voluntary): </b><input type=text size=50 name=ident value=\"",USR,"\"> &nbsp;&nbsp;","</td>");
  d.write("</table></form>");
  t="<i>NB results are accumulated during your session till you SUBMIT</i><br>Information is valuable for statistical purposes and improvement of exercises.<br>It will not be linked to personal records and we do not require personal identification.<p>";
//  t+= BUTT+"'CANCEL' name=user onclick='self.close(); return false;'> &nbsp; &nbsp;";
//  t+= BUTT+"'  OK  ' name=user onclick=\"x=opener.chkuserinfo(); if(x) alert(x); else {  opener.proceed(0); self.close(); return false;} \">";
  t+= BUTT+"'Cancel / Continue' name=user onclick='self.close(); return false;'> &nbsp; &nbsp;";
  t+= BUTT+"'Submit' name=user onclick='x=opener.chkuserinfo(); if(x) alert(x); else { opener.proceed(0); self.close(); return false;} '> &nbsp; &nbsp;";
  t+= BUTT+"'Finish without Submission/Analysis' name=user onclick='opener.SUBD=true; opener.finish(); self.close(); return false;'>";
  d.write(t); d.close(); d.iform.inst.focus();}

function chkuserinfo() { 
  var t="", f; if(!USERWIN) return("not yet"); f=USERWIN.document.iform; 
  USR=f.ident.value; IDR=f.inst.value; STATUS=getmultvalue(f.status); TOPIC=getmultvalue(f.subj); 
  if(IDR=="") t+="INSTITUTION: Please say NONE if you are not affiliated to any educational institution.\n\n";
//  if(STATUS<0) t+="STATUS :Please enter OTHER if you are not a student or teacher.";
  if(t!="") t="* Asterisks mark compulsory fields.\n\n" + t;
  return(t); }

//function chkinfo() { }
//  var f; if(USERWIN) { 
//    f=USERWIN.document.iform; IDR=f.inst.value;
//    STATUS=getmultvalue(f.status); TOPIC=getmultvalue(f.subj); } }  

//function okuserinfo() { return((!(IDR==""))&&(STATUS>-1)); }
function okuserinfo() { return(!(IDR=="")); }

function subform() { 
  var t=""; // chkinfo();
  if((!RESWIN)||RESWIN.closed) {proceed(3); return;}
  RESWIN.document.rform.submit();
//alert("T1: subform"+SUBD);
  SUBD=true; 
  display.document.close(); }

function proceed(info) { if(info) INFO=info; 
  if(!okuserinfo()) {userinfo(INFO); return;}
  if(INFO==1) getcomment(1); 
  if(INFO==2) getcomment(0); 
  if(INFO==3) resultform(false); 
  if(INFO==4) resultform(true); } 
 
function helpconf() { 
  var url="lpcfhelp.htm", name="CBM Help";
  if(HLPWIN && (!HLPWIN.closed)) HLPWIN.close(); 
  if(!HLPWIN || HLPWIN.closed) HLPWIN=fchkopen("","help","width=800,height=500,top=200,left=300,menubar=no,scrollbars=yes,resizable=yes");
//  if(!HLPWIN || HLPWIN.closed) HLPWIN=fchkopen("","help","");
  if(HLPWIN) {
    HLPWIN.location=PROG+url;
    HLPWIN.focus(); }
  }
//  if(focus) HLPWIN.focus(); } 

function helptips() { 
  var url="lptips.htm", name="LAPT-lite Tips";
  if(HLPWIN && (!HLPWIN.closed)) HLPWIN.close(); 
  if(!HLPWIN || HLPWIN.closed) HLPWIN=fchkopen("","help","width=800,height=500,top=200,left=300,menubar=no,scrollbars=yes,resizable=yes");
  if(HLPWIN) {HLPWIN.location=PROG+url; HLPWIN.focus();}
  }

function helpscore() { 
  t="lpscoring.htm?"+NFIRST+"?"+TOTFIRST+"?"+SCACC+"?"+SCK+"?"+SCCBS+"?"+(NRESP-NFIRST);
  HLPWIN=fchkopen(t,"help","width=900,height=600,top=100,left=100,menubar=no,scrollbars=yes,resizable=yes");
  d.close(); HLPWIN.focus();
  } 

function vcomments() { 
  var url="http://www.ucl.ac.uk/lapt/laptlite/results/comments/" + EXID + ".htm", name="LL Comments"; //results/comments/gcsemath.htm
  if(HLPWIN && (!HLPWIN.closed)) HLPWIN.close(); 
  if(!HLPWIN || HLPWIN.closed) HLPWIN=fchkopen("","comments","width=800,height=500,top=200,left=300,menubar=no,scrollbars=yes,resizable=yes");
  HLPWIN.location=url; 
  HLPWIN.focus(); }

function foccom() {
  COMWIN.document.cform.comments.focus();} 

//var T_COMMENTS = "<p>Enter your comment and save it:<br> <form name=cform method=POST action='" + SUBCOM + "'><textarea name=comments rows=2 cols=50></textarea><p><input type=button value='Save Comment' onclick='opener.storecomment(1); return true;'> <input type=button value='Cancel' onclick='opener.storecomment(0); return false'>";

function getcomment(a) {
//alert("model=" + REPLY.model + " > " +cleantxt(REPLY.model));
  if(!COMWIN || COMWIN.closed) {
    COMWIN=fchkopen("","comwin",""); if(! COMWIN) return; }
  COMWIN.focus();
  COMTAG="Context: S"+CS.qseq+",Q"+(QN+1)+","+SCREEN+","; 
  if(REPLY.model!="") COMTAG+="C"+REPLY.conf +",M"+REPLY.mark +", " +cleantxt(REPLY.text) +" FOR " + cleantxt(REPLY.model)+","; else COMTAG+=",,,";
//alert(QUESTIONS.length);
  if((QN>=0)&&(SCREEN!="i") && CQ && CQ.text) COMTAG+="LastQ: "+repZ(CQ.text)+",";
  var d=COMWIN.document; d.open();
  d.write("<form name=cform method=POST action='" + SUBCOM + "?"+EXID+"'>");
  loc=String(document.location).replace(/http:\/\/www.ucl.ac.uk\/lapt\/laptlite\/sys\/run.htm/i,"..");
  d.write("<input type='hidden' name='exid' value='"+EXID+"'>");
  d.write("<input type='hidden' name='usr' value='"+USR+"'>");
//  d.write("<input type='hidden' name='tag' value=\""+loc+","+COMTAG+" "+cvtdate(new Date())+"\"></form>");
  d.write("<input type='hidden' name='tag' value=\""+cvtdate(new Date())+", "+COMTAG+"\"></form>");
  d.close(); 
  d.cform.submit(); }

function chkcomment() {
  if(!COMWIN) return false;    // if(COMWIN!=undefined) { xxx better for IE5+?
  if(COMWIN==null) return false;    // if(COMWIN!=undefined) { xxx better for IE5+?
  if(COMWIN.closed) return false;    
// alert(COMWIN.focus); 
  COMWIN.focus(); 
  alert("You haven't saved or cancelled your last comment\n\nPlease do it now."); 
  if(COMWIN.closed) return false; COMWIN.focus(); return true; }

function storecomment(s) { 
  if(s>0) { //store if a comment
    var c = COMWIN.document.cform.comments;
    if((c!=null)&&(c.value!="")) { 
      c=cleantxt(c.value); c=c.replace(/\n/g , "|");
      c= COMTAG + c+", "+cvtdate(new Date());
      COMWIN.document.cform.submit();
      COMMENTS[COMMENTS.length] = c; SUBD=false; } }
//  if(!parent.okuserinfo()) parent.userinfo();
  if(SCREEN=="r") proceed(3); 
  if(s==0) COMWIN.close(); } 

function resultform(chk) {
//alert(RESWIN);
// open RESWIN
  if(RESWIN && !RESWIN.closed) RESWIN.focus(); // self.close();}
  if(!RESWIN || RESWIN.closed) {
    RESWIN=fchkopen("","reswin","width=800,height=600,menubar=no,toolbar=yes,resizable=yes,scrollbars=yes");
    if(! RESWIN) {
      alert("IMPORTANT !!\n\rYour system is blocking automatic submission. Click OK, then\n\r IMMEDIATELY click SUBMIT at the bottom of the window."); 
      return;
      } }
  RESWIN.focus(); var d=RESWIN.document; d.close(); d.bgColor='#FFFFB0';
  var i,t,tots="";
  var vname, c,i,n,loc,tim; d.close(); SCREEN="r"; tscore();
  var now=new Date(), mins=0;
  if(STARTTIME) mins=Math.round((now-STARTTIME)/600)/100; 
  loc=String(document.location); tim=cvtdate(now);
  loc=loc.replace(/http:\/\/www.ucl.ac.uk\/lapt\/laptlite\/sys\/run.htm/i,"..");
  if(chk) chkcomment(); n=COMMENTS.length;
  d.write("<title>Submit</title><h3>Submit Results for analysis and feedback</h3>");   
//LOCAL=false;
//alert("Hi2!"+NVIEW+"|");

  if(LOCAL) {
    t="<table><td valign='top'><b><large>Results:<br><br><br><br>Comments:</large></b></td><td><table border>";
    t+="<tr><td><i>Source: </i>" + EXID + " &nbsp;&nbsp;<i><b>Date, time= </b></i>" + tim + "<br>";
    t+="<i>Report:</i> <b>Qs=</b>" + NRESP +"<b> Correct=</b>" + NCORR +"<b> Score=</b>" +TOTAL;
    t+="<b> Comments=</b>",n,"<b> Time=</b>",mins," min ","<i>";
    d.write(t);
    d.write("<a href='' onClick='alert(opener.scoreinfo()+\"\\n\"+opener.TXT2);return false'>(Detail)</a><br>");
    d.write("User Info:</i><b> Institution=</b>",IDR);
    d.write("<b> Status=</b>",STATUS>=0 ? STATUSArray[STATUS] : "-");
    d.write("<b> Topic=</b>",TOPIC>=0 ? TOPICArray[TOPIC] : "-");
    d.write("<b> Ident=</b>",USR ? USR : "-"," <a href='' onClick='opener.userinfo(3);return false'><i>(Revise)</i></a></td><br>");
    d.write("<tr><td><table><tr>");
    if(n==0) d.write("<td><b><i>None</i><b></td>");
    else { 
      for (i=0 ; i<n ; ++i) { c = COMMENTS[i]; 
        d.write("<tr><td><small><b>" +(i+1)+": "+c +"</small></td>"); } }
    d.write("<tr><td> ",B_ADDCOMM,"</td></table></td></table>"); }// </td></table>
  else {
    t="Your results are being submitted.<br> If an error message appears, please check your network connection and click 'Submit'.";
    if(IDR=="webct") t+="<br><i>NB submission is essential for your score to be recorded within WebCT.</i>";
    d.write(t); }
  t="<p><i>Results and comments help to establish patterns of usage and improve exercises.<br>";
  t+="For a reply to a query or comment about this exercise, please email to </i><a href='mailto:";
  if(EMAILADD) t+=EMAILADD; else t+=EMAILDEF;
  t+= "'> " + EMAILADD + "</a> ";
  t+="<br><b>Submission site:</b> <select name='subsite' onchange='opener.chksub(selectedIndex);'>"; 
  for(i=0;i<SUBSITES.length;++i) 
    if(SUBSELECT==i) t+="<option value='" +SUBSITES[i] +"' selected>" +SUBNAMES[i] +"</option>";
    else t+="<option value='" +SUBSITES[i] +"'>" +SUBNAMES[i] +"</option>";
  t+="</select> <a href='' onclick='alert(\"" + SUBSITES[SUBSELECT] +"\"); return false;'><i>[url]</i></a>"; 
  d.write(t);
  t= "<form name=rform method=POST action='" + SUBSITES[SUBSELECT]+ "'>"; //  + B_SAVE;+ B_ADDCOMM   target='_blank'
  d.write(t);  
  t="<br><input type=button value='Submit Results to this Site' onclick=\"document.rform.submit(); opener.SUBD=true; return true; \">";
  t+=" &nbsp;&nbsp; <b>NB You need an open network connection to submit.</b><br>";
  t+="<p>Submission will give you a breakdown of your performance, and allow you to view comments on this exercise.<br><i> Successful submission should be acknowledged within a few seconds.</i>";
  t+="<i> If you get an alert like <b>'cannot find ..'</b> or <b>'connection refused ..'</b>, then check or open your internet connection (if you have one) and submit again.</i>";
  t+="<p><input type=button value='Skip Submission' onclick='opener.SUBD=true; self.close(); return false; '><p>";
  t+="<b>Copyright:</b> UCL, London WC1E 6BT. &nbsp;&nbsp;&nbsp;";
  t+="<b>System Problems:</b> email to <a href='mailto:cusplap@ucl.ac.uk'> cusplap@ucl.ac.uk </a><br>";
  d.write(t);
  if(NRESP>0) {i=Math.round(100*NCORR/NRESP); n=Math.round(50*TOTAL/NRESP);} else i=n=0; 
  t="<input type='hidden' name=REP value=\"" + loc + ", ";
  t+=NRESP +", "+i+"%, "+n+"%, "+COMMENTS.length+", "+mins+", "+IDR+", "+STATUS+", "+TOPIC+", "+tim+", ";
  t+=scoreinfo()+"\">";
//alert("NVIEW="+NVIEW+"\n\rPlease ignore this box and click OK");
  t+=" <input type='hidden' name='USR' value='" + USR + "'>"; //hidden
  t+=" <input type='hidden' name='COURSE' value='" + COURSE + "'>"; //hidden
  t+=" <input type='hidden' name='HEAD' value='" + HEAD + "'>"; //hidden
  t+=" <input type='hidden' name='EXID' value='"+EXID+"'>";
  t+=" <input type='hidden' name='rec' value='"+REC+"'>";
  t+=" <input type='hidden' name='vle' value='"+VLE+"'>";
  t+=" <input type='hidden' name='max' value='"+MAX+"'>";
  t+=" <input type='hidden' name='IDR' value='"+IDR+"'>";
  t+=" <input type='hidden' name='NCOM' value='" + COMMENTS.length + "'>";
  t+=" <input type='hidden' name='NVIEW' value='"+NVIEW+"'>";
  for (i=0 ; i<COMMENTS.length ; ++i) { 
    t+="<input type='hidden' name=C_"+(i+1)+" value=\""+loc+","+COMMENTS[i]+"\">"; }  
  t+=" <input type='hidden' name='NSEC' value='" + NDONE + "'>"; 
  u=USR; if(USR=="unknown") u="";
//alert(u);
  for (i=0 ; i<NDONE ; ++i) { 
    t+="<input type='hidden' name=S_"+(i+1)+" value=\""+u+","+DONETXT[i]+"\">"; }  
  t+="</form>"; d.write(t); d.close();
//alert("test1");
  if(!LOCAL) { 
    RESWIN.document.rform.submit();
//    if(IDR!='webct') alert("Hi! Your results are being automatically submitted for statistical use, to help provide a database to improve exercises. Thanks.");
    SUBD=true; RESWIN.focus();
//alert("test2");
    }
  }

function scoreinfo() { //nr,1,2,3,4,1+,2+,3+,4+
  var i,j,k,m=0,s,n,sc,u="",tots=new Array(); for(i=0;i<10;++i) tots[i]=0;
  if(QTYPE==2) t="-"; else t=""; t+=(TNQ+TNQQ);
  DONETXT=new Array(); 
  for(i=0;i<SECTIONS.length;++i) { 
    sc=SECTIONS[i].scores; n=nq=sc.length; nc=0;
    for(done=0,u="",j=0;j<n;++j) {
      k=sc[j]; u+=","+k; if(k==0) continue; //not viewed
      if(k!=5) done=1; //some data to record for this sect
      --nq; while(k>0) { s=k%10; k=(k-s)/10; ++nq;
        ++tots[Math.abs(s-5)]; if(s>5) {++tots[s-1]; ++nc;} } } //0,1,2,3,4,1+,2+,3+,4+
    if(done) {
      nc=Math.floor(100*nc/nq); DONETXT[m]=SECTIONS[i].qseq+","+nc+"%"+u; ++m;} }
  NDONE=m; TXT2=""; if(m>0) for(i=0;i<m;++i) TXT2+=DONETXT[i]+" | ";
  for(i=0;i<9;++i) {t+=","+tots[i]; if(i==4) t+=" ";} t+=" "; // t=all,0,1,2,3,4, 1+,2+,3+,4+
  for(i=0;i<5;++i) t+=","+(NS[i]-tots[i]); t+=" "; 
  for(i=1;i<5;++i) t+=","+(NC[i]-tots[i+4]); //add repeats at 0,1,2,3,4,1+,2+,3+,4+
  t+=","+TOTALCH+ ","+TOTALCHFIRST;
  return(t); }
      
function chksub(index) { 
  SUBSELECT=index; // RESWIN.close(); 
//alert("Hi" + RESWIN.closed); 
  resultform(false); }

function fchkopen(a,b,c) { 
  x=self.open(a,b,c); if(!x) alert("Can't open file: "+b+"\n\rDo you have popups blocked?"); 
  return x; }

function MM_calljs(jsstr) {return eval(jsstr);} // for r.pucci

function APPLET(attribs) { // & optional args: toptext, bottxt
  t='http://www.ucl.ac.uk/lapt/laptlite/sys/applet.htm?'+attribs; n=arguments.length;
  if(n>1) t+="?"+arguments[1]; //param
  if(n>2) t+="?"+ENCODE(arguments[2]);
  if(n>3) t+="?"+ENCODE(arguments[3]);
  APPLETWIN=open(t,"laptapplet","width=500,height=500,top=200,left=250,resizable=yes");
  if(!APPLETWIN) alert("Can't open Applet Window\n\rCheck you don't have popups blocked.");
  else APPLETWIN.focus(); }

function ENCODE(t) { t=t.replace(/'/g,"\""); t=encodeURI(t); return(t); }

var STAT=new Array(), ZZ1=new Array(), ZZ2=new Array();
function compareNumbers(a, b) { return a-b; } 
function Stat() {  
  var i,x,nm,nf,sum=ss=m=0., v=sd=sem=med=NaN, n=ZZ1.length;  
  if(n>0) {
    for(i=0;i<n;++i) { x=ZZ1[i]; sum+=x; ss+=x*x;}
    m=sum/n;  
    ZZ2=ZZ1; ZZ2.sort(compareNumbers);  
    nm=n/2.; nf=Math.floor(nm); med=ZZ2[nf]; if(nm==nf) med=0.5*(med+ZZ2[nf-1]); }
  if(n>1) {v=(ss-m*sum)/(n-1); sd=Math.pow(v,0.5); sem=sd/Math.pow(n,0.5);}
  STAT.n=n; STAT.mean=m; STAT.variance=v; STAT.stdev=sd; STAT.sem=sem; STAT.median=med; }
 

