function factors(n){ 

  return (n==6?[2,3]:n==12?[3,4]:n==15?[3,5]:n==18?[2,9]:n==20?[2,10]:n==24?[3,8]:[])};

function failsfactor(n,d){

  for(var i=0;i<factors(d).length;i++)

     {if(n%factors(d)[i]!=0)return factors(d)[i]}

  return 0;

};

function checkdiv(nb,fname){ 

  if(arguments.length==1)fname=nb.toString();

  var img=document["tickcrossD"+fname];

  with(eval("document.dtest"+fname))

  {

    var opt=ans.options[ans.selectedIndex].value;

        if(opt=='0' && (n.value%nb)==0 || opt!='0' && (n.value%nb)>0)

           {img.src= "tick.gif"; mark.value='Correct: ';  return true }

      else {img.src= "cross.gif";mark.value='Wrong: '  ;  return false}

}};

function randmult(N){

  var F=N;  

  var f=eval("document.dtest"+F);

  if(isNaN(N)){N=f.Dvsr.value};

  var tc=eval("document.tickcrossD"+F);

 f.mark.value='';

 tc.src='empty.gif';

 f.n.value=Math.floor(Math.random()*100000);

 if(Math.random()>0.5)f.n.value=f.n.value+9-f.n.value%N

};

function digitsum(n){  

  var dsum=0;while(n>0){dsum+=n%10;n=(n-n%10)/10};return dsum

};

function eleven(N){

  if(typeof N != "string")N=N.toString();

  var s=N.charAt(N.length-1), op="1";

    for(var i=N.length-2;i>=0;i--) 

     s=s+(op=-op,(op<0?"-":"+"))+N.charAt(i);

  return s

};

var isNetscape= window.navigator.appName.toLowerCase().indexOf("netscape")!= -1 ;

var maxDIGlen=15;
function MSG(xx){   var s,t="";
      if(arguments.length==1 && typeof arguments[0]=="object")s=arguments[0]
 else if( arguments.length>0)s=arguments;
 for(var i=0;i<arguments.length;i++)t=t+s[i];
 alert(t)
}; 
function DoErr(){return false};
function NoErr(){self.onerror=DoErr;return true} ;
function STOP() {self.onerror=NoErr;  xxhaltxx() };
function ERR(xx){ MSG(arguments);  STOP()};
function isOK(msg){ 
  if(arguments.length>1)msg=arguments.join('');
  if(!confirm(msg))STOP() 
};

var auxwin;

function auxwinOpen(params){
  if(arguments.length==0)params="";
  auxwin=window.open("","tip",params+"scrollbars=yes,status=no,width=400,height=300")
  auxwin.focus()  
};

function auxwinClose(){  auxwin.close()  };

function auxwinWrite(xx){
  for(var i=0;i<arguments.length;i++)auxwin.document.write(arguments[i]);
};

function auxwinHTML(params,backToWIN,xx){ //1st two params mandatory!
  auxwinOpen(params);
  for(var i=2;i<arguments.length;i++)auxwinWrite(arguments[i]);
  auxwinClose(backToWIN);
};

// ----
function isprime(N){ //returns a boolean
  if(N%2==0)return (N==2);
  var i=3,L=Math.sqrt(N),ct=0;
  var stime=(new Date()).getTime();
  while(i<=L && N%i!=0){i=i+2; ct++};
  var inctime=(new Date()).getTime()-stime;  //milltime as number of millisecs 
  return(N>1 && i>L)
};


function primefactors(N){ //return an (ordered) array of primes whose product is N
  //print with    primesfactors(INT).join(' x ')
    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 factors(N){  //return an array of all factors from 1 to N
  if(N==1)return [1];
  return cpfrom([],0,oLb(primefactors(N)),function(L){return eval(L.join('*'))})
   .sort(function(a,b){return a-b});
};

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 oLb(L){  //ASSERT L is ordered.  Return an array of 2-arrays [elt,freq]
  //where elts are in same order as first of each is in 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};
   return z.concat([[s,ct]]);
};

function EulerPhi(N){  //needs primefactors, oLb
  var pfs=oLb(primefactors(N));
  //isOK("Ephi of ",N," pfs=",pfs);
  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)};
  //isOK("EulerPhi of ",N," is ",phi);
  return phi
};

// ---

function put(X){  var s="";
  for(var i=0;i<arguments.length;i++)  s=s+arguments[i];
  s=s+"\r";  
  document.OUT.ans.value=document.OUT.ans.value+s;
};

function toolong(N){var ndigs=N.toString().length;
  if(timing[ndigs]>eval(document.calc.secs.value) &&
     !confirm(ndigs+" digit numbers might take up to "+Math.round(timing[ndigs])
        +" seconds to check if prime.  Is this OK?"))
     ERR() 
};

function checkSecs(){
   var s=parseInt(document.calc.secs.value);
   if(isNaN(s) || s<=0){document.calc.secs.value="5";ERR('Please give a NUMBER of seconds (reset to 5).')}
   document.calc.secs.value=s
};

var timing=new Array();

function dur(e){
  var stime,inctime;
  stime=new Date();eval(e);inctime=new Date();
  return (inctime.getTime()-stime.getTime())/1000
}
function timeit(){ 
    var timeBase=10;
    for(var i=1;i<timeBase;i++)timing[i]=0;
    timing[timeBase]=dur('isprime(9999999967)');
    for(var i=1;i<=maxDIGlen;i++)
         timing[i]=timing[timeBase]*Math.pow(Math.sqrt(timeBase),(i-timeBase));
};

function init(){ timeit() };

function getn(){  
  var str=document.calc.n.value;
  var nbsRAW=str.replace(/\s|,|\./g,"").match(/\d+/g); 
  var nbs=nbsRAW;  
  if(!nbs || typeof nbs!="object" || nbs.length==0)
      ERR("I didn't find any numbers in the\n'Number or range' box.\nPlease enter a number and try again.");
  if(nbs[0].length>maxDIGlen || nbs[0].length>maxDIGlen)
        ERR("Number is too large (must be ",maxDIGlen," digits or less)");
  for(var i=0;i<nbs.length;i++)nbs[i]=eval(nbs[i]);
  if(nbs.length==2)
      {if(nbs[1]<nbs[0])
         ERR("The end of the range ("+nbs[1]+") is less that its start ("+nbs[0]+")")}
  else if(nbs.length==1)nbs[1]=nbs[0]
  else if(nbs.length==0)ERR("Type a number into the 'Number(range)' box first.")
  else ERR('You have given me ',nbs.length,' numbers: please give just 1 (2 for a range)');
  if(nbs[1]-nbs[0]>500 && 
   !confirm("Please confirm that you want me to check all "+eval(nbs[1]-nbs[0])+" numbers in the range "+nbs[0]+" to "+nbs[1]+"."))
    STOP(); 
  return nbs  
};

function doprimefactors(){ 
  var N=getn(); 
  var lo=N[0], hi=N[1];
  toolong(N[1]);
  put();
  for(var I=lo;I<=hi;I++)
  { 
    var f=primefactors(I);
    put(I," = ",f.join(' x '))
  };
};

function dofactors(){
  var n=getn();
  var lo=n[0], hi=n[1];  toolong(n[1]); 
  put();
  for(var i=lo;i<=hi;i++)
    {var fs=factors(i);
     put(i," has ",fs.length," factors: ",fs)
    }
};

function doprimes(){
  var prms=new Array(),i;
  var rng=getn(); 
  var lo=rng[0],hi=rng[1]; toolong(hi); 
  put();
  if(lo==hi)put(lo," is ",(isprime(lo)?"":"not "),"prime")
  else {
        for(i=lo;i<=hi;i++)
          {if(isprime(i))prms=prms.concat(i)};
         put("There ",(prms.length==1?"is ":"are "),
             (prms.length==0 ?"no":prms.length)," prime",
             (prms.length==1?"":"s")," between ",lo," and ",hi,(prms.length>0?":": "."),
             (prms.length==1?prms:""));
         if(prms.length>100)
             {if(confirm("List all "+prms.length+" primes?"))put(prms)}
         else if(prms.length>1) put(prms)
       }
};

function dogoldbach(){
   var nn=getn();  
   var lo=nn[0],hi=nn[1];
   if(lo<6)
     {lo=6;if(hi<lo)hi=6;
      put('Minimum value in range reset to 6 which is ',
          'the lowest even number that is the sum of two primes.');
      };
   if(lo==hi && lo%2==1)
      {put('The "Sum of 2 odd primes" button only works on EVEN numbers');return}
   put();
   for(var i=lo;i<=hi;i++)  goldbach(i)
};

function goldbach(n){ 
  var onlyOne=true;
  if(n%2==1)return;      toolong(n);
  var twoprimes=new Array();
  for(var i=2;i<=n/2;i++)
     if(isprime(i) && isprime(n-i))
        {twoprimes=twoprimes.concat(i+" + "+(n-i))
         if(onlyOne)break};
  put(n," = ", twoprimes[0]);
};

function auxwinOUT(which,xx){
  auxwinOpen();
  auxwin.document.open();
  auxwinWrite("<html><head><title>Help for: ",which,"</title></head>",
   "<style>BODY{background-color:#fff9cb; color:#000000; font-size:10pt; font-family:Verdana, monospace}</style>",
    "<body>", // bgcolor='#fff9cb' text='#000000'><font size=2> 
    "<div align=center>");
  for(var i=1;i<arguments.length;i++)auxwinWrite(arguments[i]);
  auxwinWrite("<hr><form><input type='button' value='Back to Primes Calculator' onClick='window.close()'></form></div><script src='http://www.google-analytics.com/urchin.js' type='text/javascript'></script><script type='text/javascript'>_uacct = 'UA-2036050-1';urchinTracker();</script></body></html>");
};


function popUpWindow(which){
  if(which=="Test")
      auxwinOUT("","Primes Calculator","<p>Help on the word and its meaning<br> and examples will appear in this window.<p>")
   else if(which=="Number Entry")
      auxwinOUT(which,"<h3>Entering a Number</h3>You can enter numbers which are up to <b>",
                  maxDIGlen," digits long</b>.<br>",
          "You can use commas(,) or a dot(.) or spaces in the numbers if you want.",
          "<br><b>Examples</b><br>All the following are valid ways of writing one million:<br>",
          "<b>1000000</b>  or  <b>1 000 000</b>  or   <b>1,000,000</b> or <b>1.000.000</b><P>",
          "<H3>Entering a RANGE of Numbers</h3>",
          "If you want to use the same button on a sequence of numbers,<br> separate the two numbers",
          " which define the <b>range</b> by '-'<br> or any characters <b><i>except</i></b>",
           " digits, spaces, dots and commas.<br><b>Examples</b><br>",
          "<b>10 - 20</b>  will apply a button operation to 10,11,...,19,20<br>",
          "  <b>2,000 to 2,100</b> represents 101 numbers starting at 2000.")
   else if(which=="Prime")
      auxwinOUT(which,"<h3>A number is <b>prime</b> if</h3>",
              "the only numbers that divide into it exactly (its <i>factors</i>) are",
              "1 and itself.<p>",
              "<b>Examples</b><br> 5 is <b><i>prime</i></b> since its only factors are 1 and 5.<br>",
              "12 is <b><i>not prime</i></b> since 2, 3 and 6 also divide into 12 exactly",
              " as well as 1 and 12.")
   else if(which=="Prime Factors")
      auxwinOUT(which,"<h3>A <b>prime factor</b> of a number</h3> is one that is",
             " <i>both</i> prime <i>and</i> divides exactly",
       " into the number.<p><b>Examples</b><br>",
       "2 is a <b><i>prime factor</i></b> of 12<br>",
       "3 is a <b><i>prime factor</i></b> of 12<br>",
       "6 is not a <b>prime factor</b> of 12 since although it is a factor, 6 is not prime.<br>",
       "7 is not a <b>prime factor</b> of 12 even though it is a prime because it is not also a factor of 12.")
   else if(which=="Factor")
      auxwinOUT(which,"<h3>A <b>factor</b> of a number</h3>",
             " is a number that divides into it exactly.<p>",
            "<b>Examples</b><br> 6 is a factor of 12 since 12 = 2 x 6 i.e. 12/6 is a whole number<br>",
             "2 is a factor of 12 since 12 = 6 x 2 i.e. 12/2 is a whole number<br>",
             " 8 is not a factor of 12 since 12/8 is 1.5 which is not a whole number.")
   else if(which=="Goldbach's Conjecture")
      auxwinOUT(which,"<h3>Is every <i>even</i> number (bigger than 5) the <i>sum</i> of",
         " two <i>odd</i> primes?</h3><b>Examples</b><br>",
         "<table><tr><td align=right>6 =</td><td> 3 + 3</td></tr>",
            "<tr><td align=right>8 =</td><td> 3 + 5</td></tr>",
           "<tr><td align=right>10 =</td><td> 3 + 7</td></tr>",
          "<tr><td align=right>10000 =</td><td> 59 + 9941</td></tr></table><p>",
         "<i>Christian <b>Goldbach</b></i> in 1742 said that this question",
            " <b>always</b> has the answer <i>Yes</i> and so it is called",
         " <a href='http://www-groups.dcs.st-and.ac.uk/~history/Mathematicians/Goldbach.html' ",
        "target='_blank'>Goldbach's Conjecture.</a><p>",
          "No one has yet found a mathematical proof that he is correct even though no",
         " even number bigger than 5 has been found that <i>cannot</i> be written in this way.");
};
