var global_js_version="2 August 2010";// (c) Dr R D Knott  enquiry (AT) ronknott (DOT) comvar Phi = (Math.sqrt(5)+1)/2 ,  phi = (Math.sqrt(5)-1)/2, Pi=Math.PI;var unsure=0,present=1,absent=0; // states for searchingvar myErr=false; //self.onerror=function(ErrMsg,URL,LineNb){if(myErr){halt(ErrMsg+"\r");return true}else{return false}};function halt(msg){if(msg&&msg.toString().length>0)alert(msg);ERROR()};function DoERROR(){return false};function resetERROR(){self.onerror=DoERROR;return true};function HALT(msg){alert("**Error**\r"+msg);//self.onerror=resetERROR;   ERROR();};function ignoreERROR(){self.onerror=function(){return true}};//ignoreERROR()function jsERROR(){self.onerror=function(){return false}};function equalArrays(a1,a2,opts){//opts: shortest (ignore length check)  var Opts=getopts(opts);  if(!Opts.shortest  &&  a1.length!=a2.length)return false;  var eq=true;  for(var i=0;eq&&i<a1.length&&i<a2.length;i++)eq=a1[i]==a2[i];  // putmsg('%%  equalArrays '+a1+(eq?" == ":" != ")+a2) return eq};function inArray(elt,A){  var found=false;  for(var i=0;!found && i<A.length;i++)    found=A[i]==elt;  return found};function ECHO(txt){alert(txt);return txt};//  ARGUMENTS and Optionsfunction getArgs(opts){  if(arguments.length==0)opts=location.search.substring(1);   //alert("getArgs "+opts);  var args=new Object();  var pairs=opts.split(",");  //if(pairs.length>0)alert("getArgs "+pairs);  for(var i=0;i<pairs.length;i++)  { var pos=pairs[i].indexOf("=");	if(pos==-1)args[pairs[i]]=true  //allow ids with no values	else args[pairs[i].substring(0,pos)]=pairs[i].substring(pos+1);   };   return args }; function getopts(opts){ //options as string of {,fld[=val]}*  var args=new Object();  if(opts==undefined)return args;  var pairs=opts.split(",");  //if(pairs.length>0)alert("getArgs "+pairs);  for(var i=0;i<pairs.length;i++)  { var pos=pairs[i].indexOf("=");	if(pos==-1)args[pairs[i]]=true  //allow ids with no values	else args[pairs[i].substring(0,pos)]=pairs[i].substring(pos+1);   };   return args}function objdump(obj,seperator){var s="";  if(arguments.length<2)separator="; ";  for(var prop in obj)    {//if(!confirm("<"+(typeof obj[prop])+">"))halt();     if(inArray(typeof obj[prop],["function","object"])||        prop=="innerHTML")s+=prop+": ["+(typeof obj[prop])+"];"     else s+=prop+" "+(typeof obj[prop])+": "+obj[prop];     s+="<br>"    };  return s };//SELECT and OPTIONS shortcutfunction getId(id){  var it= document.getElementById(id);  if(!it||it==undefined)halt('@@ cannot getId '+id);  return it};function getIdval(idnm,newval){  var it=getId(idnm);  var old=it.value;  if(arguments.length==2)it.value=newval;  return old}function setId(idnm,fldvals){ //fldvals: prop=val LIST var obj=document.getElementById(idnm); var pairs=fldvals.split(",");  //if(pairs.length>0)alert("getArgs "+pairs); for(var i=0;i<pairs.length;i++)  { var pos=pairs[i].indexOf("=");    var p=(pos==-1?pairs[i]:pairs[i].substring(0,pos)),        v=(pos==-1?true:pairs[i].substring(pos+1));     //alert(idnm+" "+p+": "+obj[p]+" > "+v);	 obj[p]=v  //allow ids with no values	}}; function getSELval(selIDname){ var s=document.getElementById(selIDname); if(!s||!s.options)halt("@@ getSELval called on non-SELECT object id "+selIDname); s=s[s.selectedIndex]; return s.value};var outF;function clearmsg(F){ if(arguments.length==0)F=outF;    document.getElementById('msg'+F).innerHTML=''};   function putmsg(txt,br){     if(arguments.length==0)txt="";   if(arguments.length<2)br=true;   // if(arguments.length>1)txt=arguments().join("");   var olist = document.getElementById('msg'+outF);        olist.innerHTML += txt+(br?"<br>":"");        olist.scrollTop = olist.scrollHeight;        olist.scrollLeft=0;};function clearForm(FormNm){ var Form=document.getElementsByName(FormNm); //if(Form.length>0)halt("@@ "+FormNm+" is used more than once!"); Form=Form[0]; //putmsg(objdump(Form),"<br>");  //alert("name: "+Form.name+" id: "+Form.id); //alert(Form.elements.length+" elemens"); for(var i=0; i<Form.elements.length; i++)   { //if(!confirm(Form.elements[i].type+": "+Form.elements[i].id+"="+Form.elements[i].name))halt()     if(Form.elements[i].type=="text")       Form.elements[i].value="";   }};function spn(clas,str){return "<span class='"+clas+"'>"+str+"</span>"};function mathspan(str){return spn('math',str)};function isInt(i){return i.toString()!="" && i.toString().indexOf(".")==-1  &&i.toString().toLowerCase().indexOf("e")==-1  && !isNaN(i) && isFinite(i) && ((eval(i)+1)!=i)};function isNb(r){return r!="" && !isNaN(r) &&isFinite(r)};function log10(x){return Math.log(x)/Math.LN10}; function logB(B,x){return Math.log(x)/Math.log(B)};function logBase(B,x){return logB(B,x)};function ln(x){return Math.log(x)};function range(lo,hi){  if(lo>hi)halt("@@ range called on illegal range params");  var a=new Array(hi-lo+1);  for(var i=lo;i<=hi;i++)a[i-lo]=i;  return a };function chooseRfromRange(N,Lo,Hi,Pre,Process){// choose N items from array Items delivering an ARRAY of choices (array) // putmsg("choose "+N+" from "+Lo+rangech+Hi+" pre="+Pre);  if(N==0) {Process(Pre);return};  var nb=Hi-Lo+1,ans=new Array();  if(N<0)halt("@@ setrem called with negative count");  if(N>nb)return;   for(var i=Lo;i<=Hi;i++)    {//putmsg(" psh "+i);     Pre.push(i)     chooseRfromRange(N-1,i+1,Hi,Pre,Process);     Pre.pop()    }};   function maxInArray(arr){   if(arr.length==0)halt("@@ Empty array passed to maxinArray")  var m=arr[0];  for(var i=1;i<arr.length;i++)    m=Math.max(m,arr[i])  return m};function zeroArray(a,zero){ // all arrays are passed by reference  if(arguments.length<2)zero=0;  for(var i=0;i<a.length;i++)a[i]=zero}; function gcd(a,b){  return gcd1(Math.abs(a),Math.abs(b))  };function gcd1(a,b){     do{     if(a==0) return b      else if(b==0) return a      else var aa=a;a=b%a;b=aa     }while(true)};//var test=new Array("gcd(0,2)","gcd(2,0)","gcd(12,15)","gcd(144,89)");//for(var i=0;i<test.length;i++)alert(test[i]+" = "+eval(test[i]));function lcm(a,b){ return a/gcd(a,b)*b };function powmod(Base,Pow,Mod){   var pm;         if(Pow==0)pm= 1  else if(Pow==1)pm= Base%Mod  else if(Pow>1)       {var s=powmod(Base,Math.round((Pow-Pow%2)/2),Mod);        var ss=mul(s,s)%Mod;        pm= (Pow%2==0 ? ss : (Base*ss)%Mod )  } ;  return pm     };function isprime(N){   if(N%2==0)return (N==2);  var i=3,L=Math.sqrt(N);  //var stime=(new Date()).getTime();  while(i<=L && N%i!=0){i=i+2}; // var inctime=(new Date()).getTime()-stime;    return(N>1 && i>L)};function primefactors(N){       if(N==1)return [1];    var f=new Array(), II=N,L=Math.sqrt(N);    while(II%2==0){f=f.concat(2);II=II/2;L=Math.sqrt(II)};    for(var i=3;i<=L;i=i+2)       while(i<=L && II%i==0){f=f.concat(i);II=II/i;L=Math.sqrt(II)};    if(II>1)f=f.concat(II);    return f};function cpfrom(PrevAnss,Li,L,F){    if(L.length==Li)return F(PrevAnss);   var ans=[];   for(var i=0;i<=L[Li][1];i++)      ans=ans.concat(cpfrom(PrevAnss.concat(Math.pow(L[Li][0],i)), Li+1, L, F));   return ans};function ordlistToZbag(L){       var s=L[0],ct=1,i,z=[];   for(var i=1;i<L.length;i++)     if(L[i]==s)ct++     else {z=z.concat([[s,ct]]);s=L[i];ct=1};   z=z.concat([[s,ct]]);    return z};function EulerPhi(N){    var pfs=ordlistToZbag(primefactors(N));  var phi=1,i=0;  while(i<pfs.length)  {var pr=pfs[i][0],po=pfs[i][1]; i++; phi=phi*Math.pow(pr,po-1)*(pr-1)};  return phi};function countdivisors(N){  if(N==1)return 1;  var pfs=ordlistToZbag(primefactors(N));  var d=1,i=0;  while(i<pfs.length)  {var po=pfs[i][1]; i++; d=d*(po+1)};   return d};function factors(N){    if(N==1)return [1];  return cpfrom([],0,ordlistToZbag(primefactors(N)),function(L){return eval(L.join('*'))})   .sort(function(a,b){return a-b});};function strip(s,remCh){  if(arguments.length==1)remCh=" ";  var i=0;while(i<s.length && s.substring(i,i+1)==remCh)i++;  return s.substring(i)};  function endswith(s,x){if(typeof s != "string")s=s.toString(); if(typeof x != "string")x=x.toString();  if(s.substring(s.slength-1)==" ")s=revstr(strip(revstr(s)));  if(s.length>=x.length){return s.substring(s.length-x.length)==x }else{return false}};  function beginswith(s,x){ if(typeof s != "string")s=s.toString(); if(typeof x != "string")x=x.toString();  s=strip(s," ");  if(s.length>=x.length){return s.substring(0,x.length)==x }else{return false}}; function revstr(r){var s="";for(var i=0;i<r.length;i++)s=r.charAt(i)+s;return s};  function repstr(nbreps,str){//return "" if nbreps==0 var s=""; for(var i=0;i<nbreps;i++)s+=str; return s};function randint(lo,hi){ with(Math){return floor(random()*(hi-lo+1))+lo} };function randelt(vals){   if(arguments.length==1)      {if(typeof vals=="object")return vals[randint(0,vals.length-1)]       else if(typeof vals == "string")return randelt(vals.split(""));      }   else return arguments[randint(0,arguments.length-1)]};function evalstr(fld,caught)  {if(arguments.length<2)caught="null";   with(Math)   try{var i=eval(fld.replace(/(^|[^0-9])0*([1-9])/g,"$1$2")                  .replace(/infinity/g,"Infinity")                  .replace(/(\d+)\^(\d+)/g,"pow($1,$2)")                  .replace(/pi/ig,"Math.PI"))       }catch(e){eval(caught)};   //alert('evalstr-> '+i)   return i};function pisano(m){ // Renault's code!  var a = 0, b = 1,  c = (a+b)%m,k = 1,z;   while(b != 0){    	a = b; b = c; c = (a+b)%m;k++;	}    z=1;	if (k%2 == 1){k = k*4; z = 4;}	else {if (c != 1){k = k*2; z = 2;}	}    if (m == 2){k = 3; z = 1;}    return k};   //WYTHOFF ARRAYfunction wyth(r,c){return Math.floor( (r+1)*Phi )*fib(c+2) + r*fib(c+1) };function findWcol(n){var zinds=zeckinds(n);return zinds[zinds.length-1]-2};function findWrow(n){var c=findWcol(n),r=0;while(wyth(r,c)<n)r++;return r};//ZECKENDORF REPfunction zeckinds(n){       var zinds=new Array(),i=2;	   while(fib(i)<=n)i++;i--;	   do{ zinds[zinds.length]=i;		   n=n-fib(i);		   if(n==0)return zinds;		   while(fib(i)>n)i--;		  }while(true);	};function zbits(zis)	{var bits="",zi=0;	   if(zis.length==0)return "0"	   else for(var i=zis[0];i>1;i--)if(i==zis[zi]){bits+="1";if(zi<zis.length)zi++}else{bits+="0"};	   return bits	};	// STOLARSKI ARRAYfunction stol(r,c){         if(c==0){a= Math.floor((r+0.5)*Phi)+r+1}    else if(c>=1){var a=stol(r,0);for(var i=1;i<=c;i++)a=Math.round(a*Phi)};    return a    };    function findSrc(n){var c=0,nn;     do{nn=Math.round(n/Phi);        if(Math.round(nn*Phi)==n){c++;n=nn;}        else break;       }while(true);     r=Math.floor((n+Phi/2)/(1+Phi));    return [r,c]  };function findSrow(n){return findSrc(n)[0] };function findScol(n){return findSrc(n)[1] }; //INPUT NUMBERS  function checkinput(fld,nm,opts){  // default: eval input, or include opt "noeval"   var i,res;//alert("checkinput "+fld+" "+nm);   var opts=arguments.length<3?new Object():getArgs(opts);   if(!opts.emptyval)opts.emptyval=""; //Empty always allowed (when clicking on (?) button; use 'emptyval=NaN' otherwise    //alert(typeof opts.noeval);   if(!opts.hasOwnProperty("noeval"))opts.noeval=false;   //alert(fld);   fld=fld.replace(/\s/g,"");   //alert("< "+fld+" "+nm);   if(fld=="")return opts.emptyval;   if(!opts.noeval)       {var xtra=fld.replace(/sqrt/g,"").replace(/[Ii]nfinity/g,"").replace(/pi/gi,"").replace(/[0-9eE\.\-\*\/+\(\)\^\s]/g,"")         // if(xtra!="" )         //     halt(nm+": Only numbers, fractions, E, Pi, +,-,*,/, sqrt, Infinity and -Infinity are allowed in input boxes\nFound "+xtra)              // don't allow trig fns etc          //else                i=evalstr(fld,                  'halt("I do not understand your input to '+nm+' Please change it")');                if(opts.eval&&isNaN(i))         {//alert(nm+" is NaN");            if(fld=="") i=opts.emptyval // empty fields always allowed as input ELSE use:-           //else if(isemptyinput(fld))halt("The "+nm+" input box must have a value typed in.")         else halt("No number found for "+nm)         };         res=i        }     else res=fld;   //alert(nm+" Noeval="+opts.noeval+" = "+res);   return res }; function isemptyinput(str){return str.replace(/\s/,'')==''};var maxdps=Math.PI.toString().length-2;function pad(used,requd){ if(typeof used != "string")used=used.toString();  used=used.length;  return (requd<=used?"":"                    ".slice(0,requd-used).replace(/ /g,"&nbsp;"))};function fw(n,fwd,pad){ if(arguments.length<3)pad=" ";   var s=n.toString(); while(s.length<fwd)s=pad+s;  return s};function fw2(n){  if(n<10){return " "+n   } else return n};// HIDE & SHOW// POP UPSfunction clickedAt(e){  var pos=new Object();    if (!e) var e = window.event;	if (e.pageX) 	{pos.x = e.pageX;pos.y = e.pageY;}	else if (e.clientX) 	{		pos.x = e.clientX + document.body.scrollLeft			+ document.documentElement.scrollLeft;		pos.y = e.clientY + document.body.scrollTop			+ document.documentElement.scrollTop;      }   else {pos.x=e.clientX;pos.y=e.clientY};  alert('clicked '+pos.x+" "+pos.y);  return pos};function moveObjectToClick(e,obj){	 var where=clickedAt(e);	 if(typeof obj=='string')id=document.getElementById(obj);	 alert("click at "+obj.name+" to "+where.x+","+where.y);	obj.style.left = where.x; 	obj.style.top  = where.y; };function showAtClick(e,id){moveObjectToClick(id); alert(is+" is moved");showId(id)};//<A href="javascript:;" onClick="showAtClick(event,'n1');">Pop-up available here.</A>function popupID(fldnm,pos,winsizex,winsizey){   //if(!pos)alert('clicked at '+clickedAt());   if(arguments.length<3){winsizex=400;winsizey=350};    var w=window.open("","tip","scrollbars=no,resizable=yes,menubar=no,"     +"status=no,toolbar=no,dependent=yes,location=no");     w.blur();   //  alert('resz +winsizex+","+winsizey);    w.resizeTo(winsizex,winsizey);    if(pos&&pos.x)w.moveTo(pos.x,pos.y)    else w.moveTo(200,100);     w.document.open();    w.document.writeln("<html><head><link rel='stylesheet' type='text/css' href='../global.css'>  "    +"</head><body class='popupwin' style='overflow:auto'>"    +(fldnm     ?document.getElementById(fldnm).innerHTML     :		"You can enter Numbers or Expressions:<dl>"+		"<dt>Operations:<dd> + - * / <dt>Constants:<dd> E PI Phi phi "+		"<dt>Functions:<dd> <ul><li>abs(real),pow(num,power),sqrt(real)</li>"+		"<li>sin,cos,tan,asin,acos,atan,</li><li>exp,log,log10,logBase(b,x)</li>"+		"<li>gcd(a,b),lcm(a,b),powmod(x,toPow,mod),EulerPhi</li><li> ... </li></dl>"     )    +" <input type=button value='Close window' onClick='window.close()')></body>");    w.document.close();      w.focus()          return w}	function showMoreOrLess(divId,incdec){ //needs a hidden field divId+"depth" containing the depth in em    var //v=document.getElementById(divId+"depth").value,       newd,       v=document.getElementById(divId).style.height.replace("em","");    if(!isNaN(v))    {  newd=eval(v)+incdec; //alert(newd);       if(newd<15)newd=15;       //alert("ht="+v+" new="+newd);       //v=newd;       document.getElementById(divId).style.height=newd+'em'}   }function showhideIdBTN(info,btnID){   if(arguments.length==1)btnID=info;   if(document.getElementById(btnID).value.match('Hide'))   {if(arguments.length==2)document.getElementById(info).style.display='none';    document.getElementById(btnID).value= document.getElementById(btnID).value.replace('Hide','Show')   }else   {if(arguments.length==2)document.getElementById(info).style.display='block';    document.getElementById(btnID).value= document.getElementById(btnID).value.replace('Show','Hide')   };   document.getElementById(btnID).blur();};function hideId(nm) { if(arguments.length==0)nm="Soln";        if (document.getElementById) {document.getElementById(nm).style.visibility = "hidden";}   else if (document.all) {document.all[nm].style.visibility = "hidden";}   else if (document.layers) {document[nm].visibility = "hide";}   else {var w=eval(nm).style;w.visibility="hidden"};};function showId(nm) {if(arguments.length==0)nm="Soln";	     if (document.getElementById) {document.getElementById(nm).style.visibility = "visible"; }     else if (document.all) {document.all[nm].style.visibility = "visible"; } 	else if (document.layers) {document[nm].visibility = "show"; } 	else {var w=eval(nm).style;w.visibility="visible"};};function setStyle(nm,valpair) {if(arguments.length==0)nm="Soln";   var attr=valpair.slice(0,valpair.indexOf(":")),attrval=valpair.slice(valpair.indexOf(":")+1);        if (document.getElementById) {document.getElementById(nm).style[attr] = attrval }     else if (document.all) {document.all[nm].style[attr] = attrval } 	else if (document.layers) {document[nm][attr] = attrval } 	else {var w=eval(nm).style;w[attr]=attrval};};function findpos(obj){  var curleft=0,curtop=0;  if (obj.offsetParent)     do {			curleft += obj.offsetLeft;			curtop += obj.offsetTop;    } while (obj = obj.offsetParent);  return [curleft,curtop];}/////////////// SET Objectfunction isEltOfArray(elt,a){  var found=false;  for(var i=0;!found&&i<a.length;i++)found= a[i]==elt;  return found};  function SET(els){ if(els.setsize)  //copy SET   {this.elts=els.elts.slice();    this.setsize=elts.setsize;    return}; this.elts=new Array(); for(var i=0;i<els.length;i++)   if(!isEltOfArray(els[i],this.elts))this.elts.push(els[i]); this.setsize=this.elts.length;};SET.prototype.newElt=function(e){this.elts.push(e);this.setsize++};function isInSET(e,s){ return isEltOfArray(e,s.elts) };function SETunion(s1,s2){  var u=new SET(s1);  for(var i=0;i<s2.setsize;i++)     if(!isInSET(s2.elts[i],u))u.newElt(s2.elts[i]);  return u}  /////////////////// ARR Object - Array allowing -ve indicesfunction ARR(lo,hi,mt){//a JS array type which allows -ve indices//putmsg("ARR "+lo+" "+hi+" "+mt)  if(arguments.length<3)mt=0;  this.empty=mt;  this.lwb=lo;this.upb=hi;  this.elts=new Array(hi-lo+1);for(var i=0;i<hi-lo+1;i++)this.elts[i]=this.empty;  this.length=this.upb-this.lwb+1;  this.at=function(i){if(this.inrange(i)){return this.elts[i-this.lwb]} else return this.empty};  this.set=function(ind,val){          if(ind<this.lwb){var extra=new Array();for(var i=this.lwb-1;i>=ind;i--)extra[i-ind]=this.empty;this.lwb=ind;                 this.elts=extra.concat(this.elts)}     else if(ind>this.upb){var extra=new Array();for(var i=0;i<ind-this.upb;i++)extra[i]=this.empty;this.upb=ind;                 this.elts=this.elts.concat(extra)}     this.elts[ind-this.lwb]=val};  this.inc=function(i,addon){var currval=this.at(i);this.set(i,currval+addon)};  this.inrange=function(i){return i>=this.lwb && i<=this.upb};  this.toString=function(){return this.elts};  this.inrng=function(lind,rind){           return this.elts.slice(lind-this.lwb,rind-this.lwb+1)} }  function changeOpac(opacity, id) {    var object = document.getElementById(id).style;    object.opacity = (opacity / 100);     object.KhtmlOpacity = (opacity / 100);}function RANGE(f,t){	this.from=f;	this.to=t;	this.size=t-f+1;};RANGE.prototype.toString=function(){    return (this.from==this.to?this.from:this.from+rangech+this.to) }function RANGEby(f,len){  return new RANGE(f,f+len-1)  };function stringhasRANGE(str,sub){  // alert(str+" :: "+sub)  return RANGEby(str.indexOf(sub),sub.length) };function blendimage(divid, imageid, imagefile, millisec) {    var speed = Math.round(millisec / 100);    var timer = 0;        //set the current image as background    document.getElementById(divid).style.backgroundImage = "url(" + document.getElementById(imageid).src + ")";        //make image transparent    changeOpac(0, imageid);        //make new image    document.getElementById(imageid).src = imagefile;    //fade in image    for(var i = 0; i <= 100; i++) {        setTimeout("changeOpac(" + i + ",'" + imageid + "')",(timer * speed));        timer++;    }} function changeStyle(objID,stypairs){ // style:value separator=;  var S=document.getElementById(objID).style;  var pairs=stypairs.split(";");  for(var i=0;i<pairs.length;i++)  { var pos=pairs[i].indexOf(":");	if(pos==-1)S[pairs[i]]=true  //allow ids with no values	else S[pairs[i].substring(0,pos)]=pairs[i].substring(pos+1);   };};function changeProp(objID,proppairs){  //prop=value separator=,  var S=document.getElementById(objID);  var pairs=proppairs.split(",");  for(var i=0;i<pairs.length;i++)  { var pos=pairs[i].indexOf("=");	if(pos==-1)S[pairs[i]]=true  //allow ids with no values	else S[pairs[i].substring(0,pos)]=pairs[i].substring(pos+1);   };};
