/* This library contains functions that support the "E2" tools. The E2 tools are designed to work with SPEC files.
   Note that this library uses functions in several other javascript libraries --  including 
   svyinputs.js and (indirectly) xmlRequest2b.js
   See the bottom of the file for a list of function (with a 1 line description of what they do)
*/  
/* --------------------------------------

Note: this is the typical GET request that a client uses to start a session:
http://127.0.0.1/dsurvey/client/defaultStart.html?
        instrument=PICK6&
        sessionName=s21&
        myID=5906315675527439=&
        myRefID=&3333333333
        myName=A&
        myNickName=FatAlbertA& 
        myContact=fat@aol.com&
        resubmitOkay=0&                 (or resubmitOkay=0CYCLE, or other such combo)
        debugMode=1

)

 Note: usage of the E2 tools REQUIRES that the E2_start function be called as soon as the main page is loaded -- say, by using an
       onLoad="E2_start()"  in the main page's <BODY> 

E2_start does a number of actions. These include:
   * creating "required blocks"
   * checking for the existence of required variables
   * loading the SPEC file
   * loading the current-parameter-values file
   * parsing the SPEC File
   * using info in the SPEC file, loading modules files


** Required blocks (DIVS and  SPANS)
 The following blocks are created (if they do not exist) on the main page.


** Display attributes of blocks
  You can customize the display attributes of the various blocks by modifying svyLiBE2.CSS.

** Required variables
     Permanent variables (for this user in this session) are passed in the 1st argument to E2_start.
     In particular, the following are expected:
        instrument = name of this instrument (used to lookup files)
        sessionName :: the session name
        myID    :: client ID
        myREFID  :: client's reference ID (might be '')
        myNAME :: client name
        myContact :: optional contact info
        myNickName :: optional nickname

 example:     ?instrument=$RISK_HOLTLAURY_BASIC
                      &sessionName=$risk_hb1
                      &myID=4896906416587765=
                      &myRefID=&
                      &myName=
                      &myNickName=a a aa
                      &myContact=a a
                      &resubmitOkay=0
                      &debug_Mode=1

Note: the session descriptor file is NOT accessed by client-side functions. However, the join utilities
      will read the session descriptof file, and willl include the required session's descriptor parameters 
      as part of the "join" request (that is sent to the server).

---------------------------------------------- */

//  Start up function -- reads the SPEC file (an XML file) and parses it. This should be called using a onLoad="E2_start(startVars)", or similar syntax,
//    in the instruments main HTML page
//  If specified, sStart should be the name of the section to start with. If not specified, start with the first section
// Start vars should be a ?name=val&name=val "search string". the "name" will be extracted as saved as permanent variables (for this participant in this session)
//    By default, startVars should specify: myID, myREFID, myNAME, myNICKNAME, myCONTACT, sessionName, specFileURL, and instrumentName
//  It might also specify SPY
// Note: astat argument should NOT be set when first called (it is used internally)

function E2_start(startVars,sStart,astat) {

var reqlist,lgotspec,initnode,anode,anode2,flist,iNodes,iij,ii1;
var thisid,anodei,tmp,elen,elemSec,ij,asec,elemSec,esecs,jj,aother;

var myname,myid,mysession,specfile,aat,ie0,myinstrument,mynickname,mycontact ;
var gfile,myinstrumentBaseUrl,ibase,goo,goo2;
var aname,taname,ieq,ieq2,foo2Text,foo2TextArray,doRetain;
var ieq3,oldval,vs,alines,vvname,foo3;
var ieq4,wlist;                       
var glug,iglug,foo,tmp,itmp,foo2;
var ic,tmp2,aword,mtmp;

if (typeof(E2_toolkit)=='undefined') {
  alert('E2_start error: E2_toolkit undefined -- does the main page load svyLibE2_globals.js ?');
  return 0;
}


if (arguments.length<2) sStart=''
if (arguments.length<3) astat=0 ;

// setup
if (astat==0) {                                 // first call -- do some setup
  SvyGlobals=new Object() ;
  SvyGlobalsHistory=  new Object() ;
  SvyGlobalsHistory['$roundlist']=[];                   // array of rounds in SvyGlobalsHistory (augmented by save_globalHistory functions
  SvyGlobalsHistory['$recent']={};                      // object containing most recently saved-to-history-round
  SvyGlobalsHistory['_recent']=0;                      // the most recently saved round (augmented by E2_loadSectio

  xmlFileCache={};                             // the cache for xml files

  messageData={};
  messageData['MESSAGE_OPTIONS']='DISABLE' ;          // default is disabled (overwritten by <message> and by postCap
  messageData.on=0 ;                           // <message> in <init> turns it on
  messageData.messages=[] ;                // each row should be an object with three fields: .full, .shown, and .row
  messageData['$varlist']=[];
  messageData['$constlist']=[];
  messageData['$index']=0 ;
  messageData['$lastRetrieve']=0 ;
  messageData.notes=[];

  clientMessageOptions={}; 
  clientMessageOptions.isOpen=0;                // mail boxes are not open

  initRetains=[];                               //  INIT to be retained (and re-processed when PARAMS are reset) DEPRECATED 16 Nov 2009

  includesFile_iter=0

  specSections=new Object() ;                           // already defined as global, but zap it anyways
  specSections['sectionIndex']=new Object() ;
  specSections['sectionNames']=new Object() ;
  specSections['eventQueue']=new Object() ;
  specSections['saveNodeList']={}
  specSections['saveCallsList']=[] ;
  specSections['elementList']=new Object() ;                    //  array of string ids: by section
  specSections['elementList']['__NODES']=[] ;                    // array to store nodes of <anatt> in <attributes>
  specSections['elementList']['0']=[] ;                       // defaults (for all sections) -- each item in the array is an object with 3 fields: name, isName, node

  specSections['start']=sStart ;                                // the section to start with, or '' for "section #1"
  xmlModuleList=new Object() ;                     // for saving the modules pulled from the xmlModulesBase nodes, and the modules created with <create>
    xmlModuleList[0]=new Array() ;              // array of the modules names (pullled from module files)
  xmlIncludes=new Array() ;                     // for saving XML include nodes (from XML files)

  submitVars=new Object() ;                     // saves variables to be submitted
  submitVars['0']=0 ;
  submitVars['__message']='Submitting current information to the server. Please wait.... ';
  submitVars['__status']='SUBMIT';

  displayWindows=new Object() ;
    displayWindows[0]=new Array() ;              // array of the currently open windows

  enableStrongTyping=0;

  simpleHistory={} ;         // for storing status messages
    simpleHistory['names']=[];
    simpleHistory['useround']=0; 
    simpleHistory.specs=[];
    simpleHistory['gotSubmitted']=[];

}

// start
if (astat==0) {                                 // first call -- check some basic stuff

  var wlist=E2_start_startVars(startVars)  ;               // check that required variables are available.

  enableStrongTyping=strongTyping ;                     // enableStrongTyping is a global used by dSurvey procs
  if (strongTyping==2) {
     enableStrongTyping=0 ;
     foo=Read_Global('_debug_mode',-1);
     if (foo==-1) foo=debugMode;
     if (foo>0) enableStrongTyping=1;
     Save_Global('_enableStrongTyping',enableStrongTyping); //  might be useful
  }

  E2_start_divs()  ;                                 // create required divs: main, work, footer, header
  doExpandDots();

  E2_writeStatus(' Variables saved: '+wlist);
  E2_toggleStatus(1) ;
  doExpandDots();

   myname=Read_Global('myname',' ERROR: no NAME specified.');
   myid=Read_Global('MYID',' ERROR: no ID specified ');
   myrefid=Read_Global('MYREFID','');                         // empty myrefid is okay (myrefid only non-empty under client-extraction
   mynickname=Read_Global('MYNICKNAME','');                         // empty mynickname is okay
   mycontact=Read_Global('MYCONTACT','');                         // empty mycontact is okay

  doExpandDots();

   mysession=Read_Global('_sessionName',' ERROR: no sessionName specified');
  specfile=Read_Global('_specFileURL','ERROR: no Spec File specified ');
  myinstrument=Read_Global('_instrument',' ERROR: no INSTRUMENT name specified.');
  myinstrumentBaseUrl=Read_Global('_instrumentBaseURL',' ERROR: no INSTRUMENTbaseUrl specified.');
  E2_writeStatus(myname + ' (' + myid +', '+myrefid+') joining survey ' + mysession);  // write some basic info to  "status history buffer"
  foo=E2_writeName('You are ' + myname );                        // Footer info ...

  foo=E2_writeQdesc(' ... short descriptions are written here ');
  if (_spying==1) { 
        E2_writeQdesc('<span style="font-weight:600;color:red;border:1px solid gold">SPYING on '+ myname+' ('+myid+')</span>') ;
        E2_writeHeaderMessage('<span style="font-weight:600;color:red;border:1px solid gold">SPYING on '+ myname+' ('+myid+')</span>') ;
   };

  doExpandDots();


// read the Spec file
   if (debugOn()) E2_writeStatus('Retrieving SpecFile.');
   E2_start_spec(Read_Global('_specFileURL'));                   // note: specfile is saved to the _specFile global variable, which is a "node"
   return 0 ;                           // E2_start_spec, on success calls E2_start with astat=1
} ;

  doExpandDots();

if (astat==1 ) {                         // just got spec file -- look for <INCLUDE>
  includesFile_iter=0;
  iNodes=_specFile.getElementsByTagName('include') ;
  if (iNodes.length>0) {
     ii1=E2_start_includes_file(iNodes,0,0,Read_Global('_specFileURL'),'E2_start') ;                 // insert <INCLUDE file= ...
     doExpandDots();
     if (ii1!==11)   return 1 ;
     astat=11;
  } else {
      astat=11 ;                                // no include, so skip <include sub=
  }
}


if (astat==1.1 ) {                         // check for <include file= again
  includesFile_iter++;
  if (includesFile_iter>10) {
     var vv=confirm('Warning: depth of include files is now '+includesFile_iter+'. Continue? ',0);
     if (vv==0) return 0;
   }

  iNodes=_specFile.getElementsByTagName('include') ;
  if (iNodes.length>0) {
     ii1=E2_start_includes_file(iNodes,0,0,Read_Global('_specFileURL'),'E2_start') ;                 // insert <INCLUDE file= ...
     doExpandDots();
     if (ii1!==11) return 1;
     astat=11;
  } else {
      astat=11 ;                                // no include, so skip <include sub=
  }
}

if (astat==11 ) {                         // check for <include sub=
  E2_replaceSubs(_specFile) ;
  doExpandDots();
  astat=12 ;
}

if (astat==12 ) {                         // just got spec file, and filled in <include> -- start processing INIT section

// first, remove <COMMENT> s
 tmp=0;
 iNodes=_specFile.getElementsByTagName('cmt') ;
 tmp=tmp+iNodes.length;
 removeNodes(iNodes);
 iNodes=_specFile.getElementsByTagName('comment') ;
 tmp=tmp+iNodes.length;
 removeNodes(iNodes);
 E2_writeStatus(' COMMENTS removed='+tmp);

  doExpandDots();

// and now process the INIT
 initnode=E2_getNodes(_specFile,'INIT',1) ;                     // <INIT> 
 if (initnode.length==0) {
        alert('Error in E2_start: SPEC file does NOT have an INIT section.');
        return 0;
  }
  initnode=initnode[0] ;            


// enable message feature
  foo=E2_getNodes(initnode,'MESSAGE MESSAGES');                     // <MESSAGE> 
  leftat='';
  if (foo.length>0) {
    messageData.on=1 ;                
    tmp=getAttributes(foo[0],'where','0');
    foo2=E2_getNodes(foo[0],'where');                   // <where> instead of using an attribute?
    if (foo2.length>0) {
        tmp=E2_getNodeText(foo2[0]);
        if (strip(tmp)==='') tmp='0';
    }

    if (tmp=='0') {
        tmp='_headerClientMessage';
        itmp=document.getElementById(tmp);
        if (!itmp) {
          alert('Error on initializaton: no default area for the client-messages button: '+tmp);
          return 0 ;
        }
        itmp.setAttribute('onClick','doClientMessages()');
        clientMessageOptions.buttonId=itmp;
        clientMessageOptions.buttonIdOrigStyle='inline';
        mtmp=getAttributes(foo[0],'defaultMessage','');

        foo2=E2_getNodes(foo[0],'defaultMessage');              // or use a <defaultMessage> ?
        if (foo2.length>0) {
             mtmp=E2_getNodeText(foo2[0]);
             leftat=getAttributes(foo2[0],'left','');            // example:  left="61%" 
//alert(mtmp+' llll '+leftat);
        }
        if (strip(mtmp)!=='') {
           itmp.innerHTML=mtmp ;
           if (strip(leftat)!=='') itmp.style.left=strip(leftat)
//itmp.style.display='block';
//           alert('USING '+mtmp);

        }

    } else {
        itmp=document.getElementById(tmp);
        if (!itmp) {
          alert('Error on initializaton: no  custom area for the client-messages button: '+tmp);
          return 0 ;
        }
        itmp.setAttribute('onClick','doClientMessages()');
        clientMessageOptions.buttonId=itmp;
        clientMessageOptions.buttonIdOrigStyle=itmp.style.display ;
    }


    foo2=E2_getNodes(foo[0],'options');

// set up default values
        clientMessageOptions.enable=1 ;
        clientMessageOptions.show=0 ;
        clientMessageOptions.notify=0 ;
        clientMessageOptions.send='ALL' ;
        clientMessageOptions.poll='0' ;
        clientMessageOptions.notes='1' ;

    if (foo2.length==0) {                               // enable, but button not shown
        tmp='enable, noshow ,nopoll, nonotify ,sendall, notes ';
    } else {
        tmp=E2_getNodeText(foo2[0]);  
    }
    messageData['MESSAGE_OPTIONS']=tmp ;    // default is enabled
    
// create 2 moveBoxes for messages

     clientMessageOptions.myname=Read_Global('myname',' ERROR: no NAME specified.');
     clientMessageOptions.myid=Read_Global('MYID',' ERROR: no ID specified ');
     create_moveBox(7,['45%','10%'],['52%','20%'],'Messages (you are '+clientMessageOptions.myname+')',' LOCK BOXSTYLE=border:2px_solid_blue') ; close_moveBox(7);
     create_moveBox(8,['45%','42%'],['52%','30%'],' ... ...','LOCK  BOXSTYLE=border:2px_solid_cyan') ; close_moveBox(8);

// create a moveBox for help
     create_moveBox(9,['10%','65%'],['80%','25%'],'Help',' LOCK BOXSTYLE=border:1px_solid_gray') ; close_moveBox(9);
 
  }

// load CSS and JS from the server 
  foo=E2_getNodes(initnode,'LOAD');                     // <LOAD> 
  if (foo.length>0) {
      myinstrumentBaseUrl=Read_Global('_instrumentBaseURL',' ERROR: no INSTRUMENTbaseUrl specified.');
      myinstrument=Read_Global('_instrument',' ERROR: no _INSTRUMENT name specified.');
      ibase=myinstrumentBaseUrl.replace(/!INST!/g,myinstrument);     // instrumentBaseURL is a global

      goo=strip(E2_getNodeText(foo[0]));
      if (goo=='*') goo=myinstrument+'.js '+myinstrument+'.css  myFunctions.js myStyles.css ';
      goo2=getWord(goo);
      for (var j=0;j<goo2.length;j++){
           gfile=ibase+'LIB/'+goo2[j] ; 
           doExpandDots();
           loadJsCssFile(gfile);
      }
      E2_writeStatus(' JS/CSS files loaded: '+goo);

   }
    
// process variables and equations specified in INIT
  svy_retainVars='';                            // reset a global
  foo=E2_getNodes(initnode,'CALL');                     // <CALL> 
  if (foo.length>0) {
     for (var ieq=0; ieq<foo.length;ieq++) {
        doRetain=getAttributes(foo[ieq],'RETAIN','');
// check for no = sign in an equation
       if (doRetain==1) {
         glug=foo[ieq].innerHTML;
         glug=glug.split('\n');
         for (var iglug=0;iglug<glug.length;iglug++ ) {
           if (strip(glug[iglug])=='') continue ;
           if (glug[iglug].indexOf('=')<0) {
              alert('Error in <INIT><CALL retain="1">: no = in equation: '+glug[iglug]);
              return 0;
           }
         }
       }                                // doretain=1
      doExpandDots();

        E2_doEquations('',foo[ieq]);
        if (doRetain==1) svy_retainVars=svy_retainVars+' '+doEquationsSet ;     // use global set in e2_doEquations
        if (debugOn()) {
              if (doRetain==1) E2_writeStatus(' INIT: equations processed and retained= '+foo[ieq].childNodes.length);
              if (doRetain!=1) E2_writeStatus(' INIT: equations processed= '+foo[ieq].childNodes.length);
        }
     }
     svy_retainVars=getWord(svy_retainVars);
    doExpandDots();
 }

// process <HISTORY> in <INIT>
  foo=E2_getNodes(initnode,'HISTORY');            
         
  for (var ieq=0; ieq<foo.length;ieq++) {
       var aname=getAttributes(foo[ieq],'name','_DEFAULT');
       taname=strip(aname).toUpperCase();
       if (typeof(simpleHistory.specs[taname])!=='undefined') {
           alert('Error: <HISTORY> name is already specified: '+aname);
           return 0;
        }
        simpleHistory.specs[taname]={};
        simpleHistory.names=simpleHistory.names.concat(taname);
        var adiv=getAttributes(foo[ieq],'where','0');
        simpleHistory.specs[taname].where=adiv;
        simpleHistory.specs[taname].rounds=[];
//alert('HISTORY IN IT USING '+taname);
     doExpandDots();

// read variables?
       simpleHistory.specs[taname].varList=[];
       foo2=E2_getNodes(foo[ieq],'vars');
       if (foo2.length>0) {
          foo2Text=E2_getNodeText(foo2[0]);             // only use first <vars>
          foo2TextArray=getWord(foo2Text,0,',')         // parse on commas (columns)
          for (var ieq2=0;ieq2<foo2TextArray.length;ieq2++) { 
              avar=strip(foo2TextArray[ieq2]);
              tmp=[];
              if (avar=='') {
                  simpleHistory.specs[taname].varList[ieq2]=tmp;
               } else {
                  simpleHistory.specs[taname].varList[ieq2]=getWord(avar);  // might be multiple variables (space delimited list)
              }
          }                     // x , y , z in <vars>
       }                        // vars


// read colDesc, if they exist (not, if not specified use variable names. This is done in make_simpleHistoryRow
       simpleHistory.specs[taname].topRow='';
       simpleHistory.specs[taname].colDesc=[];
       foo2=E2_getNodes(foo[ieq],'colDesc');
       if (foo2.length>0) {
          foo2Text=E2_xmlToString(foo2[0]);             // only use first <colDesc>
          foo2TextArray=getWord(foo2Text,0,',')         // parse on commas (columns)
          for (ieq2=0;ieq2<foo2TextArray.length;ieq2++) {   
             simpleHistory.specs[taname].colDesc[ieq2]=foo2TextArray[ieq2];
         }
       }

 // read colStyle-- default is no style
       simpleHistory.specs[taname].colStyle=[];
       for (ieq2=0;ieq2<simpleHistory.specs[taname].varList.length;ieq2++) {   
            simpleHistory.specs[taname].colStyle[ieq2]='';
       }
       foo2=E2_getNodes(foo[ieq],'colStyle');
       if (foo2.length>0) {
          foo2Text=E2_getNodeText(foo2[0]);             // only use first <colDesc>
          foo2TextArray=getWord(foo2Text,0,',')         // parse on commas (columns)
          for  (var ieq2=0;ieq2<foo2TextArray.length;ieq2++) {  
            simpleHistory.specs[taname].colStyle[ieq2]=foo2TextArray[ieq2] ;
          }
       }

     doExpandDots();

 // read recode
       simpleHistory.specs[taname].recodes={};
       foo2=E2_getNodes(foo[ieq],'recode');
       if (foo2.length>0) {
         simpleHistory.specs[taname].cReplace=getAttributes(foo2[0],'replace','*');
         foo3=E2_getNodes(foo2[0],'*');                         // each node refers to a variable
         for (var ieq2=0;ieq2<foo3.length;ieq2++) {
            vvname=foo3[ieq2].nodeName; vvname=strip(vvname).toUpperCase() ;
            if (typeof(simpleHistory.specs[taname].recodes[vvname])=='undefined') simpleHistory.specs[taname].recodes[vvname]={} ;
            tmp=E2_getNodeText(foo3[ieq2]);
            alines=tmp.split('\n');
            for (var ieq3=0;ieq3<alines.length;ieq3++) {
                 vs=parseAt(alines[ieq3],'=');
                 if (vs.length<2) {
                   alert('Error in <recode>, no equal sign: ' +alines[ieq3]);
                   return 0;
                 }
                 oldval=strip(vs[0]).toUpperCase() ;
                 if (oldval===''){
                        simpleHistory.specs[taname].recodes[vvname][' ']=vs[1];                 
                 } else {
                    wlist=getWord(oldval);
                    for (ieq4=0;ieq4<wlist.length;ieq4++) {
                        oldval=strip(wlist[ieq4]).toUpperCase() ; 
                        simpleHistory.specs[taname].recodes[vvname][oldval]=vs[1];                 
                   }                                                     // ieq4
                 }                                      // oldval==''
            }                                                   // ieq3
         }                              // ieq2
       }                                // look for <recode>

     doExpandDots();

// read header and footer (copy of node)
       simpleHistory.specs[taname].header=0;
       foo2=E2_getNodes(foo[ieq],'header');
       if (foo2.length>0)  {
           simpleHistory.specs[taname].header=E2_copyNode(foo2[0]);
       } else {                         // no specified header, and using SUBMITTED Variables? Then use a default header
         if (simpleHistory.specs[taname].varList.length==0) {
            simpleHistory.specs[taname].header='<input type="button" value="close" onClick="window.close()" /> '+
           ' <span style="font-size:120%;font-weight:600;padding-left:50px">Prior variables</span><br/><em>Using variables submitted to the server</em><p/> ';
         }
      }

       simpleHistory.specs[taname].footer=0;
       foo2=E2_getNodes(foo[ieq],'footer');
       if (foo2.length>0)  simpleHistory.specs[taname].footer=E2_copyNode(foo2[0]);

   }                                      // next <HISTORY> (taname)

   if (simpleHistory['names'].length>0) {  
         E2_writeStatus(' History specified for: '+simpleHistory.names);
   }

     doExpandDots();

// pre-process the ATTRIBUTES, creating seperate subtrees for defaults, and for sections and groups-in-sections 

  tmp=E2_getNodes(_specFile,'ATTRIBUTES ELEMENTS');                      // read  <attributes>
   if (tmp.length>0) {                    // an ATTRIBUTES (or ELEMENTS) exists?
     for (var iij=0;iij<tmp.length;iij++) {
      anode=tmp[iij];
      elemSecs=['0'];                                // start with  "all groups & sections "
      for (var ie=0; ie<anode.childNodes.length;ie++) {           // for all nodes defined in ATTRIBUTES
        anodei=anode.childNodes[ie];
        if (anodei.nodeType!=1)       continue ;                // skip comments and text
        thisid=strip(anodei.nodeName) ;

//section/group assignment flag -- change elemsSecs 
        if (thisid.toUpperCase()=='FOR' ||thisid.toUpperCase()=='SCOPE' ) {      // <SCOPE> (and <FOR>, which is deprecated
            elemSec=getAttributes(anodei,'NAME','0') ;
            elemSec=strip(elemSec.toUpperCase()) ;
            if (elemSec=='') elemSec='0' ;                      // default is ALL groups and sections 
            elemSec=elemSec.replace(/,/g,' ');
            elemSecs=getWord(elemSec);
            for (var ij=0;ij<elemSecs.length;ij++) {
                   asec=strip(elemSecs[ij].toUpperCase());
                   elemSecs[ij]=asec ;
                   if (typeof(specSections['elementList'][asec])=='undefined') specSections['elementList'][asec]=[] ;                   // for this sections -- each item in the array is an object with 3 fields: name, isName, node
            }  
            continue ;                                  // don't store this node!
        }

// not a scope  -- save to default, or one or several FOR groups (in elementList)
       for (ij=0;ij<elemSecs.length;ij++) {
           elen=specSections['elementList'][elemSecs[ij]].length ;
           specSections.elementList[elemSecs[ij]][elen]=new Object ;
           specSections.elementList[elemSecs[ij]][elen].name=thisid ;
           specSections.elementList[elemSecs[ij]][elen].node=anodei;
           specSections.elementList[elemSecs[ij]][elen].isName=strip(getAttributes(anodei,'NAME',0));
        }                       // all lists defined in current FOR
     }                   // all nodes in elements
   }                           //ij
  }                             // ELEMENTS (or ATTRIBUTES) found 


     doExpandDots();

// pre-process the USE  
  tmp=E2_getNodes(_specFile,'USE ');                      // read  <use>
  if (tmp.length>0) {                    // USE exists?
    for (var iij=0;iij<tmp.length;iij++) {
      anode=tmp[iij];
      for (var ie=0; ie<anode.childNodes.length;ie++) {           // for all nodes defined in USE
        anodei=anode.childNodes[ie];
        if (anodei.nodeType!=1) continue ;                // skip comments and text
        thisid=strip(anodei.nodeName) ;
        aat=strip(thisid).toUpperCase() ;
        specSections.saveNodeList[aat]=anodei ;
      }                             // 
    }                           // iij
  }                             // all nodes in USE

     doExpandDots();

/* pre-process the CALLS, creating seperate subtrees for defaults, and for sections and groups-in-sections */
  tmp=E2_getNodes(_specFile,'CALLS');                      // read  <calls>
  if (tmp.length>0) {                    // CALLS exists?
    for (var iij=0;iij<tmp.length;iij++) {
      anode=tmp[iij];
      for (var ie=0; ie<anode.childNodes.length;ie++) {           // for all nodes defined in USE
        anodei=anode.childNodes[ie];
        if (anodei.nodeType!=1)       continue ;                // skip comments and text
        ie0=specSections.saveCallsList.length;
        aat=getAttributes(anodei,'for','*') ; aat=aat.toUpperCase();
        specSections.saveCallsList[ie0]={} ;
        specSections.saveCallsList[ie0]['node']=anodei ;
        specSections.saveCallsList[ie0]['for']=' '+aat+' ';
      }                             // ie
    }                           // all CALLS
  }                             // all nodes in calls
  E2_writeStatus(' In '+tmp.length+' CALLS,  CALLs defined=' +specSections.saveCallsList.length);


// retrieve modules files and save modules to xmlModuleLists
  doExpandDots();

  E2_start_getXmlModules(initnode,1,'',Read_Global('_instrumentBaseURL'));
  return 0 ;
}                                       // astat=12

// got module files. Recover history file?
if (astat==13 ) {                         // just got spec file, and filled in <include> -- start processing INIT section
  initnode=E2_getNodes(_specFile,'INIT',1) ;
  foo=E2_getNodes(initnode[0],'RECOVER RECOVERHISTORY ');   // <RECOVER>
  doExpandDots();
  if (foo.length==0) {                  // no RECOVER -- perhaps a recoverSimple?
        astat=14 ;
   } else {                     // history stuff: call the recoverHistory function (which will "recursively" call e2_start with astat=14)
      E2_recoverHistory(1)
      return 0 ;
   }
}

// got module files, and possibly history archive. Recover simple history file?
if (astat==14 || astat==13 ) {                         // did <recover> (or no <recover>) -- <recoverSimple>?
  doExpandDots();
  initnode=E2_getNodes(_specFile,'INIT',1) ;
  foo=E2_getNodes(initnode[0],'RECOVERSIMPLE ');   // <RECOVERSIMPLE>
  if (foo.length==0) {
        astat=2 ;
   } else {                     // history stuff: call the recoverSimpleHistory function (which will "recursively" call e2_start with astat=2)
      E2_recoverSimpleHistory(1)
      return 0 ;
   }
}


if (astat==2) {                         // module files have been retrieved. Parse them, and get parameters file
   E2_writeStatus(' Modules available:'  + xmlModuleList[0].join(', '));
}

//  modules read. Now check for sections.

E2_writeStatus('Starting first section ');
foo=E2_start_sections(_specFile,Read_Global('_specFileURL')) ;   // read the <section> portions of xml file
if (foo<1) return 0 ;                 // no sections defined, nothing to do.. so stop

doExpandDots();


dsurveyMessages();       // now we can show the message button


// Ready to load a section, to be displayed  (by default, section 1)  -- and create an array of groups for this sectionaok AND display first group (index of 0)
aok=E2_loadSection(specSections['start'],1) ;


/*  ===== debug
  ff=i_pageNow.innerHTML ;
  ff=document.body.innerHTML ;

  var dw=window.open('','debugwindow');
  dw.document.open('text/plain');
  var t1='<html><head><title>Debug window</title><body><div style="border:2px black dotted; background-color:#999999"><tt>Debug mode: </div> \n '+ff +' \n </body></html>';
  dw.document.write(t1);
  dw.document.close();
 ===== */

return 0 ;

}


// 
/* ::===============================================================================================================*/
/* ====================== FUNCTIONS CALLED BY E2_START ============================= */


//======================  ============================== ======================================================
// Initialization routines-- these are called by E2_start (right after main page is loaded, and then not again)


//============================
// read <modules>, store in specModules object
function E2_start_sections(anode,specFile) {
 var snodes,anode,bnode,anatt,foo ;

  snodes=E2_getNodes(anode,'SECTION',0) ;
  if (snodes.length==0) {
        alert('E2_start ERROR: no SECTIONs defined in specfile: '+specFile);
        return 0;
   }

  for (var n=0;n<snodes.length;n++) {
    nn=n+1;
    anode=snodes[n];
    nname=getAttributes(anode,'NAME','');            // get attributes of INIT mother node
    if (nname==='') {
        alert('E2_start ERROR:  SECTION # '+ nn+ ' does NOT have a NAME');
        return 0;
    }
    specSections[0]=nn;                         // note use of index 0 to store length of "array"
    nname=strip(nname).toUpperCase() ;
    specSections[nn]=anode ;                    // store the node
    specSections['sectionIndex'][nname]=nn ;
    specSections['sectionNames'][nn]=nname
  }
  E2_writeStatus(' # of sections  in SPEC file=  '+ specSections[0]);
  return nn;

}



//======================
// read the <file>, for use when reading XML files.
// <module> read from each file
// was function E2_start_getFILE_xml(anode) {

function E2_start_makeFileList_xml(anode){

  var vprefix,vsuffix,mname,fixes,fixes2,fnodes,fnode2,fnames,m,m2,vfnames,kk,n1;
  var mlist=new Array() ;
  fixes=getAttributes(anode,'PREFIX SUFFIX ');            // get attributes of INIT mother node (fixes used as default below)

  fnodes=E2_getNodes(anode,'FILE',0) ;         // process the FILE blocks (get FILE node children)
  for (var m=0; m<fnodes.length;m++) {
     fnode2=fnodes[m];
     fnames=E2_getNodeText(fnode2);
     if (fnames=='') continue ;

     fixes2=getAttributes(fnode2,'PREFIX SUFFIX ',fixes);   // attributes of this node, using mother node values as defaults
     vprefix=fixes2['PREFIX']; vsuffix=fixes2['SUFFIX'];
     vfnames=getWord(fnames);
     for (var kk=0 ; kk<vfnames.length;kk++) {
             var n1=vprefix+strip(vfnames[kk])+vsuffix ;
             mlist[mlist.length]=n1 ;
     }
  }                                     // this <FILE>

  return mlist ;

}


//==============
// get the SPEC file for this session (an XML File)
function E2_start_spec(afile,act) {
  if (arguments.length<2) act=0

  if (act==0) {                         // first call. get the spec file
     foo=Get_xmlFile(afile,'_specFile','Retrieve SPEC file ','E2_start_spec',afile,1)    ; 
     return 0 ;
   }

// if here, got the spec file.
  if (debugOn(2)) E2_writeStatus('Spec file retrieved: ' + afile);
  Launch_Proc('E2_start',1000,'','',1);    //  got the SPEC file -- so return control to E2_start
  return 0;
}


//=============================
/* replace <Include sub="xx"> with <sub name="XX> ..</sub> */
function E2_replaceSubs(nodec) {
  var subNodes ;
  var i,subname,getSubName,tmpnode;
  var iii,ssnode,parentn,innc;
  var inode,cnode,goo,iNodes;

// expand "subroutines"
  try {
     subNodes=nodec.getElementsByTagName('sub') ;
  }
  catch(err) {
        alert(sessName+': bad controlnode, looking for <SUB >: '+err);
   }

  E2_writeStatus('   SUBs found= '+subNodes.length);
  subStorage={} ;            // clear subStorage 
  innc=0;
//var gazebo='';
  for (var i=0;i<subNodes.length;i++) {                         // copy into subStorage object
     subname=getAttributes(subNodes[i],'name var ','');
     if (subname=='') {
         writeAlert('Note: a sub with no name was skipped');
        continue ;
     }
     subname=strip(subname).toUpperCase() ;
     subStorage[subname]=E2_copyNode(subNodes[i]);
//gazebo=gazebo+' '+subname;
     innc++ ;
  }
  removeNodes(subNodes);                // and  remove from the controlNode tree
//   alert(innc+' [sub] were stored: '+gazebo);

// step 2b: replace <include sub> with subs (stored above)
// expand "subroutines"
  try {
     iNodes=nodec.getElementsByTagName('include') ;  // note that this is a dynamic "collection" 
  }
  catch(err) {
        alert(' bad controlnode, looking for include: '+err);
   }   
  innc=0;

  for (var i=0 ; i>-1;i++) {                     // do until no more nodes in collection

      if (iNodes.length==0) break ;

      inode=iNodes[0];
      getSubName=getAttributes(inode,'sub','');
      if (debugOn()) E2_writeStatus('   including SUB: '+getSubName);

       writeStatus('   Include sub: '+getSubName);

      if (getSubName==='') {
          var tt=getAttributes(inode,'file','');
          E2_writeStatus('...... Problem: include without a SUB=  (file='+tt);
          alert('Problem: include without a SUB=  (file='+tt);
          return 0;
       }

      getSubName=strip(getSubName).toUpperCase() ;
      if (typeof(subStorage[getSubName])=='undefined') {
         alert('Error: <include sub="'+getSubName+' : no such <SUB> defined ');
         return 0;
      }
       ssnode=subStorage[getSubName] ;
       parentn=inode.parentNode ;
       for (var iii=0; iii<ssnode.childNodes.length;iii++) {         // copy all children of <SUB> to before <INSERT>
          cnode=E2_copyNode(ssnode.childNodes[iii]) ;              // make a copy of this child of a <SUB> (copy the tree)
          goo=parentn.insertBefore(cnode,inode);                    // and insert before the <INSERT>
      }
      innc++ ;
      inode.parentNode.removeChild(inode);
   }

return 1;
}



//==============
// Get include subroutines.
// inodes: <include sub="xx"> nodes
// snodes: <sub> nodes

function E2_start_includes_sub(inodes,snodes,skipok) {

if (arguments.length<3) skipok=0 ;

var i,anode,bnode,sname,iname,iname0,inode,cnode,parentn;
var imatch,snode,ssnode,ii,iii,imatch ;
for  (var i=0;i<inodes.length;i++) {            
   inode=inodes[i];
   iname0=getAttributes(inode,'SUB','');
   if (iname0=='') {
        if (skipok==1) continue ;
        alert('Error in includes_sub: no NAME attribute ');
        return 0;
   }
  imatch=-1;
  iname=strip(iname0.toUpperCase()) ;
  for (var ii=0;ii<snodes.length;ii++) {
        sname=getAttributes(snodes[ii],'NAME','');
        if (sname==='') continue ;
        sname=strip(sname.toUpperCase());
        if (sname==iname) {
              imatch=ii;
              break ;
        }
   }
   if (imatch<0) {
        alert('Error in includes_sub: no SUB with name= '+iname0) ;           
       return 0 ;
   }
  ssnode=snodes[imatch];
  parentn=inode.parentNode ;
  for (var iii=0; iii<ssnode.childNodes.length;iii++) {         // copy all children of <SUB> to before <INSERT>
      cnode=E2_copyNode(ssnode.childNodes[iii]) ;              // make a copy of this child of a <SUB> (copy the tree)
      goo=parentn.insertBefore(cnode,inode);                    // and insert before the <INSERT>
   }
}

// now remove the INCLUDE nodes 
removeNodes(inodes,1);


return 1 ;
}


//==============
// Get SPEC include files.  This is a bit tricky -- it asks for all the include files.
// todo=0: toget is a nodelist of includes
// todo=1: toget ignored
// igot : if todo=1 --- where to store the contents of _includeNode
//           15 sep 2010: check _includeNodeError for error message
// callFunc: function to call when all done.
// specfile: the url to the specfile. Used to create base of the specfile (used to resolve relative incldue files) ;
// note use of xmlIncludes global for storage


function E2_start_includes_file(toget,todo,igot,specfile,callFunc,justGot) {

var avar,inode,i,aerr,ierr,afile;
var parentn,doadd,inodes1,cnode,goo,inode,goo;
if (arguments.length<5) callFunc='E2_start';
if (arguments.length<6)  justGot='';

if (todo==0) {                           // first call -- determine what files are to be retrieved from server
  xmlIncludes=new Object() ;            // reset global
  xmlIncludes.incNodes=new Array() ;    // -- these store WHERE the include
  xmlIncludes.incFiles=new Array() ;    // these store the names of files icnldued

  avar=toget ; toget='' ;
  for  (var i=0;i<avar.length;i++) {            // avar is a list of "INCLUDE" nodes (from spec file)
     inode=avar[i];
     afile=getAttributes(inode,'VALUE FILE','');
     if (afile=='') continue ;                          // probably a SUB=".." include
     xmlIncludes.incNodes=xmlIncludes.incNodes.concat(inode);                // store the node that is to be REPLACED (by the content of afile)
     xmlIncludes.incFiles=xmlIncludes.incFiles.concat(afile);                // store the node that is to be REPLACED (by the content of afile)
     igot=-1 ;                                          // hack used below
  }
  if (xmlIncludes.incNodes.length==0) return 11 ;       // no more <INCLUDE FILE=
}

igot=parseInt(igot) ;

if (todo==1) {                                  // just got an include file. SO include it
  aerr=''+_includeNodeError;
  if (aerr.substr(0,1)>2) {
   inodes1=xmlIncludes.incNodes[igot];                 // get rid of this node 
   goo=getAttributes(inodes1,'okMiss okMissing missOk','');
   if (goo!=='1') {
      alert('Error: problem ('+_includeNodeError+') retrieving file '+justGot);
      if (debugOn()) E2_writeStatus('Error: problem ('+_includeNodeError+') retrieving file '+justGot) ;
    } else {
        if (debugOn()) E2_writeStatus('   Warning: non-existent include file is ignored: '+justGot) ;
    }
    parentn=inodes1.parentNode ;
    try {
        parentn.removeChild(inodes1);
     }
     catch(err) {
        if (debugOn()) E2_writeStatus('      ... problem removing nodes');
     }
        
  } else {                              // okay response 

     checkXMLDocErr(_includeNode,justGot)
     if (debugOn()) E2_writeStatus('     Include file retrieved: '+xmlIncludes.incFiles[igot]);

     inodes1=xmlIncludes.incNodes[igot];
     parentn=inodes1.parentNode ;
     doadd=_includeNode.childNodes.length ;
     for (var ii=0;ii<doadd;ii++){                       // always use [0] since insertBefore moves (not copies)
             cnode=_includeNode.childNodes[0];
             try {
                 goo=parentn.insertBefore(cnode,inodes1);
             } 
             catch(err) {
                alert('Problem with include file: '+ xmlIncludes.incFiles[igot]+':'+err);
                return 0; 
             }
     };                        // for ii
     try {
        if (debugOn()) E2_writeStatus('      ... nodes added for '+xmlIncludes.incFiles[igot] +'= '+doadd);
        parentn.removeChild(inodes1);
     }
     catch(err) {
        if (debugOn()) E2_writeStatus('      ... problem removing nodes');
     }
  }                             // 200?
}

igot++   ;                  // skip to next item in arrays
if (igot>=xmlIncludes.incFiles.length) {                                // no more inclue files to get
      E2_writeStatus('    '+xmlIncludes.incFiles.length+'  include files retrieved');
      Launch_Proc(callFunc,10,'','',1.1) ;                          // go back to start procedure (or proc specified in callFunc -- note of "10" as first argument
      return 0;
}

afile=strip(xmlIncludes.incFiles[igot]) ;
//gfoo=afile;
afile=resolveRelativeURL(afile,specfile);
//alert('aboutxx to get '+gfoo+' === '+afile);

Get_xmlFile(afile,['_includeNode','_includeNodeError'],'Retrieve SPEC or Control Include file ','E2_start_includes_file','',1,igot,specfile,callFunc,afile) ;   
return 0 ;


}               // end of E2_start_includes_file



// --------------------
// Extract variables from "search string". These are particpant/session permaenent variables.
// Typically, they will include  myID, myREFID, myNICKNAME, myCONTACT, myNAME, specFileURL, and sessionName
// They will be saved as survey-global variables (and to the root "survey globals history") 
//
// the default spec file, and instrument base, for this session
//        specFileURL=/dsurvey/instruments/instname/SPECS/SPEC.XML
//        instrumentBaseURL=/dsurvey/instruments/instname/

function E2_start_startVars(reqlist) {
 var r2,ir2,acheck,achecks,aword,aval,tmp,tmp1,tmp2,uaword ;
 var gotspec=0,gotinstb=0,gotsess='',gotinst='';
 var vre,vhow;

 if (reqlist.substr(0,1)=='?') reqlist=reqlist.substr(1) ;
 var r2=getWord(reqlist,0,'&') ;
 wlist='' ;

// these are the javascript global (not just dSurvey globals) defaults -
//  these are set in lib\svyUserServerHeaders.js
//     instrumentBaseURL='/dsurvey/instruments/!INST!/' ;
//     specFileURL='specs/!INST!.xml';
// The !Inst! will be replace by the instrument name

 for (var ir2=0 ; ir2<r2.length;ir2++) {
    acheck=r2[ir2];
    achecks=getWord(acheck,0,'=');
    aword=strip(achecks[0].toUpperCase()) ;  wlist=wlist+' '+aword;
    uaword=aword;
    aval=unescape(strip(achecks[1]));    
    if (aword=='SPECFILEURL') { gotspec=1 ;uaword='_'+aword ; }
    if (aword=='INSTRUMENTBASEURL') { gotinstb=1; uaword='_'+aword ; }
    if (aword=='SESSIONNAME') { gotsess=aval; uaword='_'+aword ; }
    if (aword=='INSTRUMENT') {gotinst=aval; uaword='_'+aword ; }
    if (aword=="DEBUG_MODE") uaword='_'+aword ; 
    if (aword=="SPY") { 
         uaword='_'+aword ; 
         if (aval=='1') _spying=1 ;            // _spying is  javascript global  (also sets a _spy control variable)          
    }

    if (aword=="RESUBMITOKAY")     {                             // resubmit okay does double duty
        if (aval==='0' || aval==='1') {
           vre=0;
           vhow=0;
           if (aval=='1') vre=1;
       } else {
          vre=aval.substr(0,1);
          vhow=unescape(strip(aval.substr(1)));
        }
        Save_Global('_RESUBMITOKAY',vre);
        Save_Global('_HOW_ASSIGN',vhow);
     } else {
         Save_Global(uaword,aval);
     }

  }
  if (gotsess==='') {
        alert('Error starting session: no sessionName provided: '+reqlist);
        return 0;
  }
  if (gotinst==='') {
        alert('Error starting session: no instrumentprovided: '+reqlist);
        return 0;
  }
  if (gotinstb==0) {                     // use default instrumentBaseUrl
      gotinstb=instrumentBaseURL.replace(/!INST!/g,gotinst);     // instrumentBaseURL is a global
      Save_Global('_INSTRUMENTBASEURL',gotinstb);
  }

  if (gotspec==0) {                     // use default "specfileurl
      gotspec=specFileURL.replace(/!INST!/g,gotinst);     // specFileURL is a global
      tmp2=gotinstb+gotspec;
      Save_Global('_SPECFILEURL',tmp2);
  }

  Save_GlobalHistory('START') ;           // save the survey-global version of the  required variables  to "permanent" storage

  return wlist ;
}


//========
// tweak the dotsToExpand content
function doExpandDots(i) {
 var arf,vv;
 arf=document.getElementById('dotsToExpand');
 if (!arf) return 0;
 vv=arf.innerHTML; 
 vvl=vv.length;
 if (vv>20)  {
      vv='...';
 } else {
      vv=vv+'.';
 }
 arf.innerHTML=vv;
 return 1;
}

// ==========================================
// Initialization routine 2-- create several required DIVS etc on main page
function E2_start_divs() {

var a1,a2,a3,xx,tmp,txx,ffb,txx,a2a ;

// destination div for modules exists. If not, create at top of body
i_pageNow=document.getElementById("_PAGE_NOW");                 // global js var: points to the the DIV  that holds the current page 
if (!i_pageNow) {                               // doesn't exist: put at TOP of body.
      ffb=document.createElement('div');
      tmp='\nPlease wait while pages are downloaded   ';
      tmp=tmp+'<a href="#" title="view load status"   onClick="E2_viewStatusHistory(1);return false"><span style="text-decoration:blink" id="dotsToExpand">.....</span></a> <p/>';
      ffb.innerHTML=tmp;
      ffb.id='_PAGE_NOW';
       document.body.insertBefore(ffb,document.body.firstChild);

      i_pageNow=document.getElementById("_PAGE_NOW");   

}

//  the header
  i_headerBlock=document.getElementById('_headerBlock');      
  if (useHeader_flag ) {

    if (!i_headerBlock) {                                           
       ffb=document.createElement('div');
       ffb.id='_headerBlock';
       document.body.insertBefore(ffb,document.body.firstChild);
       i_headerBlock=document.getElementById("_headerBlock");   
    }    

// block for writing short header messages. Starts with display:none
     i_headerMessage=document.getElementById('_headerMessage');       //  message block already defined?
     if (!i_headerMessage) {                                        //  No -- make one.
        a1=document.createElement('div');
        a1.id='_headerMessage';
        a1.setAttribute('class','styleHeaderMessage');
        a1.setAttribute('className','styleHeaderMessage');

        a1.setAttribute('style','display:none');

        tmp=document.createTextNode(' Header messages will be written here...');
        a1.appendChild(tmp);                                          
        ffb.appendChild(a1);
        i_headerMessage=document.getElementById("_headerMessage");   
     }



// block for writing client message button. Starts with display:none
     i_headerClientMessage=document.getElementById('_headerClientMessage');       //  cliemt message block already defined?
     if (!i_headerClientMessage) {                                        //  No -- make one.
        a1=document.createElement('span');
        a1.id='_headerClientMessage';
        a1.setAttribute('class','styleHeaderClientMessage');
        a1.setAttribute('className','styleHeaderClientMessage');

        a1.setAttribute('style','display:none');

        a1.title='Click here to send/retrieve messages';
        tmp=document.createTextNode(' Messages');
        a1.appendChild(tmp);                                          
        ffb.appendChild(a1);
        i_headerClientMessage=document.getElementById("_headerClientaMessage");   
     }

// "absolute location" block for writing timers
     i_headerTimer=document.getElementById('_headerTimer');       //  timer block already defined?
     if (!i_headerTimer) {                                        //  No -- make one.
        a1=document.createElement('div');
        a1.id='_headerTimer';
        a1.setAttribute('class','styleTimerButton');
        a1.setAttribute('className','styleTimerButton');
        a1.setAttribute('style','display:none');
        tmp=document.createTextNode(' Other Buttons, etc. will be written here...');
        a1.appendChild(tmp);                                          
        ffb.appendChild(a1);
        i_headerTimer=document.getElementById("_headerTimer");   
     }


// "absolute location" block for writing buttons
     i_headerButton=document.getElementById('_headerButton');       //  button block already defined?
     if (!i_headerButton) {                                        //  No -- make one.
        a1=document.createElement('div');
        a1.id='_headerButton';
        a1.setAttribute('class','styleHeaderButton');
        a1.setAttribute('className','styleHeaderButton');
        a1.setAttribute('style','display:none');
       
        tmp=document.createTextNode(' Buttons ... etc. will be written here...');
        a1.appendChild(tmp);                                          
        ffb.appendChild(a1);

        i_headerButton=document.getElementById("_headerButton");   
     }


  } else {
       i_headerBlock=0 ;
  }

//  the footer
  if (useFooter_flag) {
    i_footerBlock=document.getElementById('_footerBlock');       // the footer block will contain several subblocks

    if (!i_footerBlock) {                                           
       ffb=document.createElement('div');
       ffb.id='_footerBlock';
       ffb.setAttribute('class','styleFooterBlock');
       ffb.setAttribute('className','styleFooterBlock');
    }

/* create 3 sub blocks in footerblock.
        _nameBlock           _qDescBlock
        _statusBlock
  _nameBlock and _qDescBlock uses <SPAN>, _statusBlock uses <DIV>
*/

       a1=document.createElement('span');
         a1.id='_nameBlock';
         a1.setAttribute('class','styleNameBlock');
         a1.setAttribute('className','styleNameBlock');
         a1.setAttribute('onClick','E2_toggleStatus();');
            tmp=document.createTextNode(' Name/ID ...');
         a1.appendChild(tmp);                                         

       a2=document.createElement('span');
         a2.id='_qDescBlock'; 
         a2.setAttribute('class','styleQdescBlock');
         a2.setAttribute('className','styleQdescBlock');
            tmp=document.createTextNode(' Quick Description ...');
         a2.appendChild(tmp);                                         
         a2.setAttribute('onClick',"if (prompt('Which view?')=='debug') displayDiv('_controlOptionsDiv');");

       a2a=document.createElement('div');
       a2a.id='_controlOptionsDiv';
         a2a.setAttribute('class','styleControlOptions');
         a2a.setAttribute('className','styleControlOptions');
            tmp=document.createTextNode(' Control options ...');
         tmp='<input type="button" onClick="displayDiv(\'_controlOptionsDiv\')" value="Click to  close" /> ';
         tmp=tmp+' <input type="button" value="PageSource" onClick="E2_showPageSource()" />';
         tmp=tmp+'<input type="button" value="Refresh" onClick="E2_refreshThePage();" /> ';
         a2a.innerHTML=tmp;

       a3=document.createElement('div');
          a3.id='_statusBlock';  
          a3.setAttribute('class','styleStatusBlock');
          a3.setAttribute('style','display:none');
          a3.setAttribute('className','styleStatusBlock');
          a3.setAttribute('onClick','E2_viewStatusHistory(1);');
          tmp=document.createTextNode('Status message ...');
          a3.appendChild(tmp);                                         

       ffb.appendChild(a1);
       ffb.appendChild(a2);
       ffb.appendChild(a2a);
       ffb.appendChild(a3);

       document.body.appendChild(ffb);
       i_footerBlock=document.getElementById("_footerBlock");   

  } else {
       i_footerBlock=0 ;
  }
  

// "absolute location" block for writing alerts

  i_alertBlock=document.getElementById('_alertBlock');       //  alert block already defined?
  if (!i_alertBlock) {                                        //  No -- make one.
    ffb=document.createElement('div');
    ffb.id='_alertBlock';
    ffb.setAttribute('class','styleAlertBlock');
    ffb.setAttribute('className','styleAlertBlock');
    ffb.setAttribute('onClick',"this.style.display=\'none\';  ");
    tmp=document.createTextNode(' Short alerts will be written here...');
    ffb.appendChild(tmp);                                          
    document.body.appendChild(ffb);
    i_alertBlock=document.getElementById("_alertBlock");   
  }



// "absolute location" block for writing longer messages. Starts with display:none. Has an onClick event associated with it to make it hidden once displayed 
  i_messageBlock=document.getElementById('_messageBlock');       //  message block already defined?
  if (!i_messageBlock) {                                        //  No -- make one.
    ffb=document.createElement('div');
    ffb.id='_messageBlock';
    ffb.setAttribute('class','styleMessageBlock');
    ffb.setAttribute('className','styleMessageBlock');
    ffb.setAttribute('onClick',"this.style.display=\'none\'; ");
        tmp=document.createTextNode(' Longer messages will be written here...');
    ffb.appendChild(tmp);                                         
    document.body.appendChild(ffb);
    i_messageBlock=document.getElementById("_messageBlock");   
  }

oof=E2_getNodes(document.body,'SPAN DIV');
for (var i =0 ; i<oof.length ; i++){
   var ac=getAttributes(oof[i],"CLASS",'na');
   var aid=getAttributes(oof[i],"ID",'na');
}


// temporary workspace for concatenating and tweaking modules - at bottom of page, but never displayed. Hence footer is 
// the visible bottom of the page
// check for a _statusHistory_block div (create at bottom of document if necessary)

  i_statusHistory_block=document.getElementById('_statusHistory_block');
  if (!i_statusHistory_block) {
      xx=document.createElement('div');
      xx.id='_statusHistory_block';
      document.body.appendChild(xx);
      i_statusHistory_block=document.getElementById("_statusHistory_block");
  }


  return 1 ;
}

//=======================
// copy the current contents of the page to a new window (current contents includes results of dynamic)
function E2_showPageSource() {
 var ff,dw,t1,cssc,m ;
 var t0,itt,cvar;

  if (!debugOn()) {
        alert('Sorry, this debug information is not currently being displayed');
        return 0;
   }

  ff=i_pageNow.innerHTML ;
 // ff=document.body.innerHTML ;

  dw=window.open('','debugwindow');
  dw.document.open('text/html');
  var t1='<html><head>';
  cssc='<link rel="stylesheet" type="text/css" href="/dsurvey/lib/svyLibE2.css" >';
  for (var m=0;m<listOfCssFiles.length;m++) {
      cssc=cssc+'\n'+'<link rel="stylesheet" type="text/css" href="'+listOfCssFiles[m]+'" >';
  }
  t1=t1+cssc;

  t1=t1+'<title>Page contents</title><body bgcolor="#effeed"> '+ff +' \n ';
  t1=t1+'<div style="background-color:#d4d4c3;margin-top:15px"><em>Page info...</em> </div>  \n';
  t1=t1+'<div style="background-color:#d4d4d3;border:1px dotted brown;margin:5px 5% 5px 5%"">';

  gnumber=Read_Global('_GroupNumber');
  gname=Read_Global('_GroupName');
  snumber=Read_Global('_SectionNumber');
  sname=Read_Global('_SectionName');
  modlist=Read_Global('_moduleList');

  evlist=Read_Global('_eventList');
  t1=t1+'<br/>Section '+sname+ ' ('+snumber+'), group '+gname+' ('+gnumber+') <br/> using modules: '+modlist+'<br/>Events: '+evlist+'</div>' ;

  if (debugOn(1)) {
        t1=t1+'\n <div style="margin:20px 5px 20px 4%;border:2px solid gray"> \n'+Show_Variables(0,1)+'\n </div> ';
  }


  if (debugOn(1)) {

    t0='<b>Message data:</b><br/>'+
        ' <em>Message display options: </em><tt> '+  messageData['MESSAGE_OPTIONS']+'</tt> <p/>'+
        '<em>constants:</em> '+
        '<ul> ';
        for (var itt=0;itt<messageData['$constlist'].length;itt++) {
           cvar=messageData['$constlist'][itt];
           t0=t0+'<li>'+cvar+': <tt>'+messageData[cvar]+'</tt></li> ';
        }
        t0=t0+'</ul>'+ 
        '<em>arrays:</em> '+
        '<ul> ';
        for (var itt=0;itt<messageData['$varlist'].length;itt++) {
           cvar=messageData['$varlist'][itt]; 
           t0=t0+'<li>'+cvar+': <tt>'+messageData[cvar].join(' | ')+'</tt></li> ';
        }
        t0=t0+'</ul> </p> ';
        t1=t1+'\n  <div style="padding:10px;border:2px solid blue"> <h4>Message variables </h4> \n'+t0+'\n </div> ';
  }  


  if (debugOn(1)) {
        t1=t1+'\n  <div style="padding:10px;border:2px solid blue"> <h4>Prior round variables </h4> \n'+showSvyGlobalsHistory()+'\n </div> ';
  }  


  t1=t1+' \n </body></html>';
  dw.document.write(t1);
  dw.document.close();

}

//=======================
// reload parameters, and refresh the page
function E2_refreshThePage() {
alert('not implemented');

}


//============================
// Retrieve xml module files from server.
// Parses xml "modules" and stores results to xmlModuleList
// otherwise, it
function E2_start_getXmlModules(toget,first1,justread,baseurl) {
var fnode,toget;
if (first1==1) {                        // first call --  find the list of xml module files to retrieve
  fnode=toget;
  flist=E2_start_makeFileList_xml(fnode);        //  extract <FILE> blocks.
  if (flist.length==0) {            // error. No module files to retrieve...
        alert('E2_start error: there were no modules files specified in INIT ');
        return 0;
   }
  if (debugOn()) E2_writeStatus(' Module files to retrieve= '+flist.length);
  toget=flist.join(' ');
}

if (first1==2) {                        // got an XML module file (saved to _moduleFile). Parse it
  if (_moduleInfo!==null)                {       // problem retrieveing file?
    if (debugOn(2)) E2_writeStatus('   ... check errors, and then parse module file ');
    checkXMLDocErr(_moduleInfo,justread) ;
    E2_start_parseModules(_moduleInfo,justread)  ;
  } else {
     E2_writeStatus('Error: unable to retrieve module file '+justread);
  }
}

// get next xml module
toget=strip(toget);                     // pop first word in toget.

if (toget=='') {                                // no more files to get
  Launch_Proc('E2_start',1000,'','',13);    //   so return control to E2_start
  return 0 ;
}


afile=getWord(toget,1);
afile=resolveRelativeURL(afile,baseurl+'MODULES/');

toget=getWord(toget,[2,1000000]);

//Get_xmlFile('='+afile,'_moduleInfo','Retrieve XML module file ','E2_start_getXmlModules',toget,2,afile,baseurl) ;  ;  // note use of '=' (to allow cache resolution)
Get_xmlFile(afile,'_moduleInfo','Retrieve XML module file ','E2_start_getXmlModules',toget,2,afile,baseurl) ;  
return 0 ;


}               // end of E2_start_getXmlModules



//=============
// check for parse error. If found, alert and return 1. Otherwise, return 0

function checkXMLDocErr(xmlDoc,justread) {
 
/* ==
   if (typeof(ActiveXObject)!=='undefined') {
     alert(' ug '+xmlDoc.parseError);
     if (xmlDoc.parseError.errorCode !== 0) {
        alert("Error in line " + xmlDoc.parseError.line + " position " + xmlDoc.parseError.linePos + "\nError Code: " + xmlDoc.parseError.errorCode + "\nError Reason: " + xmlDoc.parseError.reason + "Error Line: " + xmlDoc.parseError.srcText);
        if (debugOn()) E2_writeStatus('XML error in '+justread);
        return 1;
     }
     return 0;
   }
== */

    if (xmlDoc.nodeName.toUpperCase()=="PARSERERROR")   {
         alert(' Error: problem parsing XML file ('+justread+'): \n'+xmlDoc.childNodes[0].nodeValue);
         if (debugOn()) E2_writeStatus('XML error in '+justread);
         return 1;
    }
    return 0 ;
}


//============================
// parse the module-file DOM nodes in xmlModulesBase, store them in xmlModuleList

function E2_start_parseModules(mnode,mname)  {

var alist,i1,i2,anode,aname,mname,mnodes ;

var ndog=0 ;
mnodes=E2_getNodes(mnode,'MODULES MODULE')
for (var i2=0;i2<mnodes.length; i2++) {
       aname=getAttributes(mnodes[i2],'ID','');
       if (aname=='') {
           alert('Error in E2_start_parseModules: no name (ID) assigned for module '+ i2 +' in '+ mname); 
           return 0;
      }
      aname=aname.toUpperCase();
      aname=resolveIndex(aname,mnode);
      if (typeof(xmlModuleList[aname])!=='undefined') {
          E2_writeStatus(' WARNING: overwriting xmlModuleList ' + aname + '(using module in ' + mname) ;
      }
     xmlModuleList[aname]=mnodes[i2] ;
     xmlModuleList[0]=xmlModuleList[0].concat(aname) ;
}
E2_writeStatus(' MODULES from '+ mname + '=' + mnodes.length);

return xmlModuleList[0].length;

}


//====================
// retrieve and store the history file from the server
// Note: this can be called by the  <Recover> (or <recoverHistory>) init option, or the <recoverPrior>
//       event action.
// The source is determiend by the atag (if it does NOT exist, the call is from <recover>
// Depending on the source, either E2_Start (the initialization stuff), or E2_recoverPrior
// (the event stuff) is called when the history has been successfully retrieved from the server
// In either case, svyGlobalHistory is rebuilt (assuming info for this id is stored in the 
// history archive on the server)

function E2_recoverHistory(ido,atag,nnode,astuff) {

var myid,toGet,dlist,mynodes,m,aaid,anid,avar,aval,sessName,aindex3 ;
var m2,dvars,vname,vval,aelem,showm,aindex,maxround;
var roundList=[] ;                  // list of rounds in history archive (for this client)
var roundVals=[];

if (arguments.length<1) ido=1;
if (arguments.length<2) {atag='';nnode=0;astuff='' } ;

myid=strip(Read_Global('MYID',''));

if (myid=='') {
  if (atag=='') {
     writeStatus('Warning: recover history, but no MYID available');
     Launch_Proc('E2_start',1000,'','',14);    //   so return control to E2_start
  } else {
     writeStatus('Warning: download history archive (from a recoverPrior), but no MYID available');
     alert('Warning: recover history (from a recoverPrior), but no MYID available');
  }
  return 1 ;
}
sessName=Read_Global('_sessionName');

if (ido==1) {
   toGet=getSaveDataURL+'session='+sessName+'&type=HISTORY' ;
   E2_writeStatus('About to request history data ... ');
   Get_xmlFile(toGet,'historyNode',' retrieving history archive','E2_recoverHistory',2,atag,nnode,astuff);
   return 1 ;
}

dlist=E2_getNodes(historyNode,'data');

mynodes=[];
for (var m=0;m<dlist.length;m++) {
  aaid=E2_getNodes(dlist[m],'ID');
  if (aaid.length<0) continue ;
  anid=strip(E2_getNodeText(aaid[0],1,' '));
  if (myid!=anid) continue ;
  mynodes=mynodes.concat(dlist[m]);
}

E2_writeStatus('   History recovered: '+dlist.length+' records, of which '+mynodes.length+' are for this client ');
if (mynodes.length==0) {                                // no history for this client
  if (atag=='') {
     Launch_Proc('E2_start',1000,'','',14);    //    return control to E2_start
  } else {
     Launch_Proc('E2_recoverPrior',1000,2,atag,nnode,astuff);    //    return control to E2_recoverPrior
  }
}

// pull data from history, save to globalHistory. Note: convert varname_i_ to varname[i]

for (var m=0;m<mynodes.length;m++) {                    // all records for this client (each record is for a round, in rare cases there may be > 1 record per round
   arecord=mynodes[m];
   dvars=E2_getNodes(arecord,'ROUND');
   if (dvars.length==0) continue ;              // should always have a round
   around=strip(E2_getNodeText(dvars,1,''));
   if (around==='' || isNaN(around)) continue ;                 // and can't be empty or non-numeric, this round
   roundList[around]=0;
   dvars=E2_getNodes(arecord,'*');
   for (var m2=0;m2<dvars.length;m2++) {
       aelem=dvars[m2];
       vname=cvtToArrayName(aelem.nodeName);
       if (vname=='ID' || vname=='ROUND') continue  ;                   // skip ID and ROUND elements
       vval=E2_getNodeText(aelem);
       roundList[around]=1 ;
       if (typeof(roundVals[around])=='undefined') roundVals[around]={};
       roundVals[around][vname]=vval;
    }
}                               // records for this client

maxround=roundList.length-1 ;                   // this is the "recent" round

SvyGlobalsHistory['$recent']={} ;

SvyGlobalsHistory['$roundlist']=roundList;

for (var m=0;m<roundVals.length;m++) {
  if (typeof(roundList[m])=='undefined') continue ;              // nothing for this round
  SvyGlobalsHistory[m]={};
  for (var m2 in roundVals[m] ) {
       aindex3=parseUsing(m2,'[',']',1);                          // look for index in varname
       if (aindex3[1]=='') {                                    // not an array[n]
          SvyGlobalsHistory[m][m2]=roundVals[m][m2] ;
          if (m==maxround) SvyGlobalsHistory['$recent'][m2]=roundVals[m][m2] ;
       } else {                                                 // is an array[n]
         av=strip(aindex3[0].toUpperCase()) ;
         if (typeof(SvyGlobalsHistory[m][av])=='undefined')SvyGlobalsHistory[m][av]=[];
         SvyGlobalsHistory[m][av][strip(aindex3[1])]=roundVals[m][m2] ;
         if (m==maxround) {
            if (typeof(SvyGlobalsHistory['$recent'][av])=='undefined')SvyGlobalsHistory['$recent'][av]=[];
            SvyGlobalsHistory['$recent'][av][strip(aindex3[1])]=roundVals[m][m2] ;
        }
      }
  }
}

if (atag=='') {
   Launch_Proc('E2_start',1000,'','',14);    //    return control to E2_start
} else {
   Launch_Proc('E2_recoverPrior',1000,2,atag,nnode,astuff);    //    return control to E2_recoverPrior
}
return 1;

}

//==================== iround maxr
// retrieve simpleHistory archive from the server
function E2_recoverSimpleHistory(ido) {
var myid,sessname,toGet ;
var vv,vv2,m,around,hvars,dlist,svals,mm;

if (arguments.length<1) ido=1;

myid=strip(Read_Global('MYID',''));

if (myid=='') {
//   alert('Error in recoverSimpleHistory: no MYID available ');   // or first time
  Launch_Proc('E2_start',1000,'','',2);    //   so return control to E2_start

   return 1 ;
}
sessName=Read_Global('_sessionName');

if (ido==1) {
   toGet=getSaveDataURL+'session='+sessName+'&type=SIMPLEHISTORY' ;
   E2_writeStatus('About to request simple history data ... ');
   Get_xmlFile(toGet,'historyNode',' retrieving simpleHistory archive','E2_recoverSimpleHistory',2);
  return 1 ;
}

dlist=E2_getNodes(historyNode,'data') ;

hvars=[];
for (var m=0;m<dlist.length;m++) {
  aaid=getAttributes(dlist[m],'ID','xx');
  if (aaid!==myid) continue ;
  around=getAttributes(dlist[m],'round',0);
  if (isNaN(around)) {
        alert('Error reading simpleHistory: bad round = '+around);
        return 0;
  }
  vv=E2_getNodeText(dlist[m]);
  vv2=vv.split(',');
  for (var mm=0;mm<vv2.length;mm++) {    // note: each argument was escaped (commas were retained)
        vv2[mm]=unescape(vv2[mm]);
  }
  hvars[around]=vv2;
}
// hvars is an array of arrays. Each element is an array of the simpleHistory variables
E2_writeStatus('simpleHistory recovered: '+hvars.length+' records are for this client ');

if (hvars.length==0) {                                // no simpleHistory for this client
   Launch_Proc('E2_start',1000,'','',2);    //   so return control to E2_start
   return 0 ;
}

// re build the simpleHistory table using hvars
for  (var m=0;m<hvars.length;m++) {
   if (typeof(hvars[m])!=='undefined') {
      svals=E2_makeSimpleHistoryRow(m,hvars[m])      ;                 // uses globals
   }
}


Launch_Proc('E2_start',1000,'','',2);    //   so return control to E2_start
return 1;

}






//=============
// Load js and css files (from http://www.javascriptkit.com/javatutors/loadjavascriptcss.shtml
function loadJsCssFile(filename, filetype){
var ff ;
if (arguments.length<2) {
   ff=strip(filename.toUpperCase()) ;
   if (ff.indexOf('.JS')>0) filetype='js';
   if (ff.indexOf('.CSS')>0 ) filetype='css'
 }
 if (filetype=="js"){ //if filename is a external JavaScript file
  var fileref=document.createElement('script')
  fileref.setAttribute("type","text/javascript")
  fileref.setAttribute("src", filename)
 }
 else if (filetype=="css"){ //if filename is an external CSS file
  var fileref=document.createElement("link")
  fileref.setAttribute("rel", "stylesheet")
  fileref.setAttribute("type", "text/css")
  fileref.setAttribute("href", filename)
  listOfCssFiles=listOfCssFiles.concat(filename);
 } else {
       alert('Error: trying to load non css or js file: '+filename);
       return 1;
 }
 if (typeof fileref!="undefined") {
   document.getElementsByTagName("head")[0].appendChild(fileref)
 }
return 1;
}


/* ::===============================================================================================================*/
/* ======================  Functions to write messages to "blocks" (generic DIVS)                  ================*/

// ===================`
// write a message to the _nameBlock. 
function E2_writeName(aname) {
  if (useFooter_flag==0) return 0 ;                     // footer is suppressed, so do nothing 
  var foo=E2_writeBlock('_nameBlock',aname,'',-1);
  return foo;
}

// ===================`
// write a message to the _headerMessage. If aname="", make _headerMessage hidden
// if aclass specified, it should be a css class to use for the headerMessage block
function E2_writeHeaderMessage(aname,aclass) {
  if (arguments.length<1) {                     // a reest 
     E2_writeBlock('_headerMessage','','',-2,'styleHeaderMessage') ;
     return 1 ;
  }
        
  if (arguments.length<2) aclass="styleHeaderMessage";
  if (useHeader_flag==0) return 0 ;                     // header is suppressed, so do nothing 
  if (strip(aname)=='') {                               // '' means "hide" 
    var foo=E2_writeBlock('_headerMessage','','',0);
    i_headerMessage.setAttribute('style','display:none');
  } else {
    var foo=E2_writeBlock('_headerMessage',aname,'',1);
    i_headerMessage.setAttribute('style','display:block');
    if (aclass!=='') { 
        i_headerMessage.setAttribute('class',aclass);
        i_headerMessage.setAttribute('className',aclass);
     }

   }
  return foo;
}


// ===================
// write a message to the _qDescBlock. If prefix not specified, use "You are " as a prefix to aname
function E2_writeQdesc(aname) {
  if (useFooter_flag==0) return 0 ;                     // footer is suppressed, so do nothing 
  var foo=E2_writeBlock('_qDescBlock',aname,'',-1);
  return foo;
}

// ===================
// write a message to the statusBlock, but do NOT force visibility
// If saveFreq=0, don't save to status history buffer. Default is to save.
// If saveFreq=1, then save every "saveFreq" message. This is the default is save all messages
// If saveFreq>1, save every "saveFreq" message.
//     I.e.; if saveFreq=4, then only save every 4th message to the history buffer
// Special case: if writeDoStatus exists, than call it instead of processing here (i.e.; if control panel, use the control panel specific function)
function E2_writeStatus(amess,saveFreq) {

  if (typeof(writeDoStatus)!=='undefined') {            // called by control panel procedures?
        writeDoStatus(amess);
        return 1;
   }

  if (arguments.length<2) saveFreq=1 ;
  if (arguments.length==0) amess='Status messages written here.' ;
  if (useFooter_flag!==0) {                     // if footer is suppressed, do not write
       var foo=E2_writeBlock('_statusBlock',amess,'',0);                       // do NOT force visibility
   }

  if (saveFreq!=0) {
    statusHistoryStuff.count=simpleHistory.count +1 ;
    if (saveFreq<1) saveFreq=1 ;
    var  doit=statusHistoryStuff.count % saveFreq ;
    if (doit==1 || saveFreq==1 ) {
       if (typeof(statusHistoryStuff)=='undefined') {
           alert('Error in E2_writeStatus: statusHistoryStuff object not defined '); return 0 ;
        }
        statusHistoryStuff.content=amess+'\n'+statusHistoryStuff.content;
        if (statusHistoryStuff.content.length>10000) statusHistoryStuff.content=statusHistoryStuff.content.substr(0,10000)+'\n' ;
     }
  }
  return 1 ;
}

// ===================
// toggle view of the _statusBlock. Do NOT change its message.
// If no argument, toggle the view (this is the typical usage)
// If an argument: 0=hidden, 1=visible, ?=return current state ('hidden' or 'visible')

function E2_toggleStatus(istate) {

  if (useFooter_flag==0) return 0 ;                     // footer is suppressed, so do nothing 
  if (arguments.length==0) istate=2 ;
  var foo=E2_writeBlock('_statusBlock','','',istate)
  return foo ;
}

//====================
// write messsage to _headerButton or topTimer, or change visibility.  By default: On message write, make visible.
// Avis:
//   amess : string containing content to write (perhaps a <button...).  If '', and avis<>'', just change visibility
//   avis: visibility (0=no, 1=visible,2=toggle,-1=no change. Default is -1 if amess='', else default is 1
function E2_writeHeaderButton(amess,avis) {

  if (arguments.length<1) {                     // a reest 
     E2_writeBlock('_headerButton','','',-2,'styleHeaderButton') ;
     return 1 ;
  }
  if (arguments.length<2) avis=-1;

  amess=strip(amess) ;
  if (amess!=='')  {                    // a message, write it 
    if (avis==-1) avis=1 ;
  }
  E2_writeBlock('_headerButton',amess,'',avis); 
  return 1 ;
}

//====================
// write messsage to _headerButton or topTimer, or change visibility.  By default: On message write, make visible.
// Avis:
//   amess : string containing content to write (perhaps a <button...).  If '', and avis<>'', just change visibility
//   avis: visibility (0=no, 1=visible,2=toggle,-1=no change. Default is -1 if amess='', else default is 1
//  aclass: optional. If specified, the class to use to display headerTimer block
function E2_writeHeaderTimer(amess,avis,aclass) {

  if (arguments.length<1) {                     // a reest 
     E2_writeBlock('_headerTimer','','',-2,'styleHeaderTimer') ;
     return 1 ;
  }

  if (arguments.length<2) avis=-1;
  if (arguments.length<3) aclass=''
 
  amess=strip(amess) ;
  if (amess!=='')  {                    // a message, write it 
    if (avis==-1) avis=1 ;
  }

  E2_writeBlock('_headerTimer',amess,'',avis,aclass); 
  return 1 ;
}



//====================
// display the status history in the _messageBlock

function E2_viewStatusHistory(ido) {

  if (arguments.length<1) ido=0;
  if (ido==0) {
     arf=E2_writeMessage('<pre>'+statusHistoryStuff.content+'</pre>',' Status messages (click here to close this box)' ) ;
     return arf;
  }
  var aa=strip(i_statusHistory_block.innerHTML) ;
  if (aa=='') {
     i_statusHistory_block.innerHTML='\n <pre>'+statusHistoryStuff.content+'</pre> \n ';
     i_statusHistory_block.style.display='block';
  } else  {
     i_statusHistory_block.innerHTML='';
     i_statusHistory_block.style.display='none';
  }

  return 0 ; 


}

// ===================
// write, or make visible, the _messageBlock. You can specify a message and a header. 
// If no header specified, a generic "click here to close box" header is used.
// unless otherwise specified, always make visible after writing message (this is the typical usage)

function E2_writeMessage(amess,aheader,vstate) {

  if (arguments.length<3) vstate=1              ;               // make visible after writing is the default
  if (arguments.length<2) aheader='Click here to close this message box' ;               
  var foo=E2_writeBlock('_messageBlock',amess,aheader,vstate)
  return foo ;
}


// ===================
// write, or make visible, the _alertBlock  You can specify a message and a header. 
// amess: a message to write
// aheader: a header to write above the message (highlighted) (optional)
//  vstate: make the alert box visible( 0=no, 1=yes). Default is 1 (see E2_writeBlock for details on vstate)
// iduration:  if specified, after this many milliseconds, make the alert box invisible (and clear its contehts )
// atoken: identifies this call to writeAlert -- used to suppress closing (i.e.; a later writeAlert has occurred)
// If no header specified, no header is written (this is the typical usage)
// Unless specified, always make visible after writing (this is the typical usage)

function E2_writeAlert(amess,aheader,vstate,iduration,atoken) {

  
  if (arguments.length<3) vstate=1 ; 
  if (arguments.length<2) aheader='' ;
  if (arguments.length<5) atoken='T'+ (' '+Math.random()).substr(3);
  if (vstate==0) {                              // make invisible--- first check token (perhaps a later alert was written?)
       if (atoken!==_writeAlertToken) {
          return 0 ; // not the same: do nothing ;
       }
  }
  _writeAlertToken=atoken;
  var foo=E2_writeBlock('_alertBlock',amess,aheader,vstate);
  if (arguments.length>3) {                     // duration?
    if (!isNaN(iduration) && iduration > 0 )    Launch_Proc('E2_writeAlert',iduration,'','',0,0,atoken);
  }


  return foo ;
}


// =-============= the general version 
// Write message to the the whichBlock Block (such as _messageBlock and _alertBlock
// Two components can be specified:: a message  and a header
//     If aheader not specified, or ='', do NOT write a header 
// Vstate          ='', do NOT change visibility (this is the default)
//                = -2 : set to hidden, and remove innerHTML (amess, aheader are ignored)
//                =-1 , do NOT change visbility (same as '')
//                =0 , hide it
//                =1 , display it
//                =2 , toggle
//                ='?' , return current visibility, and do NOT change message or header
// aclass : Optional. If specified, change the whichBlock class to aclass
//    (-1 means is the same as NOT specifying-- if -1, then write message & header)
// Note: if message='' and header='', and vstate is specified; do NOT change message and header, JUST modify visiblity

function E2_writeBlock(whichBlock,amess,aheader,vstate,aclass) {


// reset example:     E2_writeBlock('_headerButton','','',0,'styleHeaderButton') ;

 if (arguments.length<4) vstate=-1 ;                   // -1 means ignroe
 if (arguments.length<5) aclass='' ;                
 if (strip(vstate)=='') vstate=-1 ;
 if (arguments.length<3) aheader='' ;                   // -1 means ignroe

  var arf=document.getElementById(whichBlock);

  if (!arf) {
    alert('ERROR writing message: a '+whichBlock+ ' DIV does not exist \n '+amess);
    return 0;
  }
 
 if (aclass!=='') {
   aclass=strip(aclass);
   var vv0=strip(arf.getAttribute('class')); 
   vv0a=vv0.toUpperCase() ;
   if (vv0a.indexOf(aclass.toUpperCase())<0) {
     arf.setAttribute('class',vv0+' '+aclass);
     arf.setAttribute('className',vv0+' '+aclass);
   }
 }

  if (vstate==-2) {                       // make invisible, remove contents 
       arf.style.display='none';
       arf.innerHTML='' ;
       return arf.style.display ;  
  }

  if (vstate!==-1) {                       // set or toggle visiblity
      vstate=strip(vstate);
      var isvis=arf.style.display ;
      if (vstate=='?') {
           return isvis ;                   // return current visibilty status -- do NOT change  header and message
      } else if (vstate=='2') {                  // toggle
        if (strip(isvis.toUpperCase())!=='NONE') {
            arf.style.display='none';
        }     else  {
           arf.style.display='block';
        }
      } else if (vstate=='1') {                            // make visible
           arf.style.display='block';
      } else {                                          // hide
           arf.style.display='none';
      }  

      if (aheader=='' && amess=='' ) return arf.style.display  ;     // setting visbility, and if nothing to write, then return without changing contents of block

  }


// write header and message
 aheader=strip(aheader);
 if (aheader!='') {
   var ah=  '<div class="styleWriteBlockHeader" >' +aheader +'</div>';
   amess=ah+'<div class="styleWriteBlockMessage" >'+amess   +'</div>' ;
 }
 arf.innerHTML=amess ;

//if (whichBlock=='_alertBlock') alert('writeblockmessabe ='+amess+','+arf.style.display)

 return arf.style.display ;


}

/* ::========================================================================================================================*/
/* ==============================  Function to work with DOM nodes       =========================================*/


// ==================================
// Copy contents of an XML or DOM tree.
// xnode is a node (say, from an XML tree)
// If xnode is only argument, than copy the entire tree starting at xnode, and return this new tree
//      I.e.; close xnode
// If more than one argument, than xnode is appended to the atag, where
//   atag: either a string with a tagname, or an existing node
//         if string:  create a new node with this as the tagname, and then append xnode to this new node
//                    basically, this copies XNODE onto a newly created element with atag as this new elements tagname
//         if existing node (dom or xml object): append content of xnode to end of atag, and return 0
// skipTag: 
//   If skiptag equals the nodeName of xnode, then don't copy xnode completly. Instead, copy the children of xnode to atag.
//      Thus, the children of atag become the direct children of atag (and the xnode's root element is NOT copied)
// 

// This is highly recursive. 
// Note special treatment of skiptag nodeName  -- if first node of xnode has name of skiptag, SKIP it and just use the children

function E2_xmlToDom(xnode,atag,skipTag,idebug)  {

var newNode,achild,xtype,xname,cnode,pnode,tnode,i,xattrN,xattrV,i2;
var glob='';

if (arguments.length<4) idebug=0;


xtype=xnode.nodeType ;
xname=xnode.nodeName.toUpperCase() ;

if (arguments.length>1  ) {                        // create new node, or append mode
  if (arguments.length<3) skipTag="MODULES";
  skipTag=strip(skipTag).toUpperCase() ;
  if (typeof(atag)!='object')  {                // Not an object -- so create the tree root
    pnode=document.createElement(atag) ;
    glob=atag;
    if (xname!=skipTag)  {                      // if skiptag, 
        cnode=E2_xmlToDom(xnode) ;
        pnode.appendChild(cnode);
    } else {                     // then skip parent and get children 
        for (var i2=0 ; i2<xnode.childNodes.length ;i2++) {
           cnode=E2_xmlToDom(xnode.childNodes[i2]) ;
           pnode.appendChild(cnode);
        }
    }                          // module
    return pnode ;
  } else {                             // atag  an object 
    if (xname!=skipTag)  {
        cnode=E2_xmlToDom(xnode) ;
        atag.appendChild(cnode);
     } else {                     // skip parent (just get childred)
        for (var i2=0 ; i2<xnode.childNodes.length ;i2++) {
           cnode=E2_xmlToDom(xnode.childNodes[i2]) ;
           atag.appendChild(cnode);
        }
     }                                  // module
     return 0 ;                         // append mode
  }                                     // atag an object 
}                                       // arguments.length

if (xtype==3) {
     tnode=document.createTextNode(xnode.nodeValue);
     return tnode ;
}
if (xtype==8) {
   tnode=document.createComment(xnode.nodeValue);
    return tnode ;
}

// one argument, that is a node. Create a new node, and add attributes.

pnode=document.createElement(xname);
glob=arguments.length+', xname, '+xname + ', atag= '+ atag ;

for (var i=0; i<xnode.attributes.length ; i++) {
  xattrN=xnode.attributes[i].nodeName ;
  xattrV=xnode.attributes[i].nodeValue ;
  pnode.setAttribute(xattrN,xattrV);
}

// append the child nodes
for (var i=0; i<xnode.childNodes.length; i++) {
  achild=xnode.childNodes[i];
  atype=achild.nodeType ;
  if (atype==3) {                               // text type -- add to pnode
     tnode=document.createTextNode(achild.nodeValue) ;
     try {
        pnode.appendChild(tnode);
      } 
      catch(ierr) {         
         alert('error pnode.appendchild (comment): '+glob+', value='+achild.nodeValue+' ::err= ' + ierr);
      }
      continue ;
  }
  if (atype==1) {                       // element type,   recurse
     cnode=E2_xmlToDom(achild) ;
     pnode.appendChild(cnode);
  }                                             // else, skip the node   

}                       

return pnode;                   // return a new node xmlToDom

}

//=========
// simple verison, copy retaining comments

function E2_xmlToDomCmt(xnode,iarf)  {

var newNode,achild,xtype,xname,cnode,pnode,tnode,i,xattrN,xattrV,i2;
var glob='';

if (arguments.length<4) idebug=0;


xtype=xnode.nodeType ;
xname=xnode.nodeName.toUpperCase() ;

if (xtype==3) {
     tnode=document.createTextNode(xnode.nodeValue);
     return tnode ;
}
if (xtype==8) {
   tnode=document.createComment(xnode.nodeValue);
    return tnode ;
}

// one argument, that is a node. Create a new node, and add attributes.

pnode=document.createElement(xname);
glob=arguments.length+', xname, '+xname ;

for (var i=0; i<xnode.attributes.length ; i++) {
  xattrN=xnode.attributes[i].nodeName ;
  xattrV=xnode.attributes[i].nodeValue ;
  pnode.setAttribute(xattrN,xattrV);
}

// append the child nodes
for (var i=0; i<xnode.childNodes.length; i++) {
  achild=xnode.childNodes[i];
  atype=achild.nodeType ;
  if (atype==8 ) {                               // comment -- add to pnode
    tnode=document.createComment(achild.nodeValue);
    try {
        pnode.appendChild(tnode);
      } 
      catch(ierr) {
         alert('error pnode.appendchild (text): '+glob+', value='+achild.nodeValue+' ::err= ' + ierr);
      }
      continue ;
  }  
  if (atype==3) {                               // text type -- add to pnode
     tnode=document.createTextNode(achild.nodeValue) ;
     try {
        pnode.appendChild(tnode);
      } 
      catch(ierr) {         
         alert('error pnode.appendchild (comment): '+glob+', value='+achild.nodeValue+' ::err= ' + ierr);
      }
      continue ;
  }
  if (atype==1) {                       // element type,   recurse
     cnode=E2_xmlToDomCmt(achild,1) ;
     pnode.appendChild(cnode);
  }                                             // else, skip the node   

}                       

return pnode;                   // return a new node xmlToD


}

// ========== 
// === a synonym
function E2_copyNode(xnode,atag,skipTag,idebug)  {
var xnode ;
if (arguments.length==1) {
  xnode=E2_xmlToDom(xnode)  
}
if (arguments.length==2) {
  xnode=E2_xmlToDom(xnode,atag)  
}
if (arguments.length==3) {
  xnode=E2_xmlToDom(xnode,atag,skipTag) 
}
if (arguments.length==4) {
  xnode=E2_xmlToDom(xnode,atag,skipTag,idebug)  
}
return xnode;
}


// xmlToDom
//======================
// return an array of nodes pulled from the children of the adom "dom object", using atags to  choose which ones to return
// Unlike getElementsByTagname --- will NOT return seperate array items for grandchildren
//  adom is a XML object, say as read from xmlhttprequest for an XML file.
// taglist should be a space delimited list of tags to retrieve -- case insensitive matching is used.
// if first1 =1,then only return the first child that matches one of the tags
// Note: text nodes are NOT returned

function E2_getNodes(adom0,taglist,first1) {

  var imatch,nn0,i,tarray,dachilds,thistag,adom;
  if (arguments.length<2) taglist='*';     // default: all children
  taglist=strip(taglist);
  if (arguments.length<3) first1=0 ; 

  if (typeof(adom0)!=='object') {
    alert('Error in E2_getNodes: variable to process is not an object: '+adom0 +' ( ' + taglist);
    E2_writeStatus('Error in E2_getNodes: variable to process is not an object: '+adom0);
    return 0 ;
  }

  if (typeof(adom0)=='null' || typeof(adom0)=='undefined') {
        alert('Error in e2_getNodes: empty source node (looking for '+taglist);
        return 0 ;
   }

  if (typeof(adom0.length)!='undefined') {                       // only do first object in an array of objects
       if (adom0.length==0) return [] ;
        adom=adom0[0];
   } else {
        adom=adom0;
    }
  

  try {
     var dachilds=adom.childNodes ;
  }
   catch(err) {
     alert('Error in getNodes ('+err+'):'+adom+'\n'+adom0);
     return 1;
  }



  var dachilds=adom.childNodes ;
  var tarray= new Array() ;
  if (typeof(dachilds)!='object' || typeof(dachilds.length)=='undefined') {
        alert('Error in e2_getNodes: no childnodes for '+adom+','+taglist);
        return 0 ;
   }
  for (var i=0;i<dachilds.length;i++) {
     nn0=dachilds[i];
     if (nn0.nodeType!==1) continue ;           // not a "node" type (proabably text). Skip
     var thistag=nn0.nodeName ;
     if (taglist=='*' ) {
         imatch=1  ;
    } else {
        var imatch=Word_inString(thistag,taglist);
    }
    if (imatch>0) {
         tarray[tarray.length]=nn0;
         if (first1==1) return tarray ;
    } 
  }
  return tarray ;
}


/* ========================================== */
/* 

 NOT YET IMPLEMENTED (maybe never)


  procedure to read XML file and save it's contents to array containing CSV strings.
 Each "top level" element in the xml file is a row in the array.
   The 0th element contains a csv string of  variable names.
   Thus, actual values begin at index 1.

 The string contains values for every variable name specified in the XML file.
 Thus, the same number of CSV seperated values appear in each row.

 However, if a value is NOT specified in a "row", a missing value (by default, a blank) is included
 Variable names are created by concatenating node names with (by default, using a ".")

 There is no overwriting -- if a node has an identical hierarchy of names, a unique array-like
 name is created
 Thus
      <myxml>
        <v0> 100 </v0>
        <v1>  <v2>2</v2> <v3>3</v3>  </v1>
        <v1>  <v2>22</v2> <v3>33</v3>  </v1>
     </myxml>

 Would yield the CSV list of following variable names

     V0, V1.1, V1.1.V2, V1.1.V3, V1.2.V2, V1.2.v3

 and 
      <myxml>
        <v2> <i1>1.5 </i1> </v2>
        <v3> 
           <v3a>
              <v4>30</v4>  
           </v3a>
           <v3a>
             <v5>200</v5>   
           </v3a>
        </v3>
      <myxml>

 Would yield the CSV list of following variable names
     V2.I1, V3.V3A.1.V2, V3.V3A.1.V4,  V3.V3A.2.V5

===========*/

/* ========================================== */
/* procedure to read XML file and save it's contents to an object variable database. 
The object variable may have many elements, corresponding to the nesting of the xml file

Basic syntax:
   copyXmlToObject(xnode,'objectName',reset);
where:
   xnode: a node pointing to an XML file, or to a node within an XML file. Typically, this will be read using the Get_xmlFile.
   objectName : the name of the  object to create
   reset : if 1, delete the objectName object. Else, add to it

Basic structure:
  Given the xml file structured as
     <v1>
        <v1a> x1 </v1a>
        <v1b>  x2 </v1b>
      </v1>

  The structure of the objectName will be 
      objectName['V1']['V1A'] = x1
      objectName['V1']['V1B'] = x2


  Notes:
      *  if a node exists with the same name (but in a different part of the XML file), prior
         values will be overwritten

           <car>
              <name> ford </v1a>
              <year> 2008 </v1b>
           </car>
           <car>
              <name> toyota </v1a>
              <year> 2002 </v1b>
           </car>
        yields:
            objectName['CAR']['NAME'] = toyota
            objectName['CAR']['YEAR'] = 2002
        (the "ford" is overwritten)
         
      *  if any child nodes exist, text nodes are ignored. Thus:
           <v1>  t0
              <v1a> x1 </v1a>
              <v1b>  x2 </v1b>
           </v1>
        yields:
            objectName['V1']['V1A'] = x1
            objectName['V1']['V1B'] = x2
        (the "t0" value is ignored)

      * node names are always CAPITALIZED in the object.
      * node values are always Strings (even if they numeric)
        

  You can also specify multiple nodes with the same name, and use an "id" or a "name" attribute to create
  child nodes.
      * These "multiple nodes with the same name" should ONLY contain text (or arrays) 
      * That is, name and id attributes are IGNORED if the node has children.

  Thus:
      <v1> 
          <row > z0 </row >
          <row id="1"> x1 </row >
          <row id="2"> x1 </row >
          <row name"3"> x1 </row >
      </v1>
  yields:
      objectName['V1']['ROW']['1'] = x1                      
      objectName['V1']['ROW']['2'] = x2
      objectName['V1']['ROW']['3'] = x2
  (note that the "1", "2", and "3"  are strings)

    Notes:
     
     * while permitted, we do not recommend mixing nodes with and without h "id", or "name", attributes.
        That is, in the above example one can include
          <row > z0 </row >     
        to yield
           objectName['V1']['ROW'] = z0                      
        but we don't recommend doing so.
     * To identify how the XML file was structured, a ['type'] node (lower case) node is added to the object  for all
       "value" nodes. This 'type' node can have a value of "node", "id", or "name".
        Thus, in the above example, the following are created:
              objectName['V1']['ROW']['1']]['type'] = id                      
              objectName['V1']['ROW']['2']['type'] = id
              objectName['V1']['ROW']['3']['type'] = name
              objectName['V1']['ROW']['type'] = node                      
   

  You can specify an array, using an array="1" attribute, and using commas as delimiters. For example:
      <v1>
          <v1a>  x2 </v1a>
          <v1b array="1">100,200,300 </v1b>
          <v1b id="JJ" array="1">10,20 </v1b>
      </v1>
   To specify a different delimiter, include a delim="x" attribute (where x is the desired delimiter)

  yields:                          
      objectName['V1']['V1A'] = x2
      objectName['V1']['V1B'][0] = 100
      objectName['V1']['V1B'][1] = 200
      objectName['V1']['V1B'][2] = 300
      objectName['V1']['V1B']['JJ'][0] = 10
      objectName['V1']['V1B']['JJ'][1] = 20


  Notes
       * if an element spans multiple lines, \n (crlfs) will be included
       * the array elements (i.e.; [0]) are numbers, not strings.
       * the following values are also created:
           obj
ctName['V1']['V1B']['type'] = node
           objectName['V1']['V1B']['JJ']['type'] = id

============== */
function copyXmlToObject(xnode,objectName,ido,nmlist) {
if (arguments.length<3) ido=0 ;
if (arguments.length<4) nmlist=[] ;

var aname,m,cnode,aval,adelim,aid,nlist,isArray,atype ;

aname=strip(xnode.nodeName.toUpperCase()) ;
nmlist=nmlist.concat(aname);

if (ido==0) {                   // first call, no reset
  if (typeof(window[objectName])=='undefined') window[objectName]=new Object() ;                   
}

if (ido==1) {                   // first call, reset 
   window[objectName]=new Object() ;                   // 
}

nlist=E2_getNodes(xnode,'*');
if (nlist.length==0) {                          // no children. Must be a value node, so save it to object
    aval=E2_getNodeText(xnode);                // may concatenate several text nodes
    atype='node';
    aid=getAttributes(xnode,'id','');
    if (aid!='') {                                          // Check for NAME, ID, and ARRAY, attributes
/*         nmlist=nmlist.concat('!'+strip(aid.toUpperCase()));              */
         nmlist=nmlist.concat(strip(aid.toUpperCase()));                  
         atype='id'  ;         
    } else { 
        aid=getAttributes(xnode,'name','');                             
        if (aid!='') {
/*       nmlist=nmlist.concat('$'+strip(aid.toUpperCase()));            */
         nmlist=nmlist.concat(strip(aid.toUpperCase()));
         atype='name';
        }
    }
    isArray=getAttributes(xnode,'array','');
    if (isArray==1) {
        adelim=getAttributes(xnode,'delim',',');
        aval=aval.split(adelim) ;
    }
    saveObjectElementValue(objectName,nmlist,aval,atype);
    return 1 ;
}

// child nodes exist.  Process them 
for (var m=0;m<nlist.length;m++) {
   cnode=nlist[m];
   copyXmlToObject(cnode,objectName,2,nmlist) ;
}
return 1;
}

// ==================== 
// save an object value, using multiple indices in the nmlist array
function saveObjectElementValue(aobject,alist,aval,atype) {

  if (typeof(window[aobject])!='object') window[aobject]=new Object() ;             
  if (alist.length==0) {                            
        window[aobject]=aval;
        return 1 ;
  }
  if (alist.length==1) {               
       window[aobject][alist[0]]=aval      ;  
       window[aobject][alist[0]]['type']=atype      ;  

       return 1 ;
  }

  if (alist.length>1) {               
        if (typeof(window[aobject][alist[0]])!='object') window[aobject][alist[0]]=new Object() ;             
        if (alist.length==2) {
           window[aobject][alist[0]][alist[1]]=aval      ;  
           window[aobject][alist[0]][alist[1]]['type']=atype      ;  
           return 1 ;
        }
   }
  if (alist.length>2) {               
        if (typeof(window[aobject][alist[0]][alist[1]])!='object') window[aobject][alist[0]][alist[1]]=new Object() ;             
        if (alist.length==3) {
           window[aobject][alist[0]][alist[1]][alist[2]]=aval      ;  
           window[aobject][alist[0]][alist[1]][alist[2]]['type']=atype       ;  
           return 1 ;
        }
   }
  if (alist.length>3) {               
        if (typeof(window[aobject][alist[0]][alist[1]][alist[2]])!='object') window[aobject][alist[0]][alist[1]][alist[2]]=new Object() ;             
        if (alist.length==4) {
           window[aobject][alist[0]][alist[1]][alist[2]][alist[3]]=aval      ;  
           window[aobject][alist[0]][alist[1]][alist[2]][alist[3]]['type']=atype       ;  
           return 1 ;
        }
   }
  if (alist.length>4) {               
        if (typeof(window[aobject][alist[0]][alist[1]][alist[2]][alist[3]])!='object') window[aobject][alist[0]][alist[1]][alist[2]][alist[3]]=new Object() ;             
        if (alist.length==5) {
           window[aobject][alist[0]][alist[1]][alist[2]][alist[3]][alist[4]]=aval      ;  
           window[aobject][alist[0]][alist[1]][alist[2]][alist[3]][alist[4]]['type']=atype      ;  
           return 1 ;
        }
   }
  if (alist.length>5) {               
        if (typeof(window[aobject][alist[0]][alist[1]][alist[2]][alist[3]][alist[4]])!='object') window[aobject][alist[0]][alist[1]][alist[2]][alist[3]][alist[4]]=new Object() ;             
        if (alist.length==6) {
           window[aobject][alist[0]][alist[1]][alist[2]][alist[3]][alist[4]][alist[5]]=aval      ;  
           window[aobject][alist[0]][alist[1]][alist[2]][alist[3]][alist[4]][alist[5]]['type']=atype     ;  
           return 1 ;
        }
   }
  if (alist.length>6) {               
        if (typeof(window[aobject][alist[0]][alist[1]][alist[2]][alist[3]][alist[4]][alist[5]])!='object') window[aobject][alist[0]][alist[1]][alist[2]][alist[3]][alist[4]][alist[5]]=new Object() ;             
        if (alist.length==7) {
           window[aobject][alist[0]][alist[1]][alist[2]][alist[3]][alist[4]][alist[5]][alist[6]]=aval      ;  
           window[aobject][alist[0]][alist[1]][alist[2]][alist[3]][alist[4]][alist[5]][alist[6]]['type']=atype       ;  
           return 1 ;
        }
   }
  if (alist.length>7) {               
        if (typeof(window[aobject][alist[0]][alist[1]][alist[2]][alist[3]][alist[4]][alist[5]][alist[6]])!='object') window[aobject][alist[0]][alist[1]][alist[2]][alist[3]][alist[4]][alist[5]][alist[6]]=new Object() ;             
        if (alist.length==8) {
          window[aobject][alist[0]][alist[1]][alist[2]][alist[3]][alist[4]][alist[5]][alist[6]][alist[7]]=aval      ;  
          window[aobject][alist[0]][alist[1]][alist[2]][alist[3]][alist[4]][alist[5]][alist[6]][alist[7]]['type']=atype       ;  
          return 1 ;
        }
   }

  if (alist.length>8) {               
        if (typeof(window[aobject][alist[0]][alist[1]][alist[2]][alist[3]][alist[4]][alist[5]][alist[6]][alist[7]])!='object') window[aobject][alist[0]][alist[1]][alist[2]][alist[3]][alist[4]][alist[5]][alist[6]][alist[7]]=new Object() ;             
        if (alist.length==9) {
          window[aobject][alist[0]][alist[1]][alist[2]][alist[3]][alist[4]][alist[5]][alist[6]][alist[7]][alist[8]]=aval      ;  
          window[aobject][alist[0]][alist[1]][alist[2]][alist[3]][alist[4]][alist[5]][alist[6]][alist[7]][alist[8]]['type']=atype       ;  
          return 1 ;
        }
   }

  if (alist.length>9) {               
        if (typeof(window[aobject][alist[0]][alist[1]][alist[2]][alist[3]][alist[4]][alist[5]][alist[6]][alist[7]][alist[8]])!='object') window[aobject][alist[0]][alist[1]][alist[2]][alist[3]][alist[4]][alist[5]][alist[6]][alist[7]][alist[8]]=new Object() ;             
        if (alist.length==10) {
          window[aobject][alist[0]][alist[1]][alist[2]][alist[3]][alist[4]][alist[5]][alist[6]][alist[7]][alist[8]][alist[9]]=aval      ;  
          window[aobject][alist[0]][alist[1]][alist[2]][alist[3]][alist[4]][alist[5]][alist[6]][alist[7]][alist[8]][alist[9]]['type']=atype       ;  
          return 1 ;
        }
   }


  alert('Error: nodes are too deep in copyXmlToObject ');
  return 0 ;
}

/* ==============================
Create an xml node from an object.
See copyXmlToObject for syntax of the object.
Syntax:
    anode=copyObjectToXml(object,startName)
where
        object : see copyXmlToObject for syntax 
        startName : the nodename of the root node. If blank, start with the object's first index
        nlist : a  xml node containing the contents of the object. 

======== */
function copyObjectToXml(aobject,aname,aid) {


//var iss=document.getElementById('statusMessages2');
//iss.innerHTML=iss.innerHTML+' <br>Starting name, id= '+aname+','+aid ;

var atype,mm,avar,newnode,nlist,iin,tt,mynode,isfirst,gotnamed ;
var ith=0;

if (arguments.length<3) aname='';

isfirst=0;
if (arguments.length<3) {
  isfirst=1  ; aid='';
}
nlist=[];

mynode=document.createElement(strip(aname.toUpperCase()));

if (aid!='' ) {
    if (aid.substr(0,1)!=='$' && aid.substr(0,1)!=='!' ) {
     alert(' Bad ID in copyObjectToXml: '+aid);
     return 1 ;
  }
   if (aid.substr(0,1)=='!' ) {                  // double $$ means "id"
      mynode.setAttribute('id',aid.substr(1)); 
  } else {
     mynode.setAttribute('name',aid.substr(1));  
  }
} 

atype=typeof(aobject);
if (atype!=='object') {                         // aobject is number of string -- it's a terminal node
    tt=document.createTextNode(aobject);
    mynode.appendChild(tt);
    nlist[0]=mynode;
    return nlist  ;
}

if (typeof(aobject.length)=='number') {                 // if here, an object. But maybe an array (hence a terminal node)
    tt=document.createTextNode(aobject.join(','));
    mynode.setAttribute('array',1);
    mynode.appendChild(tt);
    nlist[0]=mynode;
    return nlist  ;
}

// an object, with no indices (empty)?
iin=0;
for (var mm in aobject) { iin++ };
if (iin==0) {
   if (isfirst==1)  return mynode ;
   return nlist ;                                   // create an empty object 
}

// This object has elements. Each element may represent a new nodes (with possibly sub nodes) or ids (or names) for several instances of same nodename (with NO sub nodes).
gotnamed=0;
for (var mm in aobject) {
     ith++ ;
     avar=strip(mm.toUpperCase()) ;
     if (!isNaN(avar) || avar.substr(0,1)=='$' || avar.substr(0,1)=='!') {              // a numeric or "id/name" index.  Create a <name id="xx" node (rather than a <name> <name2> ...
          gotnamed=1;
          newnode=copyObjectToXml(aobject[avar],aname,avar);
           nlist=Concat_Arrays(nlist,newnode);
     } else {                                   // non-numeric index. Create a node with it's name
           newnode=copyObjectToXml(aobject[avar],avar,'');
           nlist=Concat_Arrays(nlist,newnode);
     }             
}

if (gotnamed!=1) {
  for (var mm=0;mm<nlist.length;mm++) {
     mynode.appendChild(nlist[mm]);
  }
}

if (isfirst==1)  {
  if (aname=='') return mynode.childNodes[0] ;
  return mynode ;
}

if (gotnamed!=1) {
   nlist=[];                       // otherwise, internal call. So array is expected
   nlist[0]=mynode ;
   return nlist ;
}
return nlist ;

}




//======================
// return TEXT in a node.
// adom: the DOM node that may contain text nodes AND other nodes. Note: if an array, use the adom0[0] element.
// nth : which text node to get
//    ''  or 0, or if no 2nd argument : all of them (concatenate, with crlfs)
//    1,2,....  : the first, 2nd, etc. text node
// If nth > # of text nodes, return ''
//  adef : default if no textnodes. If not specified, use ''

function E2_getNodeText(adom0,nth,adef) {
if (arguments.length<2) nth=0;
if (arguments.length<3) adef='' ;
var i,tnode,iat=0;
var gotit='';
var adom;

if (typeof(adom0)!='object' ) return adef ;  // not a dom node with children
if (typeof(adom0.length)!='undefined') {
  adom=adom0[0];
} else { 
  adom=adom0 ;
}

if (adom.childNodes.length==0) return adef ;                      // no children, so no text nodes.

for (var i=0; i<adom.childNodes.length;i++) {               // check each child
        tnode=adom.childNodes[i] ;
        if (tnode.nodeType!==3) continue ;    // just check text nodes
        iat++ ;
        if (nth==0 || nth=='') {
           if (gotit!=='') gotit=gotit+'\n';
           gotit=gotit+tnode.nodeValue ;
           continue;
        }
        if (nth==iat) return tnode.nodeValue ;
}
return gotit ;
}


// == a synonym 
function E2_getTextNode(adom0,nth,adef) {
 var vv ;
 if (arguments.length==1) {
    vv=E2_getNodeText(adom0)  ;
 }
 if (arguments.length==2) {
    vv=E2_getNodeText(adom0,nth)  ;
 }
 if (arguments.length==3) {
    vv=E2_getNodeText(adom0,nth,adef)  ;
 }
 return vv;
}


// ===============================
// add IDX tags to all elements, under doNode, with a tagname in the IDXTAGS or a class in IDXCLASS 

function E2_addIdx(doNode,jiter,tlist,tclass) {

var tlista,dlist,look1,i,atag,look2;

if (arguments.length<3) tlist='';
if (arguments.length<4) tclass='' ;
tlist=strip(tlist.toUpperCase()); tclass=strip(tclass.toUpperCase()) ;
var goolist=tlist;
if (tlist==='' && tclass!=='0' ) tlist="INPUT SPAN DIV"  ;
look1={}  ;  look2={} ; 
if (tlist!=='0') {
  tlista=getWord(tlist) ; 
  for (var i=0; i<tlista.length;i++){
     look1[tlista[i]]=1 ;                          // any value will do
  }
}
if (tclass!=='') {
  tlista=getWord(tclass) ; 
  for (var i=0; i<tlista.length;i++){
     look2[tlista[i]]=1 ;                          // any value will do
  }
}

 atag=doNode.nodeName.toUpperCase()   ;          // check the root ...
 if (typeof(look1[atag])!='undefined')  {
      doNode.setAttribute('idx',jiter);                   // add IDX="current iteration #" attribute
  } else {                                      // check class of root 
    if (tclass!=='') {
        aclass=getAttributes(doNode,'class',''); aclass=getWord(aclass.toUpperCase()) ;
        for (var nn=0;nn<aclass.length;nn++) {
            if (typeof(look2[aclass[nn]])!='undefined') {
                  doNode.setAttribute('idx',jiter);                   // add IDX="current iteration #" attribute
                  break ;
             }
        }
    }
  }

  dlist=doNode.getElementsByTagName('*')      ;           // get all the elements
  for (var i=0; i<dlist.length;i++) {                     // examine all the elements
     atag=dlist[i].nodeName.toUpperCase()   ;
     if (typeof(look1[atag])!='undefined') {
         dlist[i].setAttribute('idx',jiter);                   // add IDX="current iteration #" attribute
         continue ;
     } else {                                   // check class?
        if (tclass=='') continue ;
        aclass=getAttributes(dlist[i],'class',''); aclass=getWord(aclass.toUpperCase()) ;
        for (var nn=0;nn<aclass.length;nn++) {
            if (typeof(look2[aclass[nn]])!='undefined') {
                  dlist[i].setAttribute('idx',jiter);                   // add IDX="current iteration #" attribute
                  break ;
             }
        }
     }                      
  }     // for

  return 1;

}

// look2
// ===============================
// Copy attributes from fromNode to toNode. SKip attribues in noList (case insensitive match) 

function E2_copyAttributes(fromNode,toNode,noList) {

 var  i,tt,attval,attname,tattname,poo;

 if (typeof(fromNode)!=='object' || typeof(fromNode.attributes)=='undefined') return 1  ; // no attrtibutes, quit
 if (typeof(toNode)!=='object' || typeof(toNode.attributes)=='undefined') return 1  ; // no attrtibutes, quit

 poo=new Object() ;
 if (arguments.length>2) {
    noListA=getWord(noList.toUpperCase());
    for (var i=0; i<noListA.length;i++){
       poo[noListA[i]]='1'     
    }   
  }

  for (var i=0 ; i<fromNode.attributes.length;i++) {
     tt=fromNode.attributes[i];
     attname=tt.nodeName; tattname=strip(attname.toUpperCase());
     if (typeof(poo[tattname])!='undefined') continue ;                    // in the nolist
     attval=tt.nodeValue ;
     toNode.setAttribute(attname,attval);
  }
  return 1;
}

//==================================================
// get and read several xml parameters files
// toget: either a dom node to be processed (for a list of XML files to retrive), or a string containing
//        a list of files.
// daSection, daGroupNum are used when "calling" E2_loadSection (after all parameter files have been retrieved)
// first1=1 : Used on first call: signals that toget is an XML node that contains list of files to retrieve
// first1=2 : Used on "recursive" calls": signals just finished retrieving an XML parameter file, with documentElement stored in _paramInfo.
//            so process _paramInfo
// (called by the <params> processing code in e2_loadSection)


function  get_CAPfile(toget,daSection,daGroupNum,first1,aafile,afterParam) {
var todo,haa,afile,getList,nlist,fnode;
var t1,z,todo,k;
if (first1==1) {                        // look for which= and <file> in fnode -- and create the getList
     getList='';
     fnode=toget ;

     todo=strip(getAttributes(fnode,'GET',''));
     todo=todo.toUpperCase() ;

     if (todo=='SESSION' || todo=='BOTH') {                     // get session params?
         afile=E2_paramsURL('SESSION') ;
         getList=getList+' ' + afile ;
      }
      if (todo=='' || todo=='ROUND' || todo=='BOTH') {                    // get round params?
         afile=E2_paramsURL('ROUND') ;
         getList=getList+' ' + afile ;

       }
      nlist=E2_getNodes(fnode,'GET');                           // custom params?
      for (var k=0;k<nlist.length;k++){
         afile=strip(getAttributes(nlist[k],'FILE',''));
         if (afile=='') continue ;
         afile=E2_paramsURL('FILE',afile) ;
         getList=getList+' ' + afile
      }
      toget=strip(getList) ;                           // a hack to use what is below
      if (toget!=='') {
          if (debugOn()) E2_writeStatus('Preparing to get XML parameters files: '+getList);
      }
}

if (first1==2) {                        // just got a param file. It is stored in _paramInfo. Parse it, ...
    if (debugOn(2)) E2_writeStatus('   ... parsing  parameter file '+aafile);

     E2_processXmlParams(_paramInfo,Read_Global('myID'),Read_Global('myREFID'));                      // myID and myREFID ares stored as dSurvey globals
}

// Done processing just retrived file, or done constructing list of files to retreive.

// now, get the next xml parameter file (in toget)

if (toget=='') {                                // no more files to get -- go back to the caller (always E2_loadsection)
    Launch_Proc('E2_loadSection',10,daSection,daGroupNum,afterParam) ;         //  done with parameter file reads and processing
    return 0 ;
}

toget=strip(toget);                     // pop first word in toget.

afile=getWord(toget,1);
toget=getWord(toget,[2,1000000]);
Get_xmlFile(afile,'_paramInfo','Retrieve XML parameter file ','get_CAPfile',toget,daSection,daGroupNum,2,afile,afterParam) ;         //  callback launches get_CAPfile with shortened toget. NOTE that caching is NOT used
return 0 ;

}

// ===============================
// construct a URL to a session file
// Uses the following globals (appends a file name to end):
//  sessionParamURL='/dsurvey/pinfo/!SESS!/!SESS!.XML
//  roundParamsURL='/dsurvey/pinfo/!SESS!/!SESS!.XML
//  fileParamsURL='/dsurvey/pinfo/!SESS!/';

function E2_paramsURL(atype,aname) {
atype=strip(atype.toUpperCase());

if (atype=='SESSION') {
   if (typeof(sessionParamsURL)=='undefined') { alert('ERROR: no sessionParamsURL variable '); return '' }; 
   sessname=Read_Global("_sessionName");
   aurl=sessionParamsURL.replace(/!SESS!/ig,sessname);
   return aurl ;
}
if (atype=='ROUND') {
   if (typeof(roundParamsURL)=='undefined') { alert('ERROR: no roundParamsURL variable '); return '' };
   sessname=Read_Global("_sessionName");
   aurl=roundParamsURL.replace(/!SESS!/ig,sessname);
   return aurl ;
}
if (atype=='FILE') {
   if (typeof(fileParamsURL)=='undefined') { alert('ERROR: no fileParamsURL variable '); return '' } ;
   sessname=Read_Global("_sessionName");
   aurl=fileParamsURL.replace(/!SESS!/ig,sessname);
   return aurl ;
}
alert('Error in E2_sessionFileURL. Unknown type= ' + atype);
return '' ;
}


// ===============================
// parse an XML parameters file; saving to dSurvey global variables  and arrays
// up to 4 sections: <general>, <reference>, <message> and  <USERS>
//  Within general: <varname> .. </varname> sets variables
//                  <varname array="1" delim="adelim"> </varname> sets arrays (using adelim delimiter)
//                           if delim not specified, use ","
//
// Within <message> : <varname type="1"> --
// if type ne 1, store as array (name of varname) to messageData database
//  otherwise, store as the message options string (type="1" is always named message_options)
//
// <USERS has two sections: <VARS> and <VALS>
//              <VARS> varlist</vars>: contains a comma delimited list of variables
//              <VALS> contains numerous <ID value="anid" > vallist</ID>,   where vallist is a comma delimited list of escaped  values
//                   if anid== myid,its valList is parsed and saved to corresponding variables in varlist
// <REFERENCE> has the same syntax as <USERS>
//       i) Except instead of <ID>, <ROW> is used
//       ii) anid is compared to myrefid
//
// Notes
//   *  all USER and REFERENCE values will be unescaped before being saved as a dSurvey global
//   *  the provenence of a variable does not matter -- once it is saved as a dSurvey global, whether it was read from GENERAL, USERS, or REFEFERENCE is irrelevant
//   * in USERS and REFERENCE, names that end with _n_ are saved as array values (i.e. foo_3_ is saved as foo[3])
function  E2_processXmlParams(pnode,myid,myrefid) {
//alert(' ' +myid+','+myrefid);
var gnodes,amess;
if (arguments.length<2) myid=''
if (arguments.length<3) myrefid=''


// process general parmas

gnodes=E2_getNodes(pnode,'general');
if (gnodes.length>0) {                                 // if there is  <general> section
  amess= E2_processXmlParamsGeneral(gnodes[0]);
  if (debugOn()) E2_writeStatus('      variables retrieved from GENERAL: '+amess);
}


gnodes=E2_getNodes(pnode,'message');
if (gnodes.length>0) {                                 // if there is  <message> section
  amess= E2_processXmlParamsMessage(gnodes[0]);
  if (debugOn()) E2_writeStatus('      variables retrieved from MESSAGE: '+amess);
}


if (myid!='') {                                 // if no myID, don't bother checking users <users>
  gnodes=E2_getNodes(pnode,'users',myid);
  if (gnodes.length>0) {                                 // if there is  <general> section
    amess= E2_processXmlParamsUR(gnodes[0],'USERS',myid);
    if (debugOn()) E2_writeStatus('      variables retrieved from USERS: '+amess);
  }
}

if (myrefid!='') {                                 // if no myrefID, don't bother checking reference <reference>
  gnodes=E2_getNodes(pnode,'reference',myrefid);
  if (gnodes.length>0) {                                 // if there is  <general> section
    amess= E2_processXmlParamsUR(gnodes[0],'REFERENCE',myrefid);
    if (debugOn()) E2_writeStatus('      variables retrieved from REFERENCE: '+amess);
  }
}

return 1 ;

}


// =====================
// process variables in a GENERAL node in a client-accessible parameters file. Save to dSurvey globals

function    E2_processXmlParamsGeneral(agnode) {

var nvar=0,narr=0,i,ii,vv,ispart,tnode,thisvar,thisVal,isArray,isPrior,amess,i,m,var2,qArray,qPrior,tmp;

  for (var i=0; i<agnode.childNodes.length;i++) {               // check each child
        tnode=agnode.childNodes[i] ;
        if (tnode.nodeType!==1) continue ;    // just check nodes

        qPrior=0; qArray=0;
        thisvar=strip(tnode.nodeName.toUpperCase()) ;

        isArray=getAttributes(tnode,'ARRAY','-1');     // array=0 means "array that starts at index 0. Hence -1 signsls "not an array"

        if (thisvar.indexOf(".")>-1) {                // name.round (round an integer) means this is meant for the "prior" variables database
             var2=parseAt(thisvar,'.');
             thisvar=var2[0];
             isPrior=strip(var2[1]);
             qPrior=1;
        }
        isElement=getAttributes(tnode,'ELEMENT','-1');     // element>-1 means "this is an element in the array, <0 means "not an element". Note that isArray trumps isElement
        
        thisVal=E2_getNodeText(tnode,1) ;
        if (!isNaN(isArray) && isArray>-1 ) {            // an array, start with a valid array index
            qArray=1;
            isArray=parseInt(isArray) ;
            tmp=thisVal.split(',');
            thisVal=[];
            for (var m=0;m<tmp.length;m++) thisVal[m+isArray]=unescape(tmp[m]);   // unescape, and offset
        } else {                                // not an array. Is it an element of an array?
           if (!isNaN(isElement) && isElement>-1 ) {            // an element: so use the 'x[i]' varname hack
                thisvar=thisvar+'['+strip(isElement)+']' ;
            }
        }

// now save
        if (qPrior==0) {                   // not setting a prior variable
           if (qArray==1)  {                         // an array, start with isArray index
               Save_Global(thisvar,thisVal,0,1);      // save as an array object (and don't need to use save_global's shifting option)
               narr++ ;
           } else {
               thisVal=unescape(thisVal);
               Save_Global(thisvar,thisVal) ;
               nvar++ ;
           }
        }  else {                                       // save to priorGlobals
           if (qArray==1) {                         // an array, start with isArray index
               Save_priorGlobal(isPrior,thisvar,thisVal,0,1) ;
               narr++ ;
           } else {
               thisVal=unescape(thisVal);
               Save_priorGlobal(isPrior,thisvar,thisVal) ;
               nvar++ ;
           }                                    // array
        }                       // isprior
   }                           // for childnodes

   amess=nvar + ' / ' + narr;
   return amess ;
}



// =====================
// process variables in a <MESSAGE> node in a client-accessible parameters file. Save to dSurvey globals

function    E2_processXmlParamsMessage(agnode) {

var nvar='',amess='',i,tnode,thisvar,itype,thisVal,vv,ii;

  for (var i=0; i<agnode.childNodes.length;i++) {               // check each child
        tnode=agnode.childNodes[i] ;
        if (tnode.nodeType!==1) continue ;    // just check nodes
 
        thisvar=strip(tnode.nodeName.toUpperCase()) ;

        nvar++;
        amess=amess+' '+thisvar;

        itype=getAttributes(tnode,'type','0'); 


        thisVal=E2_getNodeText(tnode,1) ;
        if (itype=='1') {                       // options or other scalars
           if (typeof(messageData[thisvar])=='undefined') {
                messageData['$constlist']=messageData['$constlist'].concat(thisvar);
           }
           messageData[thisvar]=unescape(thisVal);

        } else {
            vv=getWord(thisVal,0,',');   
            if (typeof(messageData[thisvar])=='undefined') {
                messageData['$varlist']=messageData['$varlist'].concat(thisvar);
           }
            messageData[thisvar]=[];
            for (var ii=0;ii<vv.length;ii++) {
                 messageData[thisvar][ii]=unescape(vv[ii]);   // content was escaped to avoid , and other problems
             }

        }
  }
//alert('ammemem '+messageData['$varlist'].length+','+messageData['$constlist'].length);
   return amess ;
}


// =====================
// process variables in a USERS or REFERENCE node in a client-accessible parameters file. Save to dSurvey globals
// note that values are unescaped, and then saved to dSurvey global.

function  E2_processXmlParamsUR(agnode,atype,myid) {
 var varlist,tmp,varlist0,amess;
var vnodes,tnodes,vallist,i,unode,anid ,thisVal,aval,avar,isprior,pp;
 myid=strip(myid);

  varlist=[] ;
  vnodes=E2_getNodes(agnode,'VARS VAR');
  if (vnodes.length==0) return ' No VARS ' ;                          // no ids, so nothing to save
  tmp=strip(E2_getNodeText(vnodes[0],1)) ;
  varlist0=tmp ;
  if (tmp!=='')  varlist=tmp.split(',');

  vnodes=E2_getNodes(agnode,'VALS VAL');
  if (vnodes.length==0) return ' No VALS ' ;                          // no ids, so nothing to save
  tnodes=E2_getNodes(vnodes[0],'USER RECORD ROW CLIENT ID');         // synonyms. USER typically used in USERS, ROW typically used in REFERENCE
  vallist=[];

  for (i=0; i<tnodes.length;i++){
     unode=tnodes[i];
     anid=strip(getAttributes(unode,'ID VAL ',''));            // synonyms
     if (anid==='') {
              alert('Error in E2_processXmlParamsUR: a row in '+atype+' does not have an ID attribute ');
              return 1;
     }
     if (anid!=myid) continue ;                  // this is NOT a match

     thisVal=E2_getNodeText(unode,1);
     vallist=thisVal.split(',');
     if (vallist.length!=varlist.length) {
              alert('Error in E2_processXmlParamsUR ('+atype+'):  #of values in VARLIST ('+varlist.length+') ne # in VALLIST ('+vallist.length+' :: \nfor ID '+anid+'\n: ' + thisVal +'\n'+varlist0);
              return 1;
     }
     break ;
  }
  if (vallist.length==0) E2_writeStatus(' Warning: no values for '+atype+' with id: ' +myid);
  // save vars in vallist
  for (var i=0;i<varlist.length;i++){
    if (vallist.length==0) {                      // myid not found, or  no USER specified
          aval='' ;
    } else {
       aval=unescape(strip(vallist[i]));          // values are escaped, so unescape.
    }
    avar=strip(varlist[i].toUpperCase());
    if (avar.indexOf('.')>-1) {                   // prior
        var pp=avar.split('.');
        avar=pp[0];
        isprior='' ;
        if (pp.length>1) isprior=pp[1] ;
        if (isprior.toUpperCase()=='RECENT') isprior='' ;
        Save_priorGlobal(isprior,avar,aval);            // might be saving an array element
    } else {
      Save_Global(avar,aval);                       // might be saving an array element
    }
  }                                     // for
  amess='  #'+atype+' vars= '+varlist.length +', # of rows='+tnodes.length ;
  return amess ;

}

      // prior


// ===============================
// add a comment to anode

function E2_addComment(toNode,acomment) {

var acrlf1,acrlf2,acmt ;
if (arguments.length<2) acomment='' ;
if (!toNode.appendChild) return 1 ;                  // not a DOM object, give up.
 var acrlf1=document.createTextNode(' \n');
 var acmt=document.createComment(acomment);
 var acrlf2=document.createTextNode(' \n');
 toNode.appendChild(acrlf1);
 toNode.appendChild(acmt);
 toNode.appendChild(acrlf2);
 return 1;
}



/* ::========================================================================================================================*/
/* ==============================  Functions to display section & group     =========================================*/

//=================================
// start display of the daSection section. If not specified, do the first section
/*

 Note: because of <if>, this should be called EACH time before a section starts -- you can not do this once for a section and use
       stored values in future displays of the same section (since the groups, and contents, may change as survey global variables change)

 We start with the global object.
     specSections: an array. Each element of the array is a DOM node pointing to a <section>
     specSections.sectionNames[i]  : an array -- array-element [i] is name of the section i
     specSections.sectionIndex[aname]  : an object. Each object-element "aname" points to the  numeric section index 

 Set
     specSections.current = isection ;
     specSections.sCurrentName = ''  (used to hold current section name      )
     specSections.gCurrentName = ''  (used to hold current group  name in current section)
     specSections.gCurrent = ''  (used to hold current group  name in current section)

 For the desired section (daSection), create:
     specSections[isection].g  : An array. Each element of the array is a DOM node pointing to a <group> (after processing of <if>
 
 For each group (i=0,...,) in the section
    specSections[isection].g[i].gname  -- a string containing the name of this function (optional)
    specSections[isection].g[i].gAttributes  -- an array. Each element is an object with attName and attValue fields
    specSections[isection].g[i].gevents --  An array of  DOM node of a <events> and <NOTIFY> (or undefined if no <events>)
    specSections[isection].g[i].gcontent  -- An array, element is a DOM node of a <content> (length 0 if no <content>)
                                          Note that <content> with <if> that are "false" will NOT appear in this array.
    specSections[isection].g[i].gcontent[i].gnode  = A DOM node of <content>...
    specSections[isection].g[i].noDefault  -- 1 if "noDefault="1" specified for this group. Otherwise, 0

    specSections[isection].gNames[i]  : an array -- element [i] is name of the i'th group in this section (after removing groups that have <if> that are false)
    specSections[isection].gIndex[aname] : an object. Each element points to the group index (in this section) for aname


afterParam: if -2 (the default): process <params> for client accessible parameter(CAP) files
                -1 : <params> already processed for CAP files, nothing saved to prior variables
                -3 : after saving to simpleHistory archive
                0,1... : <params> already processed for CAP files, vars saved to prior variables round number afterParam
            Note: even if no parameter files, or after all parameter files read, the equations in a 
                  <PARAMS> will be processed

    Clarification:
        * on first call, afterParam should be -2 (it is set to -2 if no afterParam argument 
        * if -2, variables may be saved to prior variables, and current variables are reset.
            If saved, afterParam changed to current round number (>0)
            If no variables saved, afterParams=-1
       *  Then, cap files are read. variables in cap files are parsed. It is possible that a
          prior variable will be set using information in a cap file (i.e.; a cap file variable
          with a varname of aname.around)
       *  If noHistory="1" is NOT specified, process simpleHistory, using afterParam
                If afterParam=-1, a warning is displayed
                Otherwise, afterParam is used to dictate where to save the simpleHistory variables (for what round)
       *  If saveSimple is specified, these simpleHistory variables are uploaded to the simpleHistory server archive
          AfterParam is set to -3.
       * afterParam of -3 signals "process equations" (after which, <params> is done)
               
        
         

Notes on calling order:
  1) check <PARAMS>
       1a) Possibly save information to "prior" variables (to the global variables history) $recent, and current-round, entries
       1b) Possibly reset global variables
       1c) read CAP files  -- session, round, or custom
       1d) for each CAP file retrieved from the server...
           process it for globals variables, participant specific variables, etc. 
           (this requires converting an XML file to dSurvey variables)
           Note: globals and users can have varname.round notation -- the .round means "save this to
                 the "round" of the history variables. 
                 Thus, this complements step 1 above.
     1e) using global history (the prior) variables, and values from CAP files, write simpleHistory rows
         If specified, upload these values to the simpleHistory server archive. 
           After upload is done, E2_loadSection  is again called with afterParam=-3 
           (which means "only thing left in <params> are  the equations  
     1f) process equations in  a <PARAMS>
   2) Create modules
   3) process groups
   4) show a group

======================= */

function  E2_loadSection(daSection,daGroupNum,afterParam)      {

var i1,i2,i3,anode,anode1,anode2,isection,ares,nn,goo,goo2,fooc ;
var fnodes,createNodes,nowNode,gnodes ;
var achild,pnode,cnodes,tmp,nowr;
var darets,retlist,retstuff,mm,a ;
var svals ;

if (arguments.length<1) daSection='' ;
if (arguments.length<2) daGroupNum='' ;
if (arguments.length<3) afterParam=-2 ;        // signals "<params> not yet processed 

dasection=strip(daSection).toUpperCase();  
daGroupNum=strip(daGroupNum).toUpperCase();

 if (daSection=='') {
     isection=1 ;
 } else {
     var garf=strip(daSection).toUpperCase();
     if (typeof(specSections.sectionIndex[garf])=='undefined') {
        alert('ERROR ... in E2_loadSection: no such section= '+daSection);
        return 1;
    }
    isection=specSections.sectionIndex[garf] ;
 }

 if (isection>specSections[0]) {
      alert('ERROR in E2_loadSection: section # too large '+isection);
      return 1;
 }

specSections.current=isection  ;                 // used as reference in calls to E2_startGroup
specSections.sCurrentName=''  ;                      // used as reference in calls to E2_startGroup
specSections.gCurrentName=''  ;                      // used as reference in calls to E2_startGroup
specSections.gCurrent=''  ;                      // used as reference in calls to E2_startGroup
specSections.currentSectionTag=Math.random()  ;  // identifies the section being processed.
specSections.currentGroupTag=''           ;    //  will be use to identify the group being processed.

delete specSections['eventQueue'] ;       // zero out the event queue
specSections['eventQueue']=new Object() ;       

nowNode=specSections[isection] ;

E2_writeStatus('Starting section # ' +isection + ' = ' + specSections.sectionNames[isection]);
if (afterParam==-2) {                   // not a "return from parameter get_CAPfile -- then check for param files
  afterParam=-1 ;                               // signals "<params> processed, no prior-vars saved
  fnodes=E2_getNodes(nowNode,'PARAM PARAMS PARMS  ');                   // <params>
  if (fnodes.length>0 ) {                       // found a PARAM


// save and reset?
     goo=getAttributes(fnodes[0],'PRIORS PRIOR','NONE');
     goo=strip(goo.toUpperCase()) ;

     if (goo=='BOTH' || goo=='SAVE') {                  // save prior variables
         goo2=getAttributes(fnodes[0],'USEROUND ROUND ROUNDVAR','');
         if (strip(goo2)==='') {
            nowr=Read_Global('nowRound','');
         } else {
            nowr=Read_Global(strip(goo2),'');
         }

         if (nowr=='' || isNaN(nowr)) {                        // no nowRound variable  -- use the _recent value of svyglobalshistory
            if (typeof(SvyGlobalsHistory['_recent'])!='undefined') {
                var tmp=SvyGlobalsHistory['_recent'] ;
                if (isNaN(tmp)) {
                        nowr=0;                 // no _recent -- then save to position 0 (0'th round?)
                } else {
                     nowr=parseInt(tmp);
                }
            } else {
                 nowr=0 ;                       // default-- call this the zeroth round
            }
         }

         Save_GlobalHistory('$recent');            // save to the $recent element of the SvyGlobalsHistory object
         Save_GlobalHistory(nowr,globalHistoryMaxRounds);            // save to the nowr element of the SvyGlobalsHistory object
         if (debugOn()) E2_writeStatus('Saved variables (for round ' + nowr);
         afterParam=nowr ;                       // signals round prior vars were saved for round nowr

     }

     if (goo=='BOTH' || goo=='RESET') {             // reset current variables (but retain the retain="1" vars)
          retlist=[];
          for (var irr=0;irr<svy_retainVars.length;irr++) {   // these variables retain the values they had (they are not discarded)
                    retlist[irr]=Read_Global(svy_retainVars[irr]);
          }

           Retrieve_GlobalHistory('START');                  // reset SvyGlobals, with just the  "required variables"

          for (var irr=0;irr<svy_retainVars.length;irr++) {
                    Save_Global(svy_retainVars[irr],retlist[irr]);
          }
     }                                                            // BOTH or RESET

// variables have been saved to prior and/or reset. Now retrieve CAP files?
// Note: afterParam is (by default) set to the old value of nowRound -- the value that was used in the
// "just completed" section: which means that afterParam is the round number of the Just Completed round 
// Typically, nowRound is set in the CAP file -- so the round number is augmented AFTER the cap file is read
// Note: if you do not use nowRound as the round counter variable,
//       you should use  a "roundVar"  attribute in <params> to    set the name of the round variable 
//       (which can be a "retained" variable that is changed in your SPEC file)

      goo=get_CAPfile(fnodes[0],daSection,daGroupNum,1,'',afterParam) ;   // get_CAPfile launches several threads to read param files, then recalls loadSection
      return 0;
  }                     // <params> in fnodes[0]
}                               // afterParam=-2

// if here, no PARAM files, or all done reading/processing paramfiles (afterParam>-2) 

// create a history row? process equations?
fnodes=E2_getNodes(nowNode,'PARAM PARAMS  ');
if (fnodes.length>0) {

  if (strip(afterParam)!=='-3') {                // -3 signals "after saving to simpleHistory archive
    tmp=getAttributes(fnodes[0],'noHistory','0');
    if (strip(tmp)!=='1') {
        svals=E2_makeSimpleHistoryRow(afterParam)      ;                 // uses globals (afterParam is round number)
        tmp=getAttributes(fnodes[0],'saveSimple','0');
        if (tmp==1 && svals.length>0 && _spying!==1 ) {                                   // save svals to simpleHistory server archive
              E2_uploadSimpleHistory(svals,daSection,daGroupNum,afterParam,Read_Global('myID'));
              return 0;
        }
    }
  }

  var fooc=E2_getNodes(fnodes[0],'CALL');
  if (fooc.length>0) {
        alert('ERROR in PARAMS section: a CALL node is specified (equations should NOT be inside of a <CALL>)');
        return 0 ;
  }
  E2_doEquations('',fnodes[0]);
}

// done reading stuff

// reset message options (<message> section in CAP file  may have reset messageData.MESSAGE_OPTIONS)
dsurveyMessages() ;

  
specSections[isection].gpriors='' ;                      // zero out "priors" (for use by ADDPRIOR and USEPRIOR, or PRIOR, in CONTENT ) 
              
// process the CREATE instructions (create new modules)
var dCreate=E2_modulesCreate(nowNode);

// Create a list of groups to use, store in groups array. Uses <if> to determine whether to include a <group>
gnodes=E2_getNodes(nowNode,'GROUP');
if (gnodes.length==0) {
  alert('ERROR in E2_loadSection, section '+specSections.sectionNames[isection]+ ' :  no GROUP elements defined  ') ;
  return 0 ;
}
specSections[isection].g=new Array() ;
var dog=1;
for (var i=0 ; i<gnodes.length;i++) {           // which groups to include in this section (check <if> )
  anode=gnodes[i] ;
  ares=E2_node_doIf(anode)  ; 
  if (ares==0) continue ;
  specSections[isection].g[dog]=anode ;
  dog ++ ;
}

if (debugOn(2)) E2_writeStatus('   ...parsing '+specSections[isection].g.length+ ' groups in section '+isection);

// Process each group; 
// a) find name and label attributes:
// b) For each group find content, events, and target components.  Remove all <content> with false <if>. Retain resuls in 'stuff' array

specSections[isection].gNames=new Array() ;                     // lookup table for this section
specSections[isection].gIndex=new Object() ;

for (var i=1; i<specSections[isection].g.length;i++) {

   anode=specSections[isection].g[i] ;
   ares=getAttributes(anode,'NAME','');
   if (isNaN(ares)) ares=strip(ares).toUpperCase() ;
    if (ares!='') {
       specSections[isection].gNames[i]=ares ;
       specSections[isection].gIndex[ares]=i ;
   } else {
       specSections[isection].gNames[i]='' ;
   }

   ares=getAttributes(anode,'NODEFAULT','0');
   anode.noDefault=ares ;

// look for common errors 
   fnodes=E2_getNodes(anode,'MODULES MODULE LITERAL FOCUS LABEL GAP  ');           
   if (fnodes.length>0) {
        ares='';
        for (var mm=0;mm<fnodes.length;mm++) {
           ares=ares+' '+fnodes[mm].nodeName;
        }
        alert('Error: the following should elements should be inside of a <CONTENT>: '+ares);
        return 0;
    }


   fnodes=E2_getNodes(anode,'QUERY BUTTON TIMER EXEC ');            
   if (fnodes.length>0) {
        ares='';
        for (var mm=0;mm<fnodes.length;mm++) {
           ares=ares+' '+fnodes[mm].nodeName;
        }
        alert('Error: the following should elements should be inside of a <EVENTS>: '+ares+'\n'+anode.innerHTML);

        return 0;
    }

   fnodes=E2_getNodes(anode,'EVENT EVENTS ');            // <EVENTS> events that may cause group to be abandoned
   if (fnodes.length>1) {
        alert('ERROR in E2_loadSection: more than one EVENT is specified in section '+isection);
        return 0 ;
   }
   
   anode.gevents=[]; anode.gevents[0]=0; 
   if (fnodes.length>0) anode.gevents[0] =fnodes[0] ;      // <EVENTS> are contained in one node of gevents

   fnodes=E2_getNodes(anode,'NOTIFY ');            // each <NOTIFY> is a seperate note in geevents
   if (fnodes.length>0) {
        for (var nn=0;nn<fnodes.length;nn++) anode.gevents[nn+1]=fnodes[nn];
   }

   fnodes=E2_getNodes(anode,'QUERY BUTTON TIMER ');            // a common error
   if (fnodes.length>0) {
        alert('ERROR in E2_loadSection: QUERY BUTTON or TIMER must be specified inside of an EVENTS');
        return 0;
   }

   anode.gcontent=new Array() ;

   fnodes=E2_getNodes(anode,'CONTENT');            // the "stuff" to display. <CONTENT>
   var idog=0 ;
   anode.gcontent.length0=fnodes.length ;
   for (var i2=0 ; i2<fnodes.length; i2++){         // build the stuff array, checking for ifs 
     anode1=fnodes[i2] ;   
     ares=E2_node_doIf(anode1)  ; 
     if (ares==0) continue ;                      // false, do not include in "stuff" 
     anode.gcontent[idog]=new Object() ;
     anode.gcontent[idog].gnode=anode1;
     idog++ ;
   }
}


daGroupNum=strip(daGroupNum);

// used by  "show page source" (as a footer) 
  a='<p>For section: ' + isection+' (' +specSections.sectionNames[isection]+') <ul>';
  a=a+'<li> # GROUPS=' +gnodes.length + ' and retained= ' + specSections[isection].g.length ;
  a=a+'<br> ';
 for (var i1=0 ; i1<specSections[isection].gNames.length ; i1++){ a=a+ ' Group '+i1+' name:' + specSections[isection].gNames[i1]}+' |  ';
  a=a+'<li> #  CREATES found = ' + dCreate ;
  a=a+'</ul><hr>';
  a=a+'Functions & items by ' + specSections[isection].g.length + ' groups <ol>';
  for (var i=1; i<specSections[isection].g.length;i++) {
     a=a+'<li> Name -- Label  == ' +specSections[isection].g[i].gname  ;
     a=a+ '  <br> # of contents retained=' + specSections[isection].g[i].gcontent.length+ '(of '+specSections[isection].g[i].gcontent.length0+')';
     a=a+ ' ,  # of events=' + specSections[isection].g[i].gevents ;
  }
  a=a+'</ol> <p><br> ';
specSections.currentSectionInfo=a;

if (daGroupNum!=='') {
  if (!isNaN(daGroupNum)) {                               // a group number  
          E2_showGroup('',parseInt(daGroupNum));  
 } else {
          E2_showGroup(daGroupNum);
 }
}
//var a='';
//for (var i1=0 ; i1<specSections[isection].gNames.length ; i1++)  {
//        a=a+ ' Group '+i1+' name:' ;
//        a=a+ specSections[isection].gNames[i1] +' #xxxf events=' ;
//        a=a+ specSections[isection].g[i1].gevents+ '\n '
// }
//alert(a);

/* ===  ========================
  a='<p>For section: ' + isection+' (' +specSections.sectionNames[isection]+') <ul>';
  a=a+'<li> # GROUPS=' +gnodes.length + ' and retained= ' + specSections[isection].g.length ;
  a=a+'<br> ';
 for (var i1=0 ; i1<specSections[isection].gNames.length ; i1++){ a=a+ ' Group '+i1+' name:' + specSections[isection].gNames[i1]}+' |  ';
  a=a+'<li> #  CREATES found = ' + dCreate ;
  a=a+'</ul><hr>';
  a=a+'Functions & items by ' + specSections[isection].g.length + ' groups <ol>';
  for (var i=1; i<specSections[isection].g.length;i++) {
     a=a+'<li> Name -- Label  == ' +specSections[isection].g[i].gname  ;
     a=a+ '  <br> # of contents retained=' + specSections[isection].g[i].gcontent.length+ '(of '+specSections[isection].g[i].gcontent.length0+')';
     a=a+ ' ,  # of events=' + specSections[isection].g[i].gevents ;
  }
  a=a+'</ol> <p><br> ';
  specSections.currentSectionInfo=a;

  var dw=window.open('','debugwindow_structure');
  dw.document.open('text/html');
  var t1='<html><head><title>Debug window</title><body><div style="border:2px black dotted; background-color:#999999"><tt>Section structure: </div> \n '+a +' \n </body></html>';
  dw.document.write(t1);
  dw.document.close();
                          
============ ============= */
return 1 ;

}

//=============================
// upload simpleHistory variables to simpleHistory server archvie
function    E2_uploadSimpleHistory(vvals,daSection,daGroupNum,around,aid){
var stuff,v1,sessName,amessage,toPost;



stuff='<data id="'+aid+'" round="'+around+'">';
for (var m=0;m<vvals.length;m++) {
  v1=escape(vvals[m]);
  if (m<vvals.length-1) v1=v1+',';
  stuff=stuff+v1;
}
var sessName=Read_Global("_sessionName");

var amessage='simpleHistory_'+aid+'_'+around ;

// todo=4011
toPost=svyPostSimpleHistoryHeader+'session='+sessName+'&message='+amessage+'&contents='+stuff+'</data>';

// since simpleHistory archive isn't that important, don't do any verification
 var SendVars = new svy_CreateXMLHTTP(svyPostSubmitURL) ;
   SendVars.onDraw=callback_doSimpleHistory  ;
   SendVars._method="POST" ;                    // note that the ?xx will be parsed out by the xmlhttp request function (._postRequest is not used)
   SendVars._timeout=10000  ; //  10 seconds until timeout
   SendVars._showstatus=false ;  // note: by default, do NOT suppress cache-buster
   SendVars._comment='Submitting simpleHistory from round ' +around ;
   SendVars._ID=aid  ;
   SendVars._postRequest = toPost ;

//   E2_writeAlert('Submitting simpleHistory for '+amessage,'.... ',2);

   SendVars._variable='SAVE_SIMPLE';
   SendVars._variable2=daSection ;
   SendVars._variable3=daGroupNum ;

   SendVars.load(amessage,1) ;

  if (debugOn()) {
          writeStatus(' upload simpleHistory: '  + amessage);
   }
   return 1 ;
}


//  =============================== _status 
// callback function used by  saveSimpleHistory
// oinfo contains the "state" variable 
// chkval the string returned by the server
// astat the response code (should contain 200)

function callback_doSimpleHistory(oinfo,chk_val,rcode,astat,nth) {
var amess=chk_val;

if (astat=='TIMEOUT') {                                                  // timedout, give up
    E2_writeAlert(' Connection problem: '+chk_val+' ...  simpleHistory results for this round may be missing');
    return 1 ;
}

 if (astat=='ERROR') {                                                  
    E2_writeAlert(' Connection error: '+chk_val+' ... simpleHistory results for this round may be missing');
    return 1 ;
 }

// if here, no server error. But perhaps a survey error?

if (chk_val.toUpperCase().indexOf('OK')!=0) {                        // response, but problem processing
    E2_writeAlert(' Problem on upload: '+chk_val+' ... simpleHistory results for this round may be missing');
    return 1 ;
}

 var vv=this._variable ;                                        // save response from last saveSimple request
 if (vv) ControlVars[vv]=chk_val;

 if (debugOn()) E2_writeStatus('simpleHistory results saved for: ' + oinfo+ ' == ' + chk_val);
  E2_loadSection(this._variable2,this._variable3,-3);
  return 1;

}




//=============================
// add a row to simpleHistory tables. Call this when <params> is processed and noHistory="1" is NOT specified
// also called by recoverSimpleHistory
// uses variables specified with <vars> inside of <history>
// prior round values of these variables will be saved to the simpleHistory object

function E2_makeSimpleHistoryRow(useRound,vrecover)      {                 // uses globals

var aname,useme,m,m1,m2,m3,atd,atr,arow,vval;
var vuse,svars,tmp,vvals,vvars,vvar,vval2;
var svals=[],vtmp,iv,foo,tmp0;

if (simpleHistory.names.length==0 || useRound ==0 ) return svals    ;        // no <history> specified, or "prior round" was  zeroth round, so do nothing
 if (simpleHistory.gotSubmitted.length==0) {                 // set the gotSubmitted variable?
      svars=svyPrior('__SUBMITVARS','','---');    // use submitted vars?
      if (svars!=='---'){                         // none available yet? keep waiting
         simpleHistory.gotSubmitted=svars ;
      }
 }
if (useRound<0) alert('Caution: a row is being added to simpleHistory, but no variables were recently saved ');


for (var m=0;m<simpleHistory.names.length;m++) {                // for one or more History
  aname=simpleHistory.names[m]  ;
  useme=simpleHistory.specs[aname]  ;

// check to see if topRow is built for this simpleHistory. If not, and variables are defined, do it (and don't do it again!)
  if (useme.topRow=='' ) {
     vuse=[];
     if (useme.varList.length>0) {              // use explicitily defined variables
        vuse=useme.varList ;
     } else {
       if (typeof(simpleHistory.gotSubmitted)!=='undefined') vuse=simpleHistory.gotSubmitted ;
     }
     if (vuse.length>0) {
       arow='<tr><td><span style="'+simpleHistoryStyleCol1+'">Round</span></td>';                                       // vuse MUST have some length
       m1=Math.min(useme.colDesc.length,vuse.length);
       for  (var ieq2=0;ieq2<m1;ieq2++) arow=arow+'<th>'+useme.colDesc[ieq2]+'</th>' ;
       if (m1<vuse.length) {
          for ( var ieq2=m1;ieq2<vuse.length;ieq2++) arow=arow+'<th>'+vuse[ieq2]+'</th>' ;
       }
       useme.topRow=arow+'</tr> \n ';
     }
  }                                     // make aname's toprow

  if (typeof(useme.rounds)=='undefined') useme.rounds=[];

  arow='<tr><td><span style="'+simpleHistoryStyleCol1+'">'+useRound+'</span></td> ';                            // first cell is always the round number

// make valLlist, using  either varlist, or gotSubmitted
  vvals=[];vvars=[];
  if (useme.varList.length==0) {
      if (arguments.length>1) {
         tmp=vrecover;
      } else {
         tmp=svyPrior('__SUBMITVALS','','----');    // use submitted vars?
         if (tmp=='----') tmp='' ;
      }
      for (var m2=0;m2<tmp.length;m2++) {
           vtmp=tmp[m2];
//           if (arguments.length>1)
           svals=svals.concat(vtmp);
           vvals[m2]=vtmp ;    //convert each element to a 1 element array
           if (simpleHistory.gotSubmitted.length>m2) {
               vvars[m2]=[simpleHistory.gotSubmitted[m2]];
           } else {
               vvars[m2]='VAR_'+m2;
           }
      }
  } else {      // else, use varlist

    if (arguments.length>1) {
      iv=-1;
      for (var m2=0;m2<useme.varList.length;m2++) {
        vvals[m2]=[];     vvars[m2]=[];
        for (var m3=0;m3<useme.varList[m2].length;m3++) {            // one, or several vars in this cel
          iv++;
          vtmp=vrecover[iv];
          vvals[m2][m3]=vtmp;
          vvars[m2][m3]=useme.varList[m2][m3] ;
        }
      }                         // use vrecover
    } else {                                            // not a recovery
       for (var m2=0;m2<useme.varList.length;m2++) {
        vvals[m2]=[];     vvars[m2]=[];
        for (var m3=0;m3<useme.varList[m2].length;m3++) {            // one, or several vars in this cel
          vtmp=svyPrior(useme.varList[m2][m3]) ;
          svals=svals.concat(vtmp);
          vvals[m2][m3]=vtmp;
          vvars[m2][m3]=useme.varList[m2][m3] ;
        }
      }                         // use vrecover
    }                                   // use varlist
  }                     // gotsubmitted length

// note: svals is what is uploaded to simpleHistory server archive

// make a row using vvals and colStyle
  for (var m2=0;m2<vvals.length;m2++) {

       if (typeof(vvals[m2])!=='object') {
          foo=vvals[m2];
          vvals[m2]=[];
          if (strip(foo)!=='') vvals[m2][0]=foo;
       }

       atd='<td ';
       if (typeof(useme.colStyle[m2])!=='undefined' && useme.colStyle[m2]!=='') {
          atd=atd+' style="'+useme.colStyle[m2]+'" > ';
       } else {
          atd=atd+' > ';
       }
       if (vvals[m2].length==0) {                   // empty cell
           atd=atd+' </td> ';
           arow=arow+atd ;
           continue ;
       }
       for (var m3=0;m3<vvals[m2].length;m3++) {            // one, or several vars in this cel
          vval=vvals[m2][m3] ; vvar=vvars[m2][m3];
          vval2=simpleHistoryRecode(useme,vval,vvar) ;
          vval='<span title="'+useRound+','+vvar+'">'+vval2+'</span>';
          atd=atd+vval ;
          if (m3==(vvals[m2].length-1) ) {
               atd=atd+' </td> ';                               // last variable for this cell
          } else {
               atd=atd+' <br /> ';
          }
       }
       arow=arow+atd ;
   }

   arow=arow+'</tr> ';
   useme.rounds[useRound]=arow ;
}

return svals ;                          // svals ignored if called by recoverSImpleHistory

}

//=============================
// recode a value for display in simpleHistory table
function simpleHistoryRecode(useme,vval,vvar0) {
var tval,vvar,dd,tmp,nval='';
vvar=strip(vvar0).toUpperCase();
if (typeof(useme.recodes[vvar])=='undefined') return vval ;

tval=strip(vval).toUpperCase() ;
if (typeof(useme.recodes[vvar][tval])!=='undefined') {
    nval=useme.recodes[vvar][tval];
} else  {                                       // check for *
     if (typeof(useme.recodes[vvar]['*'])!=='undefined') nval=useme.recodes[vvar]['*'];
}
if (useme.cReplace=='') return nval ;
if (useme.cReplace=='*') {
   vval=nval.replace(/\*/g,vval);
} else {
   tmp=RegExp(useme.cReplace,'g');
   vval=nval.replace(tmp,vval)
}

return vval;


}

//=============================
// display a simpleHistory table

function E2_showSimpleHistory(hname)      {                 // uses globals 

var useme,afooter,aheader,tmp,zork;
var bigone,im,idiv;

   if (typeof (simpleHistory.specs[hname])=='undefined') {
       alert('Error: <HISTORY> ... special tagname points to non-defined History: '+hname);
      return 0;
  }
  useme=simpleHistory.specs[hname];
  afooter='' ;
  if (useme.footer!==0) {
       zork=E2_copyNode(useme.footer);
       E2_procSection_actionTags(zork,'simpleHistory footer');         // add use="xx" stuff?
       afooter=E2_xmlToString(zork);

  } 
  aheader='' ;
  if (useme.header!==0) {
       if (typeof(useme.header)!=='object') {                    // if set by default 
          aheader=useme.header;
       } else {
         zork=E2_copyNode(useme.header);
         E2_procSection_actionTags(zork,'simpleHistory header');         // add use="xx" stuff?
         aheader=E2_xmlToString(zork);
       }
  }

  bigone=aheader+'\n <table border="1" style="margin:5px 2% 5px 2%"> \n ';
  bigone=bigone+useme.topRow+' \n ';
  for (var im=0; im<useme.rounds.length;im++) {
        if (typeof(useme.rounds[im])!=='undefined' && useme.rounds[im]!=='') bigone=bigone+useme.rounds[im]+ '\n ';
   }
   bigone=bigone+'</table> \n ';
   bigone=bigone+afooter +' \n ';
   atarget=useme.where;

   if (atarget=='0') {                   // open window if it doesn't already exist
        var w1=window.open('','simpleHistoryWindow',simpleHistoryWindowAttributes); 
        w1.document.body.innerHTML=bigone;                                  // overwrite contents
        w1.document.title='History of your decisions and variables';          // the window title
   } else {
      idiv=document.getElementById(atarget);
      if (!idiv) {
          alert('Error displaying History: no such ID = '+atarget);
          return 0;
      }
      idiv.innerHTML=bigone ;                           //overwrite contents     
      idiv.style.display='block';
   }
   return 1 ;
}




//====================
// display the group, in the current section, with the name daGroup. If daGroup='', display group number daNumber.
// IF daGroup='' and  if daNumber=0, display first group  (at index 0)
// default (no arguments) is to display first group 
// if lastbig=1, the if group#> # of groups, display last group
/*
    specSections[isection].gNames[i]  : an array -- element [i] is name of the i'th group (as a dom node) in this section (after removing groups that have <if> that are false)
    specSections[isection].gIndex[aname] : an object. Each element points to the group index (in this section) for aname

    specSections[isection].g[i].gname  -- a string containing the name of this function (optional) (i=0,...)


    specSections[isection].g[i].gevents --  An array of DOM nodes of <nodify> and  <events> (or empty
    specSections[isection].g[i].gcontent  -- An array, element is a DOM node of a <content> (length 0 if no <content>)
                                            Note that <content> with <if> that are "false" will NOT appear in this array.
    specSections[isection].g[i].gcontent[i].gnode  = A DOM node of <content>...

*/
            
function  E2_showGroup(daGroup,daNumber,lastbig)      {

 var anode,isec,gName,gNumber,gContent,useNode,aContent,new1,cDiv ;
 var i,iff,ii,gDiv,tval,fuse,fuseL,clistS,clistG,iff2 ;
 var ndo,ndo1,ndo2,doRepeat,gtag0;
 var docid,chknode,attname,attval,attnode;
 var tname,chkit,isName,chkId,doit,tnameAt ;
 var groupNode,sectionNode,eelist ;
 var dd,wrem,nretain,awind,tmp,mm;
 var ttname,ttid ;

// reset header stuff (message, button, timer) 
  E2_writeHeaderButton();
  E2_writeHeaderTimer();
   E2_writeHeaderMessage();

// close non-retained windows
 if (displayWindows[0].length>0) { 
    nretain=0;
    for (var dd=0; dd<displayWindows[0].length; dd++) {
        wrem=displayWindows[0][dd];
        if (wrem=='') continue ;                        // already deleted 
        if (typeof(displayWindows[wrem])=='undefined')  {
              displayWindows[0][dd]='';
              continue ;       // doesn't exist. skip
        }
        w1=displayWindows[wrem].retain ;
        if (w1==1) {
          nretain=1 ;
          continue ;                           // retain, so skip
        }
        awind=displayWindows[wrem].wind;
        awind.close();
        delete displayWindows[wrem];
        displayWindows[0][dd]='';
    }
    if (nretain==0) {                      // reset displayWindows?
       displayWindows=new Object();
       displayWindows[0]=new Array();
    }
  }                               // closing windows ===========================

  if (arguments.length<1) daGroup='' ;
  if (arguments.length<2) daNumber=1 ;
  if (arguments.length<3) lastbig=0 ;

  if (typeof(specSections.current)=='undefined') {
        alert('Error in E2_showGroup -- no section defined (was E2_loadSection called)?');
         return 1 ;
   }
  isec=specSections.current ;

  sectionNode=specSections[isec] ;

  isecName=specSections.sectionNames[isec]; 
  specSections.sCurrentName=isecName   ;

  gtag0=Math.random()
  specSections.currentGroupTag=gtag0  ;  // identifies the group being processed.

  daGroup=strip(daGroup);
  if (isNaN(daGroup)) daGroup=daGroup.toUpperCase() ;
  if (daGroup!='') {                            // a named group
     if (typeof(specSections[isec].gIndex[daGroup])=='undefined') {
         alert('ERROR in E2_showGroup: in section '+ isec + ' there is no group with name= ' + daGroup);
         return 0 ;
     } else {
       daNumber=specSections[isec].gIndex[daGroup] ;
     }
  }


  if (!isNaN(daNumber) && lastbig==1 &&  daNumber>=specSections[isec].g.length  ) daNumber=specSections[isec].g.length-1 ;

  if (isNaN(daNumber) || daNumber>=specSections[isec].g.length  || daNumber<1 ) {
     alert('ERROR in E2_showGroup: in section '+ isec + ' the group number is invalid=' +daNumber+','+daGroup)
     return 0
  }
  gNumber=daNumber ;
  gName=specSections[isec].gNames[gNumber] ;
  specSections.gCurrentName=gName   ;

  Save_Global('_GroupNumber',gNumber);
  Save_Global('_GroupName',gName);
  Save_Global('_SectionNumber',isec);
  Save_Global('_SectionName',isecName);

  if (_spying==1) {
      ttname=Read_Global('myname',' ERROR: no NAME specified.');
      ttid=Read_Global('MYID',' ERROR: no ID specified ');
      E2_writeHeaderMessage('<span style="font-weight:600;color:red;border:1px solid gold">SPYING on '+ ttname+';  Section.group='+isecName+'.'+gName+' </span>') ;
  }

  groupNode=specSections[isec].g[gNumber] ;

 specSections.gCurrent=gNumber  ;
 useGroup=specSections[isec].g[gNumber] ;
 gContents=useGroup.gcontent ;

i_pageNow.innerHTML='' ;                        // clear the display area, so we can add stuff specifiedin this GROUP
gDiv=document.createElement('div');             // in GROUP, everything is always placed in a big div
E2_copyAttributes(specSections[isec].g[gNumber],gDiv,'NAME LABEL');

E2_addComment(i_pageNow,isecName+':  Group# '+gNumber+ '= '+gName  );

// NOTE: REPEAT, IDXCLASS and IDXTAGS are seomewhat deprecated: consider using <INCLUDE> and <REPEAT>

for (var i=0; i<gContents.length;i++){          // process each of the <CONTENT> in the <group>
  inContent=gContents[i]; doRepeat=0;
  var repeats=getAttributes(inContent.gnode,'REPEAT IDXCLASS IDXTAGS DESC MODULE ')
  inContentList=E2_getNodes(inContent.gnode,'focus label literal gap modules');

  if (repeats.MODULE!=='') {                            // add a modules node to inContentList
     var gMod=document.createElement('modules');             // in GROUP, everything is always placed in a big div
     gMod.setAttribute('value',repeats.MODULE);
     inContentList=Concat_Arrays(gMod,inContentList);
  }

  ndo1=0; ndo2=1 ;
  if (!isNaN(repeats.REPEAT) && repeats.REPEAT!=='' && repeats.REPEAT!=0 ) {
      ndo1=1 ; ndo2=(1*repeats.REPEAT)+1 ; doRepeat=1 ;
  }
  if (doRepeat==0)    E2_addComment(gDiv,' _ Content# '+i+ ' ('+repeats.DESC+')');

//  note: group might be repeated

  cDiv=document.createElement('div');
  E2_copyAttributes(inContent.gnode,cDiv,'REPEAT IDXTAGS XDESC MODULE IDXCLASS');
  for (var ndo=ndo1;ndo<ndo2;ndo++) {                                   // possibly repeat REPEAT times 
     if (doRepeat==1) E2_addComment(cDiv,' _ Content# '+i+ ' iter#  '+ndo+  ' ('+repeats.DESC+')');
     for (var ii=0 ; ii<inContentList.length; ii++) {                      // proess each child (label, literal, etc) of this CONTENT
       E2_addComment(cDiv,'  _'+i+'_ ContentChild# '+ii+  ' ('+inContentList[ii].nodeName+ ') ');
       new1=E2_contentMake(inContentList[ii],isec,gNumber,0);
       if (doRepeat==1) E2_addIdx(new1,ndo,repeats.IDXTAGS,repeats.IDXCLASS) ;
       cDiv.appendChild(new1) ;
     }                                             // ii (child of content 
  }                                              // ndo (iteration of content
  gDiv.appendChild(cDiv) ;                      // append this content onto group div
}                                               // i (content in group

i_pageNow.appendChild(gDiv);

E2_goSection(isecName,gName) ;                        // process special tagnames, <attributes> and <use>, and attributes

// Note: group and section equations are somewhat deprecated. Use the <calls> section (in above) instead 

//  unless suppressed (groupNode.noDefault!=1), do section equations
if  (groupNode.noDefault!=1) {
   clistS=E2_getNodes(sectionNode,'CALL') ;
   for (var ii=0; ii<clistS.length;ii++) {
       ano=getAttributes(clistS[ii],'AFTER',0);
       if (ano!=1)  E2_doEquations('',clistS[ii]);
   }
}

// 3:   do group equations
clistG=E2_getNodes(groupNode,'CALL') ;
for (var ii=0; ii<clistG.length;ii++) {
    E2_doEquations('',clistG[ii]);
}

// 4: if groupNode.noDefault!=1, do section equations (after=1)
if  (groupNode.noDefault!=1) {
   for (var ii=0; ii<clistS.length;ii++) {
       ano=getAttributes(clistS[ii],'AFTER',0);
       if (ano==1) E2_doEquations('',clistS[ii]);
   }
}

// do the various events (such as buttons & timers & query). 
// All events are done just after a group's content is displayed.
//  NOTIFY specified outside of <EVENTS> is done first.
//   EXEC  is done next (its event actions are processed):  before any other EVENTS (within <EVENTS> are considered 
//  Assuming EXEC doesn't cause a transfer to another sections/group ...
//   NOTIFY and QUERY events happen right away 
//       NOTIFY may repeat, but does NOT do any event actions.
//       QUERY will often repeat, waiting for a particular value from the sever  before doing the event actions
//   BUTTON events happen (the event actions are processed) when a button is clicked (but the button is created right away)
//   TIMER events happen (the event actions are processed) when the time expires (the timer starts right away)

delete specSections['eventQueue'] ;       // zero out the event queue
specSections['eventQueue']=new Object() ;       
tmp='';
if (useGroup.gevents.length>0) {

//   <notify> (outside of <events>) are started first (pre EXEC)
//  Note that these NOTIFYS are essentially  asynchronous, so one can
//  treat all these NOTIFYs as happening simultaneously. And even though they are "started first", they could
//  be chugging along while the exec's etc are also processing.
// In particular, it is possible for a notify to complete AFTER an exec has transfered control to a different section

  for (var mm=1;mm<useGroup.gevents.length;mm++) {
    E2_setupNotify(useGroup.gevents[mm],gtag0,gName,1) ;
  }

// now to the stuff inside of <EVENTS>, which might include a notify.
// Note that EXEC is ALWAYS done first -- and if EXEC causes transfer to a different section/group, then
// the other EVENTS will NOT occur.

  if (useGroup.gevents[0]!==0) {
      eelist=[];
      if (useGroup.gevents[0]!==0) eelist=E2_getNodes(useGroup.gevents[0],'*');         // look for bad event (such as an eventaction outside of an event option
      for (var kk=0;kk<eelist.length;kk++) {
         aev=' '+strip(eelist[kk].nodeName.toUpperCase())+' ';
          if (supportedEvents.indexOf(aev)<0) {                      // supportedEvents defined in svylibe2_glboals.js 
             alert(' in section '+isecName+' a bad event ('+aev+') is specified (event must be one of: '+supportedEvents);
             return 0;
          }
         tmp=tmp+aev+' ';
      }
      Save_Global('_eventList',tmp);

      specSections.eventQueue.locked=0 ;            
      var arr=E2_setupExec(useGroup.gevents[0],gtag0) ;         // do an <exec> 
      if (arr==-1) return 1 ;                               // done (error or a GOTO) -- so DO NOT startup other events
      E2_setupButtons(useGroup.gevents[0],gtag0) ;
      E2_setupTimers(useGroup.gevents[0],gtag0) ;
      E2_setupQuery(useGroup.gevents[0],gtag0,gName) ;
      E2_setupNotify(useGroup.gevents[0],gtag0,gName) ; 
     }
 
}
 
/// set focus

iff=get_elements('DIV SPAN INPUT','FOCUS');            // jump to element with a "FOCUS" class (perhaps added using focus="1" in <button> ?
iff2=get_elements('span div','','__MODULEFOCUS');

if (iff.length>0 && iff2.length>0) {
  E2_writeStatus('Warning: multiple focus in group '+SvyGlobals['_GROUPNAMEFULL']) ;
}

if (iff.length>0  ) {

  if (strip(iff[0].nodeName).toUpperCase()=='INPUT') {
        var nn=getAttributes(iff[0],'name','');
        if (nn=='') {
                nn='__MODULEFOCUS2';
                iff[0].setAttribute('name',nn);
        }
       iff[0].focus() ;
  } else {                                      // not an input 
     var goo=document.createElement('a');          // a hack, but it works
     goo.name='__MODULEFOCUS2';
     iff[0].parentNode.insertBefore(goo,iff[0]);
     window.location.hash="#__MODULEFOCUS2" ;
  }
} else {                                                // "FOCUS" trumps <focus />
  if (iff2.length>0) location.hash="#__MODULEFOCUS" ;
}

/* === DEBUG    
   var arf=document.body.innerHTML ;
 var dw=window.open('','debugwindow');
  dw.document.open('text/plain');
  var t1='<html><head><title>Debug window</title><body><div style="border:2px black dotted; background-color:#999999"><tt>Debug mode: </div>  </body></html>';
  dw.document.write(arf);
  dw.document.close();
 ==== */

return 1;

}

//=== ========
// a default function; called after d <calls> processing
// this will process setValue, etc.

function E2_goSection(isecName,gName) {

valueSpecs=[];                  // zap some storage arrays (for <value> and <radio> and <checkbox>
radioSpecs=[];
radioSpecs[0]={};
checkboxSpecs=[];
doitSpecs=[]; 

doitSpecsContent=[];

loopVarList={};              // list of currently active loopvariables

var orderlist,aorder,i,mo3,mo2,mo,imo,ii,bnode,vg,igg,ug;
var foo1,foo2,foo3,foo,dolist,dolist123,remList,j ;
var checkClassList ;

Save_Global('_groupNameFull',isecName+'.'+gName);


if (!debugOn()) {                           // rmb ALWAYs enabled if debugmode=1
   document.oncontextmenu=function() {return false;}  ;  // suppress rmb actions
}

E2_procSection_calls(isecName,gName);                   // call session/section/group specific <call> in <calls>

 ug=E2_procSection_actionTags('','(processing section)') ;                         //  process <REPEAT> and other tags

 E2_procSection_attributes('','(processing section)',isecName,gName);             // use <attributes> to modifiy elements. also store the <use> elements


// find all the eleements that might have "class based" modifications (i.e.; class="SET" setvalue="xxx"
// These are identified by looking at all elements (after possible <REPEAT> and <INCLUDE>, and looking for a 
//  SET, SUBMIT, KEYINC CHECKBOUNDS CONFIRM CHANGE INFOLINKS 
    checkClassList=get_elements('*','SET SUBMIT KEYINC CHECKBOUNDS CONFIRM CHANGE INFOLINKS ');

  ug=e2_procSection_setValue(checkClassList,'(processing section)') ;                         //  process SETVALUE

 if (ug==0) return 0 ;                  // an error occured

// keep/discard elements

var ug=E2_procSection_keep(checkClassList,'(processing section)') ;                         //  keep/discard elements
if (ug==0) return 0 ;                  // an error occured

// add InfoLInks 

dolist=get_elements(checkClassList,'INFOLINKS');
Add_Event(dolist,'click',E2_showHelp)
var ss=Read_Global('_styleInfoLinks','') ;
if (ss!=='') {
  update_styles(dolist,ss);
} else {
   update_class(dolist,'styleInfoLink')
}

for (var igg=0;igg<dolist.length;igg++) {
  vg=getAttributes(dolist[igg],'title summary','');
  if (vg!=='') dolist[igg].setAttribute('title','::'+ vg) ;
}

// add event handlers (KEYINC, CHECKBOUNDS, CONFIRM

E2_addHandlers(checkClassList) ;


return 1 ;
} 



//==================================================
// Various functions to process elements in dom tree


// --- process a module for  special tagnames and a few class based modifications
// These is used by POPUP and UPDATE. It complete a subset of the actions done on the main page.
// useModule: name of node module to process. Often, this is just a <div>
// refmodule : name of module to copy to usemodule BEFORE processing. The contents of refmodule are never changed
//            Thus, you can make several different copies of refmodule, each with it's own
//              customization (say, over different rounds) via multiple calls to e2_procmodule
// isecName, gName : section and name of current group & section -- used when updating elements.
// Note: <attributes> are NOT processed with modules.

function E2_procModule(useModule,refModule,isecName,gName,idebug,doingm) {

 var ug,dolist,dolistC ;
 var igg,vg;
 var checkClassList ;
 if (arguments.length<3) isecName='';
 if (arguments.length<4) gName='' ;
 if (arguments.length<2) refModule='' ;
 if (arguments.length<5) idebug=0 ;
 if (arguments.length<6) doingm=0 ;
 if (useModule==0) useModule='';


 if (useModule==='' || useModule===0) {
     if (refModule=='') {
       alert('Error in e2_procmodule: you must specify a target node ');
       return 0;
    }
 }
  if (useModule==='') {
      useModule=E2_copyNode(refModule,'','MODULE');               
  } else {
     if (refModule!=='' && refModule!==0)  {             // copy from ref module to end of usemodule?
         E2_copyNode(refModule,useModule,'MODULE');               
     }
  }

// now process/modify elements in this new module (change "in place")


// Note: in comparison to the main page
//      a) the <use> elements detected on group startup are still valid
//      b) do NOT process <calls> (popups and updates don't have the same power as the main page)
//      c) do NOT add eventhandlers

   ug=E2_procSection_actionTags(useModule,'(processing module)'),1 ;                         //  process <REPEAT> and other tags

   ug=E2_procSection_attributes('','(procModule)',isecName,gName,useModule) ;        //  add stuff from  <attributes>. 

   if (ug==0) return 0 ;                  // an error occured

//   dolistC=get_elements('*','SET SUBMIT KEYINC CHECKBOUNDS CONFIRM CHANGE INFOLINKS ','','',useModule);

   dolistC=get_elements('*','SET KEEP INFOLINKS ','','',useModule);

   dolist=get_elements(dolistC,'SET');
   ug=e2_procSection_setValue(dolist,' (procSection) ',idebug) ;
   if (ug==0) return 0 ;                  // an error occured


   dolist=get_elements(dolistC,'KEEP');
   ug=E2_procSection_keep(dolist,'(procSection)') ;     
   if (ug==0) return 0 ;                  // an error occured

   dolist=get_elements(dolistC,'INFOLINKS');                  // add InfoLInks 
   if (doingm!==0 && dolist.length>0) {
        alert('Error in INFOLINKS: attempting to add INFOLINKS to a module '+isecName+', '+gName);
        return 0 ;
   }
   Add_Event(dolist,'click',E2_showHelp);
   var ss=Read_Global('_styleInfoLinks','') ;
   if (ss!=='') {
      update_styles(dolist,ss);
   } else {
      update_class(dolist,'styleInfoLink')
  }
 for (var igg=0;igg<dolist.length;igg++) {
    vg=getAttributes(dolist[igg],'summary','');
    if (vg!=='')  dolist[igg].setAttribute('title',vg) ;
 }

// note: event handlers are NOT added here (only added when building a group/section)

return 1 ;
}


//======================
// process elements in a section, resolving <INSERT> <INSERT_AFTER> <REPEAT>, <IF>, <INFO>, <HISTORY>, <SHOW>, <DOIT>, <DISPLAY>, <VALUE>, <RADIO>, <CHECKBOX> and <SET>. 
// And intrnal variable <LOOPVAR>
// okTags, if specified, means only process these action tags (space delimited list)
function  E2_procSection_actionTags(amod,errmess,okTags) {
var vv,anode,aname,mm,alist,aval,avar,m,i,daIf,stuff,addnode,tmp,redisp=0;
var daMod,amodname,mnode,tavar,noSpan ; 
var bmod,snode,ith,mugs,m2,uset ;
var attLoop,cvalue,daVar,daVal;
var ss,snode,daHelpWord,daInfoName,daNoHelp,anode1;           
var isThen,istrue,isElse,useif;
var hname,datext;
var insdone,foo;
var wasl,skipMiss;
var amess,atype,dohide,anid,cnode;
var dTarget,foo,amess2,useStyle,hideContent,isAfter;


if (arguments.length<3) okTags='*';
if (arguments.length<2) errmess='error';

okTags=strip(okTags).toUpperCase(); okTags=' '+okTags+' ';

if (typeof(amod)==='string' && amod==='') {
         alist=i_pageNow.getElementsByTagName('*')   ;
         redisp=1;
} else {
         alist=amod.getElementsByTagName('*')   ;
}


// first, process <insert>

mm=-1; ;
insdone=0;
for (m=1;m>0 ; m++) {                   // leave with a break
    mm++;
    if (mm>=alist.length) break ;                // no more nodes. Note that alist is a nodelist, hence dynamically grows
    anode1=alist[mm];
    aname=anode1.nodeName;
    aname=strip(aname.toUpperCase()) ;

    if (aname!=='INSERT') {
        continue  ;
    }

    anode=E2_procSection_actionTags_use(anode1) ;         // add use="xx" stuff?
    if (anode===0) return 0;                             // error?

    isAfter=getAttributes(anode,'after 2','0');
    if (isAfter=='1') continue ;

    daMod=getAttributes(anode,'module mod','');
    if (daMod=='') {
              alert('Error in procSection_actionTags: no module specified in an INSERT');
              return 0;
    }
    amodname=strip(resolveIndex(daMod)).toUpperCase() ;
    if (typeof(xmlModuleList[amodname])!=='object') {
              skipMiss=getAttributes(anode,'miss skipMiss okSkip skipOk skip','0');
              if (skipMiss!=='1') {              // error: no such module
                 alert('ERROR in procSection_action Tags:  INSERT an unknown module= ' +amodname) ;
                 return 0 ;
              } else {                          // no such module, but just skip it
                wasl=alist.length;
                anode1.parentNode.removeChild(anode1);
                if (wasl!=alist.length)    mm=mm-1;
              }
              continue ;
    }
    mnode=xmlModuleList[amodname] ;
    for (var m2=0; m2<mnode.childNodes.length;m2++) {  
         tmp=E2_copyNode(mnode.childNodes[m2]);
         anode1.parentNode.insertBefore(tmp,anode1);
    }
    wasl=alist.length;
    anode1.parentNode.removeChild(anode1);
    if (wasl!=alist.length)    mm=mm-1;
    insdone++ ;
    if (insdone > 100 ) {
        foo=confirm('Warning: over 100 <INSERT> processed (possibly recursive inserts?). Are you sure? ');
        if (!foo) return 0;
        insdone=50 ; 
    }
}

//if (debugOn(1))  E2_writeStatus('INSERT added: '+insdone);


mm=-1; ;
for (m=1;m>0 ; m++) {                   // leave with a break
   mm++;
   if (mm>=alist.length) break ;                // no more nodes. Note that alist is a nodelist, hence dynamically grows
   anode1=alist[mm];

   if (typeof(anode1)=='undefined' || typeof(anode1.parentNode)=='undefined' || typeof(anode1.parentNode.removeChild)=='undefined') continue ; // odd stuff when working with modules

   aname=anode1.nodeName;
   aname=strip(aname.toUpperCase()) ;

   anode=E2_procSection_actionTags_use(anode1) ;         // add use="xx" stuff?
   if (anode===0) return 0;                             // error?

  if (okTags!=' * ') {
        if (okTags.indexOf(aname)<0) {
          continue ;                            // just ignore (might be a <b> or similar )
        }
    }
        

  if (aname=='REPEAT') {
        aval=getAttributes(anode,'value var  do','');
         if (aval=='') {
                alert('Error in procSection_actionTags: missing do loop ' );
                return 0;
          }
         dobj=parseDoList(aval,errmess) ;
         if (dobj.errmess!='') {
             alert(dobj.errmess);
             return 0;
        }
// do loop (<REPEAT>)
        var loopVarName=strip(dobj.loopvar.toUpperCase()) ;
        for (var iloop=dobj.start;iloop<=dobj.end;iloop=iloop+dobj.step) {  
             avar=document.createElement('SET');
             aval=document.createTextNode(loopVarName+'='+iloop);
             avar.appendChild(aval);
             anode1.parentNode.insertBefore(avar,anode1);

             avar=document.createElement('LOOPVAR');
             avar.setAttribute('var',loopVarName);
             avar.setAttribute('val',iloop);
             anode1.parentNode.insertBefore(avar,anode1);

             SvyGlobals[loopVarName]=iloop ;
             for (var m2=0; m2<anode.childNodes.length;m2++) {  
                tmp=E2_copyNode(anode.childNodes[m2]);
                if (tmp.childNodes.length>0) {
                   replaceNAMES(tmp,iloop,loopVarName);                  // replace name="xx[avar]" with name="xx[iloop]"
                   doAddStyles(tmp,iloop,loopVarName);                  // process addStyle attributes
                 }
                anode1.parentNode.insertBefore(tmp,anode1);
             }
        }

        var wasl=alist.length;
        anode1.parentNode.removeChild(anode1);
        if (wasl!=alist.length)    mm=mm-1;
        continue ;
   }

   if (aname=='IF') {                                                   // <IF> special tagname 

       isThen=E2_getNodes(anode,'THEN',1) ;           // <then> speicifed? 
       useif=1 ;
       if (isThen.length>0) {                           // use advanced syntax 
          istrue=E2_node_doIf(anode,2,anode1) ;         // first text node within  <if> .... </if>, or a value attribute (first text node has priority)
          if (istrue==0) {                              // use ELSE? <else>
             isElse=E2_getNodes(anode,'ELSE',1);
             if (isElse.length==0) {
                 useif=0 ;           // no else, so do nothing
             } else {
                anodeIf=isElse[0]
             }
          } else {
             anodeIf=isThen[0];
          }
       } else {                                         // no <then>,  value attribute inside of <if  ... >
          istrue=E2_node_doIf(anode,3,anode1) ;
          if (istrue==0)  { 
                useif=0 ;           
           } else {
               anodeIf=anode ;
           }
       }


// reminder: anode is the working node (after <USE> have been processed)
//           anode1 is the original node (from the DOM tree) -- anode starts as a copy of anode1

         if (useif==0) {                        // remove the IF and its children
         } else {                                       // remove IF (retain children)
             for (var m2=0; m2<anodeIf.childNodes.length;m2++) {  
                tmp=E2_copyNode(anodeIf.childNodes[m2]);
                anode1.parentNode.insertBefore(tmp,anode1);
             }
         }
        var wasl=alist.length;
        anode1.parentNode.removeChild(anode1);
        if (wasl!=alist.length)    mm=mm-1;
        continue ;
   }                                            // end of <IF>


/*==
    if (aname=='INSERT') {                                       // insert tag <INSERT> 
        alert("ERROR: <INSERT> should of been preprocessed ");
        return 0;
   }
=== */

   if (aname=='INSERT') {                                       // insert tag <INSERT_AFTER> 

      isAfter=getAttributes(anode,'after 2','0');
      if (isAfter!=='1') continue ;

        daMod=getAttributes(anode,'module mod','');

        if (daMod=='') {
              alert('Error in proceSection_actionTags: no module specified in an INSERT_AFTER');
              return 0;
        }
       amodname=strip(resolveIndex(daMod)).toUpperCase() ;
       if (typeof(xmlModuleList[amodname])!=='object') {

              skipMiss=getAttributes(anode,'miss skipMiss okSkip skipOk skip','0');
              if (skipMiss!=='1') {              // error: no such module
                 alert('ERROR in procSection_action Tags:  INSERT (after) an unknown module= ' +amodname) ;
                 return 0 ;
              } else {                          // no such module, but just skip it
                wasl=alist.length;
                anode1.parentNode.removeChild(anode1);
                if (wasl!=alist.length)    mm=mm-1;
              }
              continue ;
       }
       mnode=xmlModuleList[amodname] ;

       for (var m2=0; m2<mnode.childNodes.length;m2++) {  
                tmp=E2_copyNode(mnode.childNodes[m2]);
                anode1.parentNode.insertBefore(tmp,anode1);
         }
        var wasl=alist.length;
        anode1.parentNode.removeChild(anode1);
        if (wasl!=alist.length)    mm=mm-1;
        continue ;

    }


// see svyValue.js for details on how <VALUE> is used
   if (aname=='VALUE') {
        if (typeof(valueSpecs)=='unknown') valueSpecs=[];
        ith=setValueSpecs(anode);
        if (ith<0) return 0 ;

        mugs=''; 
        for (var m2 in loopVarList) mugs=mugs+m2+'='+loopVarList[m2]+ '  ';
        setValueSpecsInsert(ith,anode,mugs,anode1) ;
    }

// see svyValue.js for details on how <RADIO> is used
   if (aname=='RADIO') {
        if (typeof(radioSpecs)=='unknown') {
            radioSpecs=[];
            radioSpecs[0]={};            // store some lookup tables here
        }
        mugs=''; 
        for (var m2 in loopVarList) mugs=mugs+m2+'='+loopVarList[m2]+ '  ';

        ith=setRadioSpecs(anode);
        if (ith<0) return 0 ;
        setRadioSpecsInsert(ith,anode,mugs,anode1) ;
        mm=mm-1;
        continue ;
    }

// see svyValue.js for details on how <CHECKBOX> is used
   if (aname=='CHECKBOX') {
        if (typeof(checkBoxSpecs)=='unknown') {
            checkboxSpecs=[];
        }
        mugs=''; 
        for (var m2 in loopVarList) mugs=mugs+m2+'='+loopVarList[m2]+ '  ';

        ith=setCheckboxSpecs(anode);
        if (ith<0) return 0 ;
        setCheckboxSpecsInsert(ith,anode,mugs,anode1) ;
        mm=mm-1;
        continue ;
    }


// see svyValue.js for details on how <DOIT> is used
   if (aname=='DOIT' || aname=="DO" ) {
        if (typeof(doitSpecs)=='unknown') {
            doitSpecs=[];
            doitSpecsContent=[];
        }
        mugs=''; 
        for (var m2 in loopVarList) mugs=mugs+m2+'='+loopVarList[m2]+ '  ';
        ith=setDoitSpecs(anode);
        if (ith<0) return 0 ;
        setDoitSpecsInsert(ith,anode,mugs,anode1) ;
        mm=mm-1;
        continue ;
    }

//xxxxxxxxxxxxxxxxx
   if (aname=='DISPLAY' ) {
       amess=getAttributes(anode,'message text mess','Click to display');
       amess2=getAttributes(anode,'messageHide text2 mess2 message2 messHide','');
       useStyle=getAttributes(anode,'useStyle','');
       atype=getAttributes(anode,'type','button'); atype=strip(atype).toUpperCase();
       dohide=getAttributes(anode,'hideButton hide','0');
       hideContent=getAttributes(anode,'hideContent','1'); 
       anid=''+Math.random(); anid=anid.substr(3);
       
       dTarget=getAttributes(anode,'target','');
       if (dTarget=='') {
         dTarget=anid
       } else {
          foo=document.getElementById(dTarget);
          if (!foo) {
                alert('Error in <DISPLAY>: no such target =' +dTarget);
                return 0;
          }
       }

       if (atype=='BUTTON') {
            lnode=document.createElement('input');
            lnode.setAttribute('type',"button");
            lnode.value=amess;
            lnode.setAttribute('atype',"button");
       } else {
            lnode=document.createElement('span');
            aval=document.createTextNode(amess);
            lnode.appendChild(aval);
            if (useStyle=='') {
               lnode.style.color='blue'; lnode.style.textDecoration='underline';
            } else {
                lnode.style.cssText=useStyle;
            }
            lnode.setAttribute('atype',"link");
       }        
       lnode.setAttribute('dTarget',dTarget);
       lnode.setAttribute('message',amess);
       lnode.setAttribute('message2',amess2);
       lnode.setAttribute('messageAt',1);
       lnode.setAttribute('hideMe',dohide);
       lnode.setAttribute('onClick',"doDisplayNow(this)");
       
       if (dTarget==anid) {        
          mnode=document.createElement('DIV');
          if (hideContent==1) {
              mnode.style.display='none';
          } else {
              mnode.style.display='block';
          }
          mnode.setAttribute('id',anid);
          for (var m2=0; m2<anode.childNodes.length;m2++) {
             tmp=E2_copyNode(anode.childNodes[m2]);
             mnode.appendChild(tmp);
           }

           anode1.parentNode.insertBefore(lnode,anode1);
           anode1.parentNode.insertBefore(mnode,anode1);
        } else {                                                // do NOT create the targeted div
           anode1.parentNode.insertBefore(lnode,anode1);
        }
        
        var wasl=alist.length;
        anode1.parentNode.removeChild(anode1);
        if (wasl!=alist.length)    mm=mm-1;
        continue ;
   }


//xxxxxxxxxxxxxxxxxxx

    if (aname=='LOOPVAR') {                                         // <LOOPVAR> 
           daVar=getAttributes(anode,'var','');
           daVal=getAttributes(anode,'val','');
           loopVarList[daVar]=daVal;
           var wasl=alist.length;
          anode1.parentNode.removeChild(anode1);
         if (wasl!=alist.length)    mm=mm-1;

        } 

    if (aname=='SET') {                                         // <SET> 
        avar=getAttributes(anode,'var value  ','');              // check for common error 
        if (avar!=='') {
           alert('Error: a var, or value, attribute inside of a SET: '+avar);
           return 0;
        }
        cvalue=E2_doEquations('',anode);                     // note '' argument means "no DOM element to recieve value of  equation values)
        if (cvalue!=='') {
           snode=document.createElement('span');
           snode.innerHTML=cvalue;
//           snode.appendChild(avar) ;
           E2_copyAttributes(anode,snode,' ');

           uset=getAttributes(anode,'useStyle','.');
           if (uset!=='.') snode.setAttribute('style',uset);

           anode1.parentNode.insertBefore(snode,anode1);
        }
        var wasl=alist.length;
        anode1.parentNode.removeChild(anode1);
        if (wasl!=alist.length)    mm=mm-1;

     }

    if (aname=='HISTORY') {                                        // <HISTORY>
        hname=getAttributes(anode,'name','_DEFAULT');
        hname=strip(hname.toUpperCase());
//      alert('LOOKUP <HISTORY SPECIAL TAG   ='+hname);
        if (typeof(simpleHistory.specs[hname])=='undefined') {
          alert('Error: <HISTORY> special tagname points to non-defined History: '+hname);
          return 0;
        }
        datext=E2_getNodeText(anode);
        avar=document.createTextNode(datext);
        snode=document.createElement('span');
        snode.appendChild(avar) ;
        E2_copyAttributes(anode,snode,'VAR VALUE INFONAME HELPWORD NOHELPBOX ONCLICK');
        if (getAttributes(snode,'class style','0')=='0') {

         snode.className='historyButton';   // can't use snode.class='xxx' cause of stupid ie
         snode.setAttribute('class','historyButton');

        }
        snode.setAttribute('onClick',"E2_showSimpleHistory('"+hname+"')");
        anode1.parentNode.insertBefore(snode,anode1);
        if (wasl!=alist.length)    mm=mm-1;
        anode1.parentNode.removeChild(anode1);
        continue ;
        
    }

    if (aname=='INFO') {                                        // <INFO>
           datext=E2_getNodeText(anode) ;  
           avar=document.createTextNode(datext);
           snode=document.createElement('span');
           snode.appendChild(avar) ;
           E2_copyAttributes(anode,snode,'VAR VALUE INFONAME HELPWORD NOHELPBOX ONCLICK');
           daInfoName=getAttributes(anode,'info infoname help','');
                if (daInfoName=='') {
                     alert('Error: INFO without an INFONAME attribute: '+datext);
                     return 0;
                 }
                 snode.setAttribute('infoName',daInfoName);
          daNoHelp=getAttributes(anode,'nohelpbox ','');
                if (daNoHelp!=='') snode.setAttribute('noHelpBox',daNoHelp);          
          daHelpWord=getAttributes(anode,'helpword word ','');
                if (daHelpWord!=='') snode.setAttribute('helpWord',daHelpWord);          

          var ss=Read_Global('_styleInfoLinks','') ;
          if (ss!=='') {
             update_styles(snode,ss);
          } else {
             update_class(snode,'styleInfoLink')
          }

// addling click event doesn't seem to work (maybe cause this element is moved later?. So see add onclick instead
//          Add_Event(snode,'click',E2_showHelp);
           snode.setAttribute('onClick','E2_showHelp("'+daInfoName+'","","'+daNoHelp+'")'); 
      
           anode1.parentNode.insertBefore(snode,anode1);
           if (wasl!=alist.length)    mm=mm-1;
           anode1.parentNode.removeChild(anode1);
           continue ;
    }
        
    if (aname=='SHOW') {                                        // <SHOW>
         avar=E2_getNodeText(anode) ;
         if (avar=='') avar=getAttributes(anode,'var value','');
         if (avar=='') avar=getAttributes(anode,'name','');
         noSpan=getAttributes(anode,'nospan',0);
         if (avar!='') {                                        
           tmp=avar.match(/[\)\(\+\-\*\\]/);
           if (tmp!==null) {                            // check for common error
                alert('Error: a ( ) + - * or \ in a SHOW: '+avar); return 0;
            }
            tavar=avar.toUpperCase();
            if (tavar.indexOf('.G')>-1 || tavar.indexOf('.C')>-1 || tavar.indexOf('.U')>-1 ) {
                alert('Error: a .x modifier is used in variable in SHOW: '+tavar); return 0;
            }
           aval=svy_getVal(avar);     
           avar=document.createTextNode(aval);
           if (noSpan!=1) {
              snode=document.createElement('span');
              snode.appendChild(avar) ;
              E2_copyAttributes(anode,snode,'VAR VALUE NAME LABEL');
              anode1.parentNode.insertBefore(snode,anode1);
           } else {
              anode1.parentNode.insertBefore(avar,anode1);
           }

        } else {
            alert('Error in SHOW: no var specified');
        }
        wasl=alist.length;
        anode1.parentNode.removeChild(anode1);
        if (wasl!=alist.length)    mm=mm-1;
         continue ;

    }
// nothing special, so advance to next node 
  }                             // for 


// goo=E2_xmlToString(i_pageNow);  
// Display_Content('goo','oof')

if (redisp==1) i_pageNow.innerHTML=i_pageNow.innerHTML+' ' ;           // forces redisplay (avoids some quirks in the browser)


  return 1;

}               // use anode.par

// --------------------------
// take care of a click due to a <DISPLAY>
function doDisplayNow(athis) { 
var anid,amess,amess2,dohide,messat;
 anid=  athis.getAttribute('dTarget');
 amess= athis.getAttribute('message');
 amess2= athis.getAttribute('message2');
 dohide=athis.getAttribute('hideMe');
 messat=athis.getAttribute('messageAt');
 atype=athis.getAttribute('aType');
 
 displayDiv(anid);
 if (dohide==1) { 
   athis.style.display='none'; 
 } else {
    if (amess2!=='') {
        useMess=amess;
        if (messat==1) useMess=amess2 ;
        messat=1-messat ;
        athis.setAttribute('messageAt',messat);
        if (atype=='button') {
           athis.value=useMess ;
        } else {
           athis.innerHTML=useMess ;
        }
    }    
 }
 return 1;

}


// --------------------------
// process a use="saveName" attribute in a special tagname 
function  E2_procSection_actionTags_use(anode0) {

var anode,ainclude,snode,i2,cnode,astyle;

// check for an use="savename" attribute. If found, add the stuff defined in the <savename>... node in <use> section of spec file
ainclude=getAttributes(anode0,'INCLUDE USE INSERT','');
if (ainclude==='') return anode0 ;

ainclude=strip(ainclude).toUpperCase() ;  

if (typeof(specSections.saveNodeList[ainclude])=='undefined') {
     alert('Error in procSection_actionTags_use: non-existent USE= '+ainclude);
     return 0;
}

anode=E2_copyNode(anode0);              // copy of anode  UH OH, better incldue pointer to parent!
snode=specSections.saveNodeList[ainclude];
for (var i2=0 ; i2<snode.childNodes.length ;i2++) {
   cnode=E2_copyNode(snode.childNodes[i2]) ;
   anode.appendChild(cnode) ;
}
astyle=getAttributes(snode,'useStyle','.')
if (astyle!=='.') {
// alert('usettt '+astyle);
   anode.setAttribute('usestyle',astyle);
}

return anode ;

}

// ---------- 
// look for NAME attributes of the form name[aname], and repace the [ith] with [n] 
function replaceNAMES(danodes,n,aname) {

var dlist,i,atag,aindex3,anid,vname,newid,nn ;
var iem,ems;
aname=strip(aname.toUpperCase()) ;

dlist=danodes.getElementsByTagName('*');

for (var i=0; i<dlist.length;i++) {                     // examine all the elements
  anid=dlist[i].getAttribute('name');
  if (anid=='' || anid==null) continue ;
  if (anid.indexOf('[')<0) continue ;
   aindex3=parseUsing(anid,'[',']',1);                          // look for index in varname
  vname=strip(aindex3[1].toUpperCase());
  if (!isNaN(vname)) continue ;                 // leave numbers alone

// simple case, no commas (1 dim)
  if (vname.indexOf(',')<0) {
    nn=n;                                 // replace match to aname (the loop variable name)  with current loop variable  (in n)
    if (vname!=aname) continue ;        
    newid=aindex3[0]+'['+nn+']';
    dlist[i].setAttribute('name',newid);
  } else {                                      // replace several elements
    ems=parseAt(vname,',');
    for (var iem=0;iem<ems.length;iem++) {
      nn=n;                                 // replace match to aname (the loop variable name)  with current loop variable  (in n)
      if (ems[iem]!=aname) continue ;
      ems[iem]=nn ;
    }  
    newid=aindex3[0]+'['+ems[0];
    for (var iem=1;iem<ems.length;iem++)  newid=newid+','+ems[iem];
    newid=newid+']';
    dlist[i].setAttribute('name',newid);
  }

}

return 1 ;

}


// ---------- 
// look for addStyle attributes, parse, and change the style attibute
function doAddStyles(danodes,n,aname) {

var tmp3,vname,aindex3,iii;
var i,aname,ii,sname,svalue,svalues,plist,tmp1,tmp2,dlist;

aname=strip(aname.toUpperCase()) ;

dlist=danodes.getElementsByTagName('*');

for (var i=0; i<dlist.length;i++) {                     // examine all the elements
  addStyle=getAttributes(dlist[i],'addStyle','');
  if (addStyle=='') continue ;
  plist=addStyle.split(';');

  newstyle='';
  for (var ii=0;ii<plist.length;ii++) {
     ado=plist[ii].split(':');
     tmp1=ado[0]+':' ;
     svalue=ado[1];
     svalues=svalue.split('$+');

     for (var iii=0;iii<svalues.length;iii++) {
        tmp2=strip(svalues[iii]);
        if (tmp2.toUpperCase()==aname) {                // replace with loop variable
          tmp1=tmp1+n
        } else if (tmp2.substr(0,1)=="'") {             // ' quoted string
          tmp1=tmp1+tmp2.replace(/'/g,'');
           
        } else if (tmp2.indexOf('[')>0) {
          aindex3=parseUsing(tmp2,'[',']',1);                          // look for index in varname
          vname=strip(aindex3[1].toUpperCase());
          if (vname==aname) {                                   // index is the loop variable -- replace with loop value
              tmp3=aindex3[0]+'['+n+']';
              tmp1=tmp1 + svy_getVal(tmp3);     
          }else {                                               // just a standard dsurvey array variable
             tmp1=tmp1 + svy_getVal(svalues[iii]);     
          }
        } else {
          tmp1=tmp1 + svy_getVal(svalues[iii]);                 // no [, not loopvar, not string
        }
      }
      newstyle=newstyle+tmp1+';' ;  
  }
//alert('nww ' +newstyle);
  update_styles(dlist[i],newstyle)

}


return 1 ;

}



// ---------- 
// For a list of elements, process the setValue attributes (in elements with a SET class) . 
// dolistSET should be a list of elements, say as created using get_elements

function e2_procSection_setValue(dolistSET,errmess,idebug) {
 var orderlist,aorder,i,ii,bnode,io,iio ;


// DEPRECATED: dolistset will never by empty
// if (arguments.length<1  || dolistSET===''  || dolistSET===0   ) dolistSET=get_elements(' div span input option select tr th td ','SET');        


 if (arguments.length<2) errmess='' ;
 if (arguments.length<3) idebug=0 ;

// look for highest order value 
  orderlist=[];
  for (var i=0;i<dolistSET.length; i++) {
     aorder=getAttributes(dolistSET[i],'order',1);
     if (isNaN(aorder)) {
        alert('ERROR in E2_procSection_section ' + errmess+ ' : bad value of order attribute = ' +aorder);
        return 0;
     }
     if (typeof(orderlist[aorder])=='undefined') {
          orderlist[aorder]=[] ;
          orderlist[aorder][0]=dolistSET[i] ;
    } else {
          orderlist[aorder]=orderlist[aorder].concat(dolistSET[i]) ;
    }
  }
// now do in orderlist...

//if (idebug==1) alert(dolistSET.length + ' orderlist.length ' + orderlist.length) ;
for (var io=0; io<orderlist.length;io++) {
  if (typeof(orderlist[io])=='undefined') continue ;              // nothing has this order 
  for (var iio=0; iio<orderlist[io].length;iio++) {
     bnode=orderlist[io][iio] ;
     E2_setValue(bnode,idebug)
  }
}
return 1; 
}


//===========================
// parse a do synax (do="avar=start,end,by")
// return in an object doobj.loopvar doobj.start, doobj.end dooby.step
// return dobj.errmess='message'  if an error
function parseDoList(doList,errmess) {
var ff,loopvar,ff2;
var loopStart,loopEnd,loopStep;
var dobj={};
dobj.errmess='';

 if (doList.indexOf('=')<0) doList='LOOP='+doList;
   ff=doList.split('=');
   loopVar=strip(ff[0].toUpperCase());
   if (loopVar=='') loopVar="LOOP";
   ff2=ff[1].split(',');
   if (ff2.length<2) {
           dobj.errmess='ERROR ('+errmess+'):  REPEAT : DO without end: '+doList;
            return doby ;
   }
   loopStart=strip(svy_getVal(ff2[0],''));
   if (isNaN(loopStart)) {
          dobj.errmess='ERROR ('+errmess+'): REPEAT : do Start not a number: '+doList ;
          return dobj ;
   }
   loopEnd=strip(svy_getVal(ff2[1],'n.a.'));
   if (isNaN(loopEnd)) {
          dobj.errmess='ERROR  ('+errmess+') :  REPEAT : do End ('+ff2[1]+'='+loopEnd+') not a number: '+doList;
          return dobj ;
   }
   loopStep=1;
   if (ff2.length>2)  {
          loopStep=strip(svy_getVal(ff2[2],''));
          if (isNaN(loopStep) || loopStep<0 ) {
                 dobj.errmess='Error ('+errmess+') :  REPEAT : do Step not a number: '+doList;
                return -1  ;
          }
   }

  dobj.start=parseInt(loopStart);  dobj.end=parseInt(loopEnd); dobj.step=parseInt(loopStep);
  dobj.loopvar=loopVar;
  return dobj ;
}




// =----------------------------------
// process dolist for KEEP elements. If found, examine IF attribute, and keep or discard the contents of the element.
// If dolist not specified, examine all div,span,li,tr, and th and td elements in the dom tree
// note: errmess not currently used (but maybe in future)

function E2_procSection_keep(dolist,errmess) {

var remList,i,try1,aif,foo ;

if (arguments.length<1 || dolist===0 || dolist==='') dolist=get_elements('div span li tr th td ','KEEP');
if (arguments.length<2) errmess='' ;

remList=new Array();
for (var i=0;i<dolist.length;i++){
  var try1=dolist[i];
  aif=getAttributes(try1,'KEEPIF ','');
  var gob=1;
  if (aif=='') {
         aif=getAttributes(try1,'IF','');                 // use IF only if no KEEPIF
         gob=0;
  }
  if (aif=='') continue         ;               // if no IF, do NOT hide

if (gob==1) {
    hh=svy_getVal('#iloop','',try1);
    hh2=svy_getVal('itick['+hh+']','',try1);
    hh3=svy_getVal('itick[#iloop]','',try1);
 }

  foo=E2_doEquations1(try1,aif);
  if (foo!=1) {
       remList=remList.concat(try1);
  }
}
removeNodes(remList,0);
return 1 ;
}

//=--------------------------------
// add attributes using the <attributes> section of the spec  file
// If w1='' or 0 or not specified, use main window. Otherwise, w1 should be pointer to a window opened (say, using DISPLAY)
// errmess not currently used

function E2_procSection_attributes(w1,errmess,isecName,gName,anode) {

var chkit,tname,tnameAt,i ;
if (arguments.length<1) w1='';
if (arguments.length<2) errmess='' ;
if (arguments.length<3) isecName='' ;
if (arguments.length<4) gName='' ;
if (arguments.length<5) anode='' ;

var taglist=document.getElementsByTagName('*');

// first: process non-group/non-section elements
for (var i=0;i<specSections.elementList['0'].length;i++){
  chkit=specSections.elementList['0'][i];
  E2_attributeToNode(chkit,w1,anode,taglist) ;
}

// next, process section specific elements

if (isecName!=='') {                            
tname=strip(isecName.toUpperCase()) ;                                   
tnameAt=tname ;                                         
if (typeof(specSections.elementList[tnameAt])!='undefined') {
   for (var i=0;i<specSections.elementList[tnameAt].length;i++) {           // name, isName, node
     chkit=specSections.elementList[tnameAt][i];                           
     E2_attributeToNode(chkit,w1,anode,taglist) ;
   }
}
}

// last, process section.group specific elements

if (isecName!=='' && gName!=='') {
tname=strip(isecName)+'.'+strip(gName);
tname=tname.toUpperCase() ;
tnameAt=tname ;                                         
if (typeof(specSections.elementList[tnameAt])!='undefined') {
   for (var i=0;i<specSections.elementList[tnameAt].length;i++) {           // name, isName, node
     chkit=specSections.elementList[tnameAt][i];                           
     E2_attributeToNode(chkit,w1,anode,taglist) ;
   }
}
}
return 1 ;
}

//=--------------------------------
// call functions/equations using stuff listed in the <calls> section of the spec file
//   specSections.saveCallsList[ie]['node']=anodei ;
//   specSections.saveCallsList[ie]['for']=aat;

function E2_procSection_calls(isecName,gName) {
var dolist=[];
var i,anode,i0;

isecName=strip(isecName).toUpperCase(); 
gName=isecName+'.'+strip(gName).toUpperCase() ; 

isecName=' '+isecName+' ';
gName=' '+gName+' ';

//alert(gName);


for (var i=0;i<specSections.saveCallsList.length;i++){ 
  chkit=specSections.saveCallsList[i]['for'];
  if (chkit.indexOf('*')>-1) {
        dolist=dolist.concat(i);
  } else {                              // not *
      if (chkit.indexOf(isecName)>-1){      // check secname
         dolist=dolist.concat(i);
     } else {                           // check gname
      if (chkit.indexOf(gName)>-1) {
           dolist=dolist.concat(i);
      }

    }
  }
}                               // for

for (var i0=0;i0<dolist.length;i0++) {                     // process all Calls that this "gruop/section" matches to
  i=dolist[i0] ;
  anode=specSections.saveCallsList[i]['node'] ;
  E2_doEquations('',anode);                     // note '' argument means "no DOM element to recieve value of  equation values)
}

return 1 ;
}





// END OF  Various functions to process elements in dom tree
//==================================================


// ==== ====================================
// look for setValue, or if- then - else attributes; and set the value of the cnode element
function E2_setValue(cnode,idebug) {

if (arguments.length<2) idebug=0 ;

var daIf,isif,doit,daThen,daElse,jji  ;
var isnew,aval,makeval,v1,stuff,doit2,i,i2,aids;

  daIf=getAttributes(cnode,'setIf setCond ','');
  if (daIf==='') daIf=getAttributes(cnode,'IF ','');     // use IF only if no setIf 
  if (daIf=='') {                            // no if condition, look for setValue
        isif=0;
        doit=getAttributes(cnode,'setValue set setVar  ','');
        if (doit=='') return 0       ;                  // no setValue, leave as is
  } else {                                           // got an if, for then and else
        isif=1 ;
        daThen=getAttributes(cnode,'then  setThen ','_AF_%'); 
        if (daThen=='_AF_%') {                       // error: must specify a then
            alert('Error in E2_setValue: If but no THEN (if= '+daIf);
            return 0;
        }
        daElse=getAttributes(cnode,'ELSE setElse ','');
  }

  if (isif==1) {
      useif=E2_doMath(daIf,cnode);
      if (useif!=0)  {
           doit=daThen;
       } else {
          doit=daElse;
      }
  }

  if (doit=='') return 0;                       // no setValue, or no else? Do nothing

  if (strip(doit.toUpperCase())=='HIDE')  {                    // HIDE means "do not display this element
        cnode.style.display='none';
        return 1 ;
  }

  if (strip(doit.toUpperCase())=='NODISPLAY')  {                    // NODISPLAY is  stronger than HIDE
        cnode.style.display='none' ;
        return 1 ;
  }

  if (strip(doit.toUpperCase())=='DELETE')  {                    // DELETE is even stronger
        cnode.parentNode.removeChild(cnode) ;
        return 1 ;
  }

  doit2=doit.split(';');
  makeval=''    ; evalue=null ;

  for (var jji=0; jji<doit2.length; jji++) {           // examine many possible "components"

       v1=strip(doit2[jji]);
       stuff=E2_parseEqu(v1);
       makeval=E2_doMath(stuff,cnode);
       if (makeval==null) return '' ;           // an error occured
       if (stuff.varname!=='') {
           svy_setVal(strip(stuff.varname),makeval,cnode);
       } else {
          if (evalue==null) {
             evalue=makeval ;
          }  else {
            evalue=evalue + makeval +' ';
          }
       }                        // varname==''
  }                              // loop through components

  if (evalue!=null && evalue.length!=0) set_elemValue(cnode,evalue);                        // writes cumulative results of functions that do not start with x=

  return 1 ;

}

//========================================
// save a value to global variable, prior variable, attribute, or value field of a dom element
function svy_setVal(aname,avalue,anode) {
var ac,idi,i,vv,ivv ;
var idxcheck,ix,myidx,idi ; 
var aindex3,vname,nn,ems,iem;

ac=aname.substr(0,1);
if (ac=='@') {                          // set value attribute of a DOM element
  aname=aname.substr(1) ;
  idxcheck='';
  idi=aname.indexOf('#');
  if (idi>-1) {          // use IDX attribute to narrow down ? 
        if (typeof(anode)!=='object') {
              alert('ERROR: svy_setVal -- using # in an element name, but node not specified ');
              return 1 ;
        }
        idxcheck=getAttributes(anode,'IDX','') ;
        idxcheck=strip(idxcheck.toUpperCase()) ;
        aname=aname.substr(0,idi);
  }
  
// replace [x,y] with values of x and y (if they are defined)
  if (aname.indexOf('[')>-1) {
     aindex3=parseUsing(aname,'[',']',1);                          // look for index in varname
     vname=strip(aindex3[1].toUpperCase());
     if (vname.indexOf(',')<0) {                        // one index
          nn=svy_getVal(vname,'');
         if (nn!=='')   aname=aindex3[0]+'['+nn+']';
      } else {                                      // more than one index
         ems=parseAt(vname,',');                     
         for (var iem=0;iem<ems.length;iem++) {
            nn=svy_getVal(ems[iem],'');
            if (nn!=='')  ems[iem]=nn ;
         }  
        aname=aindex3[0]+'['+ems[0];
        for (var iem=1;iem<ems.length;iem++)  aname=aname+','+ems[iem];
        aname=aname+']';
    }                                   // 2 elements
  }                                             // [x,y] in element name

  idi=get_elements('*','',aname);                       // use this to avoid capitalization problems
  if (idi.length==0) return  0 ;         // no such elements, just give up
  for (var i=0;i<idi.length;i++) {
     if (idxcheck=='') {
         set_elemValue(idi[i],avalue);                        // writes cumulative results of functions that do not start with x=
     } else {                                   // also check for matching value of idx
        myidx=getAttributes(idi[i],'IDX',''); myidx=strip(myidx.toUpperCase()) ;
        if (myidx===idxcheck)  {
              set_elemValue(idi[i],avalue);
        }
     }
  }
  return 1 ;
}

if (ac=='#') {                          // set value attribute of a DOM element
  if (anode=='') return 0 ;                    // no node info, give up
  aname=aname.substr(1) ;
  if (aname=='') aname='value';         // # by itself means "value attribute" (note that # by itself in a read means "IDX" attribute)
  anode.setAttribute(aname,avalue);
  if (aname.toUpperCase()=='VALUE') anode.value=avalue ;
  return 1 ;
}

// else, set survey global
if (ac=='%')   aname=aname.substr(1) ;

// prior variable?
var ip=aname.indexOf('.');
if (ip>-1) {
   var pp=aname.split('.');
   aname=pp[0];
  var nround='';
  if (pp.length>1) nround=pp[1];
  if (nround.toUpperCase()=='_RECENT') nround='';
  if (nround!=='')  nround=svy_getVal(nround,'',anode);   // allow for .varname (varname points to what round to use)
}

// check for [index]. If found, convert into number (using svy_getVal)
aname=resolveIndex(aname,anode,'');

if (ip<0) {
   Save_Global(aname,avalue);
} else {
   Save_priorGlobal(nround,aname,avalue);
}
return 1 ;

}

 
  

//========================================
// add attributes to dom node, using xml elements stuff: 
// step 1= is there an element in document, or document of other window, or xml node anode .... with this id or name?
// chkit : the element that contains the reference attributes 
// usewin: if specified, the window containing elements whose attributies will be modified (using the reference attributes)
// anode: the node  containing elements whose attributies will be modified (using the reference attributes)
// if usewin and anode not specified, look in the current section (main window) for elements to modfiy

function E2_attributeToNode(chkit,usewin,anode,taglist) {

var useself=0,usenode=0 ;
var isName,chkId,doit,docid,i,ii,cnode,aname,km,zoo;
var gettags=0;
var tname,jj;

if (arguments.length<2 || usewin===0 || usewin==='' )  useself=1 ;
if (arguments.length>3) gettags=1;


if (arguments.length<3) anode=0;
if (anode===0 || anode==='' )  {
        usenode=0 ;
} else {
        usenode=1;
}

if (useself==0 && usenode==1) {
        alert('Error in E2_attributetoNode: can mot specify a window and a node ');
        return 0;
}

 isName=chkit.isName;
 chkId=chkit.name ;
 chkid=strip(chkId.toUpperCase()) ;
 cnode=chkit.node ;

/* ----
// DEPRECATED. Use <CALLS> instead 
 if (strip(chkId.toUpperCase())=='CALL') {              // special case: call functions independently of an element  (done for ALL groups in ALL sections)
     E2_doEquations('',cnode);                     // note '' argument means "no DOM element to recieve value of  equation values)
     return 1;
  }
====*/

 if (usenode==1) {                                       // look in module
//      chkid=strip(chkId.toUpperCase()) ;
      zoo=anode.getElementsByTagName('*') ;
      docid=[] ;
      if (isName==1) {                                       // look for possibley several names
          for (var km=0;km<zoo.length;km++) {
              aname=getAttributes(zoo[km],'name','');
              if (aname!==chkid) continue ;
              docid=docid.concat(zoo[km]);                      // many nodes with same name permitted 
          }
       } else {
          for (var km=0;km<zoo.length;km++) {
              aname=getAttributes(zoo[km],'id','');
              if (aname!==chkid) continue ;
              docid=docid.concat(zoo[km]);
              break ;                                   // only one unique ID permitted 
          }
       }
       if (docid.length==0) return 0 ;                           // no such id under this xml node
       E2_attributeToNode2(docid,cnode);
       return 1 ;
 }

// not a node (i.e.; a module) 
 if (useself==1) {                              // look in current section (in main window)
   if (gettags==0) taglist=document.getElementsByTagName('*');
   docid=[];
   if (isName==1) {                                       // look for possibley several names
        for (var jj=0;jj<taglist.length;jj++)  {
             tname=getAttributes(taglist[jj],'name',' ');
             if (strip(tname).toUpperCase()==chkId) docid=docid.concat(taglist[jj]);
         }
//         docid=document.getElementsByName(chkId) ;
         if (docid.length==0) return 0 ;                           // no such name in current document
    } else {
         for (var jj=0;jj<taglist.length;jj++)  {
             tname=getAttributes(taglist[jj],'id',' ');
             if (strip(tname).toUpperCase()==chkId) docid=docid.concat(taglist[jj]);
         }
//         docid=document.getElementById(chkId) ;
         if (!docid) return  0 ;              // no such id in current document
    }
    E2_attributeToNode2(docid,cnode);
    return 1;
 }

// else, other window
  
  if (isName==1) {                                       // look for possibley several names
      docid=usewin.document.getElementsByName(chkId) ;
      if (docid.length==0) return 0 ;                           // no such name in current document
  } else {
      docid=usewin.document.getElementById(chkId) ;
      if (!docid) return  0 ;              // no such id in current document
  }
  E2_attributeToNode2(docid,cnode);
  return 1;

}


// =============
// add attributes to dom node, using xml elements stuff: step 2: add attributes to element (or elements)
// toNode: a dom node, or list of dom nodes, to have attributes added to
// fromNode: the xml node that contains the attributes to be added

function E2_attributeToNode2(toNode,fromNode) {
var i,ii,tonode2,anattNode,anName,anVal,anatt,doset,ij,iappend;
var islist=0;

for (var i=0; i<fromNode.childNodes.length ; i++ ) {            // add all the attributes defined for this id
  anattNode=fromNode.childNodes[i];
  if (anattNode.nodeType!=1) continue ;                     // not an element
  anName=strip(anattNode.nodeName) ;                               // name of attribute
  doset=0;
  iappend=0;
  if (anName.toUpperCase()=='SET') {                    // set is special case
        doset=1 ;
  } else {
       anVal=E2_getNodeText(anattNode,1);
       if (anVal==='')   anVal=getAttributes(anattNode,'VALUE','');
       iappend=getAttributes(anattNode,'append','0');
  }     

  if (typeof(toNode)=='object' && typeof(toNode.length)!=='undefined') islist=1 ;
  ii=0; ii2=1;
  if (islist==1) ii2=toNode.length
 
  for (var ii=0 ; ii<ii2;ii++) {
     if (islist==0) {
        tonode2=toNode ;
      } else {
          tonode2=toNode[ii];
      }
      if (doset==1) {  
            E2_doEquations(tonode2,anattNode);                     // send the node (that specifies the SET
      } else {
            if (iappend==1) {
               var tmp=getAttributes(tonode2,anName,'');
               anVal=tmp+' '+anVal;
             }
            tonode2.setAttribute(anName,anVal);
            var ij=specSections.elementList.__NODES.length ;
            specSections.elementList.__NODES[ij]=anattNode;
            tonode2.setAttribute('__'+anName,ij);
      }                                         // doset
   }
}                               // for all childnodes (attributes specifications
return 1 ;

} 

//========================================
// process CREATE nodes (create new modules

function  E2_modulesCreate(anode)  {

var cnodes,i,attname,tattname,attval,basenode,newname,usetag,contlist;
var doRepeat,arepeat,aClass,aTags,inContent,ndo,ndo1,ndo2,inContentList,j,ii,iii ;
var ndo,ndo1,ndo2,amod ;
var dude='' ;

cnodes=E2_getNodes(anode,'CREATE') ;
if (cnodes.length==0) return 1 ;
if (debugOn(2))  E2_writeStatus('Processing '+cnodes.length+' CREATE') ;

for (var i=0;i<cnodes.length;i++){
  cnode=cnodes[i];
  mattr=getAttributes(cnode,'modulename tagname');
  if (mattr.MODULENAME==='') {
        alert('Error in E2_modulesCreate: CREATE without a moduleName attribute ');
        return 1;
 } else {
       newname=mattr.MODULENAME ;
  }
  if (mattr.TAGNAME==='') {
        usetag='DIV'
  } else {
       usetag=mattr.TAGNAME ;
  }
  newname=strip(newname.toUpperCase());
  newname=resolveIndex(newname,anode);
  if (debugOn(2))   E2_writeStatus('   creating '+usetag+' element: '+newname);

  basenode=document.createElement(usetag);
  E2_copyAttributes(cnode,basenode,'MODULENAME TAGNAME');

 var foo=getAttributes(cnode,'idxtags idxclass','');
 if (foo!=='') {
        E2_writeAlert('E2_ModulesCreate warning: idxtags or idxclass improperly included in a CREATE ('+foo );
  }
  
  contlist=E2_getNodes(cnode,'CONTENT');
   if (debugOn(2))   E2_writeStatus('      with '+contlist.length+' CONTENTs' );
  for (var ii=0; ii<contlist.length; ii++) {                            // all contents in this create

      var ares=E2_node_doIf(contlist[ii])  ; 
      if (!ares) continue ;                      // false, do not include in "createf" 

       arepeat=getAttributes(contlist[ii],'REPEAT','');
       arepeat=svy_getVal(arepeat,'',contlist[ii]);
       aTags=getAttributes(contlist[ii],'IDXTAGS','');
       aClass=getAttributes(contlist[ii],'IDXCLASS','');
       amod=getAttributes(contlist[ii],'MODULE','');
       doRepeat=0;       ndo1=0; ndo2=1;
       if (!isNaN(arepeat) && arepeat!=='' && arepeat!=0 ) {
          ndo1=1 ; ndo2=(1*arepeat)+1 ; doRepeat=1 ;
       }

       inContentList=E2_getNodes(contlist[ii],'focus label literal gap modules');
       if (amod!=='') {                            // add a modules node to inContentList
          var gMod=document.createElement('modules');             // in GROUP, everything is always placed in a big div
          gMod.setAttribute('value',amod);
          inContentList=Concat_Arrays(gMod,inContentList);
       }
       if (debugOn(2))  E2_writeStatus('          content# '+ii+ ' with '+inContentList.length+' children');
       for (var ndo=ndo1 ; ndo<ndo2; ndo++){
          if (doRepeat==1) ccnode=document.createElement('module') ;                        // any element will do, we will be pulling out children
          for (var iii=0 ;iii<inContentList.length; iii++) {                               // children of the content
             if (debugOn(2))   E2_writeStatus(doRepeat+ ',' + ndo +'.'+ndo1+'.'+ndo2+'             child# '+iii+ ' tag '+ inContentList[iii].nodeName+','+inContentList[iii].nodeType+','+contlist.length);
            if (doRepeat==1) {
                 E2_contentMake(inContentList[iii],-1,-1,ccnode);                        // append mode -- repeated
             } else {
                 E2_contentMake(inContentList[iii],-1,-1,basenode);                        // append mode -- just once
             }
          }
          if (doRepeat==1) {
                E2_addIdx(ccnode,ndo,aTags,aClass );
                E2_copyNode(ccnode,basenode,'MODULE');
           }
       }                                // iterations
  }                                     // done with a CONTENT
  if (debugOn(2)) E2_writeStatus(' adding to modulelist['+newname);
  xmlModuleList[newname]=basenode ;                     // basenode contains concatenation of all contents
  xmlModuleList[0]=xmlModuleList[0].concat(newname) ;
  dude=dude+' '+newname ;

}

return dude ;

}  // create basenode



// ===============================
// Look at node that comes from a <content>.  
// If  addTo is specified: add the content of this node directly to addTo (perhaps after placing the
//   contents in a div or span, but perhaps not)
// Otherwise, create a new node (a div, or a span) and return the new node.
// UseNode: the  child node of a <CONTENT> 
// asec:  Section number being displayed (used to store priors)
// anumber:  group number (in section, after IF processing) being worked on
// addTo  : if specified, an object to add stuff to. If not specified, DIV or SPAN created and returned.

function E2_contentMake(useNode,asec,anumber,addTo) {

var doadd=0 ;
var thisTag,attname,attval,adiv,aspan,foo,anode,stuff,bdiv,foo,i,ii,oof;
var gotnum,gotname,gottext,useit,anode,damods,doshow,gotprior,cumprior,addPrior,usePrior ;
if (arguments.length>3 && typeof(addTo)=='object')  doadd=1 ;

// the recognized nodeNames (any other causes an error message): focus label literal gap modules'
thisTag=useNode.nodeName.toUpperCase();

// what to do depends on thisTag

if (thisTag=='LITERAL') {                 // create a DIV that  contains the stuff inside of literal ... /literal
   adiv=document.createElement('div');
   E2_copyAttributes(useNode,adiv);
   E2_copyNode(useNode,adiv,'LITERAL');
  if (doadd==1) {                               // and return results
      addTo.appendChild(adiv);
      return 1; ;
  } else {
     return adiv ;
  }
}


if (thisTag=='GAP') {                 // create a DIV that  contains empty space.... /literal
   adiv=document.createElement('div');
   adiv.setAttribute('class','StyleDefaultGap');
   adiv.setAttribute('className','StyleDefaultGap');
   oof=getAttributes(useNode,'SIZE COLOR');
   if (oof['SIZE']!='')   adiv.style.height=oof['SIZE']+'px';
   if (oof['COLOR']!='')   adiv.style.backgroundColor=oof['COLOR'] ;
   if (doadd==1) {                               // and return results
      addTo.appendChild(adiv);
      return 1; ;
   } else {
     return adiv ;
   }
}   


if (thisTag=='LABEL') {                 // create a DIV that  contains empty space.... /literal
   var inh=strip(getAttributes(useNode,'INHEADER','0'));
   if (doadd==1) inh=0;                                         // header mode not allowed if CREATEing
   var aclass=getAttributes(useNode,'class','')
   adiv=document.createElement('div');            // else, write to header

   if (inh!='1')  {                                    // not a "write to header"
       E2_copyAttributes(useNode,adiv,'SHOW INHEADER');
       if (aclass==='')  {
          adiv.setAttribute('class','styleLabel');
          adiv.setAttribute('className','styleLabel');
       }
   }

   doshow=getAttributes(useNode,'SHOW','') ; doshow=' '+doshow.toUpperCase()+' ' ;
   if (doshow.indexOf('NUMBER')>-1) gotnum=1 ;
   if (doshow.indexOf('NAME')>-1) gotname=1 ;
   gottext=E2_getNodeText(useNode,1);
   if (gotnum=="" && gotname=="" && gottext=="") gotnum=1  ;             // short cut used
   useit=''; 
   if (gotnum==1 && asec>-1 ) useit=useit+(1*anumber) ;       // -1 signals "processing CREATE" (no number available)
   if (gotname==1 && asec>-1) {                                 // -1 signals "processing CREATE" (no name available)
        if (useit!=='') useit=useit+' : ' ;
        useit=useit+specSections[asec].g[anumber].gname ;
   }
   if (gottext!=='') {
        if (useit!=='') useit=useit+' : ' ;
        useit=useit+gottext ;
   }

  if (inh==1) {                                         // write to header mode 
     E2_writeHeaderMessage(useit,''); 
     return adiv;
 }
  anode=document.createTextNode(useit) ;
  adiv.appendChild(anode);

  if (doadd==1) {                               // and return results
      addTo.appendChild(adiv);
      return 1; ;
  } else {
     return adiv ;
  }
}

if (thisTag=='FOCUS') {                 // a short span to recieve focus
   adiv=document.createElement('span');
   adiv.setAttribute('name','__MODULEFOCUS');
   adiv.setAttribute('id','__MODULEFOCUS');
   adiv.setAttribute('class','StyleModuleFocus');
   adiv.setAttribute('className','StyleModuleFocus');
   foo=getAttributes(useNode,'VALUE','');
   if (foo!=='') {
      gottext=document.createTextNode(foo);
      adiv.appendChild(gottext) ;
   }
   if (doadd==1) {                               // and return results
      addTo.appendChild(adiv) ;
      return 1 ; 
   } else {
     return adiv ;
   }
}      


if (thisTag=='MODULES') {                 // create a DIV that  contains empty space.... /literal

// append value="xx" modules and <modules>module names </modules> moduels 
   if (doadd!=1) {                               // not an add -- create a DIV and add attributes to it
       adiv=document.createElement('div');
       E2_copyAttributes(useNode,adiv,'PRIOR VALUE ADDPRIOR USEPRIOR ');
   }                                            // if an add, attributes ignored
   gottext=''; gotprior='' ;   
   var gottext=getAttributes(useNode,'VALUE',' ');
   gottext=gottext +' ' + E2_getNodeText(useNode,1) ;   // the list of modules to use 

   if (doadd!=1) {                                              // donot recognize PRIOR inside of CREATE 
        usePrior=getAttributes(useNode,'USEPRIOR','0');         // 1 means: display current contents of the "prior modules" cache
        addPrior=getAttributes(useNode,'ADDPRIOR','-1');        // 1 means :add these modules to the "prior modules" cache
                                                               // 0 means : clear the prior modules cache
        attval=getAttributes(useNode,'PRIOR','');               // deprecated, but still support
        if (usePrior=='1' || attval=='SHOW' || attval=='1' ) {     // include prior-modules cache in list of modules to use
                 gotprior=specSections[asec].gpriors ;                     
        }
        if (addPrior=='1' || attval=='1' || attval=='SHOW'|| attval=='2' || attval=='ADD') {
                specSections[asec].gpriors=specSections[asec].gpriors+gottext  ;                  //  Update list of prior modules
        }  
        if (addPrior=='0')   specSections[asec].gpriors='' ;            //  reset prior-modules cache?
        gottext=gotprior+' '+ gottext  ;                        // Augment the list of modules to use 
    }

   if (gottext==='') {                       // no modules to add, so return now
       if (doadd==1) {                             // add mode, just return
          return 1  ;
      } else {                                    // new div mode, return the new div
          return adiv ;
      }
    }                           // else, have module names to add

  Save_Global('_moduleList',gottext);

   damods=getWord(gottext);   
   for (var i=0;i<damods.length;i++) {                // for each name in the list of modules
       aword=strip(damods[i].toUpperCase()) ;
       if (typeof(xmlModuleList[aword])!=='object') {
              alert('ERROR in E2_contentMake: unknown module in MODULES= ' +aword);
              return 1;
       }
       if (doadd==1) {                             // add node (to existing node)
           E2_copyNode(xmlModuleList[aword],addTo,'MODULE');
        } else {                                  // add to new div
           E2_copyNode(xmlModuleList[aword],adiv,'MODULE');
        }                                           // module names
    }                                           // non empty list of modulenames
    if (doadd==1) {                             // add mode, just return
        return 1  ;
    } else {                                    // new div mode, return the new di
        return adiv ;
    }
}
        
alert('ERROR in E2_contentMake: unknown component in CONTENT, with Tag= ' +thisTag);
return 1 ;
}



// ===============================
// Check if conditions. Return 1 if true, 0 if false 
//                      Exception: if no "IF" attribute whe  isIF=3, return true.
// anode: the element that might contain a <then> or <else>
// isif controls where to find equation
//   1: look for an <If> inside of anode, and use it's value/if/or cond  attribute
//   2:  look for first text string inside of anode
//   3:  look for "IF", or VAR or VALUE or COND, attribute of anode
//   4:  look for "IF" attribute of anode
// anode1: if specified, a different element that might contain a value="..." attribute
//  we specify both because in some cases anode is a copy of anode1, that may not include anode1's attributes


function E2_node_doIf(anode,isIf,anode1) {

var ifNode1,ares,is1 ;
if (arguments.length<2) isIf=0;
if (arguments.length<3) anode1=anode ;

//alert('indoif '+isIf);

if (isIf==4) {                          // use attribute 
  is1=getAttributes(anode1,'IF ','');
  if (is1=='') return 1 ;               // 
  ifNode1=anode ;
}

if (isIf==3) {                          // use attribute 
  is1=getAttributes(anode1,'IF VAR COND VALUE ','');
  if (is1=='') return 1 ;               // 
  ifNode1=anode ;
}

if (isIf==2) {                          // use first text node in anode as the logical equation
   is1=E2_getNodeText(anode);
//alert('isif=2::: text is1= '+is1);
   if (strip(is1)==='') {
      is1=getAttributes(anode1,'VALUE IF COND VAR','');
//      alert('isif=2::: after att is1= '+is1);
   }
   ifNode1=anode ;
}

if (isIf<2)  {
  if (isIf!=1) {                                // look for IF within anode 
    ifNodes=E2_getNodes(anode,'IF',1) ;                       
    if (ifNodes.length==0) return 1 ;             // no if, return true
     ifNode1=ifNodes[0] ;
  } else {                              // anode IS the if 
     ifNode1=anode ;
  }
  is1=getAttributes(ifNode1,'VALUE IF COND VAR','');
}

if (is1=='') return 0 ;                               // if no VALUE, must be false 

// check for common error (# in string)
if (is1.indexOf('#')>-1) {
        if (debugOn()) alert('Warning: a # in an IF condition (#attributes can not be read from IF conditions): '+is1);
 }

 ares=E2_doMath(is1,ifNode1);  
 ares=ares!=0 ;

 return ares ;

}
// 




    




/* ::========================================================================================================================*/
/* ==============================  Event functions (button, timer, etc)     =========================================*/


//=========================
// make a button element, and write to adiv (replaces contents ofadiv)
// adiv-- where to create it. If '', place in the _headerButton div
// astring -- text in the button
// attributes - array of attributes to add: each element is a string with syntax: attname=attval (do not use attname="attval").
// funcList: an array of function specifications (as strings)
//   Each element if funcList is specified as:  afunc(arg1,..,arg8) -- these are called as is, so be sure to use '' (or "") to specify strings
// example: E2_makeButton('',  'Call Me Anytime ',  '',  flist)
// where:
//    flist[0]='callMe1("hello",333)'
//    flist[1]='callMe2("goodbye",10,"23")' 
// Note: return false is always added to the end of the onClick

function  E2_makeButton(adiv,astring,attribs,funclist,ifocus) {

var idiv,att1,vv,buttonNode,i,tmp;

if (arguments.length<3 || attribs.length==0 )  attribs=['class=styleMakeButton'] ;
if (arguments.length<4)  funclist=[] ;
if (arguments.length<5)  ifocus=0 ;

funclist=funclist.concat('return false  ; ') ;


if (strip(adiv)=='') {
   idiv=i_headerButton ;
} else {
  if (typeof(adiv)!='object') {
     idiv=document.getElementById(strip(adiv)) ;
     if (!idiv)  {
         alert('E2_makeButton ERROR: no such ID in document : '+adiv);
         return 0;
     }
  } else {
     idiv=adiv ;
  }
}

if (idiv.innerHTML) idiv.innerHTML='';

buttonNode=document.createElement('input');
buttonNode.setAttribute('type','button');
for (var i=0; i<attribs.length ; i++ ) {
   att1=attribs[i];
   if (att1.indexOf('=')<0 ) {
        alert('Error in E2_makeButton: attribute specified with no equal sign: '+attribs.join(' |  ')) ;
        return 0 ;
   }
   vv=att1.split('=');
   buttonNode.setAttribute(strip(vv[0]),strip(""+vv[1]));
}

// build onClick string (multiple functions)
ado='' ;
for (var i=0 ; i<funclist.length ;i++) {
   ado=ado+funclist[i]+' ; '
}  


buttonNode.setAttribute('onClick',ado);

set_elemValue(buttonNode,astring) ;
//tmp=document.createTextNode(astring);
//buttonNode.appendChild(tmp);                                          

if (arguments.length<3 || attribs.length==0 ) buttonNode.className='styleMakeButton '+buttonNode.className;

if (ifocus==1) buttonNode.className='FOCUS '+buttonNode.classname;

idiv.appendChild(buttonNode);
//idiv.innerHTML=astring ;

if (idiv==i_headerButton) E2_writeHeaderButton('',1);

return buttonNode ;
}

//========================================
// start a timer
// ttag: pointer to object in specSections.eventQueue[ttag];
//     the relevant values in the object are:
//       specSections.eventQueue[ttag].nRepeat=nrepeat ;       # times to repeat the timer (will be decrement-- at 0, don't create a timer)
//       specSections.eventQueue[ttag].doTime= doTime ;        Length of countdown, in seconds
//       specSections.eventQueue[ttag].toId= toId ;            div id of where countdown should be written to
//       specSections.eventQueue[ttag].dispOpts= toId ;        display options (see below)
//      specSections.eventQueue[ttag].timeLeft=doTime ;        time left on this particular timer, in seconds (will be decremented to zero)
//       specSections.eventQueue[ttag]oneRound=nsecs ;            seconds to wait if prior event still active (if 0, give up)

//
// dispOpts: "Display options". 
//       a number : the frequency of display (i..e.; 1=every second, 5=every 5th second, etc)
//       an array  :  of frequency and style options, as specified below
//           ''    : a default is used (as described below)
//           0     : do NOT display countdown (countdown is active, but current seconds left is not displayed)
//
// DispOpts syntax:
// To specify a complex set of display options, dispopts whould be an array.
//     dispopts[m]  (m=1,...) : element in a dispopts array should be an object with 3 attributes: 'sec', 'bysec', and 'class
//                               (i.e.; use dispopts[m]=new Object()) ;
//        dispopts[m]['sec'] = use this instruction when time <  this value. 
//    the next two are used if 'sec' is satisfied
//        dispopts[m]'bysec'] = update display every 'bysec' seconds (secDo % bysec =0, then update display)
//        dispopts[m]['class'] = the class (hence css styles) to use 
//
//  IMPORTANT NOTE: the values of dispOpts[m]['sec'] MUST be increasing. If they aren't later rows will NEVER be used!
//
// If dispOpts is not specified, or ='',the  following default values are used
//   
//   dispopts[1]['sec']=5 ; dispopts[1]['bysec']=1 ; dispopts[1]['class']='styleUpdateTimer1' 
//   dispopts[2]['sec']=15 ; dispopts[2]['bysec']=1 ; dispopts[2]['class']='styleUpdateTimer2' 
//   dispopts[3]['sec']=15000000 ; dispopts[3]['bysec']=5 ; dispopts[3]['class']='styleUpdateTimer3'
// You can  view/set these styleUpdateTimer classes in svylibe2.css        
//
// Note: to abort a timer sequence (without invoking a call),  specSections.eventQueue[ttag].timeLeft=-1;
//       to shortcut a timer sequence (and invoke a call),  specSections.eventQueue[ttag].timeLeft=0;
//
//  isInit: set to 0 on recursive calls (do not specify on initialization calls)
//

function E2_createTimer(ttag,isInit) {

var initit,aobj,foo,goo,tmp,callme,toid,secLeft   ;
if (arguments.length<2) isInit=1 

if (typeof(specSections.eventQueue[ttag])=='undefined' || typeof(specSections.eventQueue[ttag].dispOpts)=='undefined') {
    if (debugOn(2)) E2_writeStatus('Note: timer not created .. no event= '+ttag)
    return 1 ;       // this event has been zapped (new section or new group).  Do nothing
}


if (typeof(specSections.eventQueue[ttag].dispOpts)=='undefined') {
   dispopts='';
} else {
  dispopts=specSections.eventQueue[ttag].dispOpts ;
}
 
if (isInit==1)  {                               // initialization call... possibly setup dispopts
   if (typeof(dispopts)!=='object' && dispopts=='' ) {     // use defaults
        dispopts=new Array() ;
        dispopts[0]=1 ;                         // an existence flag 
        dispopts[1]=new Object();
            dispopts[1]['sec']=5 ; dispopts[1]['bysec']=1 ; dispopts[1]['class']='styleUpdateTimer1' ;
        dispopts[2]=new Object();
           dispopts[2]['sec']=15 ; dispopts[2]['bysec']=1 ; dispopts[2]['class']='styleUpdateTimer2' ;
        dispopts[3]=new Object();
           dispopts[3]['sec']=15000000000 ; dispopts[3]['bysec']=5 ; dispopts[3]['class']='styleUpdateTimer3';
        specSections.eventQueue[ttag].dispOpts=dispopts ;             
  }
  if (typeof(dispopts)!=='object' ) {                       // a number, so just set frequency
        if (isNaN(dispopts)) dispopts=1 ;
        var tmp=dispopts ;
        dispopts=new Array() ;
        dispopts[0]=1 ;                         // an existence flag 
        dispopts[1]=new Object();
            dispopts[1]['sec']=100000000000 ; dispopts[1]['bysec']=tmp ;
        specSections.eventQueue[ttag].dispOpts=dispopts ;             

   } else {                                        // an object. check for [0]
       if (typeof(dispopts[0])=='undefined') {
           alert('ERROR in E2_createTimer: dispopts not an array ');
           return 0 ;
       }
   }                                            // dispopts!==object
}                               // if isInit=0, assume dispOpts has been properly formatted


secLeft=specSections.eventQueue[ttag].timeLeft;                   // time remaining (on init = intial seconds

if (secLeft==-1) return 0 ;                        // if somehow set to 0,  "abort" 
if (isInit!=1) {
  secLeft=(1*secLeft)-1 ;                         // time left
  specSections.eventQueue[ttag].timeLeft=secLeft;                   // time remaining (on init = intial seconds
}

if (secLeft<=0) {                         // timer is done!
   specSections.eventQueue[ttag].timeLeft=0;
   callMe='E2_doEvent("'+ttag+'")';                             // TIMER event has happened, so process its event actions
   setTimeout(callMe,50);
   if (secLeft==0) {
        toid=specSections.eventQueue[ttag].toId ;      
        goo=E2_updateTimer(secLeft,toid,dispopts,isInit)          ;       
   }
   return 1  ;
}

// update the display?

toid=specSections.eventQueue[ttag].toId ;      
goo=E2_updateTimer(secLeft,toid,dispopts,isInit)          ;            // display current (possiblye starting) value 

// wait a second and check again 
Launch_Proc('E2_createTimer',1000,ttag,0);              // final 0 signals "not an init"
return 1  ;

}
 

//========================================
// do fancy timer display given current seconds and current countdown.
// This DOES not keep the timer moving -- it just displays current results
// secLeft : seconds left on timer.
// ttid: where to display timer.  Optional. topTimer used if not specified, or =''. If '0', DO not display
// slist : how to display. Optional. If specified, should be an array of objects.  If not specified, do NOT change display format (just write secLeft in ttid).


function E2_updateTimer(secLeft,ttid,slist,forceDisplay) {

var itid,j,bysec,aclass,arem,astyle ;

if (arguments.length<2)  ttid='' ;
if (arguments.length<3)  slist='' ;
if (arguments.length<4)  forceDisplay=0 ;

ttid=strip(ttid);
itid=0;

if (ttid==='0') {
  return 1 ;                      // no display
}

if (ttid!=='') {
        itid=document.getElementById(ttid);
        if (!itid) {
           alert('ERROR in E2_updateTimer: no such ID available = ' + ttid);
           return 0;
        }
}                       // ttid check

if (isNaN(secLeft)) {
   alert('ERROR in E2_updateTimer: bad seconds left: '+secLeft);
   return 0 ;
}

if (slist==='') {                       // no display fanciness... just update coutner 
  if (itid!==0) {                                         // no ttid, write to default
     itid.innerHTML=Seconds_ToTime(secLeft);
  } else {
     E2_writeHeaderMessage(Seconds_ToTime(secLeft));
  }

  return 1 ;
}

// else, check specs and update accordingly 
for (var j=1; j<slist.length ; j++) {
       if (parseFloat(secLeft)>parseFloat(slist[j]['sec'])) continue ;         // not this low yet, try next instruction phrase
       if (typeof(slist[j]['bysec'])=='undefined') {
          bysec=1;
       } else {
          bysec=slist[j]['bysec'];  if (isNaN(bysec)) bysec=1 ;
       }
       arem=(secLeft%bysec) ;
       if (arem!=0 && forceDisplay!==1) return 1 ;                 // not on the "nth second" count, so dont change display

       aclass='' ; astyle='';
       if (typeof(slist[j]['class'])!='undefined')  aclass=slist[j]['class']; 
       if (typeof(slist[j]['style'])!='undefined')  astyle=slist[j]['style'];

       if (itid===0) {
          E2_writeHeaderTimer(Seconds_ToTime(secLeft),1,aclass);
       } else {
          if (aclass!=='') {
                 itid.setAttribute('class',aclass);
                 itid.setAttribute('className',aclass);
         }
          if (astyle!=='')  itid.setAttribute('style',astyle);
          itid.innerHTML=Seconds_ToTime(secLeft);   // update display
       }

       return 1;
   }

return 1 ;              // if here, no success. So no style/class change (and no updating of value)
}

//==================
//  query server for variable


function  E2_createQuery(ttag) {

var toget,tajax,aid,asvy,daval ;
var getVar,daCmt,saveVar,daCmtVar,daStateVar;
var qType;

if (typeof(specSections.eventQueue[ttag])=='undefined' || typeof(specSections.eventQueue[ttag].sVar)=='undefined') {
    if (debugOn(2)) E2_writeStatus('Note: query not created .. no event= '+ttag)
    return 1 ;       // this event has been zapped (new section or new group).  Do nothing
}

getVar=specSections.eventQueue[ttag].sVar ;
daCmt=specSections.eventQueue[ttag].label ;
daCmtVar=specSections.eventQueue[ttag].labelVar ;
qType=specSections.eventQueue[ttag].sType ;
saveVar=specSections.eventQueue[ttag].saveVar ;

daStateVar=specSections.eventQueue[ttag].stateVar ;
if (daStateVar!=='') {
  _queryState=Read_Global(daStateVar,'_'+daStateVar+'_');  // note: poll_server ALWAYS sends value of _queryState 
}

// GLOBAL and ELEMENT qType -- just lookup value of survey-global variable OR by element name.
if (qType!='SERVER') {
  if (qType=='GLOBAL') {
     daval=Read_Global(getVar,'');
  }
  if (qType=='ELEMENT') {
     daval=svy_getVal(getVar,'','','@') ;
  }
  Save_Global(saveVar,daval);
  E2_doEvent(ttag) ;                              // QUERY event has happened, so process its event actions
  return 1 ;
}

// if here, server query.

  var mySVY ; mySVY=Read_Global('_sessionName');
  var popts=new Object();
     popts.maxtries=7 ; popts.checkFunc='**'; popts.func_to_call='callback_createQuery';
     popts.myID=Read_Global('myID'); 
     if (daCmtVar=='') {
         popts.message=daCmt ;
     } else {
        popts.message=Read_Global(daCmtVar,'_'+daCmtVar+'_');
     }
     popts.noStatus=0;
     Poll_serverVar(mySVY,getVar,popts,saveVar,ttag)

  return 1 ;

}

//==================
// == callback for createQuery (actually, callbackfor Poll_serverVar
// called as  callback_createQuery(returnedValue,serverVar,ndid,arg1,arg2,arg3,arg4,arg5)

function callback_createQuery(daval,davar,ndid,saveVar,ttag) {

var davar,saveVar,astatus,ttag ;
if (saveVar=='') saveVar='_queryResponse' ;
Save_Global(saveVar,daval);
E2_doEvent(ttag) ;                              // QUERY event has happened, so process its event actions

return 1 ;

}

//===========================
// setup buttons <button>
function E2_setupButtons(gEvents,gtag) {
var funclist,attribs,attname,attval,ii,i,bCalls,ifocus ;
var gButtons,aButton,idB,toId,bText,showText,ttag,bsec,ares,maxdo,textVar;
var clickMessage='';
 gButtons=E2_getNodes(gEvents,'BUTTON');


 for (var i=0; i<gButtons.length;i++) {
    aButton=gButtons[i];

     ares=E2_node_doIf(aButton,4)  ;            // use IF attribute of button event element
     if (ares==0) continue ;                      // false, do not include in "stuff" 

// For ID, and TEXT use attributes first. Then check for children nodes.
    toId=strip(getAttributes(aButton,'ID','')) ;
    showText=getAttributes(aButton,'TEXT VALUE','');
    clickMessage=getAttributes(aButton,'MESSAGE','please wait');
    idB=E2_getNodes(aButton,'ID',1);
    if (idB.length!=0)   toId=strip(getAttributes(idB[0],'ID VALUE',''));
    if (toId=='') toId='_headerButton';
    attribs=[];

    bText=E2_getNodes(aButton,'TEXT',1);                // a <text> ... </text> overrides a text="" 
    if (bText.length>0) {
         showText=E2_getNodeText(bText[0],1);
         textVar=getAttributes(bText[0],'VAR','');
         if (showText=='' && textVar!='') {
             showText=svy_getVal(textVar,'Submit');
         }
         for (var ii=0 ; ii<bText[0].attributes.length ; ii++ ) {
            attname=bText[0].attributes[ii].nodeName ;
            if (strip(attname.toUpperCase())=='VAR') continue ;
            attval=bText[0].attributes[ii].nodeValue ;
            attribs=attribs.concat(attname+'='+attval);
        }
    }

   if (showText=='' && textVar!='') {
        showText=svy_getVal(textVar,'Submit');
   }

   ifocus=getAttributes(aButton,'FOCUS','0');

   bsec=strip(getAttributes(aButton,'BUSY','2')) ;
   if (isNaN(bsec)) bsec=2 ;

   maxdo=strip(getAttributes(aButton,'REPEAT','100000000000')) ;
   maxdo=svy_getVal(maxdo,'')  ;
   if (maxdo==='' || isNaN(maxdo)) maxdo=10000000000 ;

   ttag=Math.random() ;
   specSections.eventQueue[ttag]=new Object() ;
   specSections.eventQueue[ttag].groupTag=specSections.currentGroupTag ;   
   specSections.eventQueue[ttag].useNode=aButton ;   
   specSections.eventQueue[ttag].eType='button' ;   
   specSections.eventQueue[ttag].Busy=bsec  ;   
   specSections.eventQueue[ttag].toDo=''  ;   
   specSections.eventQueue[ttag].maxdo=maxdo;
   specSections.eventQueue[ttag].ndo=0  ;   
   specSections.eventQueue[ttag].clickMessage=clickMessage ;
   specSections.eventQueue[ttag].showText=showText ;

   funclist=['E2_doEvent("'+ttag+'")'] ;                                // function used when button event has happened, so process its event actions
   specSections.eventQueue[ttag].buttonNode= E2_makeButton(toId,showText,attribs,funclist,ifocus);

 }                                     // do next button

 return 1;
}


//=============================== showtext
// setup timers

function E2_setupTimers(gEvents,gtag) {

var funclist,attribs,attname,attval,ii,i,bCalls ;
var gTimers,aTimer,idB,toId,bText,showText,nrepeat,dispopts ;
var dispopts,bDisp,bAt,bAt0,j,attribs,arf,wastime;
var bTime,doTime,doFunc,ttag,att1,gtag,bsec;

 gTimers=E2_getNodes(gEvents,'TIMER');

 for (var i=0; i<gTimers.length;i++) {
    aTimer=gTimers[i];

     ares=E2_node_doIf(aTimer,3)  ;            // use IF attribute of  timer event element
     if (ares==0) continue ;                      // false, do not include in "stuff" 

   
// For TIME and ID, and REPEAT use attributes first. Then check for children nodes.
    toId=strip(getAttributes(aTimer,'ID','')) ;
    doTime=getAttributes(aTimer,'TIME VALUE','');
    nrepeat=getAttributes(aTimer,'REPEAT','1');
    var bsec=strip(getAttributes(aTimer,'BUSY','2')) ;
    if (isNaN(bsec)) bsec=2 ;
   

    idB=E2_getNodes(aTimer,'ID',1);          // nodes override attributes 
    if (idB.length!=0) toId=strip(getAttributes(idB[0],'VALUE ID',''));                  // found an ID node
    if (toId==='0') {
           ii=1 ; toId='0' ;               // toid=0 means "no display"
     } else {
          if (toId==='') {                      // use default 
                ii=1;
          } else {
            ii=document.getElementById(toId);
          }
    }
    if (!ii) {
        alert('Error in E2_setupTimers: a timer has a non-existent ID: '+toId);
        return 0;
     }
    bTime=E2_getNodes(aTimer,'TIME',1);
    if (bTime.length>0) {
        doTime=getAttributes(bTime[0],'VALUE TIME','');
        nrepeat=getAttributes(bTime[0],'REPEAT','');
   }

   nrepeat=svy_getVal(nrepeat,'') ;   
   if (isNaN(nrepeat) || nrepeat=='') nrepeat=1 ;

    var tmp=doTime;
    doTime=svy_getVal(doTime,'') ;   
    if (doTime==='') {
          alert('Error in  E2_setupTimer: no  TIME value in TIMER ( '+tmp );         
          return 0 ;
    } 

// dispopts
    dispopts='' ;                                       // '' means "use default sequence "
    bDisp=E2_getNodes(aTimer,'TIMERDISPLAY',1);            
    if (bDisp.length>0) {                                 // found a TIMERDISPLAY 
        dispopts=[]  ; wastime=-1 ;      // an array of objects
        dispopts[0]=1;                   // existence flag
        bAt=E2_getNodes(bDisp[0],'AT') ;
        for (j=0; j<bAt.length; j++) {                             // found some AT
           bAt0=bAt[j];
           attribs=getAttributes(bAt0,'TIME BYSEC STYLE CLASS');

           if (attribs['TIME']==='') continue ;                    // ignore if no time given
           if (isNaN(attribs['TIME'])) {
                alert('Error in E2_setupTimers:  DISPLAY-AT has a non-numeric TIME: '+attribs.TIME ) ;
                return 1;
           }

           if (wastime==-1) {
                wastime=parseInt(attribs.TIME) ;
           } else {                             // non fatal error
               if (wastime>parseInt(attribs.TIME))   E2_writeStatus('Warning in E2_setupTimers: the times (in DISPLAY-AT) are non-increasing ( '+wastime+', '+attribs)
               wastime=parseInt(attribs.TIME) ;
           }
                
           if (attribs.BYSEC==='') attribs.BYSEC=5 ;
           arf=dispopts.length;
           dispopts[arf]=new Object() ;
           dispopts[arf].sec=attribs.TIME ;
           dispopts[arf].bysec=attribs.BYSEC ;
           dispopts[arf]['class']=attribs['CLASS'] ;
           dispopts[arf].style=attribs.STYLE ;
        }                                     
        if (dispopts.length==0) dispOpts='' ; 
    }
 


// save specs
    ttag=Math.random() ;
    specSections.eventQueue[ttag]=new Object() ;
    specSections.eventQueue[ttag].useNode=aTimer ;   
    specSections.eventQueue[ttag].eType='timer' ;   
    specSections.eventQueue[ttag].Busy=bsec  ;   

    specSections.eventQueue[ttag].group=specSections.gCurrent ;   
    specSections.eventQueue[ttag].section=specSections.current ;   
    specSections.eventQueue[ttag].groupName=specSections.gCurrentName ;
    specSections.eventQueue[ttag].sectionName=specSections.sCurrentName ;   
    specSections.eventQueue[ttag].groupTag=gtag ;   

    specSections.eventQueue[ttag].nRepeat=nrepeat ;
    specSections.eventQueue[ttag].doTime= doTime ;
    specSections.eventQueue[ttag].timeLeft=doTime ;
    specSections.eventQueue[ttag].toId= toId ;   
    specSections.eventQueue[ttag].dispOpts=dispopts ;

    E2_createTimer(ttag)    ;                           // create the timer (write values to screen, start countdown loop

 }                                     // do next button


return 1;
}

//===============================
// setup query (<query>)

function E2_setupQuery(gEvents,gtag,grpName) {

var funclist,attribs,attname,attval,ii,i,bCalls ;
var gqueries,idB,toId,bText,showText ;
var bTime,doTime,doFunc,ttag;
var nrepeat,getVar,daLabel,bsec,qType,saveVar,aQuery,daStateVar,daLabelVar,ares,tmp;
var togroup='' ;

 gqueries=E2_getNodes(gEvents,'QUERY');
 for (var i=0; i<gqueries.length;i++) {

    daLabel=grpName;    daLabelVar=''; daStateVar='';
    aQuery=gqueries[i];

     ares=E2_node_doIf(aQuery,4)  ;            // use IF attribute of query  event element
     if (ares==0) continue ;                      // false, do not include in "stuff" 

    getVar=getAttributes(aQuery,'VAR SERVERVAR','');                   // use attributes if available

    saveVar=getAttributes(aQuery,'SAVEVAR','_queryResponse');                   // use attributes if available


    daLabel=getAttributes(aQuery,'DESC','');
    doTime=getAttributes(aQuery,'TIME','');
    nrepeat=getAttributes(aQuery,'REPEAT','');
    togroup=getAttributes(aQuery,'TOGROUP','');

    var bsec=strip(getAttributes(aQuery,'BUSY','2')) ;
    if (isNaN(bsec)) bsec=2 ;

    if (togroup!=='') {
           getVar=strip(togroup);                              // a short cut
    }

       
// check for nodes. Nodes override attributes 

// var node contains VALUE (getVar) and desc (daLabel), or descVar (daLabelVar)
    idB=E2_getNodes(aQuery,'VAR SERVERVAR',1);
    if (idB.length!=0) {

         zz=getAttributes(idB[0],'SAVEVAR',0);
         if (zz!==0) {
               alert('QUERY error: a SAVEVAR is an attribute of a <SERVERVAR> (or a <VAR>) under a <QUERY> (SAVEVAR should be an attribute of <QUERY>) ');
               return 0;
         }

         getVar=getAttributes(idB[0],'VAR SERVER SERVERVAR VALUE','');
         daLabel=getAttributes(idB[0],'DESC',grpName);
         daLabelVar=strip(getAttributes(idB[0],'DESCVAR VARDESC DESC_VAR VAR_DESC',''));   // descVar trumps desc
         daStateVar=strip(getAttributes(idB[0],'STATE STATEVAR',''));  

         if (typeof(daLabelVar)=='string' && daLabelVar.indexOf('.')>-1) {
           tmp=parseAt(daLabelVar.toUpperCase(),'.');
           if (tmp.length>1) {
             if (isNaN(tmp[1])) {
                 alert('Error: descVar attribute in QUERY-SERVERVAR is incorrect: '+daLabelVar);
                 return 0;
             }
           }
         }

         if (typeof(daStateVar)=='string' && daStateVar.indexOf('.')>-1) { 
           tmp=parseAt(daStateVar.toUpperCase(),'.');
           if (tmp.length>1) {
            if (isNaN(tmp[1])) {
                 alert('Error: stateVar attribute in QUERY-SERVERVAR is incorrect: '+daStateVar);
                 return 0;
            }
          }
         }
    }
    if (getVar==='') {
          alert('Error in  E2_setupQuery: no serverVar specified: '+aQuery.innerHTML );         
          return 0 ;
    } 
    if (daLabel==='' ) daLabel='query_'+getVar;

    bTime=E2_getNodes(aQuery,'TIME',1);
    if (bTime.length>0) {
           doTime=getAttributes(bTime[0],'VALUE','');
           nrepeat=getAttributes(bTime[0],'REPEAT','');
     }

    doTime=svy_getVal(doTime,'') ;   
    if (!isNaN(doTime) && doTime!='') {
                 doTime=doTime*1000 ;                    // convert from seconds to milliseconds 
     } else { 
         doTime='' ;
     }
      if (isNaN(doTime) || doTime==0 || doTime==='' ) doTime=Read_Global('queryFreq',4000);

     nrepeat=strip(svy_getVal(nrepeat,''));   
     if (isNaN(nrepeat) || nrepeat=='') nrepeat=100000000000 ;

    ttag=Math.random() ;
    specSections.eventQueue[ttag]=new Object() ;
    specSections.eventQueue[ttag].useNode=aQuery ;   
    specSections.eventQueue[ttag].eType='query' ;   
    specSections.eventQueue[ttag].Busy=bsec  ;   

    if (togroup!=='') specSections.eventQueue[ttag].shortcut='togroup' ;   
    specSections.eventQueue[ttag].group=specSections.gCurrent ;
    specSections.eventQueue[ttag].section=specSections.current ;   
    specSections.eventQueue[ttag].groupName=specSections.gCurrentName ;   
    specSections.eventQueue[ttag].sectionName=specSections.sCurrentName ;   
    specSections.eventQueue[ttag].groupTag=gtag  ;   

    getVar=strip(getVar);
    qType='SERVER';
    if (getVar.substr(0,1)=='%') {
        getVar=getVar.substr(1);
        qType='GLOBAL';
    } 
    if (getVar.substr(0,1)=='@') {
        getVar=getVar.substr(1);
        qType='ELEMENT';
    } 
    specSections.eventQueue[ttag].sVar=getVar ;   
    specSections.eventQueue[ttag].sType=qType ;   
    
    specSections.eventQueue[ttag].saveVar=saveVar ;   
        

    specSections.eventQueue[ttag].nRepeat=nrepeat;
    specSections.eventQueue[ttag].doTime= doTime ;
    specSections.eventQueue[ttag].label= daLabel ;   
    specSections.eventQueue[ttag].labelVar= strip(daLabelVar).toUpperCase() ;   

    specSections.eventQueue[ttag].stateVar= strip(daStateVar).toUpperCase() ;   

    E2_createQuery(ttag)    ;                   // immediately do a query (doTime pause before doing next query)
 }                                     // do next button

return 1;
}



//=============================== $
// setup notify (<notify>)

function E2_setupNotify(gEvents,gtag,grpName,is1) {
if (arguments.length<4) is1=0;
var funclist,attribs,attname,attval,ii,i,bCalls ;
var gqueries,idB,toId,bText,showText ;
var bTime,doTime,doFunc,ttag,tmp;
var nrepeat,getVar,daLabel,bsec,qType,saveVar,aQuery,daLabelVar,ares,daStateVar ;
var togroup='' ;



 if (is1!==1) {
    gqueries=E2_getNodes(gEvents,'NOTIFY');
 } else {
    gqueries=[];
    gqueries[0]=gEvents;
 }
 for (var i=0; i<gqueries.length;i++) {
 
    aQuery=gqueries[i];

    daLabel=getAttributes(aQuery,'VAL DESC VALUE','');
    daLabelVar=getAttributes(aQuery,'VAR DESCVAR','');
    daStateVar=getAttributes(aQuery,'STATE STATEVAR','');

         if (typeof(daLabelVar)=='string' && daLabelVar.indexOf('.')>-1) {
           tmp=parseAt(daLabelVar.toUpperCase(),'.');
           if (tmp.length>1) {
             if (isNaN(tmp[1])) {
                 alert('Error: var attribute in NOTIFY is incorrect: '+daLabelVar);
                 return 0;
             }
           }
         }

         if (typeof(daStateVar)=='string' && daStateVar.indexOf('.')>-1) { 
           tmp=parseAt(daStateVar.toUpperCase(),'.');
           if (tmp.length>1) {
            if (isNaN(tmp[1])) {
                 alert('Error: stateVar attribute in NOTIFY is incorrect: '+daStateVar);
                 return 0;
            }
          }
         }



    doTime=1000 ;
    nrepeat=1;
    arepeat=getAttributes(aQuery,'REPEAT','NO');
    if (strip(arepeat).toUpperCase()=='YES') {
        nrepeat=100000000000000 ;
        doTime=5000;
     }
    getVar='notify';

    bsec=2 ;

    ttag=Math.random() ;
    specSections.eventQueue[ttag]=new Object() ;
    specSections.eventQueue[ttag].useNode=aQuery ;   
    specSections.eventQueue[ttag].eType='query' ;   
    specSections.eventQueue[ttag].Busy=bsec  ;   

    specSections.eventQueue[ttag].group=specSections.gCurrent ;
    specSections.eventQueue[ttag].section=specSections.current ;   
    specSections.eventQueue[ttag].groupName=specSections.gCurrentName ;   
    specSections.eventQueue[ttag].sectionName=specSections.sCurrentName ;   
    specSections.eventQueue[ttag].groupTag=gtag  ;   

    qType='SERVER';
    specSections.eventQueue[ttag].sVar=getVar ;   
    specSections.eventQueue[ttag].sType=qType ;   
    
    specSections.eventQueue[ttag].saveVar='_NOTIFY' ;   
        
    specSections.eventQueue[ttag].nRepeat=nrepeat; 
    specSections.eventQueue[ttag].doTime= doTime ;
    specSections.eventQueue[ttag].label= daLabel ;   
    specSections.eventQueue[ttag].labelVar= strip(daLabelVar).toUpperCase() ;   
    specSections.eventQueue[ttag].stateVar= strip(daStateVar).toUpperCase() ;   

    Save_Global('$'+getVar,undefined);         // set survey-global, of this serverVar, to missing

    E2_createQuery(ttag)    ;                   // immediately do a query (doTime pause before doing next query)
 }                                     // do next button

return 1;
}



//===============================
// setup do -- do events are done as soon as group is done loading. <exec> 

function E2_setupExec(gEvents,gtag,grpName) {

var funclist,attribs,attname,attval,ii,i,bCalls ;
var gdo,aDo,idB,toId,bText,showText ;
var bTime,doTime,doFunc,ttag;
var nrepeat,getVar,daLabel,bsec,qType,saveVar,ares ;
var togroup='' ;

 gdo=E2_getNodes(gEvents,'EXEC');

 for (var i=0; i<gdo.length;i++) {
    daLabel=grpName;    
    aDo=gdo[i];

     ares=E2_node_doIf(aDo,3)  ;            // use IF attribute of query  event element
     if (ares==0) continue ;                      // false, do not include in "stuff" 

    ttag=Math.random() ;
    specSections.eventQueue[ttag]=new Object() ;
    specSections.eventQueue[ttag].useNode=aDo ;   
    specSections.eventQueue[ttag].eType='do' ;   

    specSections.eventQueue[ttag].group=specSections.gCurrent ;   
    specSections.eventQueue[ttag].section=specSections.current ;   
    specSections.eventQueue[ttag].groupName=specSections.gCurrentName ;   
    specSections.eventQueue[ttag].sectionName=specSections.sCurrentName ;   

    specSections.eventQueue[ttag].groupTag=gtag  ;   

    ares=E2_doEvent(ttag) ;                              // do an exec
    specSections.eventQueue.locked=0 ;                  // force an unlock

 }                                     // do next DO

return ares ;                           // -1 meanse "done" (error, or a goto or next )
}



//==============================================
/* submit to server, the elements saved in Do_Submit calls
   ttag: node containing the <SUBMIT> (or other such instruction)
   stype: type of submit. 1=first call, 2=resubmit, 3=success, 4=failure. 2, 3, and 4 are used when e2_dosubmit is called by callback_doSubmit
   ict: counter (used if resubmit). Or, an error message (used if failure, eg stype =3 or 4). Note that this is DIFFERENT from the submitCt variable
   ithNode : the node (in list of event actions) being processed
   tocurrent: if 1, write to current data archive
   useround: if specified, the "round" of this submission. If not specified, the nowRound variable is used

   Uses svyPostHeader and svyPostDataHeader to submit a "line in an XML file" that contains the submitted data
   These lines have the syntax:
        <data id="participant_id"  round="nowround" time="milliseconds" ct="submitCt" notFinal="0/1">
         <vars> space delimited list of variables being submitted </vars>
         <vals> comma delmited list of "escaped" values of these variables</vals>
         <status> status message </status>
       </data>
   Note that variables, and their values, are pulled from the submitVars array
*/

                //         chk_val,this._variable3,this._variable4,this._variable5);
function E2_doSubmit(ttag,stype,ict,ithNode,tocurrent,useround){
 var notFinal=0,submitCt=1;
 var ndid=0,nvars='';
 var nowr,jvar,vv,jvar2,notFinal,usehdr,aa,echoval ;
 var aa,im2,im,tmp;
 var nowr,myName,resubmitOkay,myid,dd,sessName,amessage,toPost ;

 var arglist='';
 var subVars=[],subVals=[];

 if (arguments.length<2) stype=1;
 if (arguments.length<3) ict=1    ;
 if (arguments.length<5) tocurrent=0    ;
 if (arguments.length<6) useround=''   ;

 if (typeof(submitVars)=='undefined') {
        alert('ERROR: E2_doSubmit. submitVars not defined ');
        return null;
  }

             
// success -- set the the submitStatus flag and return to do_event
  if (stype==3) {
        var avv=submitVars['__submitStatus'];
        if (avv!=='') Save_Global(avv,1);
        E2_doEvent(ttag,ithNode);         // process next node in this event's list of event actions (ithNode is current -- doEvent will do node AFTER ithNode)
        submitVars={} ;                     // reset the submitVars list
          submitVars['0']=0 ;
          submitVars['__message']='Submitting current information to the server. Please wait.... ';
          submitVars['__status']='SUBMIT';
        return 1 ;
  }

// failure? set the the submitStatus flag and return to do_event
  if (stype==4) {
        nowr=useround
        if (nowr==='') nowr=Read_Global('nowRound',' ') ;
        E2_writeStatus('Problem... E2_doSubmit failed for round '+nowr+' : message= '+ict);
        var avv=submitVars['__submitStatus'];
        if (avv!=='') Save_Global(avv,'ERROR: '+ict);
        E2_doEvent(ttag,ithNode);                  // process next node in this event's list of event actions (ithNode is current -- doEvent will do node AFTER ithNode)
        return 1 ;                      // future event-actions can use avv status info
  }

// if here, a submit or a resubmit. No real difference between the two (except for value of ict)
  nowr=useround

  if (nowr==='') nowr=Read_Global('nowRound',' ') ;
  var myName=Read_Global('myName','');
  var resubmitOkay=Read_Global('_resubmitOkay','0');
  var myid=Read_Global('myId','');
  var dd=new Date() ; var nowtime=dd.getTime();
  var sessName=Read_Global("_sessionName");
 if (typeof(submitVars['__notFinal'])!='undefined') notFinal=submitVars['__notFinal'];
 if (typeof(submitVars['__ct'])!='undefined') submitCt=submitVars['__ct'];

 acurrent=''
 if (tocurrent==1) acurrent='&toCurrent=1' ;                    // mostly deprecated 

 nustff='';
 var amessage='id='+myid+' & name='+myName+' & time='+nowtime+' & round='+nowr+' & action=Submit'  ;
 if (resubmitOkay!=1) {
        toPost=svyPostDataHeader+'session='+sessName+acurrent+'&verify='+escape(myid+' '+nowtime)+'&submitStatus='+myid+':'+nowr+'&message='+escape(amessage)+'&contents=';
 } else {
        toPost=svyPostDataHeader+'session='+sessName+acurrent+'&verify='+escape(myid+' '+nowtime)+'&message='+escape(amessage)+'&contents=';
 }

 var xmlstuff='<data id="'+myid+'"  round="'+ nowr+ '" ct="'+submitCt+'" notFinal="'+notFinal+'" time="'+nowtime+'" >';

 var varlist='',vallist='' ;
 var nvv=0;

 for (jvar in submitVars) {
      var jvar2=strip(jvar.toUpperCase()) ;
      if (jvar2=='0') continue ;
      if (jvar2.indexOf('__')==0) continue ;             // ignore __ variables

 
      if (typeof(submitVars[jvar2])=='undefined') {
         vv='';
      } else {
         vv=submitVars[jvar2] ;
      }

      nvv++ ;
      if (nvv<2) {
          vallist=escape(vv);
          varlist=jvar2;
      } else {
          vallist=vallist+','+escape(vv);
          varlist=varlist+' '+jvar2
      }
      subVars=subVars.concat(jvar2); subVals=subVals.concat(vv);
      ndid++;
 }
// save list of variables submitted, and their values (ie.; for use by simpleHistory
  Save_Global('__SUBMITVARS',subVars,0,1);

  Save_Global('__SUBMITVALS',subVals,0,1);

  xmlstuff=xmlstuff+' <vars>'+varlist+'</vars><vals>'+vallist+'</vals><status>'+escape(submitVars['__status'])+'</status></data>';
  toPost=toPost+xmlstuff ;

// fields submitted:
// todo=401, 
// tocurrent=0/1  (deprecated, controls if added to full, or current, submitted database)
// session=sessionName, 
// verify=a verification string, 
// submit_status: client,round information for submitStatus storage (
// message: a descriptive message about this submission 
// content: partially escaped xml-line with content (variables/values filled in by participant)
//      Content contains <data ...> <vals>, <vars>, <status> </data>
//                <data includes attributes: id, round, ct, notFinal, time
// these may be parsed by the server and saved as seperate variables
 

// var dw=window.open('','debugwindow');
//  dw.document.open('text/plain');
//ug=toPost.replace(/\>/g,'> ');
//  dw.document.write(ug); 
//  dw.document.close();

   var SendVars = new svy_CreateXMLHTTP(svyPostSubmitURL) ;
   SendVars.onDraw=callback_doSubmit  ;
   SendVars._method="POST" ;                    // note that the ?xx will be parsed out by the xmlhttp request function (._postRequest is not used)
   SendVars._timeout=10000  ; //  10 seconds until timeout
   SendVars._showstatus=false ;  // note: by default, do NOT suppress cache-buster
   SendVars._comment='Submitting input from round ' +nowr ;
   SendVars._ID=myid  ;
   SendVars._ECHO=nowtime ;
   SendVars._counter=ict ;                         // this is the n'th submission (used by resubmit
   SendVars._postRequest = toPost ;
   message=submitVars['__message'] + ' (round='+nowr+') ' ;
   if (stype==2 ) message=message+ '(resubmit = ' + ict+')';

   writeAlert(message,2);

// (ttag,stype,ict,ithNode,tocurrent,useround){
   SendVars._variable='SUBMIT';
   SendVars._variable2=ttag ;
   SendVars._variable3=ithNode ;
   SendVars._variable4=tocurrent ;
   SendVars._variable5=useround ;

   if (_spying!==1) {
     SendVars.load(message,1) ;  
      if (debugOn()) {
          writeStatus(' Submitted  (' + message + '): for ' + ndid + ' vars= '+nvars );
       }
    } else {
         writeAlert('SPYING Mode: did NOT submit (' + message + ')' );
         writeStatus(' SPYING Mode: did NOT submit (' + message + '): for ' + ndid + ' vars= '+nvars );
         var avv=submitVars['__submitStatus'];
         if (avv!=='') Save_Global(avv,1);
         E2_doEvent(ttag,ithNode);         // process next node in this event's list of event actions (ithNode is current -- doEvent will do node AFTER ithNode)
         submitVars={} ;                     // reset the submitVars list
         submitVars['0']=0 ;
         submitVars['__message']='Submitting current information to the server. Please wait.... ';
         submitVars['__status']='SUBMIT';
    }
   return 1 ;
}

// nowr
//  =============================== _status  e2_dosubmit
// callback function used by submit
// oinfo contains the "state" variable 
// chkval the string returned by the server
// astat the response code (should contain 200)
// Note use of the &=VAR$_ID "meta-command". It causes the server to send back the value of the _ID variable included in the request string
//  If it does not match the myID variable, an error is reported.

function callback_doSubmit(oinfo,chk_val,rcode,astat,nth) {
var amess=chk_val;
if (typeof(ControlVars)=='undefined') ControlVars= new Object() ;
ControlVars['$recentSubmit']=this._dataURL ;


 if (astat=='TIMEOUT') {                                                  // timedout, try again
   var iresub=Read_Global('N_RESUBMITS',4);
   if (this._counter<iresub) {
       E2_writeAlert(' Connection problem. ReSubmitting .... (' +this._counter+' of ' +iresub +')');
       E2_writeStatus(' Connection problem, timeout. ReSubmitting .... (' +this._counter+' of ' +iresub +')');
       Launch_Proc('E2_doSubmit',1000,this._variable2,2,1*this._counter+1,this._variable3,this._variable4,this._variable5);
       return 1 ;
   }
   E2_writeAlert('<div style="color:red;font-size:120%"> Problem: connection timeout when submitting results (after ' +this._counter+' attempts). </div>  Please inform an administrator. ','','',55000);
   E2_writeStatus(' Connection problem. Timeout  (' +1*this._counter+' of ' +iresub +')');
   E2_doSubmit(this._variable2,4,chk_val,this._variable3,this._variable4,this._variable5);
   return 1 ;
}

 if (astat=='ERROR') {                                                  
   var iresub=Read_Global('N_RESUBMITS',4);
   if (this._counter<iresub) {
       E2_writeAlert(' Connection problem. ReSubmitting  (' +this._counter+' of ' + iresub + ')','','',5000);
       E2_writeStatus(' Connection problem, unknown status. ReSubmitting  (' +this._counter+' of ' + iresub + ')');
       Launch_Proc('E2_doSubmit',5000,this._variable2,2,1*this._counter+1,this._variable3,this._variable4,this._variable5);
       return 1 ;
   }
    E2_writeAlert('<div style="color:red;font-size:120%"> Problem:  submitting results (after ' +this._counter+' attempts) =' +chk_val+' </div>  Please inform an administrator.. ','','',55000);
    E2_writeStatus(' Connection problem: '+chk_val+  ' (' +this._counter+' of ' +iresub +')');
    E2_doSubmit(this._variable2,4,chk_val,this._variable3,this._variable4,this._variable4,this._variable5);
    return 1 ;
 }

// if here, no server error. But perhaps a survey error?

if (chk_val.toUpperCase().indexOf('OK')!=0) {                        // response, but problem processing
    E2_writeAlert('<div style="color:red;font-size:120%">Problem:<br/> '+ chk_val + '. </div>  Please inform an administrator');
    E2_writeStatus('PROBLEM: chk_val= '+chk_val +' || oinfo= '+oinfo+'  || rcode='+rcode+'|| astat='+astat+'|| nth= '+nth);

// e2_dosubmit called with (ttag,stype,ict,ithNode,tocurrent,useround)
// and these are used set ...
//   SendVars._variable2=ttag ;
//   SendVars._variable3=ithNode ;
//   SendVars._variable4=tocurrent ;
//   SendVars._variable5=useround ;


    E2_doSubmit(this._variable2,4,chk_val,this._variable3,this._variable4,this._variable5);
    return 1 ;
} else {                                // double check...
  var echov=strip(getWord(chk_val,2)) ;
  if (echov!=strip(this._ID)) {
    E2_writeAlert('<div style="color:red;font-size:120%">Problem:<br/>Submission error: <br/> incorrect id match: '+echov+' ne '+this._ID +'.</div>  Please inform an administrator ','','',55000);
    E2_writeStatus('PROBLEM: incorrect id match: '+echov+' ne '+this._ID );
    E2_doSubmit(this._variable2,4,chk_val,this._variable3,this._variable4,this._variable5);
    return 1 ;
 }
  var echov=strip(getWord(chk_val,3)) ;
  if (echov!=strip(this._ECHO)) {
    E2_writeAlert('<div style="color:red;font-size:120%">Problem:<br/>Submission error: <br/> incorrect timestamp match: '+echov+' ne '+this._ECHO +'.</div>  Please inform an administrator ','','',55000);
    E2_writeStatus('PROBLEM: incorrect timestamp match: '+echov+' ne '+this._ECHO );
    E2_doSubmit(this._variable2,4,chk_val,this._variable3,this._variable4,this._variable5);
    return 1 ;
  } else {
      E2_writeAlert(' Entry submitted.','','',1000);
  }
}

 var vv=this._variable ;                                        // save response from last SUBMIT request
 if (vv) ControlVars[vv]=chk_val;

 if (debugOn()) E2_writeStatus('Status of submit (for ' + oinfo+ ') == ' + chk_val);

  E2_doSubmit(this._variable2,3,chk_val,this._variable3,this._variable4,this._variable5);
  return 1;

}



//========================================
// this is called when an event is realized: a button is pushed, a timer runs down, a variable is recieved from server
// uses ttag to lookup a node in specSections.eventQueue, and uses insturctions in this node (i.e.; CALL, NEXT, GOTO, SUBMIT, DISPLAY, WAIT, RECOVERPRIOR

function E2_doEvent(ttag,at1) {

var gTag,gType,gNode,donodes,i,donode1,docall1,funclist,dotype1,i,ii,j ;
var nowGroup,nowSection ;
var dogoto,gosec,istrue,ndo,nowNode ;
var getVar,doTime,daLabel,donodesIf;
var toid,doFunc,dotime,bsec;
var gosec,gogroup,preSubmit,islock;
var aline,sname,aval,i,dasave,snodes,damessage,dacomment,saveOnly,dispid,vv,idxval,tval ;
var noConfirm=0;
var anode,istrue,isThen,isElse,isURL,daURL ;
var daSave='' ;
var dolist,remList,try1,aif,foo ;
var idolist,mo,mo2,mo3,amodname,imo,tmpname ;
var mlist,mlista,danid,jj,addto,noProcess;
var tmp,doids,ii2,iok,tmp1,tmp2,tmp3,tmp4,tmp5,anatt;
var saveToVar,taline;
var nowr;
var useTitle,atitle,attList,alist,aword;
var atarget,atitle,ims,a1,dzoo;

var gName,isecName ;
var anid,anid2,tw1,w1,anid0;
var anModule,doingModule,amod ;
var cmessage='' ;


if (arguments.length<2) at1=-2

if (at1!=-22) {
// first make sure that the display hasn't changed. If it has, give up.
  if (typeof(specSections.eventQueue[ttag])=='undefined') return 0 ;                      // never created, or zapped. give up
  gTag=specSections.eventQueue[ttag].groupTag ;
  if (gTag!=specSections.currentGroupTag) return 0  ;                // group has changed, give up

  islock=specSections.eventQueue.locked; if (islock==='') islock=0;
  if (islock!==0 && specSections.eventQueue.locked!==ttag) {                // locked, and not this event, make 'em wait
     bsec=specSections.eventQueue[ttag].Busy ;
     if (bsec==0) {
        if (debugOn()) E2_writeStatus(ttag+' locked, giving up ');
        return 0 ;
     }
     if (debugOn()) E2_writeStatus(ttag+' locked, waiting ');
     Launch_Proc('E2_doEvent',bsec*1000,ttag) ;                  
     return 0 ;
  }
}                                       // -22
if (at1==-22) at1=-2 ;           // skip the pause just ahead

if (typeof(specSections.eventQueue[ttag])=='undefined') {
        alert('Error in event: '+ttag+', you may need to reload this page \n (sometimes this happens if you are quickly hitting buttons! If so, click a little slower!)');
        return 0 ;                      // never created, or zapped. give up
}

specSections.eventQueue.locked=ttag ;

// if a button was clicked, and a clickMessages was speciifed, and this is first call  ...
if (typeof(specSections.eventQueue[ttag].clickMessage)!='undefined' &&  specSections.eventQueue[ttag].clickMessage!=='0' && arguments.length<2) {
   specSections.eventQueue[ttag].wasStyle= specSections.eventQueue[ttag].buttonNode.style.cssText ;
   var cmessage=specSections.eventQueue[ttag].clickMessage ;   
   specSections.eventQueue[ttag].buttonNode.value=cmessage;
   specSections.eventQueue[ttag].buttonNode.style.color="#9e9e9e";
   specSections.eventQueue[ttag].buttonNode.style.backgroundColor="#eaeaea";
   Launch_Proc('E2_doEvent',100,ttag,-22) ;                             // cause a moment, and start processing
//   setTimeout('E2_doEvent("'+ttag+'",-22)',100);
   return 0;
}

gType=strip(specSections.eventQueue[ttag].eType.toUpperCase()) ;
gNode=specSections.eventQueue[ttag].useNode ;   
if (at1<-1) {                                 // first call?

// check for events within events (error!)

  donodes=E2_getNodes(gNode,'EXEC BUTTON QUERY TIMER ') ;
  if (donodes.length>0) {  
      alert('ERROR: E2_doEvent. An <EXEC>, <BUTTON>, <QUERY>, or <TIMER> found in an <'+gNode.nodeName+'> event ');
      return 0;
  }

// check for shortcuts
  if (typeof(specSections.eventQueue[ttag].shortcut)!='undefined') {
     if (specSections.eventQueue[ttag].shortcut=='togroup') {                        // query togroup="avar"
         var getvar=specSections.eventQueue[ttag].sVar ;
          var isq=Read_Global('_queryResponse','');
          if (isq!='' && !isNaN(isq))  {                                     // got something
              isq=1*isq ;
              var nowg=1*Read_Global('_GroupNumber');                  
              if (strip(isq)!=strip(nowg) ) {
                   E2_showGroup('',isq,1);
                   return 0;
             }
          }                               // if same, or isq ='', do normal processing. BUt won't be any nodes, so end up skipping
     }
  }                               // shortcut

  donodes=E2_getNodes(gNode,'SUBMIT ') ;
  if (donodes.length>1) {
      alert('ERROR: E2_doEvent. More than one SUBMIT event action ');
      return null;
  }

  donodes=E2_getNodes(gNode,'IF CALL NEXT GOTO SUBMIT  SET UPDATE DISPLAY RECOVERPRIOR EMAIL POPUP BREAK STOP ') ;
  specSections.eventQueue[ttag].toDo=donodes ;                          // save for possible later use
  nowNode=-1 ;

  if (gType=='BUTTON') {
     specSections.eventQueue[ttag].ndo++ ;                          // save for possible later use
     if (specSections.eventQueue[ttag].ndo > specSections.eventQueue[ttag].maxdo) {              // too many button pushes?
        if (debugOn()) E2_writeStatus('Warning: Too many button pushes  (max of '+specSections.eventQueue[ttag].maxdo+')');
        specSections.eventQueue.locked=0;
        return 1  ; 
     }
  }
        

} else {                                        // NOT first call -- recall nodes containing action list (stored in toDo
    donodes=specSections.eventQueue[ttag].toDo ;
    nowNode=at1 ;                                 // the "most recently" completed node. If -1, havent done any nodes yet
}


nowSection=specSections.current ;               // some reference stuff
nowGroup=specSections.gCurrent ;   
isecName=specSections.sCurrentName ;   
gName=specSections.gCurrentName ;

for (var j=0 ; 1<2; j++ ) {                             // process the event actions
    nowNode++ ;
    if (nowNode>=donodes.length) break ;              // a hack to allow for inserting the nodes of an IF's goto/next/call 
    donode1=donodes[nowNode] ;
    dotype1=strip(donode1.nodeName.toUpperCase()) ;

    if (dotype1=='IF'  ) {         // check if valid. If so, process for call, next, and goto inside of the if
       isThen=E2_getNodes(donode1,'THEN',1) ;               // <then> 
       if (isThen.length>0) {                              // use advanced syntax 
          istrue=E2_node_doIf(donode1,2) ;                // first text node within  <if> .... </if>, or a value (first text node has priority)
          if (istrue==0) {                               // use ELSE? <else>
             isElse=E2_getNodes(donode1,'ELSE',1);
             if (isElse.length==0) continue ;           // no else, so do nothing
             anode=isElse[0]
          } else {
             anode=isThen[0];
          }
       } else {                                         // no <then>,  value attribute inside of <if  ... >
          istrue=E2_node_doIf(donode1,1) ;
          if (istrue==0) continue ;
          anode=donode1 ;
       }

        tmpnodes=donodes ;
        donodes=E2_getNodes(anode,'CALL NEXT GOTO SUBMIT UPDATE DISPLAY RECOVERPRIOR EMAIL POPUP IF BREAK STOP SET ') ;
        for (var jj=nowNode+1;jj<tmpnodes.length; jj++) {                     // append unprocessed nodes AFTER nodes from this IF
          donodes=donodes.concat(tmpnodes[jj]);
        }
        specSections.eventQueue[ttag].toDo=donodes ;                          // save for possible later use
        nowNode=-1 ;                                                  // start processing from BEGINNING of reformed list (IF nodes + unprocessed ndoes)
        continue ;
    }                           // IF

    if (dotype1=='STOP') {                              // stop processing this event, and do NOT repeat
         specSections.eventQueue.locked=0 ;
         return 0;                                 // done 
      }

    if (dotype1=='BREAK') {                              // 
         specSections.eventQueue.locked=0 ;
         break ;                                 // stop processing this event, but perhaps repeat
      }

    if (dotype1=='SET') {                              // stop processing this event, and do NOT repeat
        alert('Error in a '+gType+' Event: <SET> is used (you should use <CALL>)');
        return 0;                                 // done 
    }

    if (dotype1=='CALL'  ) {         // call a function 
        E2_doEquations('',donode1)    ;                 // call the function(s)  for this <event>. No NODE assoiated with an event, so use '' for arg2
     }   


    if (dotype1=='NEXT') {                              // next group (in order of appearance, after removal due to <if> )
      delete specSections.eventQueue[ttag] ;                    // clean up (also signals "done with group" to late arriving events
      specSections.eventQueue.locked=0 ;
      if (nowGroup>=specSections[nowSection].g,length) continue ;               // doing final group, so do nothing
      nextGroup=1*nowGroup+1 ;
      E2_showGroup('',nextGroup);
      return -1 ;                                 // done 
     } 

    if (dotype1=='DISPLAY') {                                            // ============================== DISPLAY 
        tmp=getAttributes(donode1,'how',0);          //  how is optional and can be 'block', "none", or "inline", or 0 (the default). 0 means "toggle"
        astyle=strip(getAttributes(donode1,'style','0')) ;
        doids= E2_getNodeText(donode1);
        doids=getWord(doids);
        for (var ii2=0;ii2<doids.length;ii2++) {
            iok=displayDiv(doids[ii2],tmp);
            if (astyle!=='0' && strip(iok).toUpperCase()!='NONE' ) {
               arf=document.getElementById(doids[ii2]) ;
                update_styles(arf,astyle,1);
            }

        }
     }


// ======== RECOVERPRIOR ==== 
    if (dotype1=='RECOVERPRIOR') {                                // ================== <RECOVERPRIOR> 
        tmp=getAttributes(donode1,'download',1);
        tmp2=getAttributes(donode1,'toModule','');
        tmp3=getAttributes(donode1,'modules','');
        E2_recoverPrior(1,ttag,nowNode,tmp,tmp2,tmp3)   ;       // recoverPrior will call e2_doEvent(ttag,nowNode) when done
        return 1 ;                                      
    }


// ======== UPDATE ==== 
    if (dotype1=='UPDATE') {                                            // ================== <UPDATE> 
        tw1='';
        anid=getAttributes(donode1,'id','');
        anModule=getAttributes(donode1,'tomodule','');
        noProcess=getAttributes(donode1,'NOPROCESS','');


        if (anid=='' && anModule==='' ) {
               alert('Error in UPDATE: no ID specified ');
              continue ;
        }
        doingModule=0 ;

       if (anModule!=='')  {                                    // update a module
           anModule=strip(anModule.toUpperCase());
           anModule=resolveIndex(anModule,donode1,'UPDATE: unknown index in  module');
           if (anModule==='') continue  ;

           anid=strip(anid.toUpperCase());
           doingModule=1 ;

           if (anid=='' && typeof(xmlModuleList[anModule])!=='object') {               // no id, unknown module -- then create the module
                danid=document.createElement('module');
                doingModule=2;
           }

           if (anid=='' && typeof(xmlModuleList[anModule])=='object') {               // no id, known module -- replace or addto contents of module
              danid=xmlModuleList[anModule];
           }

           if (anid!=='' && typeof(xmlModuleList[anModule])!=='object') {               // id known, unknown module -- error
              alert('ERROR in UPDATE: no such module = ' + anModule);
              continue ;
           }

           if (anid!=='' && typeof(xmlModuleList[anModule])=='object') {               // id known, known module -- find div inside of module
              dzoo=xmlModuleList[anModule].getElementsByTagName('*');
              danid=0;
              for (var m=0;m<dzoo.length;m++){                  // find element in this module with a matching id 
                 a1=getAttributes(dzoo[m],'id','');
                 if (a1==='') continue ;
                 a1=strip(a1.toUpperCase()) ;
                 if (a1!==anid) continue ;
                 danid=dzoo[m];
                 break ;
              }
              if (danid===0) {
                 alert('ERROR in UPDATE: no such ID ('+anid+') in module = ' + anModule);
                 continue ;
              }
           }                                    // id known, known module
       }                                               // update a module
       if (doingModule==0) {                                    // look for div in main or popup window
         if (anid.indexOf('.')>0) {                              // id in a specific window 
             anid0=anid;
             anid2=anid.split('.');
             if (anid2.length<2) {
                 alert('Error in UPDATE: no ID specified= ' + anid );
                 continue ;
             }
             anid=anid2[1];
             tw1=anid2[0];
             tw1=strip(tw1.toUpperCase());
             if (typeof(displayWindows[tw1])=='undefined') {
                 if (debugOn())  E2_writeStatus('Caution: UPDATE to nonexistent window = ' + anid0);
                 continue ;
              }
              w1=displayWindows[tw1] ;

              if (!w1.document) {                                              // window closed? Then reopen
                 w1=window.open('',tw1); 
                 if (!w1.document) {                                              // window closed? Then reopen
                     if (debugOn())  E2_writeStatus('Caution: UPDATE to closed window = ' + anid0);
                     continue ;
                 }
              }                                         // w1.document not open 
             danid=w1.document.getElementById(anid);
             if (!danid) {
                alert('Error in UPDATE: no such ID= ' + anid0 );
                continue ;
             }

         } else {                                                 // anid not in  div 
            danid=document.getElementById(anid);
            if (!danid) {
                alert('Error in UPDATE: no such ID= ' + anid );
                continue ;
            }
         }                                               // no . in anid
       }                                              // NOT a module 

// got the node to be updated. So update it (might be in main window, in popup window, or in a module )
       isAppend=getAttributes(donode1,'append','');

       if (isAppend!=1 && danid.childNodes) {
            while (danid.childNodes.length >= 1 ) {
                   danid.removeChild(danid.firstChild );       
            }
       }                                                        // doingmodule=1   ======

// start adding old modules to window, div, or existing/current module 

       mlista=getAttributes(donode1,'modules module','');

       if (mlista=='') {                                // use content between <update> .. </update>
            addto=document.createElement('update');             //   in a big div
            E2_copyNode(donode1,addto,'UPDATE');                // skip the <update> and </update> 
            if (noProcess!=1) E2_procModule(addto,'',isecName,gName);             // no reference module
            E2_copyNode(addto,danid,'update');                  // add to existing node

       } else {                                        // process a module list 
            mlist=getWord(mlista);
            for (var jj=0;jj<mlist.length;jj++) {                     // each module (specified by name in ims) is its own div 
                aword=strip(mlist[jj].toUpperCase()) ; 
                aword=resolveIndex(aword,donode1);
                if (typeof(xmlModuleList[aword])=='undefined') {
                        alert('Error in UPDATE: no such module = ' + aword);
                         continue ;
                }
   
                if (noProcess!=1) {
                    addto=document.createElement('module');       // make as module,
                    E2_procModule(addto,xmlModuleList[aword],isecName,gName,1,doingModule);       // do the setValue, etc. stuff
                    E2_copyNode(addto,danid,'module');
                } else {
                   E2_copyNode(xmlModuleList[aword],danid,'MODULE',1);
                }
            }                           // for words in mlist
       }                              // usling MLIST

/*== // SHOW CONTENT
if (typeof(w1)!=='undefined') {
 var dw=window.open('','debugwindow');
  dw.document.open('text/plain');
  dw.document.write(w1.document.body.innerHTML); 
  dw.document.close();
}
==*/

       if (doingModule==0) {                                  // if in popup window, close the popup window's document
             if (tw1!=='') w1.document.close();
       } else {
          if (doingModule==2) {
              xmlModuleList[0]=xmlModuleList[0].concat(anModule) ;
              xmlModuleList[anModule]=E2_copyNode(danid);
          }
       }
 
    }                           // END OF UPDATE  =================================================



// ======= EMAIL ======

    if (dotype1=='EMAIL') {                                     // <email>

      tmp1='' ;               // if not specified default fromDefault is used
      tmp2=' ';               // '' is an error (no recipient)
      tmp3=' ';                // emtpy subject is okay
      tmp4=' ';               // empty message is okay
       
      tmp5=getAttributes(donode1,'status statusvar var','EMAIL_STATUS');       // dsurvey global, for saving status
        
      tmp=E2_getNodes(donode1,'from');
      if (tmp.length>0) {
           anatt=getAttributes(tmp[0],'var','');        
           if (strip(anatt)!=='') {
              tmp1=Read_Global(anatt,'');
           } else {
              tmp1= E2_getNodeText(tmp[0]) ;       // from
           }
       }
       tmp1=strip(tmp1);

      tmp=E2_getNodes(donode1,'to');
      if (tmp.length>0) {
           anatt=getAttributes(tmp[0],'var','');        
           if (strip(anatt)!=='') {
              tmp2=Read_Global(anatt,'');
           } else {
              tmp2= E2_getNodeText(tmp[0]) ;       // to
           }
       }
       tmp2=strip(tmp2);        
       if (tmp2=='') {
                 alert('Error in EMAIL event action: no To specified ');
                 return 0 ;
       }
  
       tmp=E2_getNodes(donode1,'subject');
       if (tmp.length>0)  tmp3= E2_getNodeText(tmp[0]) ;       // subject

       tmp=E2_getNodes(donode1,'message');
       if (tmp.length>0) {
          amod=getAttributes(tmp[0],'var module','');   
          amod=strip(amod).toUpperCase();     
          if (amod!=='') {
             if (typeof(xmlModuleList[amod])!=='object') {
                 alert('ERROR in Email: unknown module in message= ' +amod) ;
                 return 0 ;
             }
             addto=document.createElement('div');             // temporary div
             E2_procModule(addto,xmlModuleList[amod],isecName,gName);       // do the setValue, etc. stuff
             tmp4=addto.innerHTML ;  

          } else {
             tmp4= E2_getNodeText(tmp[0]) ;       // message
          }
        }

//from,to,subject,message  

        E2_sendEmail(1,ttag,nowNode,tmp1,tmp2,tmp3,tmp4,tmp5)   ;       //      E2_sendEmail will call e2_doEvent(ttag,nowNode) when done

        return 1 ;                                      

    }

// ======= POPUP ======

    if (dotype1=='POPUP') {                                     // <popup>

        useTitle=''; attList='toolbar=0,location=0,directories=0,status=0,toolbar=0,scrollbars=1,resizable=1';
        atitle=E2_getNodes(donode1,'title');
        if (atitle.length>0)  useTitle= E2_getNodeText(atitle[0],0,'googog') ;
        alist=E2_getNodes(donode1,'ATTRIBUTES');
        if (alist.length>0) attList= E2_getNodeText(alist[0]) ;
        
        isURL=0; daURL='';                                      // write a module, or grab a url?
        var mlist=getAttributes(donode1,'MODULES','');
        if (mlist==='') {
             var mlist=getAttributes(donode1,'href url','');
             if (mlist==='') {
                 alert('Error in POPUP event action: no MODULES or URL specified ');
                 return 0 ;
             }
             isURL=1; daURL=strip(mlist);
        }

        if (isURL==0) {                                 // check for module existence
          ims=getWord(mlist);
          for (var i=0;i<ims.length;i++){
             var a1=strip(ims[i].toUpperCase()) ;
             a1=resolveIndex(a1,donode1,'POPUP:  unknown index in  module');
             if (a1==='') return 0 ;
             if (typeof(xmlModuleList[a1])=='undefined') {
                  alert('Error in  POPUP event action: unspecified module '+ims[i]+' in: '+mlist);
                  return 0 ;
              }    
          }
        }                                       // isurl=0

        var atarget=getAttributes(donode1,'TARGET','');                         // window to write to 
        if (atarget=='') atarget='VIEWER' ;
        var tw1=strip(atarget.toUpperCase());
        if (typeof(displayWindows[tw1])=='undefined') displayWindows[tw1]=new Object() ;

        if (typeof(displayWindows[tw1].wind)=='undefined' ) {                   // open window if it doesn't already exist
           var w1=window.open(daURL,atarget,attList);                           // nb: daurl='' if modules are going to be used
           displayWindows[tw1].wind=w1 ;
           displayWindows[0]=displayWindows[0].concat(tw1) ;
         } else {
           w1=displayWindows[tw1].wind;
           if (!w1.document) {                                              // window closed? Then reopen
               var w1=window.open(daURL,atarget,attList);
               displayWindows[tw1].wind=w1 ;
           } else {
               // alert(' popupstillopen '+w1);
           }
        }

        noProcess=getAttributes(donode1,'NOPROCESS','0');
        var aretain=getAttributes(donode1,'RETAIN','0');                        // set flags used when new group starts (retain or remove these windows
        if (aretain!=='1') aretain=0;
        displayWindows[tw1].retain=aretain ;

        if (isURL==1) continue ;                                // do NOT process contents of a url

         w1.document.body.innerHTML='';                          // use a module. So, first zap current contents of window
        w1.document.title=useTitle ;                           // the window title

        for (var jj=0;jj<ims.length;jj++) {                     // each module (specified by name in ims) is its own div 
                var aword=strip(ims[jj].toUpperCase()) ; 
                aword=resolveIndex(aword,donode1);
                if (isIE()) {
                   var addto=document.createElement('div');             // temporary div
                   if (noProcess!=1) {
                       E2_procModule(addto,xmlModuleList[aword],isecName,gName);       // do the setValue, etc. stuff
                   } else {
                       E2_copyNode(xmlModuleList[aword],addto,'MODULE');
                   } 
                   w1.document.body.innerHTML=addto.innerHTML ;
                       
                } else {
                  var addto=w1.document.createElement('div');             // div for new window, so create it here
                  if (noProcess!=1) {
                     E2_procModule(addto,xmlModuleList[aword],isecName,gName);       // do the setValue, etc. stuff
                  } else {
                     E2_copyNode(xmlModuleList[aword],addto,'MODULE');
                  } 
                  w1.document.body.appendChild(addto);
                }
          }                     

          w1.document.close() ;                       // all done!


/* ============  xmlTo
  var arf=w1.document.body.innerHTML ;
 var dw=window.open('','debugwindow');
  dw.document.open('text/plain');
  var t1='<html><head><title>Debug window</title><body><div style="border:2px black dotted; background-color:#999999"><tt>Debug mode: </div>  </body></html>';
  dw.document.write(arf);
  dw.document.close();
 ======== */

    }                                                   // end of POPUP  xmlToD

    if (dotype1=='SUBMIT') {                              // note: won't get here if didsubmit=1 (<submit>)

        snodes=E2_getNodes(donode1,'CALL');                    // save some variables to submitVars (for submission) <SAVE> 
        if (snodes.length>0) {
          var gg=SvyGlobals['_GROUPNAMEFULL'];  
          alert('ERROR: <CALL> is not permitted inside of a <SUBMIT> (place the <CALL> before the <SUBMIT>) :' +gg);
          return 0;
        }

        noConfirm=getAttributes(donode1,'noConfirm','');
        toCurrent=getAttributes(donode1,'toCurrent','');
        nowr=getAttributes(donode1,'round','');
        nowr=svy_getVal(nowr);     

// check for confirms
        if (noConfirm!='1' && typeof(radioSpecs)!='undefined' && typeof(radioSpecs[0])!='undefined' && typeof(radioSpecs[0]['grouplist'])!='undefined') {            
            grouplist=radioSpecs[0]['grouplist'];
            if (grouplist!=='') {
               grouplist=getWord(grouplist);
               for (var igr=0;igr<grouplist.length;igr++) {
                   agroup=grouplist[igr]
                   if (typeof(radioSpecs[0][agroup]['confirm'])!='undefined') {          // confirm found for a group
                     if (radioSpecs[0][agroup]['chosen']=='x') {                        // nothing chosen:  so failure!
                            alert(radioSpecs[0][agroup]['confirm']);
                            if (typeof(specSections.eventQueue[ttag].clickMessage)!='undefined') {
                                     specSections.eventQueue[ttag].buttonNode.style.cssText=specSections.eventQueue[ttag].wasStyle ;
                                     specSections.eventQueue[ttag].buttonNode.value=specSections.eventQueue[ttag].showText ;
                            }
                            specSections.eventQueue.locked=0;
                            return -1 ;
                     }                                                          // == 'x'                              
                   }                                            // confirm not undefined
               }                         // igr
            }                             // grouplist !=''
        }                                       // confirm

        saveOnly=getAttributes(donode1,'saveOnly','');
        submitVars['__notFinal']=getAttributes(donode1,'notFinal','0'); 
        submitVars['__ct']=getAttributes(donode1,'ct','1');
        submitVars['__dispid']=getAttributes(donode1,'ID DISPLAYID MESSAGEID','');
        submitVars['__submitStatus']=getAttributes(donode1,'saveVar var ','_submitStatus');

        snodes=E2_getNodes(donode1,'MESSAGE');
        if (snodes.length!==0) {
          var m1=getAttributes(snodes[0],'VALUE MESSAGE LONG','');
          if (m1==='') {
             m1=getAttributes(snodes[0],'VAR VARLONG VAR_LONG','');
             if (m1!=='') m1=svy_getVal(m1,'');
          }
          submitVars['__message']=m1;
          var m1=getAttributes(snodes[0],'STATUS SHORT','');
          if (m1==='') {
             m1=getAttributes(snodes[0],'VARSHORT VAR_SHORT','');
             if (m1!=='') m1=svy_getVal(m1,'');
          }
          submitVars['__status']=m1;
        }                               // in MESSAGE

        snodes=E2_getNodes(donode1,'STATUS');                   
        if (snodes.length!==0) submitVars['__status']=getAttributes(snodes[0],'VALUE STATUS COMMENT','');

        
// look for any element with a SubmitName attribute, and submit it's value (using the submitName attributes value 
// note: <value>, <radio>, and <checkbox> should NOT have these attributes (they are stored in seperate database
        dolist1=document.getElementsByTagName('*');
        for (var i=0;i<dolist1.length;i++ ) {

// submitVar attribute? If so, save to survey global variable
           sname=getAttributes(dolist1[i],'SUBMITVAR','');
           sname=strip(sname.toUpperCase()) ;                
           if (sname!=='' && sname!=='1' && sname!=='0')  {            // valid name 
               if (sname.indexOf('#')>0) {                                  // replace # with IDX attribute (possibly a '')
                    if (idxval=='') idxval=getAttributes(dolist1[i],'IDX','');
                    sname=sname.replace('\#',idxval);
               }
//alert('saving global from submitvarAttribute '+sname+'='+aval);
               Save_Global(sname,aval) ;
           }


           sname=getAttributes(dolist1[i],'SUBMITNAME','') ;
           sname=strip(sname.toUpperCase()) ;
           if (sname=='' || sname=='1' || sname=='0')    continue ;          // not a valid name 

           aval=get_elemValue(dolist1[i],null); idxval='';
           if (sname.indexOf('#')>0) {                                  // replace # with IDX attribute (possibly a '')
                    idxval=getAttributes(dolist1[i],'IDX','');
                     sname=sname.replace('\#',idxval);
            }
            if (typeof(submitVars[sname])=='undefined') submitVars['0']++ ;

            submitVars[sname]=aval ;
// alert('adding to submitVars from submitName attribute '+sname+'='+aval);            
        }                                               // all elements (skipping radio and value elements

        if (typeof(radioSpecs[0]['grouplist'])!='undefined') {
        grouplist=radioSpecs[0]['grouplist'];                  // ============ look for RADIO buttons to submit
        if (grouplist!=='') {
              grouplist=getWord(grouplist);
              for (var igr=0;igr<grouplist.length;igr++) {  
                   agroup=grouplist[igr]
                   igot=radioSpecs[0][agroup]['chosen'] ;
                   if (igot=='x') continue ;                    // no button chosen from this group
                   aval=radioSpecs[0][agroup]['useValue'] ;
                   sname=radioSpecs[igot]['submitname'];
                   if (sname!=='') {
                      if (typeof(submitVars[sname])=='undefined') submitVars['0']++ ;
                      submitVars[sname]=aval ;  
                    }
                   sname=radioSpecs[igot]['submitvar'];         // submitvar?
                   sname=strip(sname.toUpperCase()) ;                
                   if (sname!=='' && sname!=='1' && sname!=='0') {
//   alert('Saving a global from a submitVar in radio '+sname+'='+aval);
                         Save_Global(sname,aval) ;
                  }
              }                          // igr
        }                      // grouplist!==''
        }                       // grouplist exists


         for (var igr=0;igr<valueSpecs.length;igr++) {          //================== look for <VALUE> to submit 
                   aval=valueSpecs[igr]['useValue'];
                   sname=valueSpecs[igr]['submitName'];
                   if (sname!=='') {
                      if (typeof(submitVars[sname])=='undefined') submitVars['0']++ ;
                      submitVars[sname]=aval ;  
                    }
                   sname=valueSpecs[igr]['submitVar'];         // submitvar?
                   sname=strip(sname).toUpperCase() ;                
                   if (sname!=='' && sname!=='1' && sname!=='0')  Save_Global(sname,aval) ;
          }                                             // value

         for (var igr=0;igr<checkboxSpecs.length;igr++) {          //================== look for <CHECKBOX> to submit 
                   tval=checkboxSpecs[igr]['chosen'];
                   if (tval==0) {                       // possibly use the noValue
                        if (checkboxSpecs[igr]['gotNoValue']==1) {
                            aval=checkboxSpecs[igr]['novalue'];
                            tval=1 ;
                        }
                   } else {                
                        aval=checkboxSpecs[igr]['yesValue'];
                   }
                   if (tval==1)  {                                      // either a yesValue or a noValue 
                      sname=checkboxSpecs[igr]['submitname'];
                      if (sname!=='') {
                         if (typeof(submitVars[sname])=='undefined') submitVars['0']++ ;
                         submitVars[sname]=aval ;  
                      }
                      sname=checkboxSpecs[igr]['submitvar'];         // submitvar?
                      sname=strip(sname).toUpperCase() ;                
                      if (sname!=='' && sname!=='1' && sname!=='0')  Save_Global(sname,aval) ;
                   }                                                                            // tval
          }                                             // checkbox 


        processSubmitSave(donode1) ;                  // process <save>  (appends info to submitVars)


// do the submit?
        if (saveOnly!=1) {                              // yes, not a saveonly
           E2_doSubmit(ttag,1,1,nowNode,toCurrent,nowr)            ;                  // uses submitVars stuff
           return 1 ;                           // e2_doevent will be reinvoked by dosubmit
        } 

   }                                    // SUBMIT 


    if (dotype1=='GOTO') {                              // jump to section of group-within-section
        gosec=strip(getAttributes(donode1,'section',''));
            if (gosec==='.') gosec=isecName ;
        gogroup=strip(getAttributes(donode1,'group',''));
        if (gogroup==='.') {
            gogroup=nowGroup ;
        } else {
            if (gogroup.indexOf('.')>-1) {              // secname.grpname syntax
              tmp1=parseAt(gogroup,'.') ;
              tmp1[0]=strip(tmp1[0]); tmp1[1]=strip(tmp1[1]);               // secname. is same as secname 
              if (tmp1[0]==='') tmp1[0]=isecName ;                        // .grpname is same as grpname
              gosec=tmp1[0];
              gogroup=tmp1[1];
            }
        }
        delete specSections.eventQueue[ttag] ;                    // clean up ! (also signals "done with group" to late arriving events
        specSections.eventQueue.locked=0 ;
        if (gosec=='' && gogroup=='') {                         // a NEXT
              if (nowGroup>=specSections[nowSection].g,length) continue ;               // doing final group, so do nothing
              nextGroup=1*nowGroup+1 ;
              E2_showGroup('',nextGroup);
              return -1;                                 // done
        }
        if (gosec==='') {                                // goto group in this section
            if (isNaN(gogroup) ) {                        // use group name 
               E2_showGroup(gogroup);
            } else {                                     // use group number
               E2_showGroup('',gogroup);
            }
        } else {                                          // start a new section
            if (gogroup==='') {
                    E2_loadSection(gosec,1) ;
            } else {
                    E2_loadSection(gosec,gogroup) ;
            }
        }  
        return -1 ;                                 // done with goto
    }                           // goto
}                               // donodes 


// no NEXT or GOTO was processed in this event?  If this is a QUERY  event, requery server after delay? If TIMER, repeat?

if (gType=='QUERY') {
  ndo=specSections.eventQueue[ttag].nRepeat-1 ;
  specSections.eventQueue[ttag].nRepeat=ndo ;
  if (ndo>0) {                                          // repeat the query? 
    doTime=specSections.eventQueue[ttag].doTime  ;   
    specSections.eventQueue.locked=0 ;
    Launch_Proc('E2_createQuery',doTime,ttag)    ;              // wait dotime seconds, then query server (or lookup survey-global variable or an element value )
    return 1 ;
  }
}

if (gType=='TIMER') {
  ndo=specSections.eventQueue[ttag].nRepeat-1 ;
  specSections.eventQueue[ttag].nRepeat=ndo ;
  if (ndo>0) {                                          // repeat the countdown ? 
      specSections.eventQueue.locked=0 ;
      specSections.eventQueue[ttag].timeLeft= specSections.eventQueue[ttag].doTime
      E2_createTimer(ttag,1)    ;
  }
}

specSections.eventQueue.locked=0 ;

return 1;
}                               //  todo 22 


// expand  string: varname[*] to varname[1]... varname[n]. We assume oldnames contains a *.
function expandSaveName(newnames,oldnames,preVar){
var newf=[];                                   // default is nothing
var v1,vname,vval,m,tmp,t1;

// is oldnames of the form v[*]
v1=parseUsingOuter(oldnames,'[',']',1);
if (v1[1]!='*') return newf ;

vname=strip(v1[0].toUpperCase()) ;
vval=Read_Global(vname,'');
if (vval=='') return newf ;
if (typeof(vval)!=='object' || typeof(vval.length)=='undefined') return newf ;

for (var m=0;m<vval.length;m++) {
 if (typeof(vval[m])=='undefined') continue ;
 tmp=vname+'['+m+']';
 t1=newnames.replace(/\*/,m);
 tmp=t1+'='+tmp ;
 if (preVar==1) tmp='VAR '+tmp ;
 newf=newf.concat(tmp);
}
return newf ;
}

//====================
// process a <save> in a <submit>  (append to global submitVars)
function processSubmitSave(donode1a) {
 var vv,vtmp2,aval,sname,newFlist,flist;
 var snodes,daSave='',flist,aline,taline,saveToVar,i ;

        snodes=E2_getNodes(donode1a,'SAVE');                    // save some variables to submitVars (for submission) <SAVE> 
        if (snodes.length!==0) daSave=E2_getNodeText(snodes[0]);
        if (daSave!=='') {                      // save values to submitVars list
            flist=daSave.split('\n');
            for (var i=0;i<flist.length;i++){
               aline=strip(flist[i]);
               if (aline=='') continue ;                        // skip blank lines

// check for leading VAR 
               saveToVar=0;                     // default is to save to server 
               taline=aline.toUpperCase() ;
               if (aline.toUpperCase().substr(0,4)=='VAR ') {                // save to var!
                   if (aline.indexOf('=')<0) {
                        alert('Error in Submit <SAVE>: VAR must precede an equation: '+aline) ;
                        return 0;
                   }
                   saveToVar=1 ;
                   aline=aline.substr(4);
               }
               vv=parseAt(aline,'=');
               if (strip(vv[0])=='') continue ;                 // nothing on lhs of =
               if (vv[1]=='') vv[1]=vv[0];

               var vtmp2=getWord(vv[1]);
               if (vtmp2.length>1) {
                   alert('Error in E2_doEvent: SAVEd value has too many words : ' + aline );
                   return -1;
               }
               if (aline.indexOf('+')>-1 ) {
                   alert('Error in E2_doEvent: SAVEd value should not be an equation :: ' +aline);
                   return -1;
               }

               if (vv[1].indexOf('*')<0) {           // simple variable (or array element)
                   aval=svy_getVal(vv[1],'') ;
                   sname=strip(vv[0].toUpperCase()) ;
                   if (saveToVar==1) {
                       Save_Global(sname,aval) ;
                   } else {
                      if (typeof(submitVars[vv[sname]])=='undefined') submitVars['0']++ ;
                      submitVars[sname]=aval;   
//alert('adding a submitVar from <save>: '+sname+'='+aval);

                   }
               } else {                                              // expand v[*] to be all defined values of v array
                   newFlist=expandSaveName(vv[0],vv[1],saveToVar);
                   if (newFlist.length>0)   flist=flist.concat(newFlist);
               }                                                        // * processing
            }                                                          // flist.length
        }                                                               // daSave exists

  return 1;
}


// ============
// given string of form varname[anindex] -- resolve anindex, return string (i.e.; if anindex=15, return varname[15]

function resolveIndex(varname,anode,errmess) {
var avv,vindex;
if (arguments.length<3)  errmess='';
if (arguments.length<2)  anode='';
if (typeof(varname)=='undefined') {
    alert('ERROR parsing index ('+errmess+') = = ' ) ;
    return '' ;
}

if (varname.indexOf('[')<0) return varname ;

avv=parseUsing(varname,'[',']',1);                 // a hack way of dealing with indices 
vindex=svy_getVal(avv[1],'',anode);
if (vindex==='' && errmess!=='') {              // no index and an errormessage- -- alert it and return ''
    alert('ERROR parsing index ('+errmess+') = = ' +varname) ;
    return '' ;
}
varname=avv[0]+'['+vindex+']';             
return varname ;

}

// ============
// alert2 -- display values of arguments, using svy_getVal on each argument.
function alert2(a1) {
var a='';
for (var i=0; i<arguments.length;i++){
  a=a+' | '+i +' = '+svy_getVal(arguments[i]) ;
}
var dd=new Date() ;
E2_writeStatus(dd+' Arguments: '+a);
return 1 ;
}



//===========
// Send an email
// called as:  E2_doEmail(1,ttag,nowNode,sendfrom,sendto,subject,message,statusVar)
// Note: when done, return from callback using a call of:   E2_doEvent(ttag,nowNode);

function  E2_sendEmail(ido,ttag,nowNode,afrom,ato,asubject,amessage,statusVar) {

var sessName=Read_Global("_sessionName");
var aid=Read_Global("myID");
var toPost;

  if (_spying==1) { 
         writeAlert('SPYING Mode: did NOT send email ' );
         writeStatus(' SPYING Mode: did NOT send email to  '+ato);
        return 1 ;
    }

toPost=svySMTPsend+'&session='+sessname+'&asShort=1&clientId='+aid+'&' + 
       'sendfrom='+escape(afrom)+'&' +
       'sendto='+escape(ato)+'&' +
       'subject='+escape(asubject)+ '&' +
       'message='+escape(amessage) ;

 var SendVars = new svy_CreateXMLHTTP(svyPostSubmitURL) ;
   SendVars.onDraw=callback_sendEmail  ;
   SendVars._method="POST" ;                    // note that the ?xx will be parsed out by the xmlhttp request function (._postRequest is not used)
   SendVars._timeout=10000  ;           //  10 seconds until timeout
   SendVars._showstatus=false ;           // note: by default, do NOT suppress cache-buster
   SendVars._comment='Sending an email (to: '+ato;
   SendVars._ID=aid  ;
   SendVars._postRequest = toPost ;

//   E2_writeAlert('Sending email to: '+ato);

   SendVars._variable='SEND_EMAIL';
   SendVars._variable2=ttag ;
   SendVars._variable3=nowNode ;
   SendVars._variable4=ato ;
   SendVars._variable5=afrom ;
   SendVars._variable6=statusVar ;

   SendVars.load('sent from '+afrom,1) ;  

  if (debugOn()) {
          writeStatus(' sending email to: '+ato);
   }
   return 1 ;
}




//===========
// callback for sendEmail
// oinfo contains the "state" variable 
// chkval the string returned by the server
// astat the response code (should contain 200)

function callback_sendEmail(oinfo,chk_val,rcode,astat,nth) {
var vv ;

 vv=this._variable ;                                     
 if (vv) ControlVars[vv]=chk_val;

 vv=this._variable6 ;
 Save_Global(vv,chk_val);

if (astat=='TIMEOUT') {                                                  // timedout, give up
//    E2_writeAlert(' Connection problem: '+chk_val+' ...  email may not have been sent ');
    E2_writeStatus(' Connection problem: '+chk_val+' ...  email may not have been sent ');
    E2_doEvent(this._variable2,this._variable3);
    return 1 ;
}

 if (astat=='ERROR') {                                                  
//    E2_writeAlert(' Connection error: '+chk_val+' ... email may not have been sent');
    E2_writeStatus(' Connection error: '+chk_val+' ...  email may not have been sent ');
    E2_doEvent(this._variable2,this._variable3);
    return 1 ;
 }

// if here, no server error. But perhaps a survey error?

if (strip(chk_val).toUpperCase().indexOf('OK')!=0) {                        // response, but problem processing
    E2_writeStatus(' Problem sending : '+chk_val+' ... email may not have been sent');
    E2_doEvent(this._variable2,this._variable3);
    return 1 ;
}


  E2_writeStatus('Status of sending email ' + oinfo+ ' == ' + chk_val);
  E2_doEvent(this._variable2,this._variable3);          

  return 1;

} 




//===========
// recover prior parameters, rebuild history
// Called from doEvent:
//     E2_recoverPrior(1,ttag,nownode,dodownload,tomodule,modlist)   ;      
// Returned call from E2_recoverHistory:
//      E2_recoverPrior(2,atag,nnode,astuff);
//  where astuff= tomodule+'||'+modlsit
// Note: when done, return from here using a call of:
//     E2_doEvent(ttag,nowNode);

function  E2_recoverPrior(ido,ttag,nowNode,dodown,tomodule,modlist)   {

var vvs,stuff;
var isecName,gName,danid,rrid;
var mlist,jj,aword,addto,mrounds ;

var stuff=tomodule + ' || '+modlist ;
rrid=document.getElementById('_recoverPriorStatus');

if (ido ==1 && dodown!=='0') {                                  // first call, and downloadHistory not suppresesd
  if (rrid) rrid.innerHTML=' (downloading history information from server)... ';
  E2_recoverHistory(1,ttag,nowNode,stuff);
  return 1 ;
}

// if here, ido=2

vvs=parseAt(dodown,'||');
tomodule=strip(vvs[0]).toUpperCase() ;
modlist=vvs[1];

mlist=getWord(modlist);

danid=document.createElement('module');                 // container to hold the various modules in modlist (repeated over all rounds!)
if (typeof(xmlModuleList[tomodule])!=='object') {               // no id, known module -- replace or addto contents of module
      xmlModuleList[0]=xmlModuleList[0].concat(tomodule) ;
}

isecName=specSections.sCurrentName ;
gName=specSections.gCurrentName ;

roundlist=SvyGlobalsHistory['$roundlist'] ;

if (rrid) rrid.innerHTML=' (creating '+roundlist.length+  ' history rounds)' ;

for (var ir1=0; ir1<roundlist.length;ir1++) {
  if (roundlist[ir1]!==1) continue ;
  mrounds=ir1;
  Reset_recentHistory(ir1)
  for (var jj=0;jj<mlist.length;jj++) {                     // each module (specified by name in ims) is its own div
    aword=strip(mlist[jj].toUpperCase()) ;
    aword=resolveIndex(aword);
    if (typeof(xmlModuleList[aword])=='undefined') {
       alert('Error in recoverPrior: no such module = ' + aword);
       return 1  ;
    }
    addto=document.createElement('module') ;       // make as module,
    E2_procModule(addto,xmlModuleList[aword],isecName,gName,1,1);       // do the setValue, etc. stuff
    E2_copyNode(addto,danid,'module');
  }                                          // usling MLIST
  if (rrid) rrid.innerHTML=' Prior variables saved for round '+ir1;

}

xmlModuleList[tomodule]=E2_copyNode(danid);


// recent history will contain results from last good round Reset_recentHistory() ;

writeStatus('recoverPrior completed: history made for '+mrounds+' rounds ');

if (rrid) rrid.innerHTML=' Done creating history.' ;

E2_doEvent(ttag,nowNode);            // resume processing event actions

}

//====================
// add "help" links to elements

function  E2_showHelp(e,abase,uselocal) {

var amess,goo1,i,anodei;
var daname,abase,ielem,aword,usediv;
var adiv,bdiv,atext,abutton,ibox ;
var amess,eeo,eei,parnode,ahelp,gar,hnode,fnode,fnodeHelp,i;
var abold,aem,gar2,gar3;  


if (arguments.length<2) {                       // called as an event
  abase=Read_Global('_helpModule_prefix','');
  if (abase=='') abase="Help_";
  if (!e) e=window.event ;
  ielem= (e.srcElement) ? e.srcElement : e.target ;

  daname=getAttributes(ielem,'infoName','') ;   aword=daname ;          // do NOT add base if infoname used 
  if (daname==='') {                             // no name
     daname=getAttributes(ielem,'name','') ;   
     if (daname==='') {                             // no name
        alert('ShowHelpModule error: no Name or infoName attribute available ');
        return 1;
     } else {
        aword=abase+daname; 
    }
  }                             // infoname found 
  aword=aword.toUpperCase() ;
  uselocal=getAttributes(ielem,'noHelpBox','0');

} else {                                        // explicitily called 
  daname=e;  
  if (daname=='' || daname==0 ) return 0 ;
  if (arguments.length<3) uselocal=0;
  aword=abase+daname; aword=aword.toUpperCase() ;
  ielem=this ;
}

aword=resolveIndex(aword,ielem);

if (typeof(xmlModuleList[aword])!=='object') {
              alert('ERROR in E2_showHelp: unknown module: ' +aword);
              return 1;
}

aword=resolveIndex(aword,ielem);
var goo1=xmlModuleList[aword] ;

// if moveable box 

ibox=exists_moveBox(9);
if (ibox!==0) {                         // use moveable box!

  atext='<input type="button" value="Close" onClick="close_moveBox(9)" />';
  ahelp=getAttributes(ielem,'helpWord',' ')    
  if (ahelp!=='') ahelp=abutton+'<span style="marign-left:20px">  Help for: <b>'+ahelp+'</b></span>';
  bdiv=E2_copyNode(goo1,'div','MODULE');
  E2_procSection_actionTags(bdiv,'Help message');         // add use="xx" stuff?
 
  write_moveBox(9,atext,bdiv.innerHTML);
  open_moveBox(9);
 return 1 ;

}

// else, use a fixed box (create one if necessary)

if (uselocal==1 || typeof(i_messageBlock)=='undefined' ) {                              // no help box defined, add message to top of document
   amess=E2_getNodeText(goo1);'';
   eeo=ielem;                                       // there is probably a formal way of finding the 'root node' for this element
   for (var i=0;i<1000;i++) {                           // but until I find it, this hack seems to work
      eei=eeo.parentNode ;
      if (eei.createTextNode) {
         parnode=eeo;                            // use the child of the node that supports createTextNode (why? cause it works). But parnode used for child manipulation
         break ;
      }
     eeo=eei;
   }

   ahelp=getAttributes(ielem,'helpWord',' ... ')                   // used for header 
  
   abold=parnode.parentNode.createElement('b');
    gar=parnode.parentNode.createTextNode('Help for ');
    abold.appendChild(gar);
    aem=parnode.parentNode.createElement('em');
    gar2=parnode.parentNode.createTextNode(ahelp);
    aem.appendChild(gar2);
    gar3=parnode.parentNode.createTextNode(' : '+amess);
  
    hnode=parnode.parentNode.createElement('div');
    hnode.appendChild(abold);
    hnode.appendChild(aem);
    hnode.appendChild(gar3);

    hnode.setAttribute('style','background-color:#cccccc;border:1px solid gray');
    hnode.setAttribute('helpHACK','1');                                     // help message in special div that is the first child
 
   fnode=parnode.firstChild;
   fnodeHelp=fnode.getAttribute('helpHACK');                        // if special div already created, then replace it. Otherwise, add it
   if (fnodeHelp!='1') {
       parnode.insertBefore(hnode,parnode.firstChild);
    } else {
        parnode.removeChild(parnode.firstChild);
        parnode.insertBefore(hnode,parnode.firstChild);
   }      
   return 1 ;
}                                                               // cant use standard help message box 

adiv=document.createElement('div');
atext=document.createTextNode('Click here to close box');
adiv.appendChild(atext);                                           //   display (in main page area) a wait message
adiv.setAttribute('class','styleInfoLink_header')

bdiv=E2_copyNode(goo1,'div','MODULE');
E2_procSection_actionTags(bdiv,'Help message');         // add use="xx" stuff?

bdiv.setAttribute('class','styleInfoLink_body')

i_messageBlock.innerHTML='';
i_messageBlock.style.display="block";
i_messageBlock.appendChild(adiv);       // put in "click to close" message
i_messageBlock.appendChild(bdiv);       // but in help message

return 1 ;
}   //  help  word


// =============
// add some common event handlers implemented via special classes: Arrow_Increment, Check_Bounds, Div_to_Frame, and Save_Value_event
function E2_addHandlers(dolist) {
    var alist,ilist,inpList ;
    disable_autocompletes('noauto') ;  
    Add_Event(dolist,'keyup',Arrow_Increment);
    Add_Event(dolist,'change',Check_Bounds);
    Add_Event(dolist,'change',Confirm_Input);
    Add_Event(dolist,'change',E2_changeActions);
 return 1 ;

}
// =============
// process equations and functions when a CHANGE event occurs
function E2_changeActions(e) {
  var ielem,nowval,nowname,damax,flist;
  var foo,damin,daAllowed,w1,w1b,iat,dval,ccall ;

  if (!e) e=window.event ;
  ielem= (e.srcElement) ? e.srcElement : e.target ;
  if (typeof(ielem)=='undefined' || typeof(ielem.value)=='undefined') return 1 ;                // no such element, do nothing

  ccall='changeCall';
  
  nowval=strip(ielem.value);
// note use of __changeCall. the __ means "get the node, set in elements, of the "changeCall" (or the value specified in  a useChangeCall attribute)
//  In contrast, "changeCall"  gets the actual string contents of a changeCall attribute. The difference is that if the node version is used,
//   if, do, etc can be used.

  idx=getAttributes(ielem,'__'+ccall,'');
  if (idx=='') {                                // maybe its a inline (rather then in elements) short changeCall 
    idx=getAttributes(ielem,ccall,'');
    if (idx=='' || typeof(idx)!='string') return null;                   // no changeCall
    flist=idx.split(';');
    goo=E2_doEquations1(ielem,flist);
    if (debugOn(2)) E2_writeStatus(' E2_changeActions called (using '+ccall+') ');
    return 1 ;
 }                               // else use elements node

  todo=specSections.elementList.__NODES[idx];
  if (todo=='') return null ;                          // no actions, do nothing
  goo=E2_doEquations(ielem,todo);

  if (debugOn(2)) E2_writeStatus(' E2_changeActions called ');

  return 1 ;
}
 

/* ============================================================
/* copy an xml node (tree under node) to a string.  Highly recursive. Note: apad not currently used  */
// if skip1=1, then do not write the outermost tagname 
// if skipc=1, then do NOT write comments 
function E2_xmlToString(anode,skip1,skipc,docrlf) {
var astrg2,astrg,anatt,anattv,i,i2,atype,aname,anode,iss,docrlf2=0,vst,ivst,astrg2a;

if (arguments.length<2) skip1=0;
if (arguments.length<3) skipc=0;
if (arguments.length<4) docrlf=0;

if (docrlf!=0) {
   docrlf2=docrlf+2 ;
}

try {
   if (anode.childNodes.length==0) {
        if (anode.nodeType==1 && skip1==1) return '' ;
         skip1=0;
   }
}
catch(err) {
        if (anode.nodeType==1 && skip1==1) return '' ;
  skip1=0;
}

astrg='';
atype=anode.nodeType ;

if (atype==8) {                         //comment
   if (skipc==1) return '' ;                            // comment, but 
   astrg='<!--'+anode.nodeValue+'-->  '  ;
   if (docrlf!=0) astrg=astrg+  '\n';
   return astrg ;
}

if (atype==3) {                         //string
//   return '['+anode.nodeValue+'_'+escape(anode.nodeValue)+'_'+anode.nodeValue.length+']' ;
   return anode.nodeValue ;

}

aname=anode.nodeName ;
astrg='';
if (skip1!=1) {
  astrg='<'+aname+' ';
  if (docrlf!=0) {
         vst=''; for (var ivst=0; ivst<docrlf;ivst++) vst=vst+' ';
         astrg='\n'+vst+astrg; 
  }
  for (var i=0;i<anode.attributes.length; i++) {
      if (!anode.attributes[i].specified) continue ;              // skip browser added attributes (might be a problem with ie)
      anatt=anode.attributes[i].nodeName ;
      anattv=anode.attributes[i].nodeValue ;
      astrg=astrg+anatt+'="'+anattv+'" ';
  }

  if (anode.childNodes.length==0) {
    astrg=astrg+'/>' ; 
    return astrg ;
  }
  astrg=astrg+'> ';
}
  
for (var i2=0;i2<anode.childNodes.length;i2++) {
   astrg2=E2_xmlToString(anode.childNodes[i2],0,skipc,docrlf2);
   if (docrlf>0) {                              // check for repetitive crlfs
        astrg2a=strip(astrg2);
        if (astrg2a.length==0) continue ;
   }
   astrg=astrg+astrg2 ;
}
if (skip1!=1) {
  astrg=astrg+'</'+aname+'> ' ;  
}



return astrg ;

}               // xmltostring

/* ============================================================ */
/* polls the server for a variable. Stops polling when one of the desired values is returned, or after specified # of tries.
  After stopping, calls a function with returned value and with up to 5 arguments.
  Syntax:
        Poll_serverVar(sessionName,serverVar,pOpts,arg1,arg2,arg3,arg4,arg5)
where:
        sessionName : the name of the session to check (serverVariables are specific to a session
        serverVar   : the variable, stored on the server, to obtain the value of
        pOpts :   an object containing options
               The following elements of pOpts are used
                pOpts.checkFunc :   a  string containing the name of the function to call for checking on whether polling should continue
                pOpts.maxTries     : Do maxTries attempts. After maxTries attempts, failure (stop polling)
                                     If 0 (or if not specified), infinity (actually, 1000000000) is used.
                pOpts.pauseMSec   : # of milliseconds to wait between attempts
                                     If 0 (or if not specified), wait queryFreq milliseconds between server-query (or 4 seconds if
                                     queryFreq is not specified in svylibe2.js)
                pOpts.func_to_call  : a string containing the name of a procedure to call when polling is stopped (on success or failure)
                pOpts.message    : a short string to send to server (current participant status)
                pOpts.noStatus    : 1 to suppress sending status info to server 
                pOpts.myID        : id of the participant 
                pOpts.time       : time request was made DEPRECATED -- compute time on the fly

        arg1,arg2,arg3,arg4,arg5: static arguments to provide to func_to_call

   checkFunc is called using:
      checkFunc(returnedValue,serverVar,ndid,maxTries,arg1,arg2,arg3)
      ok= window[cfunc](chk_val,this._variable,ict,this._variable3,this._variable5,this._variable6,this._variable7,this._variable8,this._variable9);

   where
         returnedValue : valued returned from the server
        serverVar      : variable requested
        ndid            : the "nth" attempt
        maxTries          : number of tries specified (maxTries)
        arg1,arg2,arg3,...  : as above              (note that arg4 and arg5 are NOT provided tothe checkFunc)

   checkFunc must return either a 0, or 1 
         0  : unable to determine succes, continue to poll   
         1  : success or failure, stop polling and call func_to_call
    
  checkFunc special cases:
     0, or '' (or not specified):
              if checkFunc is NOT specified, or is '' or 0, then a simple check is undertaken:
              if the number of ndid > maxTries, failure.
              if the returned value (after stripping and conversion to upper case) equals arg1, success
                   Note: if arg1 is not specified, a value of 1 is used.
     '*'  :
            Any value, other than '', is a success. 

     '**'  :
            Any value, even '', is a success. 
                  
   func_to_call is called using:
        func_to_call(returnedValue,serverVar,ndid,arg1,arg2,arg3,arg4,arg5)

   where
        returnedValue : the last value returned from the server
        serverVar     : the serverVar variable  (that is, the name of the serverVariable being polled)
        ndid          : # of attempts actually done
        arg1,arg2,arg3,arg4,arg5 : the arg1... arg5 provided in Poll_serverVer
                         If arg1, etc not provided, a '' will be used.

   Default: If func_to_call is not provided, then the returned values is saved under the ControlVars[serverVar] global array 
            (if ControlVars does not exist, it will  be created)

   Note: the getServerVarURL global javascript variable MUST be defined (it is NOT defined in svylibe2.js)
         I.e.; in svyUserHeaders.js and/or svyServerHeaders.js

   Dec 2010:the value of the _queryState global variable will ALWAYS be sent to the  server (as the "state" variable).

========================================= */

function  Poll_serverVar(sessName,serverVar,pOpts,arg1,arg2,arg3,arg4,arg5) {

var toGet ;
var checkFunc='', maxTries=0 ,  pauseMSec=0 , func_to_call='', amessage='', aid='' , atime=''; noStatus=0;

// specSections.eventQueue[ttag].labelVar= strip(daLabelVar).toUpperCase() ;   


if (arguments.length<1) {  alert('Poll_serverVar error: no session name provided '); return 0; } ;
if (arguments.length<2) {        alert('Poll_serverVar error: no serverVar provided ');     return 0; }  ; serverVar=strip(serverVar) ;
if (arguments.length>2) {
   if (typeof(pOpts)!='object') {
        alert('Poll_serverVar error: pOptions is not an object ');
        return 0;
   }
   if (typeof(pOpts.noStatus)!='undefined') noStatus=0;
   if (typeof(pOpts.checkFunc)!='undefined') checkFunc=pOpts.checkFunc ; 
   if (typeof(pOpts.pauseMSec)!='undefined') pauseMSec=pOpts.pauseMSec ; 
   if (typeof(pOpts.maxTries)!='undefined') maxTries=pOpts.maxTries ; 
   if (typeof(pOpts.func_to_call)!='undefined') func_to_call=pOpts.func_to_call ; 
//   if (typeof(pOpts.time)!='undefined') atime=pOpts.time ; 
   if (typeof(pOpts.message)!='undefined') amessage=pOpts.message ;
   if (typeof(pOpts.myID)!='undefined') aid=pOpts.myID ; 

}
  
checkFunc=strip(checkFunc);
if (checkFunc!='' && checkFunc!='**' && checkFunc!='*' ) {                         // check that func_to_call is valid
       if (typeof(window[checkFunc])!='function') {
           alert('Poll_serverVar error: checkFunc is not a function: '+checkFunc);
           return 0;
       }
  }
if (maxTries=='' || maxTries==0) maxTries=10000000 ;
if (pauseMSec=='' || pauseMSec==0) {
        pauseMSec=4000;
        if (typeof(queryFreq)!='undefined' && !isNaN(queryFreq))  pauseMSec=queryFreq ;
}

func_to_call=strip(func_to_call) ; 
if (func_to_call!='') {                         // check that func_to_call is valie
       if (typeof(window[func_to_call])!='function') {
            alert('Poll_serverVar error: func_to_call is not a function: '+func_to_call);
             return 0;
        }
  }

if (arguments.length<4) arg1='';   if (checkFunc=='' && arguments.length<7) arg1=1 ;
if (arguments.length<5) arg2='';
if (arguments.length<6) arg3='';
if (arguments.length<7) arg4='';
if (arguments.length<8) arg5='';

if (typeof(getServerVarURL)=='undefined') {
        alert('Poll_serverVar error: getServerVarURL is not defined ');
        return 0;
}
        
 toGet=getServerVarURL+'session='+sessName+'&varname='+serverVar ;
 toGet=toGet+'&state='+escape(strip(_queryState)) ;
 if (_spying==1) toGet=toGet+'&spy=1';

 if (noStatus!=1) {                            // unless suppressed, send status info to the server (along with request)
    toGet=toGet+'&id='+escape(aid);
         var foo=new Date() ; foo=foo.getTime() ;
    toGet=toGet+'&time='+foo;
    toGet=toGet+'&summary='+escape(strip(amessage)) ;
  }


  var GetIt = new svy_CreateXMLHTTP(toGet);
  GetIt.onDraw=callback_Poll_serverVar; 
 
  GetIt._timeout=30000  ; //  30 seconds until timeout
  GetIt._showstatus=false ; 
  GetIt._isText=true ;
  GetIt._cacheBuster=2 ; 

  GetIt._counter=0 ;            // callback will augment this

  GetIt._summary=pOpts  ;               // used to recreate 
  GetIt._comment='polling for '+ serverVar;
  GetIt._ID=sessName ;
  GetIt._status=func_to_call ;                  
  GetIt._variable=serverVar ;
  GetIt._variable2=checkFunc ;                  // checkfunc is specified via load(checkFun) 
  GetIt._variable3=maxTries;
  GetIt._variable4=pauseMSec ;
  GetIt._variable5=arg1 ;
  GetIt._variable6=arg2 ;
  GetIt._variable7=arg3 ;
  GetIt._variable8=arg4 ;
  GetIt._variable9=arg5 ;

  GetIt.load('polling server variable ',1000) ;  // 

  return 1 ;
}               //status

//      ==========================================
// callback function for Poll_serverVar
/*  ----
  GetIt._ID=sessName ;  GetIt._status=func_to_call ;   
  GetIt._variable=serverVar ;   GetIt._variable2=checkFunc ;    
  GetIt._variable3=maxTries;   GetIt._variable4=pauseMSec ;
  GetIt._variable5=arg1 ;   GetIt._variable6=arg2 ;  GetIt._variable7=arg3 ; GetIt._variable8=arg4 ; GetIt._variable9=arg5 ;
---- */

function callback_Poll_serverVar(oinfo,chk_val,rcode,hstat,nthdo) { 
var dofunc,cfunc,ok,toGet,ict,notOk;

// functions used for timeout call to ajax function
  function munch(aa) {
      function munch2() {
         GetIt.load() ;
         return 1 ;
     }
     setTimeout(munch2 ,GetIt._variable4) ;   
     return 1 ;
  }

// if here, the server has responded with something. Check it is a good response.
 notOk=0;
 if (hstat!='OK') {
     chk_val='Error in callback_Poll_serverVar -- ' + chk_val + ' :  ' + this._variable+ ' -- polling will continue (inform administrator if this becomes common).';
     E2_writeStatus(chk_val) ;
     notOk=1;
 }

ok=0;                           // assume no match, and keep going
ict=this._counter+1 ;                   // ict is the number of response recieved 
if (ict>=this._variable3) ok=1 ;       // if maxTries hit, then done (even if not success. 

if (ok==0 && notOk==0) {                    // not on maxTries. So check results (and there are results to check)
  cfunc=strip(this._variable2);
  if (cfunc=='' || cfunc==='*' || cfunc=='**') {                            // use default function check
     if (cfunc=='**') {
          ok=1 ;
     } else {
         achk=strip(chk_val.toUpperCase()) ;
         if (cfunc=='') {
            if (achk==this._variable5) ok=1 ;                                      // else, not a success
         } else {
            if (achk!='') ok=1;
        }    
    }                                   // cfunc=**
  }   else {                                            // call  checkFunc(returnedValue,serverVar,ndid,maxTries,arg1,arg2,arg3)
      ok= window[cfunc](chk_val,this._variable,ict,this._variable3,this._variable5,this._variable6,this._variable7,this._variable8,this._variable9);
  }                     //             checkFunc defined
}                       // maxTries not done


if (ok==1) {                                          // success or failure, call the func_to_call
  dofunc=this._status;
  if (dofunc=='')       {                       // no func_to_call -- just save variable
      if (typeof(ControlVars)=='undefined') ControlVars=new Object() ;
      ControlVars[this._variable]=chk_val ;
  }  else {                           // else, call the func_to_call
       window[dofunc](chk_val,this._variable,ict,this._variable5,this._variable6,this._variable7,this._variable8,this._variable9);   //  call  func_to_call(returnedValue,serverVar,ndid,arg1,arg2,arg3,arg4,arg5)
  }
  return 1 ;
}                        

// else, do again


 toGet=getServerVarURL+'session='+this._ID+'&varname='+this._variable  ;

var popts=this._summary ;                           // add summary info to request to server
var noStatus=0 ;
if (typeof(popts['noStatus'])!='undefined') noStatus=popts['noStatus'];
if (noStatus!=1) {
  var amessage='',myid='';
  if (typeof(popts['message'])!='undefined') amessage=popts['message'];
  if (typeof(popts.myID)!='undefined') myid=popts.myID ; 
  toGet=toGet+'&id='+escape(myid);
         var foo=new Date() ; foo=foo.getTime() ;
    toGet=toGet+'&time='+foo;
    toGet=toGet+'&summary='+escape(strip(amessage)) ;
}

  var GetIt = new svy_CreateXMLHTTP(toGet);
  GetIt.onDraw=callback_Poll_serverVar;                         // recursive!
 
  GetIt._timeout=30000  ; //  30 seconds until timeout
  GetIt._showstatus=false ; 
  GetIt._isText=true ;
  GetIt._cacheBuster=2 ; 
 
  GetIt._counter=ict ;            // current # of calls (augmented above)

  GetIt._comment='polling for '+ this._variable ;
  GetIt._ID=this._ID;
  GetIt._status=this._status ;
  GetIt._summary=popts ;
  GetIt._variable=this._variable ;
  GetIt._variable2=this._variable2 ;
  GetIt._variable3=this._variable3 ;
  GetIt._variable4=this._variable4 ;
  GetIt._variable5=this._variable5 ;
  GetIt._variable6=this._variable6 ;
  GetIt._variable7=this._variable7 ;
  GetIt._variable8=this._variable8 ;
  GetIt._variable9=this._variable9 ;
  GetIt._otherinfo = "continuing to poll server ";
  munch(1);                                             // internal function which calls the ajax function using as settimeout
  return 1 ;


}  // _ID save_g $


//===================
//functions for writing message (for use on client pages)

//----- write to the transient "alert" message area

// write to the header block
function writeHeader(amess,aclass) {
  var avv ;
  if (arguments.length<2) {
    avv=E2_writeHeaderMessage(amess) ;
  } else {
    avv=E2_writeHeaderMessage(amess,aclass) ;
  }
  return avv ;
}

// write to the alert block (optional duration is seconds to fade away)
function writeAlert(amess,duration) {
  var avar ;
  if (arguments.length<2) {
      avar=E2_writeAlert(amess) ;
   } else {
      avar=E2_writeAlert(amess,'',1,duration*1000) ;
   }
  return avar ;
}


// write to the alert block 
function writeMessage(amess,aheader) {
  var avar ;
  if (arguments.length<2) {
      avar=E2_writeMessage(amess) ;
   } else {
      avar=E2_writeMessage(amess,aheader) ;
   }
  return avar ;
}


// write to the "description" block in the footer
function writeFooter(amess,aheader) {
  var avar ;
  if (arguments.length<2) {
      avar=E2_writeQdesc(amess) ;
   } else {
      amess='<b>'+aheader+'</b>: '+amess;
      avar=E2_writeQdesc(amess) ;
   }
  return avar ;
}

//============
// create a string with name and project
function E2_makeProjName(ainst) {
var uu,a1 ;
var vv,tt,rr=[];

ainst=strip(ainst);

 if (ainst.substr(0,1)!='$') {
      vv=parseAt(ainst,'.');
      rr[0]=strip(vv[0]) ;
      rr[1]='' ;
 } else {
     tt=parseUsing(ainst,'$','_',1);
     vv=parseAt(tt[2],'.');
     rr[0]=strip(vv[0]) ;
     rr[1]=strip(tt[1]) ;
  }

 uu=rr;

a1=uu[0];
if (strip(uu[1])=='') return a1 ;
a1=a1+' (in project '+uu[1]+')';
return a1;
}

// ==================================




/* ============================================================
List of functions...

E2_start(specfile,sStart,astat)  -- start a session, using specfile. sStart is first section. Astat used internally

Functions called by E2_start. Several are "recursive", and after their internal recursion they call E2_start (using special values of astat)
   E2_start_sections(anode,specFile)  -- read <sections>  portions of a specFile read into anode.
   E2_start_makeFileList_xml(anode)            -- read <file> portions of anode (which should contain the DOM object of the specfile)
   E2_start_startVars(startVars)      -- Parse the "startup variables" (typically provided in the ?xx portion of the request for the home page)
   E2_start_divs()                     -- Create several required & optional blocks (DIVS) in the main document

   E2_start_spec(afile)                 -- Reads  XML "spec" file
   E2_start_includes_file(toget,0)          -- read "include" files (as specified in the SPEC file)
   E2_start_includes_sub(toget,subList)         -- read "include" subroutines  (as specified in the SPEC file)

   E2_recoverHistory()                   -- read the history-of-parameters files survey from the server, and store its values in global history

   E2_start_getXmlModules(stat,act)      -- read module files from server. Uses _specifile global. stat and act used internally
   E2_start_parseModules()              -- parse the module-file DOM nodes in xmlModulesBase, store them in xmlModuleList
   E2_paramsURL(atype,afile)       -- using global headers, return the url to a session paramter file (type=SESSION, ROUND, or FILE)

   get_CAPfile(toget,daSection,daGroupNum,1)  -- get one or more xml parameter files
   E2_processXmlParams(_paramNode)              -- Parse xml file's content (saved in _paramNode) , save survey global variables and arrays

Functions to write/toggle messages to various blocks
        E2_writeHeaderMessage(aname,aclass) -- write amess the _headerMessage. If amess="", make _headerMessage hidden. aclass can be a css class to use
        E2_writeHeaderButton(amess,avis)      --  write amess to the  _headerButton block, or use avis to set visibility
        E2_writeHeaderTimer(amess,avis,aclass)      --  write amess to the  _headerTimer block, or use avis to set visibility, and aclass to set class
        E2_writeName(aname)             --  Write aname string to the _nameBlock
        E2_writeQdesc(aname)            --   Write aname string to the _QDescBlock
        E2_writeStatus(amess,saveFreq)  -- write amess to the status block, and save (with saveFreq) to the status-history variable
          E2_toggleStatus(istate)          -- toggle, or set, visibility of the status block
          E2_viewStatusHistory(ido)         -- write & view the status history variable in the _messageBlock (ido=0), or _temporary workspace
        E2_writeAlert(amess,aheader,vstate,iduration)  -- write amess string, and optionally a header, to the _alerteBlock. Visibility can be set with vstate
        E2_writeBlock(whichBlock,amess,aheader,vstate,aclass)        -- helper function (used by above) to write messages to DIVS
        E2_writeMessage(amess,aheader,vstate) -- write amess string, and optionally a header, to the _messageBlock. Visibility can be set with vstate. Used by above.

       E2_makeProjName(asessName)   -- create a string with name and project (given a session name)

Functions to work with DOM nodes
        E2_xmlToDom(xnode,oldnode,skipTag)       --  Copy xnode node tree to new node, or appended to oldnode. Skip root of xnode if tag=skiptag
        E2_copyNode(xnode,oldnode,skipTag)           synonym for E2_xmlToDom
        E2_getNodes(adom,taglist,first1)         --  Read nodes, listed in taglist string, from top-children of adom DOM object. first1 used to just get first child
        E2_getNodeText(adom,nth) {               -- return string from a text node from a dom node
        E2_getTextNode(adom,nth) {               --  synonym for E2_getNodeTex

        E2_addIdx(doNode,jiter,tlist,tclass)            --  Add IDX tags to all elements, under doNode, with a tagname in the IDXTAGS list
        E2_copyAttributes(fromNode,toNode,noList) -- Copy attributes from fromNode to toNode. Skip attribues in noList (case insensitive match)
        E2_addComment(toNode,acomment)               --  add a comment to the toNode DOM anode
        E2_xmlToString(xnode,skip1,noComment)        -- copy XML node to a string. Starts with nodename of xnode. Includes all comments and extraneous spaces

        copyXmlToObject(xnode,objectName,ido,nmlist)   read XML object and save it's contents to a datased stored in an  object variable 
        copyObjectToXml(aobject,aname,aid   --Create an xml node from an object.


Functions to display section & group
       E2_loadSection(daSection,gnum)               -- load daSection section, group gnum (gnum is almost always 1)
       E2_showGroup(daGroup,daNumber)       -- in current seciton, display group with name=daGroup, or with number daNumber
       E2_modulesCreate(anode)               --   process CREATE nodes (create new modules by calling
       E2_contentMake(useNode,asec,anumber,addTo)  -- Process a child node of <content> (such as literal, modules, etc).  Return new node, or attach to addTo
       E2_node_doIf(anode,isif)             -- Check <if> conditions. Return 1 if true, 0 if false. isif controls where the logical equation is read from
       E2_attributeToNode(chkit,winid,anode)               -- Copy attributes stored in the chkit node (from windi ,or from anode)
          E2_attributeToNode2(toNode,fromNode) --  add attributes to element (or elements)

      E2_goSection(isecName,gName)               -- the default function called after ELEMENT processing -- takes care of setValue, etc.
      E2_setValue(cnode)                -- look for a setValue in cnode, and do what it says.

      stuff= E2_parseEqu(astring)       -- stuff.varname (or '' if no x=) and stuff.value (equation string).


Event functions (button, timer, etc)
        E2_makeButton(adiv,astring,funcname,arg1,arg2,arg3,arg4,arg5,arg6,arg6,arg8) -- Create a button, in adi ID. Displays astring, calls funcname with arg1...
        E2_createTimer(ttag,initit) -- start a countdown timer in ID=anid, of secDo seconds. Dispopts are optional display optons.
        E2_updateTimer(secLeft,divId,dispopts,forcedisp)        -- Update timer display in Id=ttid. secLeft is seconds left, specId points to display options
        E2_createQuery(ttag)                           -- Query server for server variable (ttag used as lookup in eventQueue
           E2_callbackQuery(oinfo,chk_val,astat0)  -- called by above

         E2_doEquations(tonode,setNode)    -- process equations in the doonode node, that may contain if subsets. Add values to the tonode value attribute
            E2_doEquations1(thisnode,equlist)        --  process equations in equlist; thisnode is specified if setting values for a particular dom node

        E2_setupButtons(gEvents,gtag)                    -- create buttons from <button>, gEvents is a node pointing to an <events> subtree
        E2_setupTimers(gEvents,gtag)                    -- create countdown timers from <timer>, gEvents is a node pointing to an <events> subtree
        E2_setupQuery(gEvents,gtag,grpName)                    -- create server queries from <query>, gEvents is a node pointing to an <events> subtree

        E2_doEvent(ttag,at1)                            -- process an event (button, timer, etc) referenced by eventQueue[ttag]

Query server
        Poll_serverVar(sessionName,serverVar,pOpts,arg1,arg2,arg3)  -- poll server for variable, call a function when found


Note: the following functions don't start with E2_

checkXMLDocErr   loadJsCssFile copyXmlToObject      saveObjectElementValue
copyObjectToXml  get_CAPfile   simpleHistoryRecode   replaceNAMES
doAddStyles      parseDoList   expandSaveName        processSubmitSave
resolveIndex      alert2       Poll_serverVar       writeHeader  
writeAlert       writeMessage  writeFooter        svy_setVal

----- */











