 /* General library. Contains functions to support various input element fancifications, such as adding events.
   Also contains some simple string manipulation utilities

   Note: some of these require the functions in xmlrequest2b.js

   See svyinputs2.txt for the details on these procedures.

   Note: uses svy_CreateXMLHTTP and related functions specified in xmlRequest2b.js

***  Procedure list  ***

String manipulation:
  wmatch    =  Word_inString(needles,haystack)      : return first word in haystack that matches (possibly wildcarded) a word in needles (both are strings)
  astring   =  manyDots(aval,amax,dastring)  : create a string of dots, the number cycling between 1 and amax
  aword     =  parseUsing(astring,leftc,rightc,all3)    : return phrase between the first leftc char and first rightc char -- such as ( and )
  aeleminfo =  parseArrayIndex(arrayName)    : short cut to parseUsing(astring,'[',']',1)
  aword     =  parseUsingOuter(astring,leftc,rightc,all3)    : return phrase between the first leftc char and last rightc char -- such as [ and ]
  anarray   = parseAt(astring,adelim)    : parse word into 2 element array, at adelim (adelim=',' if not specified)
  thewords  =  getWord(astring,nth,adelim)   : parse string to array of words, or extract nth word
  arglist   = parseArgString(astring)        : parse a comma delimited string into an array-- recognizes ' and " (so you can quote ,)
  newstring =  strip(astring,which)          : strip spaces
  newstr    =  space(str,what)               : remove/replace internal spaces
  atime     =  Seconds_ToTime(nseconds)      : convert nseconds to time format (i.e.;  hh:mm:ss
 newname=cvtToArrayName(aname0)             convert a varname_n_ to varname[n].
 newname=cvtFromArrayName(aname0)           convert a varname[n] to varname_n_.
 damatch=matchWild(orig,candidate);         find portion of candidate "covered" by a * in orig
 tarray=CSVToArray(astring,delim,qchar)     parse a CSV string to an array of arrays
 newString=splitString(astring,ilen,abr)     Split string into ilen long chunks
 aTable=makeATable(alist,ncols2,astyle,athrow,tablespec) : use alist array to make an HTML table

 notSame=compareStrings(string1,string2,optstring) : Compares two strings, returns first character different

 makeProjName(aname) create a string with name and project
 extractProjectName(projName) : parse a $proj_name into "name" (rr[0]) and "proj" (rr[1])

Array manipulation:
  nearray  = Concat_Arrays(a1,a2,a3,a4,a5)              : concatentate from 1 to 5 arrays or nodelists or elements (or copy an array)
  theindex = find_InArray(tofind,anarray,adef,verbose)  :   Case insensitive find  in array. Returns index into anarray. Ignores element 0
  ii=mapIndexToMatrix(ival,idim,nrows,ncols)            : map from integer to round, or col, identifier
  removeAllNodes(aList)                              : remove all nodes listed in aList (aList either an array, or a collection)

Global variable read/write:
  avalue=Read_Global(varname,undef,anindex)       : read the  global variable specified in the varname string (can be an array element). undef is optional default value
  Save_Global(varname,avalue,anindex,forceArray)  : save avalue to global variable specifed in the varname string. varname can be an array element. Avalue can be an object/array

  Save_GlobalHistory(nowr)                        : save all current global variables to a history archive
  Retrieve_GlobalHistory(nowr,No_overwrite)       : retieve the "nowr" set of global variables, and copy them to the current set of globals
  Reset_recentHistory(nowr)                           : clear "recent" history variables, or copy nowr round to recent round
  
  avalue=Read_priorGlobal(nRound,varname,undef,anindex)       : read the  global variable from round nround, specified in the varname string (can be an array element). undef is optional error message
  Save_priorGlobal(nround,varname,avalue,anindex,forceArray)             : save avalue to global variable for the nround round, specifed in the varname string. varname can be an array element

  Show_Variables(adiv,retStr)                               : display, in new window, current values of survey global variables

Element attribute manipulation:
 aval=getAttributes(anode,attlist,adefs)    --  Read attributes, listed in attlist string, from the anode DOM object. anobj can contain prior values

   daval= get_elemValue(e1,defval,mods,all)     : read value of an element (INPUT, OPTION, or other). returns defval if not found (radio and checkbox)
   ok= set_elemValue(e1,newfval)          : set value of an element (INPUT, OPTION, or other)

  qis  =   Find_Class(daclasslist,this1)       : T/F if classlist (a string var) contains  is one of the classes of the this1 element.
  qis  =   Find_Name(namelist,this1)           : T/F if namelist (a string var) contains the value of this1's name attribute
  nlist  =  get_elements(a_names,classname,namelist )  : Return an array of elements in "a_name", have a class in classname, and has a name in namelist
DEPRECATED  nlist  =  get_elementsC(cname,a_names,classname,namelist,cbase )  : Caching version of get_elements
  nlist  =  delete_elements(a_names,classname,namelist )  : Delete all nodes (and their children) that match a_names, etc.
  nlist  =  get_elements_remove(a_name,classname,namelist )  : Return an array of elements in "a_name", thad do NOT have  a class in classname, and NOT a name in namelist

  Add_Attribute(elemList,d_attribute,d_val,append,replacechar) :  Add an attibute, and its value, to elemList elements.
    update_styles(elemList,styleString)      : Update style attribute to elemList elements
    update_class(elemList,classname)      :   Add a class to elemlist elements


Event handlers (typically used as afunction in the Add_Event procedure)
  Add_Event(elemList,etype,afunction)      :  Add event handlers; for etype events using afunction as the handler, to a set of elements
    Arrow_Increment(e)         :   Allow use of arrow keys to change numeric values; uses the "default" attribute as a default value.
    Confirm_Input(e)           : Check an input element's values for questionable value (uses minConfirm and maxConfirm and allowedConfirm and nameConfirm attributes)
    Check_Bounds(e)            :   Check the bounds of an input field for min and max (using min and max atttributes)
    Check_Char(e)              :  Capture keyboard and return an identifying string if arrow or other such key is hit
    disable_autocompletes(daflag)  :  Turn off autocompletes AND contextmenu in all input boxes with a daflag class

File retrieval procedures:
    -- retrieve XMLfilename, save to varname, after saving call afunc(arg1,...,arg7)
    Get_File(filename,varname,acomment,afunc,arg1,arg2,arg3,arg4,arg5)  -- retrieve text filename, save to varname, after saving call afunc(arg1,...,arg5)
    Post_toServer(url,acontent,varname,acomment,afunc,arg1,arg2,arg3,arg4,arg5)  -- put acontent to server (using aURL), save response to varname, after saving call afunc(arg1,...,arg5)
    Display_Content(varname,target,wopts) : Show  contents  of the variable specified in "varname" in the target window (varname usually html file from a Get_File call). Varname MUST be a string!

HTML Display and check procedures:
   Check_RadiosDone(formname,varlist,errmess)       :    Checks that a list of radio buttons have been chosen from.
   Highlight_One(me1,aname,astyle)                 : Highlight (change style) of one of a set of named elements
   writeStatus(m1)  : write a message to the page status div (at the bottom of the screen
   displayDiv(adiv,todo)                        : adiv to toggle between block and none. Or, if todo specified and is not 0 or '', to the todo status
   htmlSurround(tagname,string)           : return a string: <tagname>string</tagname> (used in <set>)

Other:
    make_procString(pname,arg1,arg2,arg3,arg4,..,arg8)  : Make a function string, with quoted arguments, suitable for use as an onClick, etc argument.
    Launch_Proc(pname,pwait,arg1,arg2,arg3,arg4,arg5,arg6,arg7)   : Launch a procedure using setTimeout
    evaluate_function(funcString,amess,elem)                 : evaulate a string containing a function
    isIe()                                              : if Internet Explorer, return true
    resolveRelativeURL(url,baseUrl)             : if url is "relative", prepend the directory of the baseURL
    debugOn(level)      : return true if debug enabled and has level >alevel (alevel default value is 1)
    svy_cloneObject(what)                          : CLONE an object (that may contain other objects and arrays)

     numSibling(anode,notext)                  : number of siblings (including self) of anode (can exclude non-elements
     whichSibling(anode,notext)                : position number in siblings of anode (1,...,)
     getSibling(anode,nth,notext)              : return pointer to nth sibling of anode (possibly skip non-elements)
     removeHTMLTags(htmlString)                : extract text from a string containing html 

  alertD(string)                            : short cut for confirm, where cancel aborts the program

   isIE :  return 1 if Internet Explorer
   isfalse  : returns a false


================================ */
/* return 1 if ie
    If ok8 =1, then if ie8 return false (that is, only detect ie versions Lt 8)
*/
 
function isIE(ok8) {
  if (arguments.length<1) ok8=0;
  var isMoz=typeof(addEventListener);
  if (isMoz!=='undefined') return false ;   // understands mozilla stuff -- return false

  var isIE=typeof(attachEvent);
  if (isIE=='undefined') return false ;         // doesnt udnerstand ie stuff -- return false

  if (ok8==0) return true ;                     // ie functions known, and don't check for ie8: so true

  var isIE8=typeof (window.external.AddService)  ;
  if (isIE8!=='undefined') return false ;          // exists, so this is NOT ie < 8 (so return false)
  return true ;

}

function isfalse(foo) { return false};

/* resolve a relative URL, using the directory of the baseurl
   If url starts with a /, just return url
   Else, prepend the "directory" portion of baseurl to url, and return
        In /foo/bar/help.htm, the "directory" portion would be "/foo/bar/"
Special case: if aurl starts with ~, then strip the ~, and append this stripped string to the instrumentBaseUrl
                (thus, ~ can be used to find files in the "instruments main directory"
*/
function  resolveRelativeURL(url,baseUrl)    {
var afile,iss,ahdr;
var ainst ;

if (url.substr(0,1)=='/') return url ;

if (url.substr(0,1)=='~') {
 ainst='';
 if (typeof(thisIsControl)!=='undefined') {
   ainst=instNameUse;
 } else {
   if (typeof(SvyGlobals)!=='undefined' && typeof(SvyGlobals['_INSTRUMENTBASEURL'])!=='undefined' ) {
      ainst=SvyGlobals['_INSTRUMENTBASEURL'];
   } else {                                       // control ?
       alert('Error: no instrument name variable (for use if ~ in include file) ');
   }
 }
 afile=ainst+url.substr(1);

//alert('afile='+afile);
 
 return afile
}       

 
iss=baseUrl.lastIndexOf('/');
if (iss<0) {
  afile='/'+url;
} else {
   ahdr=baseUrl.substr(0,iss);
   afile=ahdr+'/'+url
}
return afile ;
}


//==============================
// compare two strings, return first character that is different (1= means first character)
// if strings are identical, return a 0
// By default, strings will have spaces stripped, and will be capitalized
// You can control this with optstring
// optstring should be a space delimited list of options
// Supported options are: case  nostrip  crunch  tabspace crlspace
//  case: case sensitive search
//  strip: strip leading and trailing spaces
//  crunch: crunch internal spaces (sequence of spaces collapsed to one space
//  tabspace: convert tabs to 1 space
//  crlfspace : convert crlfs to 1 space
// Note that crunch occurs AFTER strip (a crunch will NOT remove a leading & trailing space)
// examples:
//  nn=compareStrings('this is real ','This is real') --> 0
//  nn=compareStrings('this is real ','This is real','CASE') --> 1
//  nn=compareStrings('This is real ','This  is real') --> 6 (two spaces in string 2 after This)
//  nn=compareStrings('This is real ','This  is real','CRUNCH') --> 0
//  nn=compareStrings('This    is real ','This\tis real','CRUNCH TABSPACE ') --> 0  (tab is converted to spacd

function compareStrings(string1,string2,optstring) {
 
var icase=0,istrip=1,icrunch=0,itabspace=0,icrlfspace=0,a1,a2,i;
if (arguments.length<3) optstring='';
optstring=' '+optstring+' ';
optstring=optstring.toUpperCase();
if (optstring.indexOf(' CASE ')>-1) icase=1;
if (optstring.indexOf(' NOSTRIP ')>-1) istrip=0 ;
if (optstring.indexOf(' CRUNCH ')>-1) icrunch=1;
if (optstring.indexOf(' TABSPACE ')>-1) itabspace=1;
if (optstring.indexOf(' CRLFSPACE ')>-1) icrlfspace=1;

if (istrip==1) {
  string1=strip(string1); string2=strip(string2) ;
}
if (icase==0) {
  string1=string1.toUpperCase(); string2=string2.toUpperCase() ;
}
if (itabspace==1) {
  string1=string1.replace(/\t/g,' ');
  string2=string2.replace(/\t/g,' ');
}
if (icrlfspace==1) {
  string1=string1.replace(/\n/g,' ');
  string2=string2.replace(/\n/g,' ');
}
if (icrunch==1) {
  string1=string1.replace(/ +/g,' ');
  string2=string2.replace(/ +/g,' ');
}

for (var i=0;i<string1.length;i++) {
  if (i>=string2.length) return 1+i ;
  a1=string1.substr(i,1); a2=string2.substr(i,1);
  if (a1!==a2) return 1+i ;
}
if (string2.length>string1.length) return string1.length+1 ;

return 0;
}



 
//==========================

// Strip leading and/or training spaces
// if which is L then leading only (left),
//             R, then trailing (right) only
// otherwise (if not specified), leading and traling
function strip(str,which) {
  if (typeof(str)=='number') {str=str+''; return str; }
  if (typeof(str)!='string') return str;
  if (arguments.length<2) {
      which=''
   } else {
    which=which.toUpperCase();
    which=which.replace(/\s+/g,'')
    which=which.substring(0,1);
  }
  if (which=='L')  return str.replace(/^\s+/, '');
  if (which=='R') return str.replace(/\s+$/, '');
  return str.replace(/^\s+|\s+$/g, '');                         // trim both sides

}


// ===============================
// convert a varname_n_ to varname[n].
// Last character MUST be a _. Thus, varname_3_a will NOT be changed
// if iboth, return [name,index] (rather than 'name[index]')
function cvtToArrayName(aname0,iboth) {
if (arguments.length<2) iboth=0 ;
  var aname,aname1,aname2,ifoo;
aname=aname0.replace(/\s/g,'');aname=aname.toUpperCase();
if (aname[aname.length-1]!='_') {                // no trailing _
  if (iboth==1) return [aname,''];
  return aname;   
}
aname1=aname.substr(0,aname.length-1);          // trim trailing _
ifoo=aname1.lastIndexOf('_') ;                  // find "second to last _ "
if (ifoo<0) {                                   // there isn't one, so trailing _ is part of a varname (odd, but permitted)
  if (iboth==1) return [aname,''];
  return aname;   
}

if (iboth==1) {                         // found a name_n_ syntax
  return [aname1.substr(0,ifoo),aname1.substr(ifoo+1) ] ;
}
aname2=aname1.substr(0,ifoo)+'['+aname1.substr(ifoo+1)+']';
return aname2 ;
}

// ===============================
// convert a varname[n] to varname_n_.
function cvtFromArrayName(aname0) {
  var aname,aname1,aname2,ifoo;
aname=aname0.replace(/\s/g,'');aname=aname.toUpperCase();
if (aname[aname.length-1]!=']') return aname;    // no trailing _
aname1=aname.substr(0,aname.length-1);
ifoo=aname1.lastIndexOf('[') ;
if (ifoo<0) return aname;                        // only a trailing _
aname2=aname1.substr(0,ifoo)+'_'+aname1.substr(ifoo+1)+'_';
return aname2 ;
}


//================
// orig has a * in it : compare orig to anew, if wildcard match, return the part of anew "covered" by the * in orig
// or, return orig with this portion replacing * (if all1=1)
// in either case, if no match return a ''
function matchWild(orig,anew,all1) {
if (arguments.length<3) all1=0;

var iat,p1='',p2='',iat2=0;
iat=orig.indexOf('*');
ilen=orig.length;
if (iat<0) return ''    ; // no wild, so no match
if (iat>0)  p1=orig.substr(0,iat);
if (iat<ilen-1) {
  p2=orig.substr(iat+1);
  iat2=p2.length;
}

if (iat>0) {
  anew1=anew.substr(0,iat);
  if (anew1!=p1) return '' ;
}
if (iat2>0) {
    iv=anew.length-iat2 ;
    anew2=anew.substr(iv);
    if (anew2!=p2) return '';
} else {
   iv=anew.length;
}

amatch=anew.substr(iat,iv-iat);

if (all1==0) return amatch;

amatch=p1+amatch+p2 ;
return amatch;

}


//===============
// parse into 2 element array, using adelim as delimiter
function parseAt(astring,adelim) {
  var ares=[] ;
  if (typeof(astring)!='string') { ares[0]=astring; ares[1]=''; return ares };

  if (arguments.length<2) adelim=',';
  i1=astring.indexOf(adelim);
  if (i1==-1) {
        ares[0]=astring ;
        ares[1]='' ;
       return ares ;
  }
  ares[0]=astring.substr(0,i1);
  ares[1]=astring.substr(i1+adelim.length) ;
  return ares ;
}

//===============
// short cut to parseUsing... same as   vv=parseUsing(astring,'[',']',1)
function parseArrayIndex(astring) {
 var vv;
 vv=parseUsing(astring,'[',']',1);
 return vv;
}

//===============
// parse from the var, between first d1 and first d2 characters (following d1)

function parseUsing(thevar,d1,d2,allp) {
if (typeof(thevar)=='undefined') {
    writeStatus('%WARNING: Undefined in parseUsing ');  
   return '' ;
 }
 if (arguments.length<2) return thevar ;
 if (arguments.length<3) d2='' ;
 if (arguments.length<4) allp=0 ;
 allp=strip(allp);
var a3=new Array('','','') ;

 var dares='' ;
if (strip(d1)==='') {                  // no first delim means :"everything upto the 2nd delim"
      var idb=thevar.indexOf(d2) ;
      if (idb<1) {                // cant find 2nd delim.. so use entire string    
         if (allp!=1)  return thevar ;
         a3[1]=thevar ;                 // no 2nd delimiter, everything matches
         return a3 ;
      }
     if (allp!=1)  return thevar.substr(0,idb) ;
      a3[1]=thevar.substr(0,idb) ;                 // match is everything up to this 2nd delminter -- there is no "leading" portion
      a3[2]=thevar.substr(idb+1) ;                           
      return a3 ;
}
if (strip(d2)==='') {                   // no second delim means "everything after the first delim"
      var ida=thevar.indexOf(d1,ida);
      if (ida<1)  {                       // cant find first delim, so use ''
         if (allp!=1) return '';                     // no first delim, so nothing to return
         a3[0]=thevar ;                        // no match to first, so all in preceder
         return a3 ;
      }
      if (allp!=1)  return thevar.substr(ida+1) ;
      a3[0]=thevar.substr(0,ida) ;                      // no trailer
      a3[1]=thevar.substr(ida+1) ;
      return a3 ;
}

//there are 2 delimters 

 var ida=thevar.indexOf(d1,ida);
 if (ida==-1) {
      if (allp!=1)    return '' ;                     // can't find first
      a3[0]=thevar ;
      return a3 ;
 }

 var idb=thevar.indexOf(d2,ida+1);
 if (idb<ida) {
      if (allp!=1)  return thevar.substr(ida+1) ;               // cant find 2nd
      a3[0]=thevar.substr(0,ida)  ;
      a3[1]=thevar.substr(ida+1)  ;
      return a3 ;
}

var tt=idb-(ida+1) ;

if (allp!=1) return thevar.substr(ida+1,tt);
a3[0]=thevar.substr(0,ida);
a3[1]=thevar.substr(ida+1,tt);
a3[2]=thevar.substr(idb+1) ;
return a3 ;

}


//===============
// parse from the var, between firat d1 and last d2 characters

function parseUsingOuter(thevar,d1,d2,allp) {
if (typeof(thevar)=='undefined') {
    writeStatus('%WARNING: Undefined in parseUsingOuter ');
   return '' ;
 }
 if (arguments.length<2) return thevar ;
 if (arguments.length<3) d2='' ;
 if (arguments.length<4) allp=0 ;
 allp=strip(allp);
var a3=new Array('','','') ;

 var dares='' ;
if (strip(d1)==='') {                  // no first delim means :"everything upto the 2nd delim"
      var idb=thevar.lastIndexOf(d2) ;
      if (idb<1) {                // cant find 2nd delim.. so use entire string    
         if (allp!=1)  return thevar ;
         a3[1]=thevar ;                 // no 2nd delimiter, everything matches
         return a3 ;
      }
     if (allp!=1)  return thevar.substr(0,idb) ;
      a3[1]=thevar.substr(0,idb) ;                 // match is everything up to this 2nd delminter -- there is no "leading" portion
      a3[2]=thevar.substr(idb+1) ;
      return a3 ;
}
if (strip(d2)==='') {                   // no second delim means "everything after the first delim"
      var ida=thevar.indexOf(d1,ida);
      if (ida<1)  {                       // cant find first delim, so use ''
         if (allp!=1) return '';                     // no first delim, so nothing to return
         a3[0]=thevar ;                        // no match to first, so all in preceder
         return a3 ;
      }
      if (allp!=1)  return thevar.substr(ida+1) ;
      a3[0]=thevar.substr(0,ida) ;                      // no trailer
      a3[1]=thevar.substr(ida+1) ;
      return a3 ;
}

//there are 2 delimters 

 var ida=thevar.indexOf(d1,ida);
 if (ida==-1) {
      if (allp!=1)    return '' ;                     // can't find first
      a3[0]=thevar ;
      return a3 ;
 }

 var idb=thevar.lastIndexOf(d2);
 if (idb<ida) {
      if (allp!=1)  return thevar.substr(ida+1) ;               // cant find 2nd
      a3[0]=thevar.substr(0,ida)  ;
      a3[1]=thevar.substr(ida+1)  ;
      return a3 ;
}

var tt=idb-(ida+1) ;

if (allp!=1) return thevar.substr(ida+1,tt);
a3[0]=thevar.substr(0,ida);
a3[1]=thevar.substr(ida+1,tt);
a3[2]=thevar.substr(idb+1) ;
return a3 ;

}


//==============
// return a list of words, or the nth word (where nth=1 means "first . Returns '' if object, or if nth > # of words
// if nth an array, get words from nth[0] to nth[1] INCLUSIVE. 
// i.e.;  astring="this is my string of words "
//  getWord(astring,1) = "this"
//  getWord(astring) = array of 6 elements 
//  getWord(astring,7)=''
//  toget=[3,4] ;  foo=getWord(astring,'',toget)  = "my string"

function  getWord(astring,nth,adelim)   {

  var   is2,foo,foonew,a1,j,n1,n2,aa;
  if (arguments.length<2) nth=0;
  if (arguments.length<3) adelim=''; adelim=strip(adelim);

  if (typeof(astring)=='object') return '' ;
  if (typeof(astring)=='number') {
        if (nth!=0) return '' ;
        return astring  ;
   }
   if (typeof(astring)=='undefined' || typeof(astring.split)!=='function' ) return 'getWord_astring_error' ;

  is2=0;
  if (typeof(nth)=='object' && nth.length && nth.length>1) is2=1;
  if (adelim=='') {
        var foo=astring.split(' ');
        var foonew=new Array() ;
        for (var j=0 ; j<foo.length;j++){
           var a1=strip(foo[j]);
           if (a1=='') continue ;
           foonew[foonew.length]=a1 ;
        }        
   } else {
        if (typeof(astring)=='undefined' || typeof(astring.split)!=='function') return 'getWord_delim_error';
        var foonew=astring.split(adelim);
   } 

   if (is2==1) {                        // subset of the words 
       n1=parseInt(nth[0]) ; n2=parseInt(nth[1]);
       if (isNaN(n1) || isNaN(n2)) return ''  ;
       if (n1>foonew.length || n2 <1) return '';
       if (n1<1) n1=1 ; if (n2>foonew.length) n2=foonew.length ;
       if (n1==n2) return foonew[n1-1] ;
       aa=adelim ; if (aa.length==0) aa=' ';
       var arf=foonew.slice(n1-1,n2) ;
       arf=arf.join(aa);
       return arf ;
   }

   if (nth>0)  {
        if (nth>foonew.length) return '' ;
        return foonew[nth-1] ;
   }
   return foonew ;                       // return the array
}

//========================
// parse a string into an array, using , as seperator -- but NOT if comma is inside of " or '
function parseArgString(vv,noquote) {
 if (arguments.length<2) noquote=0;
 var astring,i,nowquote,i,ac;
 var fargs=new Array();
 astring='';
 nowquote=0 ;   //       0=no quote, 1=', 2="
 for (var i=0 ; i<vv.length; i++){
   ac=vv.charAt(i);
   if (ac==',') {                               // might be new argument?
       if (nowquote==0) {                       // yes, it is
          astring=strip(astring);
          if (astring.charAt(0)=='"' && astring.charAt(astring.length-1)=='"') {         // strip " from end
              astring=astring.substr(1,astring.length-2);
          } else {
              if (astring.charAt(0)=="'" && astring.charAt(astring.length-1)=="'") {         // strip " from end
                 astring=astring.substr(1,astring.length-2);
              }
          }
          fargs=fargs.concat(astring);
          astring='';                           // start building next arguments
       } else {                                // in a quote
           astring=astring+ac ;                 // to treat , as a normal character
       }
       continue ;
    }                                           // , check

    if (ac=='"' ) {                             // a " 
           if (nowquote==0 ) {                    // first " 
               nowquote=2  ;                                // turn on " flag
           } else {
             if (nowquote==2) nowquote=0         // turn off flag
           }                                    // if nowquote=1, treat " as normal character
           astring=astring+ac ;                 // in any case, add it 
           continue ;
    }

    if (ac=="'" ) {                             // a -
           if (nowquote==0 ) {                    // first - 
               nowquote=1  ;                                // turn on - flag
           } else {
             if (nowquote==1) nowquote=0         // turn off flag
           }                                    // if nowquote=2, treat ' as normal character
           astring=astring+ac ;                 // in any case, add it
           continue ;
    }

    astring=astring+ac ;                 // all other cases -- add character
 }
 astring=strip(astring);
 if (astring.charAt(0)=='"' && astring.charAt(astring.length-1)=='"') {         // strip " from end
        astring=astring.substr(1,astring.length-2);
 } else {
    if (astring.charAt(0)=="'" && astring.charAt(astring.length-1)=="'") {         // strip " from end
        astring=astring.substr(1,astring.length-2);
    }
 }
 fargs=fargs.concat(astring);               // add remainder
 return fargs;
}

// CLONE an object (that may contain other objects and arrays)
function svy_cloneObject(what) {
    for (i in what) {
        if (typeof what[i] == 'object') {
            this[i] = new svy_cloneObject(what[i]);
        }        else {
            this[i] = what[i];
        }
    }
    return 1;
}

//=================== 
// given a list, create a table
// alist: array of string element to use when creating table
// ncols: number of columns in this table. If 2 elment array, 2nd element is "new row" signal (if not specified, 5 is used)
//              the new row signal, if specified, is compared to elements in alist. If an element matches
//              (exactly, case and spaces are used), then a new row is started (the element(s) that match
//              will NOT be included in the table
// astyle: style to use when displaying elements of table (use '' if no extra styles are to be added)
// th1  : if specified, use this as top row(s) of table, using <th>  (use 0 to ignore)
// tablespec: string to include verbatim in the <table >

function makeATable(alist,ncols2,astyle1,athrow,tablespec) {
var ncols,newRowSignal,lookForSignal=0,newRowSignal='';
var astyle,im,iastyle,bstyle,igoo ;

if (arguments.length<2) ncols2=5 ;
if (arguments.length<3 || astyle1===0 ) astyle1='';
if (arguments.length<4 || athrow===0 || athrow==='') athrow=[] ;
if (arguments.length<5) tablespec='';

if (typeof(ncols2)=='object') {
  ncols=ncols2[0];
  newRowSignal=ncols2[1];
  lookForSignal=1;
} else {
  ncols=ncols2;
}

astyle=[];
if (typeof(astyle)!=='object') {
   astyle[0]=astyle1;
   iastyle=0;
} else {
  for (var im=0;im<astyle1.length;im++) astyle[im]=astyle1[im];
  iastyle=astyle.length-1;
}

 for (var im=0;im<astyle1.length;im++) {
   if (astyle[im]!=='') astyle[im]=' style="'+astyle[im]+'" ';
 }

atable='<table '+tablespec+'> \n '

if (athrow.length>0) {
   iat=0;
   arow='';
   for (var m=0;m<athrow.length;m++) {
        iat=iat+1;
        if (iat>ncols) {
          atable=atable+'   <tr>'+arow+'</tr> \n ';
          arow='';
          iat=1;
        }
         igoo=iat-1;
         if (igoo>iastyle) igoo=iastyle;
         bstyle=astyle[igoo];

        atd='<th '+bstyle+'>'+athrow[m]+'</th>';
        arow=arow+atd ;
   }
   if (arow!=='') {
          atable=atable+'<tr>'+arow+'</tr> \n ';
          arow='';
   }
}

if (alist.length>0) {
   iat=0;
   arow='';
   for (var m=0;m<alist.length;m++) {
        iat=iat+1; 

        if (lookForSignal==1 && alist[m]==newRowSignal) {
          atable=atable+'   <tr>'+arow+'</tr> \n ';
          arow='';
          iat=1;
        } else {

          if (iat>ncols) {
            atable=atable+'   <tr>'+arow+'</tr> \n ';
            arow='';
            iat=1;
          }
          igoo=iat-1;
          if (igoo>iastyle) igoo=iastyle;
          bstyle=astyle[igoo];
          atd='<td '+bstyle+'>'+alist[m]+'</td>';
          arow=arow+atd ;
       }
   }
   if (arow!=='') {
          atable=atable+'<tr>'+arow+'</tr> \n ';
          arow='';
   }
}    

atable=atable+'\n</table> ';
return atable;
}



//=======================================
// split a word (or string) into ilen (or less) long chunks, using abr string to seperate chunks
// if ' ' or _ within 3 characters of an ilen long chunk, break at it (rather than at the full ilen long chunk
function splitString(aword,ilen,abr) {
var irun,ac,newword,ugly,m;

if (aword.length<ilen)  return aword;
newword='';
irun=0;
for (var m=0;m<aword.length;m++) {
   irun++ ;
   if (irun>=ilen) {
          newword=newword+abr;
          irun=1
    }
   if (irun>=(ilen-3)) {
       ac=aword[m] ;
       if (ac==' ' || ac=='_') {
          newword=newword+abr;
          irun=1
        }
    }
    newword=newword+aword[m];
}
return newword;
}

//=======================================
/* Parse CSV string into array or arrays.
Each row of the "array of arrays" is a row from the CSV string; each element of a row-array is a value

By default, "," is used as a value seperator, and "\n" (CRLF) as a row seperator.
Values can "ed -- stuff between " are read literally (they can contain commas).
   Quoted values must be completely quoted: 1,3,4 "and 5",6 will return:1,3,4,6

If 2nd arg is speciifed, it can be more than one character (it is used as value seperator)

If 3rd arg is specified, it will be interpreted as " character. I.e.; if qChar='/"', then
   1,2," do /"quote me/" now,4
yields:
  1, 2, do "quote me" now, 4

This assumes ascii or unicode characters (note that asc(3) is used for internal purposes)
*/

function CSVToArray( strData, strDelimiter,qchar ){

 if (arguments.length>2) {			// hack to allow for " (using qChar argument, i.e; /"
	var rep1=String.fromCharCode(3)
	var goou=new RegExp('\\'+qchar,'g');
	var goox=new RegExp('\\'+rep1,'g');
       strData=strData.replace(goou,rep1);

 }

		// Check to see if the delimiter is defined. If not,
		// then default to comma.
		strDelimiter = (strDelimiter || ",");
		// Create a regular expression to parse the CSV values.
		var objPattern = new RegExp(
			(
				// Delimiters.
				"(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +

				// Quoted fields.
				"(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +
 
				// Standard fields.
				"([^\"\\" + strDelimiter + "\\r\\n]*))"
			),
			"gi"
			);
 
 
		// Create an array to hold our data. Give the array
		// a default empty first row.
		var arrData = [[]];
 
		// Create an array to hold our individual pattern
		// matching groups.
		var arrMatches = null;
 
 
		// Keep looping over the regular expression matches
		// until we can no longer find a match.
		while (arrMatches = objPattern.exec( strData )){
 
			// Get the delimiter that was found.
			var strMatchedDelimiter = arrMatches[ 1 ];
 
			// Check to see if the given delimiter has a length
			// (is not the start of string) and if it matches
			// field delimiter. If id does not, then we know
			// that this delimiter is a row delimiter.
			if (
				strMatchedDelimiter.length &&
				(strMatchedDelimiter != strDelimiter)
				){
 
				// Since we have reached a new row of data,
				// add an empty row to our data array.
				arrData.push( [] );

			}
 
 
			// Now that we have our delimiter out of the way,
			// let's check to see which kind of value we
			// captured (quoted or unquoted).
			if (arrMatches[ 2 ]){
 
				// We found a quoted value. When we capture
				// this value, unescape any double quotes.
				var strMatchedValue = arrMatches[ 2 ].replace(
					new RegExp( "\"\"", "g" ),
					"\""
					);
 
			} else {
 
				// We found a non-quoted value.
				var strMatchedValue = arrMatches[ 3 ];
 
			}
 

			// Now that we have our value string, let's add
			// it to the data array.
			arrData[ arrData.length - 1 ].push( strMatchedValue );
		}
 
		// Return the parsed data.

 if (arguments.length>2) {				// reinsert " quaracter 
   for (var m=0;m<arrData.length;m++) {
     for (var m2=0;m2<arrData[m].length;m2++) {
      arrData[m][m2]=arrData[m][m2].replace(goox,'"');
    }
   }
  }

  return( arrData );
}



// =====     the next several functions save/write/read to  current and "prior variables" (aka "history" variables) ====

//==============
// save value to a global variable, possibly an array element (create array if necessary)
function Save_Global(varname0,avalue,anindex22,forceArray) {

var varname,foo,vvtmp;
if (arguments.length<4) forceArray=0;

varname=strip(varname0).toUpperCase() ;
 if (typeof(SvyGlobals)=='undefined') SvyGlobals=new Object() ;

// if avalue is an array or an object, clone it
 if (typeof(avalue)=='object' || forceArray==1) {                    // clone an object. If an array, possibly move to start at anindexx
    if (arguments.length<3 || isNaN(anindex22) ) anindex22=0 ;
    anindex22=parseInt(anindex22);
    if (forceArray==1) {
       if (avalue===null || typeof(avalue)!=='object')  {                                   // save a value to an array? small hack needed
          foo=[];
          foo[anindex22]=avalue ;
          avalue=foo ;
      }
    }
    if (avalue!==null && typeof(avalue.length)!=='undefined' && anindex22>0) {          // is an array, and possibly to be shifted
        if (!isNaN(anindex22) && anindex22!==0 ) {                        // a start number, not equal to 0
           vvtmp=[] ;
           for (var iu=0;iu<avalue.length;iu++) {
               vvtmp[anindex22+iu]=avalue[iu];
           }
           avalue=vvtmp;
       }                        // add offset to array
    }                           // an array
    if (avalue===null) {
            SvyGlobals[varname]=null
    } else {
        if (typeof(avalue.length)!=='undefined') {
           SvyGlobals[varname]=Concat_Arrays(avalue);
        } else {
           SvyGlobals[varname]=new svy_cloneObject(avalue);                   // clone the object (an array, or other kind of object)
        }
    }
    return 1;
  }


// avalue is not an object...

 var  anindex2='' ;
 if (arguments.length>2) {
        anindex2=strip(anindex22) ;
        if (isNaN(anindex2) && anindex2!=='' ) anindex2='"'+anindex2+'"' ;
  }

 var aindex=strip(parseUsing(varname,'[',']'));

 if (!aindex) {
       var tvarname=varname.toUpperCase();
       if (anindex2==='') {
           SvyGlobals[tvarname]=avalue;
       } else {
            if (typeof(SvyGlobals[tvarname])=='undefined')  SvyGlobals[tvarname]= new Array() ;
            SvyGlobals[tvarname][anindex2]=avalue ;
       }

  } else {                              // an array

     var i1=varname.indexOf('[');
     arrname=varname.substr(0,i1);
     var tarrname=arrname.toUpperCase();

     if (typeof(SvyGlobals[tarrname])=='undefined') SvyGlobals[tarrname]= new Array() ;
     if (anindex2==='') {                                // not a 2d array
        SvyGlobals[tarrname][aindex]=avalue ;
     } else {
        if (typeof(SvyGlobals[tarrname][aindex])=='undefined')  SvyGlobals[tarrname][aindex]= new Array() ;
        SvyGlobals[tarrname][aindex][anindex2]=avalue ;
     }
  }

return 1;

}

// ================
// read value ofglobal variable, possibly an array element
// optional second arg is used if undefined variable
function Read_Global(varname,undef,anindex22) {
 var  avalue='n.a.';
 var foo ;
 var  anindex2='';
 var i1,arrname,tarrname,tvarname ;
 var aindex,doTyping=0 ;

 if (arguments.length>1) avalue=undef ;

 if (typeof(enableStrongTyping)!=='undefined') {
   if (enableStrongTyping==1 && (arguments.length<2 || strip(undef)==='')) doTyping=1 ; // enableStrongTyping is a global
 }

 if (arguments.length>1) avalue=undef ;

 anindex2='';
 if (arguments.length>2) {                      // kind o a hack
        anindex2=strip(anindex22) ;
        if (isNaN(anindex2) && anindex2!=='' ) anindex2='"'+anindex2+'"' ;
  }

 aindex=parseUsing(varname,'[',']');                        // an embedded [xx] ?
 if (!aindex) {
       tvarname=varname.toUpperCase();
       
       alertStrongTyping(doTyping,tvarname);          // check if undefined, warning message if so
       if (typeof(SvyGlobals[tvarname])=='undefined') return avalue ;
       if (anindex2==='') {
          avalue=SvyGlobals[tvarname] ;
       } else {
            alertStrongTyping(doTyping,tvarname,anindex2);          // check if undefined, warning message if so
            if (typeof(SvyGlobals[tvarname][anindex2])=='undefined') return avalue ;
            avalue=SvyGlobals[tvarname][anindex2] ;
       }

  } else {                              // an array
     i1=varname.indexOf('[');
     arrname=varname.substr(0,i1);
     tarrname=arrname.toUpperCase() ;
    aindex=strip(aindex); 
       alertStrongTyping(doTyping,tarrname,-1); 
     if (typeof(SvyGlobals[tarrname])=='undefined') return avalue ;
       alertStrongTyping(doTyping,tarrname,aindex); 
     if (typeof(SvyGlobals[tarrname][aindex])=='undefined') return avalue ;
     if (anindex2==='') {
         avalue=SvyGlobals[tarrname][aindex] ;
      } else {
        alertStrongTyping(doTyping,tarrname,aindex,anindex2); 
        if (typeof(SvyGlobals[tarrname][aindex][anindex2])=='undefined') return avalue ;
        avalue=SvyGlobals[tarrname][aindex][anindex2] ;
      }
  }

return avalue ;

}               




//==============
// save value, or clone an array/object, to a  "nth-round" global variable or array/object
// ALSO, save to the $recent "round".
// If nthround =='', ONLY save to $recent round
// If value, it can be saved to an array element (create array if necessary)
// nthRound: the "round" (in the prior variables database) this variable should  be saved to.
//           Note that in addition to the nthRound "round", a value will ALSO be created in the "$recent" round
//           Note that if nthRound='', then ONLY save to the '$recent' round
//           nthRound is usually an integer. But it can be a word (which will be stripped and converted to upper case)
// varname : name of variable. Will be stripped and uppercased
// avalue   : value to save. Can be variable or object
// anindex22   : if specified and not '', then save varname is an array name, and save avalue as varname[anindex22]
//                Or, if varname is an array index, then save as 2d array.: as varname[aindex][aindex22]
//                If avalue is an array object, anindexx is a "shift" -- values in the array are shifted by anindex22;
//                so that the saved array has undefined values from 0 to anindex222-1
// forcearray   : force avalue to be saved as an array (using anindex22 as index if avalue is a value)
//
// Note: this will create an entry in SvyGlobalsHistory (row a round) if one does not exist (and save varname's value into it)

function Save_priorGlobal(nthround,varname,avalue,anindex22,forceArray) {

 if (arguments.length<5) forceArray=0;

 varname=strip(varname.toUpperCase()) ;
 nthround=strip(nthround.toUpperCase()) ;

 if (typeof(SvyGlobalsHistory)=='undefined' ) SvyGlobalsHistory={}  ;                // should never happen, but its a quick check
 if (typeof(SvyGlobalsHistory['$roundlist'])=='undefined' ) SvyGlobalsHistory['$roundlist']=[]  ;                // should never happen, but its a quick check
 if (typeof(SvyGlobalsHistory['$recent'])=='undefined')  SvyGlobalsHistory['$recent']={};               // should never happen =, but ...
 if (typeof(SvyGlobalsHistory[nthround])=='undefined') {
    SvyGlobalsHistory[nthround]={};               // first var saved to this nthround?
    if (!isNaN(nthround))  SvyGlobalsHistory['$roundlist'][nthround]=1;
 }

// if avalue is an array or an object, or forcearray specified ... clone it.
 if (typeof(avalue)=='object' || forceArray==1 ) {                        // clone an object. If an array, possibly move to start at anindexx
    if (arguments.length<4 || isNaN(anindex22) ) anindex22=0 ;
    anindex22=parseInt(anindex22);
    if (typeof(avalue)!=='object')  {                                   // save a value to a 1x1 array? small hack used
          var foo=[];
          foo[anindex22]=avalue ;
          avalue=foo ;
    }
    if (typeof(avalue.length)!=='undefined' && anindex22>0) {         // is an array, and possibly to be shifted
           var vvtmp=[] ;
           for (var iu=0;iu<avalue.length;iu++) {
               vvtmp[anindex22+iu]=avalue[iu];
           }
           avalue=vvtmp;
    }                        // add offset to array

    if (typeof(avalue.length)!=='undefined') {
           if (nthround!=='') SvyGlobalsHistory[nthround][varname]=Concat_Arrays(avalue);          // copy array
           SvyGlobalsHistory['$recent'][varname]=Concat_Arrays(avalue);          // copy array
    } else {
           if (nthround!=='') SvyGlobalsHistory[nthround][varname]=new svy_cloneObject(avalue);                   // clone the object (an array, or other kind of object)
            SvyGlobalsHistory['$recent'][varname]=new svy_cloneObject(avalue);                   // clone the object (an array, or other kind of object)
    }


    return 1;
  }

// not an array object. But it might be copied to a particular element in an array
 var  anindex2='' ;
 if (arguments.length>3) {
        anindex2=strip(anindex22) ;
        if (isNaN(anindex2) && anindex2!=='' ) anindex2='"'+anindex2+'"' ;   // a hack to support associative array.
  }

 var aindex=strip(parseUsing(varname,'[',']'));                          // look for index in varname

 if (!aindex) {                                                      // no index in varname, but maybe an argument index?
       if (anindex2==='') {                                          // not index in arguments
             if (nthround!=='')  SvyGlobalsHistory[nthround][varname]=avalue;
             SvyGlobalsHistory['$recent'][varname]=avalue;
       } else {                                                            // there is an index in arguments
            if (nthround!=='') {
                if (typeof(SvyGlobalsHistory[nthround][varname])=='undefined')  SvyGlobalsHistory[nthround][varname]=[] ;
                SvyGlobalsHistory[nthround][varname][anindex2]=avalue ;
            }
            if (typeof(SvyGlobalsHistory['$recent'][varname])=='undefined')  SvyGlobalsHistory['$recent'][varname]=[] ;
            SvyGlobalsHistory['$recent'][varname][anindex2]=avalue ;
        }
  } else {                              // an index in varname, and maybe also an argument index

     var i1=varname.indexOf('[');
     arrname=varname.substr(0,i1);

      if (nthround!=='')   if (typeof(SvyGlobalsHistory[nthround][arrname])=='undefined') SvyGlobalsHistory[nthround][arrname]=[] ;
      if (typeof(SvyGlobalsHistory['$recent'][arrname])=='undefined') SvyGlobalsHistory['$recent'][arrname]=[] ;

     if (anindex2==='') {                                // not a 2d array
        if (nthround!=='')  SvyGlobalsHistory[nthround][arrname][aindex]=avalue ;
        SvyGlobalsHistory['$recent'][arrname][aindex]=avalue ;
     } else {
        if (nthround!=='') {
           if (typeof(SvyGlobalsHistory[nthround][arrname][aindex])=='undefined')  SvyGlobalsHistory[nthround][arrname][aindex]= new Array() ;
           SvyGlobalsHistory[nthround][arrname][aindex][anindex2]=avalue ;
        }
        if (typeof(SvyGlobalsHistory['$recent'][arrname][aindex])=='undefined')  SvyGlobalsHistory['$recent'][arrname][aindex]= new Array() ;
        SvyGlobalsHistory['$recent'][arrname][aindex][anindex2]=avalue ;

     }
  }

return 1;

}

// ================
// read value ofglobal variable, possibly an array element
// nthround : round to read value from. if '', read from $recent round
// varname  : variable to find value of
// undef    : Optional. if no such varname, or no such nthround, return undef. Optional, if not specified return 'n.a.'
// anindex22 : Optional. if specified, and varname is an array, return anindex22 element. If varname is array element (i.e.; voo[1]), return voo[1][anindex22]

function Read_priorGlobal(nthround,varname,undef,anindex22) {

 var  avalue='n.a.';
 var doTyping=0 ;

 if (arguments.length>2) avalue=undef ;
 nthround=strip(nthround)
 nthround=nthround.toUpperCase();
 if (nthround==='') nthround='$recent';

 if (typeof(enableStrongTyping)!=='undefined') {
   if (strongTyping==1) {                         // don't type if debug mode (avoid lots of unimportant errors)
     if (enableStrongTyping==1 && (arguments.length<3 || strip(undef)==='')) doTyping=2 ; // enableStrongTyping is a global
   }
 }

 alertStrongTyping(doTyping,nthround);  
 if (typeof(SvyGlobalsHistory[nthround])=='undefined') {
        return avalue ;                 // no such round (or nothing saved for it)
 }

 var  anindex2='';
 if (arguments.length>3) {                      // kind o a hack to allow associative arrays
        anindex2=strip(anindex22) ;
        if (isNaN(anindex2) && anindex2!=='' ) anindex2='"'+anindex2+'"' ;
  }

 var aindex=parseUsing(varname,'[',']');                        // an embedded [xx] ?


 if (strip(aindex)==='') {
       var tvarname=strip(varname.toUpperCase());
       alertStrongTyping(doTyping,nthround,tvarname);  
       if (typeof(SvyGlobalsHistory[nthround][tvarname])=='undefined') return avalue ;
       if (anindex2==='') {
          avalue=SvyGlobalsHistory[nthround][tvarname] ;
       } else {
            if (typeof(SvyGlobalsHistory[nthround][tvarname][anindex2])=='undefined') return avalue ;
            avalue=SvyGlobalsHistory[nthround][tvarname][anindex2] ;
       }

  } else {                              // an array
     var i1=varname.indexOf('[');
     var arrname=varname.substr(0,i1);
     var tarrname=arrname.toUpperCase() ;

      alertStrongTyping(doTyping,nthround,tarrname,-1);  

     if (typeof(SvyGlobalsHistory[nthround][tarrname])=='undefined') return avalue ;
     if (typeof(SvyGlobalsHistory[nthround][tarrname][aindex])=='undefined') return avalue ;
     if (anindex2==='') {
         avalue=SvyGlobalsHistory[nthround][tarrname][aindex] ;
      } else {
        if (typeof(SvyGlobalsHistory[nthround][tarrname][aindex][anindex2])=='undefined') return avalue ;
        avalue=SvyGlobalsHistory[nthround][tarrname][aindex][anindex2] ;
      } 
  }


return avalue ;

}

//=============
// issue an alert, using args 1 as name, 2 and 3 (if defined) as array indices
function alertStrongTyping(dotype,aname,in1,in2) {
var gg;

if (dotype==0) return 0;               // typing not enabled. Do nothing

if (dotype==2) {                // globalHistory checking -- just check round and  variables (not arrays) for now
 if (typeof(SvyGlobalsHistory[aname])=='undefined') {
         gg=SvyGlobals['_GROUPNAMEFULL']
         alert("Warning: the prior round "+aname+" is undefined ("+gg+").");
         return 1;
 }
 if (arguments.length<3) return 0;              // just checking round


 if (typeof(SvyGlobalsHistory[aname][in1])=='undefined') {
          gg=SvyGlobals['_GROUPNAMEFULL']
          if (arguments.length<4) {
             alert("Warning: the prior variable "+in1+" in round "+aname+" is undefined ("+gg+").");
             return 1;
          } else {
             alert("Warning: the prior array "+in1+" in round "+aname+" is undefined ("+gg+").");
             return 1;
          }
 }
 return 0;


}

// else, global checking

if (arguments.length<3) {               // varname onely

       if (typeof(SvyGlobals[aname])=='undefined')  {
           gg=SvyGlobals['_GROUPNAMEFULL']
           alert("Warning: the variable "+aname+" is undefined.("+gg+")");
           return 1;
       }
       return 0;
}

if (arguments.length<4) {               // single index array
  if (typeof(SvyGlobals[aname])=='undefined')  {
           gg=SvyGlobals['_GROUPNAMEFULL']
           alert("Warning: the array "+aname+" is undefined ("+gg+")");
           return 1;
  } 
  if (in1<0)  return 0 ;                        // in1<0 means just checking if array exists

  if (typeof(SvyGlobals[aname][in1])=='undefined')  {
        gg=SvyGlobals['_GROUPNAMEFULL']
        alert("Warning: the array element "+aname+"["+in1+"] is undefined ("+gg+").");
        return 1;
  }
  return 0 ;  
}

// else, 2 element array 

  if (typeof(SvyGlobals[aname])=='undefined')  {
        gg=SvyGlobals['_GROUPNAMEFULL']
           alert("Warning: the 2d array "+aname+" is undefined ("+gg+").");
           return 1;
  } 
  if (in1<0)  return 0 ;                        // in1<0 means just checking if array exists

  if (typeof(SvyGlobals[aname][in1])=='undefined')  {
        gg=SvyGlobals['_GROUPNAMEFULL']
        alert("Warning: the 2d array row "+aname+"["+in1+"] is undefined ("+gg+").");
        return 1;
  }

  if (in2<0)  return 0 ;                        // in1<0 means just checking if array first index exists

  if (typeof(SvyGlobals[aname][in1][in2])=='undefined')  {
        gg=SvyGlobals['_GROUPNAMEFULL']
        alert("Warning: the 2d array element  "+aname+"["+in1+"]["+in2+"] is undefined ("+gg+").");
        return 1;
  }

  return 0 ;  

}

//==============
// save current global variables to the nowr  "history" variables.  The history variables is used by "read/write prior variables"
// if not specified, use the "nowround"  global variable as the value of nowr.
// if nowround not defined, use 0
// imax (optional) is max "numbered" rounds to retain (before adding current globals).
// That means $RECENT, $START and other such "saved globals" are never removed.
// If not specified, or 0, no limit

function Save_GlobalHistory(nowr,imax) {
   var dog ;
   var t1,t2,t3,i1,i2,tnum ;
   var igot,idel,ii,imax,didclear,rlist;

   if (arguments.length<1) nowr=Read_Global('nowRound',0);
   if (arguments.length<2) imax=0;


   if (typeof(SvyGlobalsHistory)=='undefined')  {
         SvyGlobalsHistory={};
         SvyGlobalsHistory['$roundlist']=[];
  }
  imax=strip(imax); 

  if (isNaN(imax) || imax==='') imax=0;
// clear out old entries?
  if (imax>0) {
    igot=0; didclear='';
    rlist=SvyGlobalsHistory['$roundlist']
    for (var i1=rlist.length-1;i1>=0; i1--) {
//var z=confirm('i1='+i1+': '+rlist.length+'; rlist='+rlist); if (!z) afasfdsdf(); 
        if (rlist[i1]<0 || typeof(SvyGlobalsHistory[i1])=='undefined' ) continue ;  // a gap,for some reason, so skip
        igot++ ;
        if (igot>imax) {                      // too many!
            SvyGlobalsHistory[i1]='';
             delete    SvyGlobalsHistory[i1]
             SvyGlobalsHistory['$roundlist'][i1]=-1 ;        // -1 signals "deleted"
             didclear=didclear+' '+i1 ;
        }
    }                           // found too many
    if (igot>imax)   writeStatus('Save_GlobalHistory: cleared entries: '+didclear);
   }                            // end of cleanup 

   SvyGlobalsHistory[nowr]=new svy_cloneObject(SvyGlobals) ;
   SvyGlobalsHistory['$lastSave']=nowr;
   if (typeof(SvyGlobalsHistory['$roundlist'][nowr])=='undefined') SvyGlobalsHistory['$roundlist'][nowr]=1; 
   return 1 ;
}


// clear recent round in history variables

function  Reset_recentHistory(nowr) {
 if (typeof(SvyGlobalsHistory)=='undefined') return '' ;
 if (arguments.length<1) {
    SvyGlobalsHistory['$recent']={};
    return 1;
  }

// else, clear and then copy from nowr 
  SvyGlobalsHistory['$recent']={};
  SvyGlobalsHistory['$recent']=new svy_cloneObject(SvyGlobalsHistory[nowr]) ;
  return 1;

}


// ==========
// display  table containing contents of SvyGlobalHistory
function showSvyGlobalsHistory(nth,noshrink) {
if (arguments.length<1) nth=0;
if (arguments.length<2) noshrink=0;

var rlist,stuff,inrow,j,avar,avar2 ;
rlist=SvyGlobalsHistory['$roundlist'];
if (noshrink!==1) {
  stuff='<table border="1" style="font-size:85%"> \n ';
} else {
  stuff='<table border="1" > \n ';
}
for (var m=0;m<rlist.length;m++) {
   if (typeof(SvyGlobalsHistory[m])=='undefined') continue ;
   if (nth!==0 && m!==nth) continue ;
   stuff=stuff+'<tr> <td colspan="8"><div style="background-color:cyan"><em>round '+m+'</em> </div></td></tr> \n ';
   inrow=0;
   for  (var j in SvyGlobalsHistory[m]) {
     inrow=inrow+1;
      if (inrow==6) {
           stuff=stuff+'</tr> \n  ';
           inrow=1;
      }
      if (inrow==1) {
            stuff=stuff+'<tr>';
      }
      avar=SvyGlobalsHistory[m][j];
      if (typeof(avar)=='object') {
         avar2='';
         for (var jj in avar) avar2=avar2+' | '+avar[jj] ;
         avar=avar2;
     }
      stuff=stuff+'<td><tt>'+j+'= </tt>'+avar+'</td> ';
   }
   stuff=stuff+'</tr> \n ';
}
stuff=stuff+'\n </table>';
return stuff;
}

//==============
// retrive from the nowr history variables, and write to current "global" variables
// nowr: what history object to retrieve. By default,  use '$recent'
//       for anything else, strip and capitalize nowr
//       SPECIAL CASE: if nowr='$LASTSAVE', return the most recently saved round (as saved by Save_GlobalHistory
//                      if no such save, returns ''
// no_overwrite :if 1, add values in history object to current globals (overwriting variables of the same name)
//               if 0, remove ALL variables from the current global variables object (basically, overwrite the global variables object)
// returns:
//  0 - failure (the requested nowr history  variables do not exist)
//  1 - success - overwrite current global variables
//  2 -  sucess, no overwrite, but no variables found in nowr history
// 3..  - success, n-2 variables used (thus, a return of "10" means "8 variables were extracted from the nowr history variables")
// Note: this is often used when a new "round" starts, with a save & reset of all survey globals -- calling this with  "start" (or other
//       name used in an initialization call to save_globalhistory) resets globals with just the the "required" or "permanent" variables

function  Retrieve_GlobalHistory(nowr,no_overwrite) {

  var i,k,v1,vv,rlist;

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

  if (arguments.length<1) {
       nowr='$recent';
  } else {
       nowr=strip(nowr.toUpperCase());
  }
  if (nowr==='') nowr='$recent';

  if (nowr=='$LASTSAVE') {
    if (typeof(SvyGlobalsHistory['$lastSave'])=='undefined') return '' ;
    return   SvyGlobalsHistory['$lastSave'] ;
  }

  rlist=SvyGlobalsHistory['$roundlist'] ;
  if (typeof(rlist[nowr])!=='undefined' && rlist[nowr]<0) {
        alert('ERROR: accessing a round (in global history) that was deleted: '+nowr);
        return 0 ;
   }

  if (typeof(SvyGlobalsHistory[nowr])=='undefined') {
        alert('ERROR: no entry in global history for round: '+nowr);
        return 0 ;
   }

   if (no_overwrite!=1) {
        SvyGlobals=new svy_cloneObject(SvyGlobalsHistory[nowr]) ;
        return 1 ;
   }
   var arf=SvyGlobalsHistory[nowr] ;                            // overwrite current globals, which means retain current globals if no same named variable in history
   var i=2;
   for (var k in arf) {
        var v1=arf[k];
        SvyGlobals[k]=v1 ;
        i ++ ;
   }
  return i ;                           // two more than the number of variables retrieved
}

/// == end of global/prior variables functions ---

// ===========================
// display, in a new window, list of current values of global variables
// adiv is optional. If specified, the name of a <div> to display contents in
function Show_Variables(adiv,retStr) {

var asString=0;
if (arguments.length>0) asString=1;  
if (arguments.length<2) retStr=0 ;

var z,avar,aval,ii,igoo,tmp1,tmp2;
var a=''
var myNAME=Read_Global('myname');
var myID=Read_Global('myID'); 

if (asString==0) {
  a='<html><head>Current values of variables</head>\n <body> \n';
} else {
  a='<h2>Current values of variables</h2> \n';
}

var sessionName=Read_Global('_sessionName');
a=a+'<h3>Current values of survey global variables</h3> \n ';
a=a+'For: <ul><li>Survey name: <tt>'+sessionName+'</tt> \n';
a=a+'<li>Participant name , participant ID: <tt>'+myNAME+' , '+myID+'</tt>\n';

// these _varname variables are default variables at the beginning of  USER record (in CAP files)
tmp1=SvyGlobals['_REFID']; tmp2=SvyGlobals['_CONTACT']; 
tmp3=SvyGlobals['_NICKNAME']; 
a=a+'<li>(reference ID= '+tmp1+', contact='+tmp2+', nickname='+tmp3+') \n ';
a=a+'</ul> \n ';
a=a+'<table border=2><th>Variable</th><th>Value</th> \n';
for (z in SvyGlobals ) {
  avar=SvyGlobals[z];
  if (typeof(avar)=='object' && typeof(avar.length)!='undefined') {              // array
    a=a+'<tr><td>'+z+'</td><td>&nbsp;<tt><table bgcolor="#dedede" border="1"><tr> \n' ;
    igoo=0;
    for (ii=0; ii<avar.length;ii++){
        if (igoo==10) { a=a+'\n <tr>'; igoo=0 };
        igoo++ ;
        a=a+'<td>' + avar[ii] + '</td> '
    }
    a=a+'</table></tt></td>\n';
  } else {     a=a+'<tr><td>'+z+'</td><td>&nbsp;<tt>'+SvyGlobals[z] +'</tt></td> \n';
  }
}
a=a+'</table> \n';

if (retStr==1) return a ;

if (asString==0) {
   a=a+'</body></html> \n ';
   var dw=window.open('','debugwindow');
   dw.document.open('text/html');
   dw.document.write(a);
   dw.document.close();
} else {
  var idiv=document.getElementById(adiv);
  idiv.innerHTML=a;
}

   return 1 ;

}


// ===========================
// create an array that is the concatenation of up to 5 arrays and nodelists.
// this is useful since nodelists do NOT have concat function
// note that a new array is returned 
function Concat_Arrays(a1,a2,a3,a4,a5) {
var a1a,ii,j;
var t1= new Array() ;

for (var ii=0; ii<arguments.length ; ii++) {
  a1a=arguments[ii];
  if (typeof(a1a)!=='object' || typeof(a1a.length)=='undefined') {
        t1[t1.length]=a1a;
  } else {
     for (var j=0 ; j<a1a.length; j++){
       t1[t1.length]=a1a[j];
     }
  }
}
return t1 ;
}

/* ===
 var t1= new Array() ;

if (arguments.length>0) {
   for (var j=0 ; j<a1.length; j++){
     t1[t1.length]=a1[j];
   }
}


if (arguments.length>1) {
   for (var j=0 ; j<a2.length; j++){
     t1[t1.length]=a2[j];
   }
}

if (arguments.length>2) {
   for (var j=0 ; j<a3.length; j++){
     t1[t1.length]=a3[j];
   }
}

if (arguments.length>3) {
   for (var j=0 ; j<a4.length; j++){
     t1[t1.length]=a4[j];
   }
}

if (arguments.length>4 ) {
   for (var j=0 ; j<a5.length; j++){
     t1[t1.length]=a5[j];
   }
}

return t1 ;
}

---- */

//========================
// remove all children of anode.
// children may be returned as  be a collection ( firefox 3),
// or an array  (say, as returned by getElementsByName in ie 7),
function removeChildren(anode,noShow)  {
var m2,imm ;
if (arguments.length<2) noShow=1;
if (typeof(anode)!='object') {
  if (noShow==1) return 0;
  alert('Error in removeChildren: argument not an object ');
   return 0 ;
}
if (typeof(anode.childNodes)=='undefined') {
  if (noShow==1) return 0;
  alert('Error in removeChildren: argument has no childNodes property ');
   return 0 ;
}
if (anode.hasChildNodes()) {
    while (anode.childNodes.length>=1) {
        anode.removeChild(anode.firstChild) ;
    }
}
return 1;
} 


//========================
// remove all nodes in alist. alist maybe a collection, or an array (collection size shrinks as nodes are
// removed)
function removeNodes(alist,noShow) {
if (arguments.length<2) noShow=1;
  var m2,imm,bnode;
if (typeof(alist)!='object') {
   if (noShow==1) return 0;
   alert('Error in removeNodes: argument not an object ');
   return 0 ;
}
if (typeof(alist.length)=='undefined') {
   if (noShow==1) return 0;
   alert('Error in removeNodes: argument has no length property ');
   return 0 ;
}
imm=alist.length;
for (m2=0;m2<imm;m2++) {
    if (m2==0 || imm==alist.length) {                // first element, or an array: delete m2'th element
             bnode=alist[m2] ;
    } else {
        bnode=alist[0];                         // a collection
   }
  if (typeof(bnode)!='object' || typeof(bnode.parentNode)=='undefined') {
      if (noShow==1) return 0;
      alert('Error in removeNodes: element # '+m2+' is not an object, or has no parentnode');
      return 0 ;
  }
  bnode.parentNode.removeChild(bnode);
}
return 1;
}             


//========================
// remove spaces (either shrink to 1 space, or remove altogether
//  what is a character string to replace spaces with. If not specified, ' ' (shrink to 1 space) is used.
// this does NOT strip leading and trailing spaces
function space(str,which) {
  if (typeof(str)!='string') return str;                                                    s
  if (arguments.length<2)  which=' '
  var xx=str.replace(/\s+/g,which);
  return xx ;
}

//=====================
// map from integer to a row, or column, id
// example, for 3 x5 matrix:
//  row   col
//     |   1    2    3    4   5
//  -----------------------------------------------
//  1  |   1    2    3    4    5
//  2  |   6    7    8    9   10
//  3  |  11   12   13   14   15
// so ii=mapIndex(7,1,3,5) ==> 2
// so ii=mapIndex(8,2,3,5) ==> 3

function mapIndexToMatrix(ival,idim,nrows,ncols) {
var irow,icol ;
if (idim==1) {          // row
  irow=Math.ceil(ival/ncols);
  return irow ;
}
icol=ival % ncols ;  
if (icol==0) icol=ncols;
return icol ;
}


//========================
// case insensitive find  in in array. Skips [0] (so min success is 1)
//  tofind='', return adef
//  If not found, return 0
function find_InArray(tofind,anarray,adef,verbose,errmess) {
  if (arguments.length<4) verbose=0;
  if (arguments.length<5) errmess=' ... ';
  tofind=strip(tofind);
  if (tofind=='') return adef ;
  if (!isNaN(tofind)) {                 // a shortcut: if a number is provided, just return it (within bounds)
    if (tofind<1) tofind=1 ;
    if (tofind>=anarray.length) tofind=anarray.length-1 ;
    return tofind ;
  }
  tofind=tofind.toUpperCase() ;
  for (var j=1 ; j<anarray.length;j++) {
        var huh=strip(anarray[j]);
         huh=huh.toUpperCase() ;
        if (tofind==huh) return j;
   }
  if (verbose>0) {
        writeStatus('Error: ['+errmess+'] unable to find  '+tofind + ' in \n '+anarray.join());
        if (verbose>1) alert('%Error: unable to find (in array) '+ tofind + '['+errmess);
  }
  return 0 ;
}
 


//  bunch 'o dots
function manyDots(aval,amax,dastring) {
  aval=parseInt(aval);
  if (arguments.length<2) amax=10; 
  if (arguments.length<3) dastring='.....................................................';
  var tmp= aval- Math.floor(aval/amax) * amax ; tmp=tmp+1;
  if (tmp> dastring.length) tmp=dastring.length ;
  return dastring.substring(0,tmp);
}





//=============================
// capitalize 2nd character if first is a %
function fix_directive(the2) {
var pp=the2 ;
  if (typeof(the2)!='string') return the2 ;
  the2=strip(the2); 
  if (the2.substr(0,1)=='%') {
      var i1=the2.indexOf('(') ;
      var i2=the2.indexOf('=') ;
      var j1 = i1>i2 ? i1 : i2 ;
      if (j1>-1) {
          var p1=the2.substr(0,j1) ;
          tp1=p1.toUpperCase() ;
          the2=tp1+the2.substr(j1) ;
      } else {                                  // %xxx == cap it all 
         the2=the2.toUpperCase() ;
      }
   }       // capitalize special directives
return the2 ;
}

// convert a number of seconds to hh:mm:ss format
function Seconds_ToTime(towait) {
  if (isNaN(towait)) return towait ;              //ignore non numbers
  if (towait<10) return ':0'+towait ;
  if (towait<60) return ':'+towait ;
  var thr=0;                     // convert seconds to hr:min:sec 
  var tmin=Math.floor(towait / 60);
  var tsec=towait -  (tmin*60) ;
  if (tsec<10) tsec='0'+tsec ;

  thr=Math.floor(tmin/60) ;
  tmin=tmin-(thr*60) ; 
  if (tmin<10) tmin='0'+tmin ;
  thr1=''
  if (thr>0) {
     thr1=thr ;
     if (thr1<10) thr1='0'+thr1 ;
     thr1=thr1+':';
  }
  var dahh=thr1 + tmin +':' + tsec ;
 if (dahh.indexOf('.')>0) {                     // strip out fractional seconds 
        dahh=dahh.split('.');
        return dahh[0];
 }
  return dahh ;

}

// ============================
// if value is empty, convert to ifEmpty attributes value?
function check_ifEmpty(e,a1) {
  if (arguments.length<2) {
    if (!e) e=window.event ;
    var ielem= (e.srcElement) ? e.srcElement : e.target ;
  } else {
      ielem=e;
  }
  var aempty=strip(ielem.getAttribute('ifEmpty'));
  if (aempty==='' || aempty==null ) {            // no such attribute. force to be ''
            ielem.value='';
            return 1 ;
   }
  var aval=svy_getVal(aempty,'',ielem);               // use the value of this attribute (might be a variable name, hence use svy_getVal)
  ielem.value=aval;
  return 1 ;
}

// ============================
// check for questionable numeric values, and issue a confirm if found. If confirm is NO, then set value attribute to ''
function Confirm_Input(e) {
  var ielem,nowval,nowname,damax;
  var foo,damin,daAllowed,w1,w1b,iat,dval ;
  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
   
  nowval=strip(ielem.value);
  if (nowval==null || strip(nowval)=='') {                    // if empty, check for ifEmpty. Or do nothing (well, set to '' first)
       check_ifEmpty(ielem,1) ;     
       return 1 ;
  }
  nowname=getAttributes(ielem,'confirm_Name','')  ;
  if (strip(nowname)!=='') nowname=' for ' + nowname ;

  damax=parseFloat(ielem.getAttribute('confirm_Max'));
  if (!isNaN(damax)) {                                          // check for max
     if (isNaN(nowval)) {                            
        alert('Sorry, you must enter a numeric  value (or enter nothing) for '+nowname);
        check_ifEmpty(ielem,1);
        return 1 ;
   }
   if (nowval>damax) {
      foo=confirm('Warning: your entry '+nowname+' ('+nowval+') is large (it is > '+damax+'). Are you sure you want to enter this value? ');
      if (foo!=1) { 
          check_ifEmpty(ielem,1);
          return 1 ;
     }
  }                             // is >
 }                              // maxconfirm found 

  damin=parseFloat(ielem.getAttribute('confirm_Min'));
  if (!isNaN(damin)) {                                          // check for min
     if (isNaN(nowval)) {                            
        alert('Sorry, you must enter a numeric value (or enter nothing) for ' +nowname);
        check_ifEmpty(ielem,1);
        return 1 ;
   }
    if (nowval<damin) {
      foo=confirm('Warning: your entry '+nowname+'  ('+nowval+') is small (it is < '+damin+'). Are you sure you want to enter this value? ');
      if (foo!=1) {
        check_ifEmpty(ielem,1);
        return 1 ;
      }
   }                                    // is < 
 }                                      // minconfirm fouind 


  daAllowed=ielem.getAttribute('confirm_Allowed');
  if (daAllowed!=null && strip(daAllowed)!='') {                        // list of allowed "words"
         daAllowed=' '+daAllowed.toUpperCase()+' ' ;
         w1=strip(nowval);
         w1b=w1.split(' ');
         w1=' '+strip(w1b[0].toUpperCase())+' ';
         iat=daAllowed.indexOf(w1);
         if (iat==-1 || w1b.length>1) {
            foo=confirm('Warning: your entry '+ nowname +'  ('+nowval+') is NOT one of the expected one word values. Are you sure you want to enter this value? ');
            if (foo!=1) {
              check_ifEmpty(ielem,1);
//               ielem.value='';
               return 1 ;
           }
        }        
   } 
   if (ielem.value=='') {                               // ifEmpty and value=''? 
         check_ifEmpty(ielem,1);
         return 1 ;
   }

// if here, no problems, or all confirmed. Format? 
  dval=ielem.getAttribute('value_Fmt');
  if (dval) dval=svy_getVal(dval,'',ielem);
  dval=parseInt(dval);
  if (dval && !isNaN(dval) && dval!='') {
       nowval=parseFloat(nowval);
       nowval=nowval.toFixed(dval) ;
       ielem.value=nowval ;
  }

// all done
   return 1 ;
}




// ============================
// check for maximum value. If exceeded, set to maximum value
function Check_Bounds(e) {
  var ielem,nowval,damax,damin,vv,dval ;

  if (!e) e=window.event ;
  ielem= (e.srcElement) ? e.srcElement : e.target ;
  nowval=strip(ielem.value);
  if (nowval=='' || isNaN(nowval)) {
        ielem.value='';
        return 1 ;
  }
  nowval=parseFloat(nowval);
  damax=ielem.getAttribute('value_Max');
  if (damax) damax=svy_getVal(damax,'',ielem);
  damax=parseFloat(damax);
  if (!isNaN(damax) && !isNaN(nowval)) {
        if (nowval>damax) ielem.value=damax ;
  }
  damin=parseFloat(ielem.getAttribute('value_Min'));
  if (damin) damin=svy_getVal(damin,'',ielem);
  damin=parseFloat(damin);
  if (!isNaN(damin) && !isNaN(nowval)) {
        if (nowval<damin) ielem.value=damin ;
  }

// format the number (if fmt attrbibute exists) 
   if (typeof(ielem)!='undefined' && typeof(ielem.value)!='undefined') {
    vv=ielem.value ;
    if (!isNaN(vv)) {
        vv=parseFloat(vv);
        dval=ielem.getAttribute('value_Fmt');
        if (dval) dval=svy_getVal(dval,'',ielem);
        dval=parseInt(dval);
        if (dval && !isNaN(dval) && dval!='') {
           vv=vv.toFixed(dval) ;
           ielem.value=vv ;
        }
    } 
   }


   return 1 ;
}




// ============================
// increment or decrement a value of an input field
function Arrow_Increment(e) {
  var ielem,dval,foo,nowval ;
   var vv,aname,dname ;

  if (!e) e=window.event ;
  ielem= (e.srcElement) ? e.srcElement : e.target ;
  foo=Check_Char(e) ; 

  if (foo=="") return ;

  if (foo=="ESC" ) {                    // refresh
      ielem= (e.srcElement) ? e.srcElement : e.target ;
      dval=ielem.getAttribute('value_Default');
      if (dval)  dval=svy_getVal(dval,'',ielem);
      nowval=ielem.value
      if (nowval==dval) { ielem.value=''  }
      else { ielem.value=dval };
    }

/*   if (foo=="UP" || foo=="LEFT") {                      // decrement  */
 if (foo=="DOWN") {                      // increment
      ielem= (e.srcElement) ? e.srcElement : e.target ;
      aname=ielem.name ;
      dval=ielem.getAttribute('value_Default');
      if (dval)  dval=svy_getVal(dval,'',ielem);
      nowval=ielem.value
      if (!nowval) {ielem.value=dval }
      else {
          if (!isNaN(nowval)) {ielem.value-- } ;
      }
    }


  if (foo=="PGDN" ) {                      // decrement by 1
      ielem= (e.srcElement) ? e.srcElement : e.target ;
       aname=ielem.name ;
      dval=ielem.getAttribute('value_Default');
      if (dval)  dval=svy_getVal(dval,'',ielem);
      nowval=ielem.value
      if (!nowval) {ielem.value=dval }
      else {
          if (!isNaN(nowval)) {ielem.value=(1*ielem.value)-10 } ;
      }
    }


/*  if (foo=="DOWN" || foo=="RIGHT") {                      // increment   */
  if (foo=="UP") {                      // increment
     ielem= (e.srcElement) ? e.srcElement : e.target ;
      aname=ielem.name ;
      dval=ielem.getAttribute('value_Default');
      if (dval)  dval=svy_getVal(dval,'',ielem);
      nowval=ielem.value
      if (!nowval) {ielem.value=dval }
      else {
          if (!isNaN(nowval)) {ielem.value++ } ;
      }
    }


  if (foo=="PGUP" ) {                      // increment by 1
     ielem= (e.srcElement) ? e.srcElement : e.target ;
      aname=ielem.name ;
      dval=ielem.getAttribute('value_Default');
      if (dval)  dval=svy_getVal(dval,'',ielem);
      nowval=ielem.value
      if (!nowval) {
           ielem.value=dval }
      else {
          if (!isNaN(nowval)) {ielem.value=(1*ielem.value)+10 } ;
      }
    }


// format the number (if value_Fmt attrbibute exists) 
   if (typeof(ielem)!='undefined' && typeof(ielem.value)!='undefined') {
    vv=ielem.value ; 
    if (!isNaN(vv) && vv!='' ) {
        vv=parseFloat(vv);
        var dval=ielem.getAttribute('value_Fmt');
        if (dval)  dval=svy_getVal(dval,'',ielem);
        if (dval && !isNaN(dval) && dval!='') {
           vv=vv.toFixed(dval) ;
           ielem.value=vv ;
        }
    } 
   }

 return 1 ;

}



// ============================ attrib getval 
// call as disable_autocompletes(aflag) -- all INPUT elements with a classname of daflag will have an autocomplete=off element set,
// and the contextmenu turned off.
//    If daflag='', or 0, the default value of "disableAutoComplete" is used 
//

function disable_autocompletes(daflag) { //  derived from to chrisholland.blogspot.com  -- this will turn off autocomplete in all input boxes with a daflag class
  if (daflag=="" || daflag==0) daflag="disableAutoComplete" ;
  daflag=daflag.toUpperCase();
  if (document.getElementsByTagName) {
    var inputElements = document.getElementsByTagName("input");  
    for (i=0; i < inputElements.length ; i++) {
       if (Find_Class(daflag,inputElements[i])) {
              inputElements[i].setAttribute("autocomplete","off"); 
              inputElements[i].oncontextmenu=isfalse ;
        } //if current input element has the disableAutoComplete class set.
    }//loop thru input elements
   }//basic DOM-happiness-check
}


// ============================
// not currently used (for handling click events)
function do_click(e) {            
 if (!e) e=window.event ;
 var a1=this;
 var acode=e.keyCode ;
 var akey=e.which ;
 if (document.all) {akey=acode; acode=0}                // ie is too stupid to support
}




// ============================
// capture keyboard and return an identifying string if arrow or other such key is hit
// Returned values are: ALT CRLF PGUP ESC PGDN END BKSP HOME LEFT UP RIGHT DOWN 


function Check_Char(e) {              

  if (!e) e=window.event ;
  var acode=e.keyCode ;
  var akey=e.which ;
  if (document.all) {akey=acode; acode=0}                // ie is too stupid to support


  if (akey ==10 || akey==13) {                  // crlf 
     return 'CRLF' ;
  }

  if (acode==0) return akey ;

  switch(acode) {
  case 19456:
       return 'K5'
  case 18: 
       set_add1(0,1);
       return 'ALT' ;          
   case 33:
       return 'PGUP'
   case 27:
       return 'ESC'

   case 34:
       return 'PGDN'
   case 35:
      return 'END' ;
   case 8:
      return 'BKSP' ;
   case 36:
        return 'HOME'
   case 37:
        return 'LEFT';
   case 38:
        return 'UP';
   case 39:
      return 'RIGHT';
   case 40:
        return 'DOWN';
  default:
        return '' ;
  }


return true ;
}

// Functions to find a set of elements by tagname, classname, and name. And then modify their attributes in various ways

//===============
// return a value from one of an array of elements 
// this generalizes get_elemValue -- if an array of elements is sent, then the last non "blank"
// value is returned (where an element's value is read using get_elemValue

function get_elemValueArray(e1,defval,modifiers) {
 var aval ;
  if (arguments.length<2) defval='' ;
  if (arguments.length<3) modifiers='';

   if (typeof(aelem)=='string') {                       // not a node, so look for element with this ID
          var aelem=document.getElementById(aelem);
          if (!aelem) return defval; 
    }

   if (typeof(e1)!='object') return defval ;            // not a node?

   if (typeof(e1.length)=='undefined') {
        aval=get_elemValue(e1,defval,modifiers);
        return aval;
   }

   for (var ii=e1.length-1;ii>-1;ii--) {
        aval=get_elemValue(e1[ii],'',modifiers);
        if (strip(aval)!=='') return aval;
   }
   return defval ;
}

//===============
// read an elements "value".
//  If input with type of "text", or a <textarea> read using xx.value (the stuff entered in the text box).
//  If hidden, use its value attribute
//  If option, or radio or checkbox, see if it is checked, and return its value attribute. 
//                Note: for "options" ... see if it is  selected.
//                If not checked, return "defval" 
//      otherwise, use innerhtml, 
//  defval can be null or undefined (NOT quoted)/
// Modifiers: transform value returned
//       Modifiers is a string that can contain any set of these letters (one or more, though try not
//      to use contradictory modifiers, like U and L, together)
//          N=must be numeric (default returned if it is not),
//          L=make lower case, 
//          U or 1=make upper case, 
//          S=strip spaces,
//          R=remove all spaces.

function get_elemValue(e1,defval,modifiers) {
  var tg,isRadio,useval ;

   if (arguments.length<2) defval='' ;
   if (arguments.length<3) modifiers='';

   useval=defval;

   if (typeof(aelem)=='string') {                       // not a node, so look for element with this ID
          var aelem=document.getElementById(aelem);
          if (!aelem) return useval; 
    }

   if (typeof(e1)!='object') return useval ;            // not a node?

   tg=e1.tagName ;
   tg=strip(tg.toUpperCase());                      // how to process depend on tagname
   isRadio=0 ;

   if (tg=='INPUT' ) {                                   // input element 
      var atype=e1.getAttribute("type"); atype=atype.toUpperCase();
      if (atype=='RADIO' || atype=="CHECKBOX") {                // is this something that needs to be  "checked" 
         isRadio=1;
         if (!e1.checked) return useval ;         //     this radio  button/ checkbox is not checked, so return default
      }
     useval=e1.value;                          
     if (!useval) useval=e1.getAttribute('value') ;             // sometimes .value doesn't work right

   } else if (tg=='TEXTAREA' ) {                                   // input element 
     useval=e1.value;                          
     if (!useval) useval=e1.getAttribute('value') ;             // sometimes .value doesn't work right

   } else if (tg=='OPTION') {
        if (!e1.selected) return useval ;         //     this option is not selected, so return default
        useval=e1.value;
        if (!useval) useval=e1.getAttribute('value') ;             // sometimes .value doesn't work right
        isRadio=1;

   }  else {                                    // all other tags    
       useval=e1.innerHTML ;
   }

// modify...
  if (typeof(useval)=='undefined' || useval==null || useval==='' ) {                   // should never happen..
       if (isRadio==0) return '' ;                               // defval used for "un checked", not for "unfilled"
        return defval;
  }

  if (!useval) return useval ;                   // may still happen?

  if (modifiers==='') return useval ;                   // none

  modifiers=' '+modifiers; modifiers=modifiers.toUpperCase() ;                               // make sure it is a string
  if (typeof(useval)=='string') {                        // change a string? 
    if (modifiers.indexOf('1')>-1) useval=useval.toUpperCase() ;
    if (modifiers.indexOf('U')>-1) useval=useval.toUpperCase() ;
    if (modifiers.indexOf('L')>-1) useval=useval.toLowerCase() ;
    if (modifiers.indexOf('0')>-1) useval=useval.replace(/^\s+|\s+$/g, '');    // strip leading/trailing spaces
    if (modifiers.indexOf('S')>-1) useval=useval.replace(/^\s+|\s+$/g, '');     // strip leading/trailing spaces
    if (modifiers.indexOf('R')>-1) useval=useval.replace(/\s/g,'') ;            // remove all spaces
  }
  if (modifiers.indexOf('N')>-1)  {
                if (isNaN(useval)) useval=defval ;
  } 


  return useval ;
}

// ==================
// recode a value. Case insensitive matching.  vn syntax:  oldvalue:newvalue. Oldvalue is compared to svy_getVal(avar)  (after stripping and capitalizing
// special case : 'something' -- if no :, use this (so should be last argument)
// note that avar and  v1.. arguments must be strings (so they are typically 'quoted'. That is, svy_getVal is NOT used

function svy_reCode(avar,v1,v2,v3,v4,v5,v6,v7,v8) {
  var usev,tusev,v2,i,v2a,anarg ;
  tusev=avar ;
  if (avar.toUpperCase)  tusev=avar.toUpperCase() ;
  for (var i=1;i<arguments.length;i++) {
     anarg=arguments[i];
     if (typeof(anarg)!='string') continue ;
      v2=anarg.split(':') ;
      if (v2.length<2) return v2[0] ;                   // no :, this is a default
      v2a=strip(v2[0].toUpperCase());
      if (tusev==v2a || v2a=='' ) return v2[1] ;
  }
 return avar ;
}

//===========================
// return a "true", "false", or dadef string
function svy_trueFalse(davar,dadef) {
   v1=strip(davar);
   if (v1==='') return dadef ;
   if (v1==='0') return 'false';
   if (v1==='1') return 'true' ;
   return dadef ;
}


//  vval2      = toFixed(avalue,ndec)           : avalue.toFixed(ndec) 
function svy_toFixed(avalue,ndec) {
 var v2=svy_getVal(avalue);
 avalue=parseFloat(v2);
 var foo=avalue.toFixed(ndec) ;
 return (foo) ;
}

// return a $xx.yy string, given a value
function svy_dollars(avalue) {
 var v2=svy_getVal(avalue);
 avalue=parseFloat(v2+0.00001);
 var foo=avalue.toFixed(2) ;
 if (foo>=0) return '$'+foo ;
 foo=-foo; foo=foo.toFixed(2) ;
 return '-$'+foo;
}
 


//==============
// change the style of of one of a set of named elements, setting all others in this set to an original style
// me1 is element to set (typically 'this'), aname argument is the name to look for, astyle is the new style (fully specified CSS style; such as "x:ab; y:zz")
// if me1 is not an object, it is assumed to be an ID (and an element with this ID is used)
function Highlight_One(me1,aname,astyle) {
  var pstyle,aelem,foo ;
  foo=document.getElementsByName(aname);            // set the set of elements, identified by name of aname, to "prior style" (if available)

  if (foo) {                            // found some names.. set them back to ther "Prior_STYLE"  
      for (var j=0;j<foo.length;j++) {
         aelem=foo[j];
         pstyle=aelem.getAttribute('Prior_STYLE') ;
         if (pstyle) {                                  // a prior style was defined? then use it
            if (aelem.style.setAttribute ) {
                aelem.style.setAttribute("cssText", pstyle);
             }  else {
              aelem.setAttribute("style", pstyle);
            }
        }
      }                         // for all in foo
  }                             // foo exists
  if (typeof(me1)!=='object') me1=document.getElementById(me1);                // lookup an element by ID?
  if (me1) {                                                           // element exists (as provided, or as looked up by ID)
      pstyle = me1.style.cssText;                       // save this elements "prior style"
      if (typeof(pstyle) != 'string' )  pstyle = me1.getAttribute('style');
      me1.setAttribute('Prior_STYLE',pstyle);

     if (me1.style.setAttribute ) {                                          // and now set "own" attribute
        me1.style.setAttribute("cssText",astyle);
     }  else {
           me1.setAttribute("style", astyle);  
     }
  }                             // me1 exists 
  return 1; 
}


//==============
// add st,nd,rd, or th to a number
// If addaval, include the "aval" before the "st". Otherwise, just return the "st"
function svy_addth(aval,addaval) {
  if (arguments.length<2) addaval=0 ;
  var v2=svy_getVal(aval); 
  if (isNaN(v2)) return '' ;
  if (Math.round(v2)!=v2) return ''     ; // dont mess with decimals
   var foo=''+v2 ;
   var ac=foo.substr(foo.length-1,1);
   var avaln=strip(aval);

   switch (ac) {
     case ('1') :
        if (addaval==1) ; return (avaln+'st') ;
        return 'st' ; 
        break ;
     case('2')  : 
        if (addaval==1) ; return (avaln+'nd') ;
        return 'nd' ; 
        break;
     case('3') :
        if (addaval==1) ; return (avaln+'rd') ;
         return 'rd' ;
         break ;
     default: 
        if (addaval==1) ; return (avaln+'th') ;
        return 'th' ;
        break ;
   }
}

//================
/* A general "return value of something" function.
  Syntax:
    avalue=svy_getVal(arg1,defval0,cnode,argType,pRound) {
     arg1 -- thing to get value of
    defval -- default value to return (if arg1 does not exist). Optional: '' is used if not specified
    cElem  --  a DOM node of an XHTML element.  Optional. If not specified, attribute and # lookup will not work (see below for the details)
    argType --  sets the default "type" of "arg1" . Optional: '%' (survey global) is used if not specified
    pround -- optional. The "prior round" to lookup a variable from. Only used if argtype=".'

 Arg1:
        Type of arg1                            What is returned
    a number (eg; 105.3)                  The value of the number is returned without any modification
    quoted string (eg; 'hello world')     The ' (or ") are stripped, and the string is returned without further modification
    DOM element object (or an array)      The value of the DOM object (or the 0th element of an array of dom objects)
                                          Depending on the DOM tag: value is the value attribute (INPUT and OPTION)
                                          or the innerHTML (DIV and SPAN)
    survey global variable name          The value of the "arg1" survey global variable.
                                             If % is the first character, arg1 is treated as a survey global variable (after stripping the %).
                                         You can specify elements of a survey  global array by using arg1[n].
                                            Special case: you can # as an array index, # will be replaced by the IDX of cElem.
                                            Special case: an array index can be a survey global variable, or element, or ...  -- its recursive!

    element name                         The "value" of the XHTML element with a name of "arg1".
                                            If @ is the first character, arg1 is treated as an element name (after stripping the @).
                                         Note that the "name" attribute is used, not the "id" attribute.
                                         Thus, if more than one element has this name, the value of the first element is returned.
                                         You can narrow this down by using the # character as a suffix.
                                                Example:  @cost#
                                         # means "look for an element with a name of arg1, and an IDX atttribute that matches the
                                         IDX attribute of cElem".

     attribute name                     The value of the arg1 attribute of the cElem node.
                                            If # is the first character, arg1 is treated as an attribute name (after stripping the #).
                                            If arg1 ='#', then the "IDX" attribute is used.

    survey-prior variable               The value of a survey-prior variable. arg1 must have a syntax of:
                                              varname.round or arr[n].round ; where n can be a number, variable name, or another array

   For survey global variables, and survey-prior variables, strongTyping can be enforced. If strong-typing is enforced,
   then reading a non-existent variable will cause a warning message to be displayed (via an alert).

   By default, dSurvey will enable strong typing when debug_mode > 0.
   You can weaken, or strengthen, the circumstances during which strong typiong occurs by
   modify the strongTyping javacript variable in defaultStart.html file. 

 DefVal:
        Value to return is arg1 can not be found.  For example, if no such survey global variable exists.
        Note that in some cases, an error results (defval is not used). In particular, an error message is shown when:.
                an attribute name is asked for, or a # is used in a element name lookup, but cnode is not a DOM (an XHTML) element.

cElem:
      A DOM (xhtml) element.
      cElem is used when an attribute is being looked up, a # appears in an element name, or a # is used in a
      survey global array index. In these cases, if cElem is not a DOM object, an error occurs.

argType:
     The "type of arg1".  By default, arg1 is assumed to be a survey global variable. You can override this default
      by setting argType.
      Argtype can have the following values:
         "" (the default) : survey global variable
         "%"  or 'GLOBAL' or 'G':  survey global variable (same as default)
        "@"   or 'ELEMENT'  or 'E' : element name
        "#"   or 'ATTRIBUTE' or 'A' : attribute name
        "."   or 'PRIOR' or 'P' : survey prior variable
     argTytpe is NOT used if one arg1 explicitily specifies the type. That is: if arg1 starts with a %, #, @, or contains a ".", then
     argType is IGNORED.

pRound :
    Used if argType="." -- the "round" of the prior variable to look up. Otherwise, ignored


*/
 function svy_getVal(arg1,defval,cElem,defType,pRound) {

var gotnode,c1,vv ;
var isperiod,idxCheck;
var ixx,aindex,ibb,ibb2,vv0,nround,ith,tvarname,ps,aval,e1,use1;
var aa0,goo,pVar,pIndex ;
var ii1,vv1,aidx,c1;
var goo,vindx ;

aa0=arg1;
if (arguments.length<2) defval='';
if (arguments.length<3) cElem='' ;
if (arguments.length<4) defType='' ; defType=strip(defType.toUpperCase());
if (arguments.length<5) pRound=''   ; pRound=strip(pRound);

if (!isNaN(arg1)) return arg1 ;                         // its a number, then return its value

if (typeof(arg1)=='object') {                           // this is an element
   if (typeof(arg1.length)!='undefined')   arg1=arg1[0] ;  // array of elements? use first one [0]
   aval=get_elemValue(arg1,defval);
   return aval ;
}

if (typeof(arg1)!=='string') return arg1 ;                           // this is an element

// if here, arg1 is  a string.
arg1=strip(arg1);

gotnode=0 ;
if (typeof(cElem)=='object') gotnode=1 ;                        // used if atribute lookup needs to be done

if (defType==1 || defType=='' ||defType.substr(0,1)=='G' ) defType='%' ;              // defaults
if (defType.substr(0,1)=='E') defType='@';
if (defType.substr(0,1)=='A') defType='#';
if (defType.substr(0,1)=='P') defType='.';


// if begins with ' or ", its a literal string. Return as is (stripping ' or ")

c1=arg1.substr(0,1);
if (c1=='"' || c1=="'") {
   var vv=arg1.substr(1,arg1.length-2);
   return vv ;
}

// if here, arg1 is a global variable, or an element name, or attribute name, or prior variable

if (c1=='@' || c1=='#' || c1=='%')  {                // override default?
   defType=c1 ;
   arg1=arg1.substr(1);
}

if (defType=='#' )  {                // check for [ ] or . where they should not be  (NO LONGER ENFORCED fOR @ )
     if (arg1.indexOf('.')>-1 || arg1.indexOf('[')>-1 || arg1.indexOf(']')>-1 ) {
        alert('svy_getVal bad variable specification (element or attribute with a . [ or ] ): '+arg1);
        return defval
     }
}


goo=parseArrayPrior(arg1);                             //goo[0]=varname, goo[1]=index, or undefined if not array, goo[2]=priror or undefined if not a prior
if (goo.length==0) return defval ;              // error occured, give up

pIndex=''; nround='';
pVar=goo[0];
if (typeof(goo[1])!='undefined') pIndex=goo[1];
if (typeof(goo[2])!='undefined')  {
     nround=goo[2];                             // might be ''
    if (nround=='' && pRound!='') nround=pRound ;
    defType='.';
}

// Lookup a prior variable
if (defType=='.') {
   if (pVar.indexOf('#')>-1 && gotnode==0) {                 // an attribute used?
           alert('ERROR: svy_getVal. [#] in survey global prior variable name ('+pVar+') but DOM node not specified '+cElem);
           return null ;
    }
    if (pIndex!=='') {                                    // array?
          ii1=svy_getVal(pIndex,defval,cElem,'',nround);            // so recurse (but default type of index is survey global var, and pRound is nround)
          tvarname=pVar+'['+ii1+']';                                 // a hack used below
    } else {
       tvarname=pVar;
    }
    nround=svy_getVal(nround,'',cElem);
    vv1=Read_priorGlobal(nround,tvarname,defval);
    return vv1 ;
}                                                                    // end of rior lookup


// lookup an attribute value
if (defType=='#') {
   if (gotnode==0) {
        alert('ERROR in svy_getVal: asking for attribute value '+aa0+', but no node specified ');
        return null ;
   }
   if (arg1=='') arg1='IDX';          // '#' is shorthand for #IDX (equals '' after stripping leading #)
   aval=getAttributes(cElem,arg1,defval);
   return aval;
}                                            // end of attribute lookup


// lookup  element name, possibly modified by IDX attribute, possibly with an array name resolved?
if (defType==='@') {
  ixx=arg1.indexOf('#');  idxCheck='';
  if (ixx>-1) {                 // "IDX" attribute should also be used?
        if (gotnode==0) {
           alert('ERROR: svy_getVal. # in element name ('+aa0+') but DOM node not specified ');
           return null;
        }
        idxCheck=getAttributes(cElem,'IDX','');idxCheck=strip(idxCheck.toUpperCase()) ;
        arg1=strip(arg1.substr(0,ixx));
  } else {                                                                // # found
    if (arg1.indexOf('[')>-1) {
        goo=parseArrayIndex(arg1);
        vindx=strip(svy_getVal(goo[1],''));
        if (vindx==='') {
             alert('svy_getVal error: an array index is not specified in '+arg1);
              return -1 ;
        }
       arg1=strip(goo[0])+'['+vindx+']';
    }                                   // [ found
  }                                             // # not found 

  var e1=get_elements('*','',arg1);

//  alert('egooooo '+arg1+','+e1);

  if (!e1) return defval ;
  use1='';
  if (idxCheck==='') {                                   // no # -- use first match to arg1 (element with a name of arg1)
      if (typeof(e1.length)!='undefined') {
         use1=e1[0];
       } else {
         use1=e1 ;
       }
  } else {                                      // # used -- find element with proper idx attribute
     if (typeof(e1.length)!='undefined') {      // a hack
        var tmp=[]; tmp[0]=e1; e1=tmp;
     }
     for (var ii=0;ii<e1.length;ii++) {
        aidx=getAttributes(e1[ii],'IDX','');
        if (strip(aidx.toUpperCase())!=idxCheck) continue ;
        use1=e1[ii]  ; break ;
     }
  }

  aval=defval ;
  if (use1!=='') aval=get_elemValue(use1,defval);               // could happen if  idx not matched
  return aval ;

}                                                               // end of element lookup
 

// global variable lookup
if (defType==='%') {                  // survey global array .. check for array, and for #
  if (aa0.indexOf('#')>-1  && gotnode==0) {                 // an attribute used?
          alert('ERROR: svy_getVal. # in survey global variable name ('+aa0+') but DOM node not specified '+cElem);
          return null ;
   }
   ibb=arg1.indexOf('[');
   tvarname=arg1 ;
   if (ibb>-1)  {                          // array indices found
        vv0=parseUsingOuter(arg1,'[',']',1);
        aindex=strip(vv0[1]);
        if (isNaN(aindex)) {                      // not a number, perhaps a variable to lookup?
            aindex=svy_getVal(aindex,defval,cElem,'',pRound);            // hey, its recursive (but default type of index is survey global var)
        }
        tvarname=vv0[0]+'['+aindex+']';                                 // a hack used below
    }
    aval=Read_Global(tvarname,defval);
    return aval ;
}

alert('svy_getVal error: bad type: '+ aa0);
return null;

}



//============
// step through array/prior var name, return name portion, prior portion. Might be complicated!
// basic idea: scan through characters. The first "." encountered that is not "inside of" a [ ] signals the
// break between the varname and the prior-round pointer
// returns vv[0]=varname, vv[1]=index (or undefined if NOT an array), vv[2]=priorVar (or undefined if not a prior
// note that index and priorVar may also be "prior arrays"

function parseArrayPrior(arg1) {
var im,i,m,j,ac,vv,E1=0;E1=0;
var aname='',aprior='';
var vv=[];
plevel=0;

arg1=strip(arg1);
for (var m=0;m<arg1.length;m++) {
  ac=arg1.substr(m,1);
  if (ac=='[') {
         plevel++ ;
         if (plevel==1) E1=m ;          // first [? Then this is where the index starts
  }
  if (ac==']') {
         plevel-- ;
         if (plevel==0) E2=m ;          // index ends here
  }
  if (plevel<0) {
        alert('parseArrayPrior error: too many ] in :'+arg1);
        return vv;
  }

  if (ac=='.' && plevel==0)  {                          // got a . not inside of [] 
     vv[2]=arg1.substr(m+1);                    // the prior is everything after this position (don't care if it is an array or whatever)
     if (E1!=0) {                       // found a [ ] before the .
        if (E2<E1) {                    // an error
            alert('parseArrayPrior error: bad order of  ]  :'+arg1);
            return vv ;
        }
        vv[0]=arg1.substr(0,E1);
        vv[1]=arg1.substr(E1+1,E2-E1-1);
     } else {                                   // vv[1] undefined means "not an array"
         vv[0]=arg1.substr(0,m);
     }
     return vv;
 }
}

// if here, no .

if (plevel>0) {
        alert('parseArrayPrior error: too many [ in '+arg1);
        return vv ;
  }


if (E1!=0) {                       //  found a [
   if (E2<E1) {                    // and a ] after it
         alert('parseArrayPrior error: bad order of [ and ]  :'+arg1);
         return vv ;
  }
   vv[0]=arg1.substr(0,E1);
   vv[1]=arg1.substr(E1+1,E2-E1-1);
} else {                                // not an array
   vv[0]=arg1;                     
}
return vv;                      // only 0th element means not an array and not prior


return 0;
}



//==================================================== vv1
// return nth word in a string (first word is 1)
function svy_getWord(astring,nth,adelim) {
  if (arguments.length<3) adelim='' ;
  if (arguments.length<2) {
        alert('Error in svy_getWord: no 2nd (nth word) argument ');
        return '' ;
  };
  var ss=svy_getVal(astring) ;
  if (ss=='') return '' ;
  var nn=svy_getVal(nth);
  if (isNaN(nn)) return '' ;
  nn=Math.floor(nn) ;
  if (nn<1) return '' ;
  var foo=getWord(ss,nn,adelim);
  return foo ;
}

//================
// add a style to the arf element. Typically used with a "IF" and "THEN" condition. Or, as a shortcut, acond argument specifes
// a logical condition to satisfy.
//  arf must be the ID (or element object)  to add the astyle style to.
//  this is basically a front end to update_styles()

function svy_addStyle(astyle,arf,ireplace) {
  if (arguments.length<2)   arf='';
  if (arguments.length<3) ireplace=0;
  if (arf=='') return '' ;                      // no valid ID
  if (typeof(arf)!=='object') arf=document.getElementById(arf);

  if (!arf) return '';                          // no such id

  update_styles(arf,astyle,ireplace);
  return 1;
}

//================
// add content to the arf element.
//  arf must be the ID (or element object)  to add the conteont of acontent to.
//  this is basically a front end to update_styles()

function svy_addText(acontent,arf,ireplace) {
  if (arguments.length<2)   arf='';
  if (arguments.length<3) ireplace=0;
  if (arf=='') return '' ;                      // no valid ID
  if (typeof(arf)!=='object') arf=document.getElementById(arf);

  if (!arf) return '';                          // no such id

  var isgot=arf.innerHTML ;
  if (ireplace==1) isgot='';
  isgot=isgot+' '+acontent;
  arf.innerHTML=isgot ;

  return 1;
}


//================
// return uniform random between arg1-arg2 and arg1+arg2
function svy_random(arg1,arg2,arg3) {
var v1,v2,v3,v4;

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

 v1=svy_getVal(arg1);
 if (v1==='') return '' ;
 if (isNaN(v1)) return '' ;
 v1=parseFloat(v1);

 v2=svy_getVal(arg2);
 if (v2==='') return '' ;
 if (isNaN(v2)) return '' ;
 v2=parseFloat(v2);


 var arange=v2-v1 ;
 var v3=Math.random() ;
 v4=v1 + (v3* arange) ;

if (arguments.length<3) return v4 ;

if (arg3=='') return v4 ;

// else, possibly fix to a resolution
arg3=svy_getVal(arg3);  
if (isNaN(arg3) || arg3==='' ) return v4 ;

if (arg3==0) {
     v4=v4.toFixed(0) ;
    return v4 ;
}
arg3=parseFloat(arg3);
var foo=Math.round(v4/arg3)*arg3  ;

if (arg3>1) { foo=foo.toFixed(0); 
        return foo }

var t1=0.01+(10*arg3) ;
  if (t1>1) {  foo=foo.toFixed(1); 
  return foo }

var t1=0.001+(100*arg3) ;
  if (t1>1) {  foo=foo.toFixed(2); 
   return foo }

var t1=0.0001+(1000*arg3) ;
  if (t1>1) { foo=foo.toFixed(3);
   return foo }


return foo;

}

// return  a string displaying possible draws from a uniform random distribution, using "v1,v2,...,vj,vk"
// arg1: Low end. REQUIRED. This is always the first number displayed
// arg2 : High end. REQUIRED. This is always the last number displayed
// arg3: Number of v1,v2  (if 3, v1,v3,v3 displayed, and vj,vk,vm). Optional: default is 1 (just the fist and last values)
// arg4: resolution.   Optional. Default is 1 (move by ones)
// arg5:  # decimal points to display.  Optional, default is 0 (integer display)
// arg6: string to prepend to value.   Optional. Default is '' (no prepend)
// Example: svy_randomExample(100,200,2,0.1,2,$) would yield:
//    "$100.10,$100.20,$100.30,...,$199.80,$199.90,$200.00)
function svy_randomExample(arg1,arg2,arg3,arg4,arg5,arg6) {
   var astr,v1,v2,v3;

   if (arguments.length<1) return ' error no arg1 in svy_randomexample ' ;
   var alow=svy_getVal(arg1);
   if (isNaN(alow))    return ' error no numeric arg1 in svy_randomexample:  '+ arg1 +',' + alow ;;
   alow=parseFloat(alow);

   if (arguments.length<2) return ' error no arg2 in svy_randomexample ' ;
   var ahigh=svy_getVal(arg2);
   if (isNaN(ahigh))    return ' error no numeric arg2 in svy_randomexample:  '+ arg1 +',' + ahigh ;
   ahigh=parseFloat(ahigh);

   if (arguments.length<3) arg3=1  ;
   var ndo=svy_getVal(arg3);
   if (isNaN(ndo))    return ' error no numeric arg3 in svy_randomexample:  '+ arg3 ;
   ndo=parseInt(ndo);

   if (arguments.length<4) arg4=1  ;
   var ainc=svy_getVal(arg4);
   if (isNaN(ainc))    return ' error no numeric arg4 in svy_randomexample:  '+ arg4 ;
   ainc=parseFloat(ainc);

   if (arguments.length<5) arg5=0  ;
   if (isNaN(arg5)) arg5=0 ;
   if (arguments.length<6) arg6='' ;

   astr='';
   for (var i1=0; i1<ndo;i1++) {
      v1=alow+(i1*ainc) ;
      v1=v1.toFixed(arg5);
      v2=arg6 + v1 ;
      if (i1==0) {
         astr=v2;
      } else {
         astr=astr+', '+v2
      }
    }
    astr=astr+",..., " ;
    for (var i1=1; i1<=ndo;i1++) {
      v1=ahigh-((ndo-i1)*ainc) ;
      v1=v1.toFixed(arg5);
      v2=arg6 + v1 ;
      if (i1==1) {
         astr=astr+v2;
      } else {
         astr=astr+', '+v2
      }
    }
   return astr ;
}


//=======================================================
// set an elements "value". To avoid wierdness, sets INPUT and OPTION value using .value and setAttribute!
// Otherwise, similar to get_elemValue
//   aelem : an element. If a string, id with this name is lookedup.
//   avalue  : value to "set" the elements value field (or attribute) to
// returns 1 if success, 0 if failure (i.e.; if no such Id with aelem name)

function set_elemValue(aelem,useval) {

     if (typeof(aelem)=='string') {
          var aelem=document.getElementById(aelem);
          if (!aelem) return 0; 
     }
     if (typeof(aelem.length)!='undefined')   aelem=aelem[0] ;  // array of elements? use first one [0]

     var tg=aelem.tagName ; tg=tg.toUpperCase() ;
     if (tg=='INPUT' || tg=='OPTION') {                              // add to the value field
// alert(aelem.nodeName+','+aelem.getAttribute('ID')+' settingputvalue '+useval);
           aelem.value=useval  ;
           aelem.setAttribute('value',useval);     // .value doesn't seem to work all the time
       } else {                                         // use as the innerHTML
          aelem.innerHTML=useval ;
       }
       return 1 ;
}

//=======================================================
//======================
// Find the values of the attributes listed in attlist (a space delimited list). 
// Returns an object with their values, using capitalized & stripped values as indices. Object indices are also capitalized
// If an attribute (in attlist) does not exist, a value of '' is used, or a default value is returned.
// Adefs is optional. It should either be a string, or an object
//    If adefs is not specified, an object is returned with '' used for non-existent attributes (in attlist)
//
// Adefs example:
//  object:  an object that may contain prior/default values of the attributes.
//               It will be modified -- so that if an attribute listed in attlist is NOT found, it will NOT
//               be modified in adefs. Hence, its adefs value will be returned.
//               Note that names in attlist that are NOT in adefs will be added to adefs, with a default value of ''
//   string      : return the value of the first encountered attribute (in attlist) as a string. If none of the attributes listed in attlist are
//                 found, return the value of adefs.
//                Note: this "first encountered" feature allows you to look for abbreviations, etc (i.e.; NODEF and NODEFAULT)
//
// Object Example: if attlist="a1a A2 A4"
//          anode has attributes A1a="11"  A3="33"
//          adefs['A2']='miss1';
// Then the object returned (call it newobj) will have:
//   newobj['A1A']='11'          -- note use oF capialized "a1a", note case insensitive match of "a1a" and "A1a" 
//   newobj['0~A1A']='A1a'     -- the 0~ prefix is used to find original (case preserved) attribute name
//   newobj['A2']='miss1'
//   newobj['0~A2']='A2'     -- the 0~ prefix is used to find original (case preserved) attribute name
//   newobj['A4']=''            -- if no attribute found, no 0~ object-element created
//
// Note that newobj['A4'] is set to '' (since it is not an attrtibute of the node, and it was not defined in adefs)
// Also note that newobj['A3'] is NOT an element of newobj, since A3 does not appear in attlist

// Note: "style" is a special case -- if IE, return the style.cssText 

function getAttributes(anode,attlist,adefs) {

  var newobj,vlist,m2,anatt,annat_orig,anode,asString=0,mlen;
  var useall=0 ;
  if (arguments.length<2) attlist='*' ;
  if (attlist=='*') useall=1 ;
 
  if (arguments.length<3) {
        newobj=new Object() ;
  } else {
      if (adefs===null || typeof(adefs)!='object') {            // perhaps a "return as string" signal?
             asString=1 ;
             newobj=new Object() ;
      } else {                         // is an object -- so use it
         newobj=adefs ;
      }
  }
   newobj['']='';                                 // used to store list of all attributes found
   if (useall==0) {                              // look for given set 
        vlist=getWord(attlist);
        for (var m2=0; m2<vlist.length;m2++) {                        // initialize (set all attributes='', except predefined ones 
            anatt_orig=strip(vlist[m2]) ; anatt=anatt_orig.toUpperCase() ; 
            if (typeof(newobj[anatt])=='undefined') newobj[anatt]='' ; // note that newobj is also used to identify if a name is in attlist
        }
  }                                     // otherwise, get all attributes 

  try {
    var mlen=anode.attributes.length;
  }
  catch(err) {                          // possibly a comment  (anode.attributes.length doesnt exist)
    if (asString==1) return adefs ;                           // no attributes (matching attlist) found -- return default 
    return newobj ;
   }
  for (var m2=0; m2<mlen;m2++) {                    
     anatt_orig=strip(anode.attributes[m2].name) ; anatt=anatt_orig.toUpperCase() ;
     if (useall==0) {                                           // only retain specified attriburtes
        if (typeof(newobj[anatt])=='undefined')  continue  ;               // don't care about this one, so skip it
     }
     if (asString==1) { 
        return anode.attributes[m2].value ;       // if asString, return first of the "attlist" attributes found (as a string)
     }
     newobj[anatt]=anode.attributes[m2].value ;
     newobj['0~'+anatt]=anatt_orig ;                  // original (case presreved) attribute name 
     newobj['']=newobj['']+anatt+' ';                        // if found, but not in list (and not *), just ignore 
  }

  if (asString==1) return adefs ;                           // no attributes (matching attlist) found -- return default 
  return newobj ;

}



//================
// return the sibling number of a node (that is, the child number of the node's parent that is this node
// 1 is first. <0 is error (-1: no such id, -2:no parent, -3: this child is not found in parent list)
//  anode0 : an element object, or a string to be used in document.getElementById
//       (if no such id, -1 returned)
// notext: Optional. If 1, if 1, then exclude children (when returning sibling # or #siblings.
//         so, if #children=5 but 2 are text, then will return 1,2, or 3
// Note that a "1" returned refers to the parentNode.childNodes[0] node

function whichSibling(anode0,notext){
var pnode,m,im ;

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

if (typeof(anode0)=='string') {
  anode=document.getElementById(anode0) ;
  if (!anode) return -1 ;
} else {
  anode=anode0;
}

if (typeof(anode.parentNode)=='undefined') return -2 ;
pnode=anode.parentNode ;

im=0;

for (var m=0;m<pnode.childNodes.length;m++) {
 if (notext==1) {
    if (pnode.childNodes[m].nodeType!==1) continue ;
    im++;
  } else {
    im++;
  }
  if (pnode.childNodes[m]==anode) return im ;
}
return -3;

}

//================
// Return number of siblings, possibly just elements (skip text, etc).
// Values <0 denote errors (0 is never returned)
// Note that if notext=0, this is just anode0.parentNode.childNodes.length
// 
//  anode0 : an element object, or a string to be used in document.getElementById
//  notext :  Optional. If 1, ignore all non-element nodes (i.e.; ignore comments and text nodes)
//            Thus, return the number of element nodes

function numSibling(anode0,notext){
var pnode,m,im ;

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

if (typeof(anode0)=='string') {
  anode=document.getElementById(anode0) ;
  if (!anode) return -1 ;
} else {
  anode=anode0;
}

if (typeof(anode.parentNode)=='undefined') return -2 ;
pnode=anode.parentNode ;

im=0;

for (var m=0;m<pnode.childNodes.length;m++) {
 if (notext==1) {
    if (pnode.childNodes[m].nodeType!==1) continue ;
    im++;
  } else {
    im++;
  }
}
return im ;

}


//================
// Return nth sibling (pointer to the node), possibly just of the elements (ignoring text, etc. nodes)
// 0 means error (say, nth > # of siblings)
//    anode0 : an element object, or a string to be used in document.getElementById
//    nth    : the nth node to return, OR the nth element node (depending on the value of notext)
//    notext : Optional. If 1, ignore all non-element nodes (i.e.; ignore comments and text nodes)

// note: nth=1 is the first sibling (not 0)
function getSibling(anode0,nth,notext){
var pnode,m,im ;

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

if (typeof(anode0)=='string') {
  anode=document.getElementById(anode0) ;
  if (!anode) return -1 ;
} else {
  anode=anode0;
}

if (typeof(anode.parentNode)=='undefined') return -2 ;
pnode=anode.parentNode ;

im=0;

for (var m=0;m<pnode.childNodes.length;m++) {
 if (notext==1) {
    if (pnode.childNodes[m].nodeType!==1) continue ;
    im++;
  } else {
    im++;
  }
  if (im==nth) return pnode.childNodes[m] ;
}
return 0 ;

}


//==================================
/* This script and many more are available free online at
The JavaScript Source!! http://javascript.internet.com
Created by: Robert Nyman | http://robertnyman.com/ 
Removes HTML tags from a string
*/

function removeHTMLTags(strinputCode){

 var strTagStrippedText = strinputCode.replace(/<\/?[^>]+(>|$)/g, "");
 return strTagStrippedText ;
}



//=======================================================
// call as  get_elements(chkelement,classname,namelist,usewin)
// Returns an array of elements that match the tag of e_name (or in the e_name list), that have a classname of daflag, and optionally a name in namelist
//          chkelement: the tagname  of elements to extract. Or, an array/nodelist of elements. or an id.tagname string.
//          daflag: :  only elements with this as one of their class names are considered (i.e.; "KEYINC"). If '', accept all classes
//          namelist : list of names. If specified, only elements with this name are considered
//          usewin : window id. If not specified, look in main window
//          usemod : a pointer to an XML node. Only used if usewin not specified (if usewin=0)
// If element_name is a string with a ".", then the first part is the div, the second the tagname. Only elements in the indicated div are considered.
// e_name can be a list of specifications (but NOT of objects)
//
// Order of elements returned will reflect order in the dom tree of tagnames in chkelement.
// for div.tagnames in chkelement, the order is indeterminate (they will appear after tagname elements (not in a div)

// Note: if called with chkElements as an array, and  daflag='' and no namelist, this will simply copy the  array

function get_elements(chkElement,daflag,namelist,usewin,usemod) {
  var ares= new Array() ;                       // what will be returned 
  var useMain,useModule,chkme,usemes,cc,chkElements,chk1,foo,adiv,tname,chk2;
  var atag,chk2,iae,iae2,foo,divStuff,lookups,cc,ii;
   var idxval,namelist1 ;

  if (arguments.length<2) daflag='' ;
  daflag=strip(daflag.toUpperCase());

  if (arguments.length<4  ) usewin=0 ;
  if (arguments.length<5  ) usemod=0 ;

  if (usewin===0 || usewin==='') {    
        useMain=1 ;
  } else {
       useMain=0 ;
  }
  if (usemod===0 || usemod==='') {    
        useModule=0 ;
  } else {
       useModule=1 ;
  }
  if (useMain==0 && useModule==1) {
           alert("Error in get_elements: can not specify a window and a module ");
           return 0 ;
   }

  if (arguments.length<3) namelist='' ;
  if (namelist===0)  namelist='' ;

  divStuff=[];
  if (typeof(chkElement)=='string') {                                // a tagname was provided. or id. or id.tagname 
       chkElement=strip(chkElement);
       cc=chkElement.split(' ') ;
       var lookups=new Object() ;                       // for quick lookups
       for (var ii=0;ii<cc.length;ii++) {
           a1=strip(cc[ii].toUpperCase());
           if (a1.indexOf('.')<0) {
                 lookups[a1]=1;                // don't save div.tagname
            } else {
                 divStuff=divStuff.concat(cc[ii]);
            }
       }                                               // list of tagnames
       var chkElements=new Array() ;
       if (useModule==1) {
          allelems=usemod.getElementsByTagName('*');
       } else {
          if (useMain==1) {
              allelems=document.getElementsByTagName('*');
          } else {
              allelems=usewin.document.getElementsByTagName('*');
          }
       }
       for (var iae=0;iae<allelems.length;iae++) {
           chk2=allelems[iae];
           atag=strip(chk2.nodeName.toUpperCase());
           if (!lookups[atag] && !lookups['*']) continue ;

           chkElements=Concat_Arrays(chkElements,chk2) ;
       }                                 // all words in the chkElement list
// div.tag found?
      if (divStuff.length>0) {
           if (useModule==1) {                            // no DIV in modules permitted
                      alert('Error in get_elements: no div.tagname allowed when processing a module ');
                    return 0;
           }
           for (var iae2=0;iae2<divStuff.length;iae2++) {
              chk1=divStuff[iae2];
              foo=chk1.split('.') ;
              adiv=foo[0]; tname=foo[1] ;
              if (useMain==1) {
                    var usemes=document.getElementById(adiv);       // get element in this div (with this iD)
               } else {
                    var usemes=usewin.document.getElementById(adiv);       // get element  in this div (with this iD)
               }
               if (!usemes) continue ;                         // empty? skip
               chk2=usemes.getElementsByTagName(tname);        // pull elements with this tag from this div
               chkElements=Concat_Arrays(chkElements,chk2) ;
           }
      }                                                 // divstuff

  }    else  {                                                    // else, a nodelist, or an array of nodes, was provided 

         chkElements=chkElement ;

  }                                                     // chkelement a string
  

  if (typeof(chkElements)=='object' && typeof(chkElements.length)=='undefined') {             // non array object   
       cc=new Array() ;
       cc[0]=chkElements ; chkElements=cc ;
  }

  for (i=0; i < chkElements.length ; i++) {
      if (daflag=='' || Find_Class(daflag,chkElements[i])) {     // class check passed, or no classname. So check name attribute 
             if (namelist!='') {                               // namelist check also?
                    if (namelist.indexOf('#')>-1) {
                          idxval=chkElements[i].getAttribute('idx') ;
                          idxval=svy_getVal(idxval);
                          namelist1=namelist.replace('#',idxval) ;
                     } else {
                         namelist1=namelist   ;
                     }

                    if (!Find_Name(namelist1,chkElements[i])) continue ;
             }                                                          // IF HERE, no namelist ,or name is namelist
             ares[ares.length]=chkElements[i] ;
      }
  }                   //loop thru input elements


return ares ; 
 
}

//============  
// delete elements
function delete_elements(chkElement,daflag,namelist) {
  if (arguments.length<2) {
         daflag='' ; namelist='';
  } else {
      if (arguments.length<3) namelist='' ;
  }

  var ndid=0;
  if (typeof(chkElement)=='object' && daflag=='' && namelist=='') {             // save some processing
     var adel=chkElement ;
  } else {
     var adel=get_elements(chkElement,daflag,namelist);
 }
 removeNodes(adel,1);
 return ndid;
}





// return
//=======================================================
// call as  get_elements_remove(e_name,classname,namelist)
// Returns an array of elements that match the tag of e_name (or in the e_name list), that do NOT have a classname of daflag,
// and NOT  a name in namelist
//   See get_elements for the details
// Note that if classname and namelist are not specified, get_elements and get_elements_remove are identical
// Note: if called with chkElements as an array, and  daflag='' and no namelist, this will simply copy the  array

function get_elements_remove(chkElements,daflag,namelist) {

  var ares= new Array() ;                       // what will be returned 

  if (arguments.length<2) daflag='' ;
  daflag=strip(daflag.toUpperCase());

  if (arguments.length<3) namelist='' ;
  if (namelist===0) {
        namelist='' ;
  } else {
      namelist=' '+namelist.toUpperCase() +' ';
  }

  if (typeof(chkElements)=='string') {                                // a tagname was provided. or id.tagname 
       chkElements=strip(chkElements);
       if (chkElements.indexOf('.')>-1) {                             // div.tagname format 
             var foo=chkElements.split('.') ;
             var adiv=foo[0]; var ename=foo[1] ;
             if (ename=='') ename='*';
             if (adiv=='') {
                 chkElements=document.getElementsByTagName(ename);
             } else {
                usemes=document.getElementById(adiv);
                if (!usemes) return ares ;                         // return empty array
                chkElements=usemes.getElementsByTagName(ename);
             } 
       } else {
            if (strip(chkElements)=='') chkElements='*' ;                       // get all elements 
            var chkElements = document.getElementsByTagName(chkElements);
      }
  }                                                        // else, a nodelist, or an array of nodes, was provided 

  if (typeof(chkElements)=='object' && typeof(chkElements.length)=='undefined') {             // non array object   
       var cc=new Array() ;
       cc[0]=chkElements ; chkElements=cc ;
  }


  for (i=0; i < chkElements.length ; i++) {

      arf=0;
      if (daflag!='') var arf=Find_Class(daflag,chkElements[i]);        // class found?
     if (arf==1) continue ;                            // then dont use

      arf=0;
      if (namelist!='') arf=Find_Name(namelist,chkElements[i]) ;        // name found?
      if (arf==1) continue ;                                    // then dont use

      ares[ares.length]=chkElements[i] ;                 // success.

  }                   //loop thru input elements

return ares ;
 
}

// return an elements ID. If no ID defined, create a unique one, assign it to the element, and then return it.
function svy_addID(aelem) {
     daid=strip(aelem.getAttribute("ID"));
     if (daid!=='') return daid ;
     if (typeof('svy$IDcounter')=='undefined') svy$IDcounter=0 ;
     svy$IDcounter=svy$IDcounter+1 ;
     var daid="$SVY_ID_COUNTER$_"+svy$IDcounter ;
     aelem.setAttribute("ID",daid);
     daid=strip(aelem.getAttribute("ID"));
     if (daid=="" ) aelem.ID=daid ;                     // some browsers are wierd about ID 
     return daid ;
 }
     
    


// return the 2nd,3rd,.. argument; given value of first argument
// use todo, and  arg0... as is (do NOT use svy_getval on them). Why? If used in setValue, then arguments will be resolved BEFORE calling svy_whichOne
function svy_whichOne(todo,arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7) {
var v1,v2;

v1=parseInt(todo);

if (v1==='') return '' ;
if (isNaN(v1)) return '' ;
if ((v1+2)> arguments.length) return '' ;           // max of 7 arguments
switch (v1) {
case 0:  return arg0 ;break ;
case 1: return arg1 ;break ;
case 2: return arg2 ;break ;
case 3: return arg3 ;break ;
case 4: return arg4 ;break ;
case 5: return arg5 ;break ;
case 6: return arg6 ;break ;
case 7: return arg7 ;break ;
default: return '' ;
}

}





//===========================
// concatenate up to 8 "strings" (numbers are converted to strings )
function svy_concat(v1,v2,v3,v4,v5,v6,v7,v8) {
var aa,a1,v1,va1;
aa=' ';
for (var m=0 ; m<arguments.length;m++) {
   a1=arguments[m];
   va1=strip(svy_getVal(a1));
   if (strip(va1)==='') v1a=' ';
   aa=aa+va1 ;
}
aa=strip(aa);
return aa 
}


//===========================
// add a set of numbers. If value is missing, use 0
// Or,if aval:adef, use adef.
// ie; av1 is converted to av1:0, etc.
// DEPRECATED: use svyMiss and +

function svy_add(av1,av2,av3,av4,av5,av6,av7,av8) {
  var a1,isneg,v1,adef ;
  var v1,v2,v3,v4,v5,v6,v7,v8 ;
  var tot=0;
  for (var m=0 ; m<arguments.length;m++) {
     a1=strip(arguments[m]);
     adef='0';
     isneg=1;
     if (a1.substr(0,1)=='-') {
         isneg=-1 ; a1=a1.substr(1) ;
     }
    if (a1.indexOf(':')>-1) {
         var a1s=a1.split(':');
         a1=a1s[0];
         adef=a1s[1];
    }
     v1=svy_getVal(a1,'');
     v1=parseFloat(v1); 
     if (isNaN(v1)) v1=adef;
     tot=tot+(isneg*v1);
  }
return tot ;                    // if non number, NaN is returned 
}

//===========================
// multiply a set of numbers. If value is missing, use 1
// Or,if aval:adef, use adef.
// ie; av1 is converted to av1:1, etc.
// DEPRECATED: use svyMiss and *
function svy_prod(v1,v2,v3,v4,v5,v6,v7,v8) {
 var a1,isneg,v1,adef ;

  var tot=1;
  for (var m=0 ; m<arguments.length;m++) {
     adef='1' ;
     a1=strip(arguments[m]);
     isneg=1;
     if (a1.substr(0,1)=='-') {
         isneg=-1 ; a1=a1.substr(1) ;
     }
    if (a1.indexOf(':')>-1) {
         var a1s=a1.split(':');
         a1=a1s[0];
         adef=a1s[1];
    }
     v1=svy_getVal(a1);
     v1=parseFloat(v1);
     if (isNaN(v1)) v1=adef;
     tot=tot*(isneg*v1) ;

  }
return tot ;                         // if non number, NaN is returned 
}


// ----------
// return time and/or date 
//  If no arguments: return  hh:mm:ss xM 
// timeType:  
//      0= javascript milliseconds
//          otherwise, incldue time
//      1 =  mm:hh:ss xM

// dateType:
//      1=  date Month Year
//      2 = day-of-week, date Month Year
//
// if timeType and dateType ==2 : return as: xday Month date year hh:mm:ss GMT-xxxx (tz) 

// if both time and date specified, format is date-string, time-string 

function svy_currentTime(timeType,dateType) {
  var Hours,Mins,Time,Sec,atime,adate,jdate,amonth,ayear,aday;

//alert(arguments.length+" timetype="+timeType+','+typeof(timeType) );
//    if (typeof(timeType)=='object' || strip(timeType)==='') alert(' is blank');
//    if (strip(timeType)==='0') alert(' is zero');

   if (arguments.length<1 ) timeType=1;
   if (arguments.length>0) {
       if (typeof(timeType)=='object' || strip(timeType)==='') timeType=1;
    }
   if (arguments.length<2) dateType=0 ;

  Stamp = new Date();
  atime=''; jdate='';

  if (timeType==0) return Stamp.getTime()  ;                    // internal time (milliseconds since 1970)

  if (timeType==2 && dateType==2) {
        adate=Stamp.toString();
        return adate ;
   }
  if (timeType!=0) {
      Hours = Stamp.getHours();
      if (Hours >= 12) {
         Time = "PM";
       }
       else {
         Time = "AM";
       }
       if (Hours > 12) {
        Hours -= 12;
       }
        if (Hours == 0) {
         Hours = 12;
       }
       Mins = Stamp.getMinutes();
       if (Mins < 10) {   Mins = "0" + Mins } ;
   
       Secs = Stamp.getSeconds();
       if (Secs < 10) {   Secs = "0" + Secs } ;
       atime=Hours + ':' + Mins + ':' +  Secs + ' ' + Time ;

   }
  
  if (dateType!=0) {
     adate=Stamp.toString();
     var foo=adate.split(' ');
     aday=foo[0]; amonth=foo[1]; adate=foo[2] ; ayear=foo[3];
     jdate=adate+' '+amonth+' '+ayear+' ';
     if (dateType==2 )  jdate=aday + ', ' + jdate;
  }

  atime=jdate+atime ;
  return atime ;
}


//===========================
// return prior value of avar, from round around, or defval if no such variable/round. defval='' if not specified. round =$recent if not specified
// note that avar should be a string variable
// this basically calls read_priorGlobal
//  and, checks if an object looks like an array. And if it is, converts it to an array (this deals with some
//  clone problems

function svyPrior(avar,around,defval) {
 var vv ;
 var tt,ee,iee;

if (typeof(avar)!='string') {
  alert('Error in svyPrior: avar not a string= '+avar);
  return 0;
}
 if (arguments.length<2) around='';
  around=strip(around);

 if (around.toUpperCase()=='$RECENT') around=''; 
 if (arguments.length<3) defval='';
 vv=Read_priorGlobal(around,avar,defval);

// convert array object to proper array?
  if (typeof(vv)!=='object') return vv ;
  if (typeof(vv.length)!=='undefined') return vv ;              // if length exists, no need to tinker
  
  tt=[];
  for (var ee in vv) {
        if (isNaN(ee)) return vv ;              // a non numeric object index. So not an array
        iee=parseInt(ee);
        tt[iee]=vv[ee];
  }
  return tt ;

}



//=====================
// returns value, or defval if missing. This basically call svy_getVal
function svyMiss(avar,defval) {
var vv ;
var dd ; 
if (arguments.length<2) {
  dd=0 ;
} else {
  dd=svy_getVal(defval,0) ;
}
//alert(avar+' misss ' +arguments.length+','+dd);
vv=svy_getVal(avar,dd) ;  
return vv;
}

// alternate name
function svy_miss(avar,defval) {
  if (arguments.length<2) {
    var vv=svyMiss(avar);
  } else {
    var vv=svyMiss(avar,defval);
  }
  return vv ;
}


//=======================================================
// update the css  style of elements 

function update_styles(chkElements,dastring,ireplace) {
  if (arguments.length<3) ireplace=0;
  if (typeof(chkElements)!=='object') return 0 ;
  if (typeof(chkElements.length)=='undefined') {
     if (ireplace==0) {
            chkElements.style.cssText=chkElements.style.cssText+' ; '+dastring ;
      } else {
            chkElements.style.cssText=dastring ;
      }
  } else {                      // array
     for (i=0 ; i<chkElements.length;i++){
       if (ireplace==0) {
            chkElements[i].style.cssText=chkElements[i].style.cssText+' ; '+dastring ;
        } else {
          chkElements[i].style.cssText= dastring ;
        }
      }                         // across array
  }                             // not an array
  return 1 ;
}

//=======================================================
// add a class to a list of elements

function update_class(chkElements,daclass0) {
var i,daclass;
  if (typeof(chkElements)!=='object') return 0 ;
  if (typeof(chkElements.length)=='undefined') {
    daclass=chkElements.getAttribute('class');
    if (daclass==='') daclass=chkElements.getAttribute('className');
    daclass=daclass+' '+daclass0;
    chkElements.setAttribute('class',daclass);
    chkElements.setAttribute('className',daclass);
   return 1;
}

for (var i=0 ; i<chkElements.length;i++){               // if here, an array of elements
    daclass=chkElements[i].getAttribute('class');
    if (daclass==='') daclass=chkElements[i].getAttribute('className');
    daclass=daclass0+' '+daclass; 
    chkElements[i].setAttribute('class',daclass);
    chkElements[i].setAttribute('className',daclass0);
  }
  return 1 ;
}


//=======================================================
// add attributes to elements

function Add_Attribute(chkElements,datt,dval,iappend,replaceChar) {
  var dvaluse ;
  if (arguments.length<4) iappend=0 ;
  if (arguments.length<5) replaceChar='' ;

  if (typeof(iappend)=='string') {
        var ss=strip(iappend.toUpperCase());
        if (ss=='APPEND') {
           iappend=1 ;
        } else  if (ss=='APPEND_EXISTS') {
           iappend=2 ;
        } else {
           iappend=0 
        }
   }

  if (typeof(chkElements)!=='object') return 0 ;

  for (var i=0 ; i<chkElements.length;i++){
     if (iappend==0) {                          // replace/create mode
           dvaluse=dval ;
     } else if (iappend==1) {                   // append mode
         d1=chkElements[i].getAttribute(datt);
        if (replaceChar!=='') {
           if (d1.indexOf(replaceChar)>-1) {
                dvaluse=d1.replace(replaceChar,dval);
           } else {                                     // no replacechar found
              dvaluse=d1+dval;
           } 
        } else {                                // replacechar not specified
            dvaluse=d1+dval;
        }
     } else if (iappend==2) {                   // append if exists mode
         var d1=chkElements[i].getAttribute(datt);
         if (d1 && d1!='') {
             if (replaceChar!=='') {                    // replacechar specified
                if (d1.indexOf(replaceChar)>-1) {
                   dvaluse=d1.replace(replaceChar,dval);
                } else {                                // no replaceChar
                   dvaluse=d1+dval;
                } 
              } else {                                 // replacechar not specified
                dvaluse=d1+dval;
              }
         } else {                       // empty, no append if empty.. skip
            continue ;
         }
     }
    chkElements[i].setAttribute(datt,dvaluse);
  }                                                     // for
 
 return 1 ;
}



// ============================
// add event listeners to elements. etype is the type of event, efunc is the event handler

//  
// example: Add_Event(dolist,'click',E2_showHelp)
// where dolist could be something like: dolist=get_elements(checkClassList,'INFOLINKS');

function Add_Event(chkElements,etype,efunc) {

if (typeof(chkElements)!=='object') return 0 ;

/* == no longer used 
if (typeof(chkElements)=='object' && typeof(chkElements.length)=='undefined') {             // non array object   
       var cc=new Array() ;
       cc[0]=chkElements ; chkElements=cc ;
}
==== */

if (typeof(chkElements.length)=='undefined') {                          // not an array, just a single item
     if (window.attachEvent){
        chkElements.attachEvent('on'+etype,efunc); // ie 
     } else {
        chkElements.addEventListener(etype,efunc,false);
    }
} else {                                                        // an array
  for (i=0 ; i<chkElements.length;i++){
      if (window.attachEvent) {                         // ie 
          chkElements[i].attachEvent('on'+etype,efunc);
       } else {
         chkElements[i].addEventListener(etype,efunc,false);
      }
   }
}

return 1  ;

}




// ========Functions for loading files from server



// ============================
// read a file, save the "xml documentElement" to a javascript global varname
//
//  filename (can have subdir info to start) to GET from server
//      eg: 'ers6_a.xml'  or 'cache/exper3.xml'
//      Note: if filename does NOT start with a /, then prepend SvyGetFileHdr (if it exists), otherwise prepend /
//  varname: variable name to use to store (as javascript global). Varname will be capitalized
//           and used to save, using windows[varname]=xml.documentElement
//
// april 08 addition: acomment is used in various status, etc output
//
// March 08 addition: if afunc specified, then call (with launch_proc)
//                    afunc(arg1,arg2,arg3,arg4,arg5,arg6,arg7) on successful read (or failure read) of file
//         If varname='', then do NOT save to VARNAME, but do call function specified by afunc (and return
//         results in arg1
//
//  nov 08 addition: if filename starts with an '=", then first check getXmlFileCache for this filename (with = stripped)
//                    Capitalized version of filename is used as cache entry.
//                      However, if filename starts with '==', then the == is stripped and the non-capitalized name is used as cache entry
//                   if it exists, use its contents (a node)
//                   if not, after getting file, save (the xml node from the retrieved xml file) to cache
//     This requires that an xmlFileCache global object be created. It is used as the cache. If it doesn't exist, caching is not attempted
//
//  april 2010 addition: varnames can be an array.
//                      First (varname) element is where to store dom version of xml file,
//                      second (varnameReturn)for storing returnCode (if '', do NOT store returnCode
//                            This can be used for checking errors.
//                      third (retainComments) is a flag to "retain comments" (if equal to "1")
//                      If just one variable (not an array), the on error an alert occurs and nothing is set, and
//                      comments are NOT retained
//
//    6 dec 2010 addition: filename0 can be an array
//                      filename[0] - file (actually, request string) sent to server
//                        filename[1] - cachebuster rule: 0=no cache buster, 1=strong (random string), 2=weaker (header)
//                       If a string is returned, filename=filename0 and cachebuster is 1
//
// If failure, windows[varname]=null
// Note: use E2L_ functions, which should be exact copies of E2_ functions in svyLibE2.js (usine E2L_ versions
// means you can use this library without also using svylib_e2)

function Get_xmlFile(filename0,varnames,acomment,afunc,arg1,arg2,arg3,arg4,arg5,arg6,arg7) {
var tmp;
var haa,toget,GetIt,chkCache='';
var varname,varnameReturn,retainComments,filename,cBust ;


if (typeof(filename0)=='object' && typeof(filename0.length)=='number') {
  filename=filename0[0];
   cBust=filename0[1];
} else {
  cBust=1 ;
  filename=filename0;
}


if (arguments.length<3) acomment='Retreiving XML file ';
if (arguments.length<4) afunc='' ;         
if (arguments.length<5) arg1='' ;
if (arguments.length<6) arg2='' ;
if (arguments.length<7) arg3='' ;
if (arguments.length<8) arg4='' ;
if (arguments.length<9) arg5='' ;
if (arguments.length<10) arg6='' ;
if (arguments.length<11) arg7='' ;

filename=strip(filename);
if (filename=='') {
  alert('ERROR in get_xmlFile -- no file name (comment='+acomment);
  return 0
}

//=== DEPRECATED (caching)
if (filename.substr(0,1)=='=') {                 // =filename means "check cache"
  alert('CACHING IS NO LONGER SUPPORTED BY DSURVEY ');
  return 0;
}

retainComments='0';

if (typeof(varnames)=='object' && varnames.length>1) {
  varname=varnames[0];
  varnameReturn=varnames[1];
  if (varnames.length>2) retainComments=strip(varnames[2]);
} else {
  varname=varnames;
  varnameReturn='';
}

varname=strip(varname);
if (varname=='' && afunc=='') {
  alert('ERROR in get_xmlFile -- no variable name, and no function supplied ');
  return 0 ;
}
if (varname=='1' || varname=='0' ) {
  alert('ERROR in get_Xmlfile -- invalid variable name ("0" and "1"  are reserved) ')
}  ;

// create the ajax object that will do the GET from the http server
  haa='';
  if (filename.substr(0,1)!='/') {
    if (typeof(SvyGetXMLFileHdr)=='undefined')  SvyGetXMLFileHdr='\/';
    var haa=strip(SvyGetXMLFileHdr) ;
  }

  toget=haa+filename ;
  GetIt = new svy_CreateXMLHTTP(toget);
  GetIt.onDraw=callback_Get_xmlFile ;

  GetIt._timeout=30000  ; //  30 seconds until timeout
  GetIt._showstatus=false ;
  GetIt._comment=acomment+' '+filename ;
  GetIt._variable=varname ;
  GetIt._variableReturn=varnameReturn ;
  GetIt._retainComments=retainComments;

  GetIt._isText=false ;

  GetIt._cacheBuster=cBust  ;   
  if (afunc!='') {                      // after reading, launch this proc
    GetIt._variable2=afunc ;
    GetIt._variable3=arg1 ;
    GetIt._variable4=arg2 ;
    GetIt._variable5=arg3 ;
    GetIt._variable6=arg4 ;
    GetIt._variable7=arg5 ;
    GetIt._variable8=arg6 ;
    GetIt._variable9=arg7 ;
  }

  if (varname!=='') window[varname]=null;                       // default is "no value"

   GetIt.load(varname,1000) ;  // create the request, and submit it  on response, call callback_Get_xmlFile

  return 1 ;
}

// ============================
// read a file, save contents to a javascript global varname.  Note that the options are the same as in Get_xmlFile
// if filename0 is an array, first element is what go GET, 2nd is cache-buster rule 
//          (0=NO, 1=Yes (use random string added to filename), 2=use headers)
//    6 dec 2010 addition: filename0 can be an array
//                      filename[0] - file (actually, request string) sent to server
//                        filename[1] - cachebuster rule: 0=no cache buster, 1=strong (random string), 2=weaker (header)
//                       If a string is returned, filename=filename0 and cachebuster is 2

function  Get_File(filename0,varnames,acomment,afunc,arg1,arg2,arg3,arg4,arg5,arg6,arg7) {
var varnameReturn,varname,toget;
var toget,GetIt,haa,filename,cBust;

if (typeof(filename0)=='object' && typeof(filename0.length)=='number') {
  filename=filename0[0];
   cBust=filename0[1];
} else {
  cBust=2 ;
  filename=filename0;
}

if (arguments.length<3) acomment='Retreiving file ';
if (arguments.length<4) afunc='' ;
if (arguments.length<5) arg1='' ;
if (arguments.length<6) arg2='' ;
if (arguments.length<7) arg3='' ;
if (arguments.length<8) arg4='' ;
if (arguments.length<10) arg6='' ;
if (arguments.length<11) arg7='' ;

filename=strip(filename);
if (filename=='') {
  alert('ERROR in Get_File -- no file name ');
  return 0
}

if (typeof(varnames)=='object' && varnames.length>1) {
  varname=varnames[0];
  varnameReturn=varnames[1];
} else {
  varname=varnames;
  varnameReturn='';
}


varname=strip(varname);
if (varname=='' && afunc=='') {
  alert('ERROR in Get_File -- no variable name, and no function supplied ');
  return 0
}
if (varname=='1' || varname=='0' ) {
  alert('ERROR in Get_file -- invalid variable name ("0" and "1"  are reserved) ')
}  ;

// create the ajax object that will do the GET from the http server
  haa='';
  if (filename.substr(0,1)!='/') {
    if (typeof(SvyGetFileHdr)=='undefined')  SvyGetFileHdr='/';
    haa=strip(SvyGetFileHdr) ;
  }
  var toget=haa+filename ;
  var GetIt = new svy_CreateXMLHTTP(toget);
  GetIt.onDraw=callback_Get_File ;

  GetIt._timeout=30000  ; //  30 seconds until timeout
  GetIt._showstatus=false ;
  GetIt._comment=acomment+' '+filename ;
  GetIt._variable=varname ;
  GetIt._returnCode=varnameReturn ;
  GetIt._isText=true ;

  GetIt._cacheBuster=cBust ;
  if (afunc!='') {                      // after reading, launch this proc
    GetIt._variable2=afunc ;
    GetIt._variable3=arg1 ;
    GetIt._variable4=arg2 ;
    GetIt._variable5=arg3 ;
    GetIt._variable6=arg4 ;
    GetIt._variable7=arg5 ;
    GetIt._variable8=arg6 ;
    GetIt._variable9=arg7 ;

  }

  if (varname!=='') window[varname]=null;                       // default is "no value"
   GetIt.load(varname,1000) ;  // create the request, and submit it  on response, call callback_Get_File

  return 1 ;
}


// ============================
// do a post request using ajax

function  Post_toServer(aURL,aContents,varname,acomment,afunc,arg1,arg2,arg3,arg4,arg5) {

if (arguments.length<4) acomment='Putting contents ';
if (arguments.length<5) afunc='' ;
if (arguments.length<6) arg1='' ;
if (arguments.length<7) arg2='' ;
if (arguments.length<8) arg3='' ;
if (arguments.length<9) arg4='' ;
if (arguments.length<10) arg5='' ;

aURL=strip(aURL);
if (aURL=='') {
  alert('ERROR in Post_toServer: no url ');
  return 0
}

varname=strip(varname);
if (varname=='' && afunc=='') {
  alert('ERROR in Post_toServer -- no variable name, and no function supplied ');
  return 0
}
if (varname=='1' || varname=='0' ) {
  alert('ERROR in Post_toServer -- invalid variable name ("0" and "1"  are reserved) ')
}  ;

// create the ajax object that will do the GET from the http server
  var toget=aURL ; 
  var GetIt = new svy_CreateXMLHTTP(toget);
  GetIt.onDraw=callback_Post_toServer ; 
  GetIt._method = 'POST';
  GetIt._postRequest = aContents;
  GetIt._timeout=30000  ; //  30 seconds until timeout
  GetIt._showstatus=false ; 
  GetIt._comment=acomment+' '+aURL ;
  GetIt._variable=varname ;
  GetIt._isText=true ;

  GetIt._cacheBuster=2 ; 
  if (afunc!='') {                      // after reading, launch this proc
    GetIt._variable2=afunc ;
    GetIt._variable3=arg1 ;
    GetIt._variable4=arg2 ;
    GetIt._variable5=arg3 ;
    GetIt._variable6=arg4 ;
    GetIt._variable7=arg5 ;
  }

  if (varname!=='') window[varname]=null;                       // default is "no value" 
//alert('posttos2');
  GetIt.load(varname,1000) ;  // create the request, and submit it  on response, call callback_Post_toServer
//alert('posttos3');
  return 1 ;
}




// ===============
// callback function to use by Get_xmlFile

function callback_Get_xmlFile(oinfo,chk_val,rcode,hstat,nthdo) {
 var tmp ;

 window[this._variable]=null ;            // assume failure
 if (this._variableReturn!=='')  {
        window[this._variableReturn]=rcode ;
  }
  if (hstat!='OK') {
     if (this._variableReturn=='') {
        chk_val='Error ('+rcode+') in callback_Get_xmlFil ( '+ chk_val + ') \n For '+oinfo  +':  \n  ...unable to read XML file  (' + this._dataURL + ') -- please ask for assistance.';
        alert(chk_val) ;
     }
     if (this._variable2!=='') {                       // call a function (with launch_proc -- typically the function that called getXmlFile
        Launch_Proc(this._variable2,20,this._variable3,this._variable4,this._variable5,this._variable6,this._variable7,this._variable8,this._variable9);
     }

     return 0;

  } else {                                      // begin OK status

     if (chk_val==null || typeof(chk_val)!=='object') {
         if (this._variableReturn!=='') {
//           alert('gogog '+rcode);
             window[this._variableReturn]='MISSING_XML' ;
             Launch_Proc(this._variable2,20,this._variable3,this._variable4,this._variable5,this._variable6,this._variable7,this._variable8,this._variable9);
             return 0 ;
         }
        alert('Error in callback_Get_xmlFile: file retrieved ('+this._comment+'), but it is not an object: '+chk_val+','+typeof(chk_val));
        return 0;
     }

     if (typeof(chk_val.documentElement)!=='object') {
         if (this._variableReturn!=='') {
             window[this._variableReturn]=rcode ;
             window[this._variableReturn]='MISSING_DOCUMENT_ELEMENT' ;
             Launch_Proc(this._variable2,20,this._variable3,this._variable4,this._variable5,this._variable6,this._variable7,this._variable8,this._variable9);
             return 0 ;
         }
        alert('Error in callback_Get_xmlFile: file retrieved ('+this._comment+'), but no .documentElement  ');
        return 0;
     }

     if (debugOn()) writeStatus('   '+this._comment);
     if (this._variable!=='')    {

// IE Hack prevents use of this...
//      window[this._variable]=chk_val.documentElement ;            // where to store response from server (as a node)

       if (this._retainComments=='1') {
          tmp=E2L_xmlToDomCmt(chk_val.documentElement);
       } else {
          try {                                 // this catches some bad responses
             var vv=typeof(chk_val.documentElement.nodeName);
         }
         catch(ierr) {
                alert('Error: got a problem reading XML file '+oinfo+'('+ierr+') == ' +this._comment );
                return 0 ;
         }

         tmp=E2L_xmlToDom(chk_val.documentElement);
       }

       window[this._variable]=tmp ;            // where to store response from server (as a node)

// delete ajax object
     delete chk_val ;
     chk_val='';

     }

     if (this._variable2!=='') {                       // call a function (with launch_proc -- typically the function that called getXmlFile
             Launch_Proc(this._variable2,20,this._variable3,this._variable4,this._variable5,this._variable6,this._variable7,this._variable8,this._variable9);
     }

  }                             // end OK status
  return true ;
}


// ===============
// callback function to use by Get_File

function callback_Get_File(oinfo,chk_val,rcode,hstat,nthdo) {

 window[this._variable]=null ;            // assume failure
 if (this._returnCode!=='')  window[this._returnCode]=rcode ;

  if (hstat!='OK') {

     if (this._returnCode=='') {
        chk_val='Error ('+rcode+') in callback_Get_File ( '+ chk_val + ') \n For '+oinfo  +':  \n  ...unable to read XML file  (' + this._dataURL + ') -- please ask for assistance.';
        alert(chk_val) ;
     }
     if (this._variable2!=='') {                       // call a function (with launch_proc -- typically the function that called get_File
        Launch_Proc(this._variable2,20,this._variable3,this._variable4,this._variable5,this._variable6,this._variable7,this._variable8,this._variable9);
     }

     return 0;

//     chk_val='Error in callback_Get_File -- ' + chk_val + ' : for '+this._dataURL +' : Unable to read file  (' + oinfo + ') -- please ask for assistance.';
//     alert(chk_val) ;
  } else {
      if (debugOn()) writeStatus('   '+this._comment);
      if (this._variable!=='')      window[this._variable]=chk_val ;            // where to store response from server (as a node)
          
     if (this._variable2!=='') {                       // call a function (with launch_proc -- typically the function that called getXmlFile
         Launch_Proc(this._variable2,20,this._variable3,this._variable4,this._variable5,this._variable6,this._variable7,this._variable8,this._variable9);
     }

  }

// delete ajax object
     delete chk_val ;
     chk_val='';

  return true ;
}

// ===============
// callback function to use by Post_toServer

function callback_Post_toServer(oinfo,chk_val,rcode,hstat,nthdo) { 
//alert('posttos4b  '+hstat);

  if (hstat!='OK') {
     chk_val='Error in callback_Post_toServer -- ' + chk_val + ' : for '+this._dataURL +' : Unable to post file  (' + oinfo + ') -- please ask for assistance.';
     alert(chk_val) ;
  } else {
      if (debugOn()) writeStatus('   '+this._comment);
      if (this._variable!=='')      window[this._variable]=chk_val ;            // where to store response from server (as a node)
          
     if (this._variable2!=='') {                       // call a function (with launch_proc -- typically the function that called getXmlFile
             Launch_Proc(this._variable2,20,this._variable3,this._variable4,this._variable5,this._variable6,this._variable7);
     }
  }

// delete ajax object
     delete chk_val ;
     chk_val='';

  return true ;
}

// ====================   
// Display contents of the variable named in varname in the target window, as an HTML file. Can be used as the function in a Get_File.
// will use "window open" in daopts, if specified. If not specified, use some defaults 
function  Display_Content(varname,target,daopts) {
 if (arguments.length<2) target='' ;
 if (arguments.length<3)  daopts="toolbar=0,menubar=0,directories=0,scrollbars=1,resizable=1"  ;
 var ow=window.open("javascript://",target,daopts);
 ow.document.open('text/html')
 ow.document.write(window[varname]);
 ow.document.close();
 return 1 ;
}



// ========Functions for writing to the status message DIVS (MyStatus and MyHistory )  =============



// ======================================
// local hook to E2_writeStatus (spec file function) and writeDoStatus (control panel function) , or just write to alert box

function writeStatus(m1) {
var mfreq;

// for upward compatability!
  if (typeof(writeDoStatus)!=='undefined') {            // control panel?
       writeDoStatus(m1);
       return true ;
 }
 if (typeof(E2_writeStatus)!=='undefined') {            // spec file?
       E2_writeStatus(m1);
       return true ;
  }

// otherwise, just write an alert      
alert(m1);
return 1;
}



//================================================= NEEDS WORK  6/9/08
// check that all of the  qlist questions in the fname form were answered. If not, show an error message in an alert  and return false,
// if yes, return true
// if fname='' or 0, check the first form. Note that if a group contains no <form>, the group's content (actually, the div containing the group's 
// content) will be embedded in an unnamed form
function check_RadiosDone(fname,qlist,errmess) {
  if (fname==0 || fname=='') fname='_allPage' ;
  if (typeof(document.forms[fname])=='undefined') {
        alert('%error in check_RadiosDone: no such form name:' +fname);
        return 1; 
   }

  vlist=qlist.split(' ');
  for (m=0;m<vlist.length;m++){
     if (vlist[m]=='') continue;
     var try1=strip(vlist[m]);
     if (typeof(document.forms[fname].elements[try1])=='undefined') try1=try1.toLowerCase() ;
     if (typeof(document.forms[fname].elements[try1])=='undefined') {
        alert('%error in check_RadiosDone: in form (' +fname+') there is no radio button: '+ vlist[m]);
        return 1; 
     } ;
  
     var arf=document.forms[fname][try1] ;
     var xx=0;
     for (var mh=0; mh<arf.length;mh++)  {
         if (arf[mh].checked) xx=1;
     } 
     if (xx==0) {
         if (arguments.length<3) {
            alert(' Sorry, before moving to the next page, you must answer all the questions on this page  ');
          } else { 
                alert(errmess) ;
           }
         return false ;
      }
 }
 return true ;
}




// ========================================================
// see if and of the words, possibly wildcarded, in daclass is one of the classes of the this1 element.
// Uses a case insensitive search and possibly * wildcarded search (daclass can contain words with * in them)
// return 1 if yes, 0 if no (or if no classes in this element)

function Find_Class(daclass,this1) {
 if (arguments.length<2) return 0 ;

 try {
     if (!this1.className) return 0;
 }
 catch(err) {                       // goofy this1, give up
      return 0;
 }

 var cc=this1.className;
 if (cc=='') return 0 ;                 // no classes, give up

 var ith=Word_inString(daclass,cc);
 return ith  ;
}


//====================
// see if namelist contains the name field of the this1 element 
// Uses a case insensitive search
// return 1 if yes, 0 if no (or if no name forthis element)

function Find_Name(namelist,this1) {
  var ith ;
  try {
     if (!this1.getAttribute) return 0;
  }
  catch(err) {
     return 0;
  }

//  if (!this1.getAttribute) return 0;

  var elemname=this1.getAttribute('name');
  if (!elemname) return 0 ;                           // no name specified
  var ith=Word_inString(namelist,elemname);

  return ith;

}


// ========================================================
// see if and of the words, possibly wildcarded, in myneedle are in the list of words in myhaystack
// If useCase not specified, or is 0, uses a case insensitive search and possibly * wildcarded search (myneedle can contain words with * in them)
//    useCase=1: use a case SENSITIVE search
// return word number  in HAYSTACK that is matched (starting at 1), or 0 if none
// needle can be more than one word. In which case, first match is a success (return is the word matched in haystack, but no info on needle)

function Word_inString(myneedle,myhaystack,useCase) {
 var daclass,cc,j,aneedle,needles ;
 var isi,rx,ism,ahaystack,haystack,j2,aneedle;

 if (arguments.length<2) return 0 ;
 if (arguments.length<3) useCase=0 ;

 if (!myneedle) return 0 ;

 daclass=strip(myneedle) ;
 if (daclass=='') return 0;
 var needles=daclass.split(/\s+/);
 
 cc=strip(myhaystack);
 if (cc=='') return 0 ;                 // no classes, give up

 if (typeof(cc.split)=='undefined') return 0

 if (!cc.split) return 0 ;

 var haystack=cc.split(/\s+/) ;  

 for (var j=0 ; j< needles.length ; j++) {
    var aneedle=needles[j] ;                         // a acceptable needle (word)
    if (aneedle=='') continue ;
    aneedle=aneedle.replace('*','.*') ;         // .* is the wildcard sequence 
    for (var j2=0; j2<haystack.length;j2++) {     // the elements classes
          ahaystack=haystack[j2];
          if (ahaystack=='') continue ;   
          var isi='';
          if (useCase!=1) isi='i';         
          if (aneedle.indexOf('[')>-1)       aneedle=aneedle.replace(/\[/g,'\\[');    // goofy hack to deal with [n]
          var rx= new RegExp(aneedle,isi) ;
          var ism=ahaystack.match(rx) ;        
          if (ism==ahaystack) return j2+1 ;                   // a match, so return the needle that matches (where first element is 1 , not 0

    }
}
return 0 ;                              // failure, return 0
}

//-----------------------
// make a function string, suitable for use in an onclick, etc
function make_procString(pname,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8) {
var nargs=arguments.length ;
if (nargs>9) {
        alert('Error in make_procString: max of 8 function arguments (# used= '+nargs);
        return '';
}


if (nargs<2) {
  alist='';
} else if (nargs<3) {
   var alist="'" + squoteToDquote(arg1)  + "'" ;
} else if (nargs<4) {
   var alist="'" + squoteToDquote(arg1)  + "'" ;
   var alist=alist + ','  +  "'" + squoteToDquote(arg2) + "'" ;
} else if (nargs<5) {
   var alist="'" + squoteToDquote(arg1)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg2)  +  "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg3)  + "'" ;
} else if (nargs<6) {
   var alist="'" + squoteToDquote(arg1)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg2)  +  "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg3)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg4)  + "'" ;
} else if (nargs<7) {
   var alist="'" + squoteToDquote(arg1)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg2)  +  "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg3)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg4)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg5)  + "'" ;
} else if (nargs<8) {
   var alist="'" + squoteToDquote(arg1)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg2)  +  "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg3)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg4)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg5)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg6)  + "'" ;
} else if (nargs<9) {
   var alist="'" + squoteToDquote(arg1)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg2)  +  "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg3)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg4)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg5)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg6)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg7)  + "'" ;
} else if (nargs<10) {
   var alist="'" + squoteToDquote(arg1)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg2)  +  "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg3)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg4)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg5)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg6)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg7)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg8)  + "'" ;
} ;

dafunc=pname+'('+alist+')';
return dafunc ;
}

//============
function squoteToDquote(astring) {
if (typeof(astring)!=='string' || strip(astring)=='') return astring;

//vv=confirm('aaaa '+astring); if (!vv) afjass(1) ;
var foo=astring.replace(/\'/g,'"');
return foo;
}


//-----------------------
// make a string to use in setTimeout
function Launch_Proc(pname,pwait,arg1,arg2,arg3,arg4,arg5,arg6,arg7) {

if (pwait=='' || pwait==0) pwait=500;                               // 0.5 second delay as default

var nargs=arguments.length ;
if (nargs<3) {
  alist='';
} else if (nargs<4) {
   var alist="'" + squoteToDquote(arg1)   + "'" ;
} else if (nargs<5) {
   var alist="'" + squoteToDquote(arg1)   + "'" ;
   var alist=alist + ','  +  "'" + squoteToDquote(arg2) + "'" ;
} else if (nargs<6) {
   var alist="'" + squoteToDquote(arg1)   + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg2)  +  "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg3)  + "'" ;
} else if (nargs<7) {
   var alist="'" + squoteToDquote(arg1)   + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg2)  +  "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg3)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg4)  + "'" ;
} else if (nargs<8) {
   var alist="'" + squoteToDquote(arg1)   + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg2)  +  "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg3)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg4)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg5)  + "'" ;
} else if (nargs<9) {
   var alist="'" + squoteToDquote(arg1)   + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg2)  +  "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg3)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg4)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg5)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg6)  + "'" ;
} else if (nargs<10) {
   var alist="'" + squoteToDquote(arg1)   + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg2)  +  "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg3)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg4)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg5)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg6)  + "'" ;
   var alist=alist + ','  +  "'" +  squoteToDquote(arg7)  + "'" ;

} ;

dafunc=pname+'('+alist+')';

var zz=setTimeout(dafunc,pwait) ;
return 1 ;
}
  
// arg1 arg2 arg3 arg4 arg5 arg6 arg7


//================
function debugOn(ilevel) { 
 var dd;

  if (arguments.length<1) ilevel=1;
  ilevel=parseInt(ilevel);
  if (isNaN(ilevel)) ilevel=1 ;
  dd=-1;
  if (typeof(SvyGlobals)!=='undefined') {
         dd=Read_Global('_debug_Mode','-1');
  }
  if (dd=='-1') {                                     // no such session-descriptor var. Use javascript global?
    if (typeof(debugMode)=='undefined') return false ;
    dd=debugMode ;
   }
   dd=parseInt(dd);
   if (isNaN(dd)) dd=1 ;
   if (ilevel<=dd) return true ;
  return false ;
}



/* ------------------ */
// evaluate a function == replace "@this" arguments with aelem (if aelem <>'') 
function evaluate_function(fstring,amess,aelem) {
    if (arguments.length<3) aelem='' ;

    var b1=parseArrayIndex(fstring);
    var cfunc=strip(b1[0]);
    if (typeof(window[cfunc])=='undefined' || !window[cfunc])  {
         alert('%ERROR in evaluate_function (called by ' + amess +'. Can not find function: '+cfunc+', in '+ fstring);
        return '';
    }
    if (typeof(window[cfunc])!='function') {
         alert('%ERROR in evaluate_function (called by ' + amess +'. Not a function: '+cfunc+', in '+ fstring);
        return '';
    }
    var cargs=b1[1];
    cargs=cargs.split(',');
    if (aelem!=='') {
        for (var kk=0;kk<cargs.length;kk++){
          if (strip(cargs[kk])=='@this') cargs[kk]=aelem
        }
    }
    var aresult='';
    switch (cargs.length) {
         case 0:   aresult=window[cfunc]() ; break 
         case 1:     aresult=window[cfunc](cargs[0]) ; break 
         case 2:     aresult=window[cfunc](cargs[0],cargs[1]) ; break 
         case 3:     aresult=window[cfunc](cargs[0],cargs[1],cargs[2]) ; break 
         case 4:     aresult=window[cfunc](cargs[0],cargs[1],cargs[2],cargs[3]) ; break 
         case 5:     aresult=window[cfunc](cargs[0],cargs[1],cargs[2],cargs[3],cargs[4]) ; break 
         case 6:     aresult=window[cfunc](cargs[0],cargs[1],cargs[2],cargs[3],cargs[4],cargs[5]) ; break 
         case 7:     aresult=window[cfunc](cargs[0],cargs[1],cargs[2],cargs[3],cargs[4],cargs[5],cargs[6]) ; break 
         case 8:     aresult=window[cfunc](cargs[0],cargs[1],cargs[2],cargs[3],cargs[4],cargs[5],cargs[6],cargs[7]) ; break 
         case 9:     aresult=window[cfunc](cargs[0],cargs[1],cargs[2],cargs[3],cargs[4],cargs[5],cargs[6],cargs[7],cargs[8]) ; break 
         case 10:    aresult=window[cfunc](cargs[0],cargs[1],cargs[2],cargs[3],cargs[4],cargs[5],cargs[6],cargs[7],cargs[8],cargs[9]) ; break 
         default:    alert('%ERROR in evaluate_function (called by ' + amess +'. Too many arguments= '+cargs.length); break ;
   }                                            // switch
   return aresult; 
}                               // function




/* ==============================*/
//make the next element visible, or invisible

/*
   displayNextElement is meant to be used in a clickable element. When clicked, it will (by default)
  turn on the display of the next element (following this clickable element)
  Example:
     <div> This is intro message </div>
     <a href="#" onClick="displayNextElement(this)">more...</a>
     <div style="display:none"> This is more message </div>
   When clicked, the This is more message will displayed, and the more... will be hidden

   Note that in this useage, you MUST include 'this' (without the quotes) as the argument

   Also, displayNextElement always returns false 


 Arguments:
    athis: id of element to start with. typically, the "this" in inline attribute (required)
    etype: element type. Optional, * if not specified.  The element type to change the display of
           Thus, elements AND text inbetween the clickable element and the element that matches
           etype will not be effected.  * means "any match". 
    clear1 : if 1, then hide this clickable element after it is clicked
    howdo  : how to change display of next (matching) element. Values can be:
                 'none' : hide the next element
                 'block' : display (as a DIV)
                 'inline'  : display (as a SPAN)    
                 'toggle'  : toggle current display status (between 'none' and 'block')
          

    Notes: 
      * registering displayNextElement to an object (say, using mybutton.onclick=displayNextElement), 
        is equivalent to displayNextElement(this,'*',1,'toggle')
      * Text elements, between the clickable element and the matching element, are always skipped (there
        display is not effected
      * If clear1 is not set to 1, and howdo is 'toggle', the clickable element can be used to turn off and on
        the display of the next element
                 

*/

function displayNextElement(athis,etype,clear1,howdo) {
var zz;
  if (arguments.length<1) athis=this;
  if (arguments.length<2) etype='*';
  etype=strip(etype).toUpperCase();
  if (arguments.length<3) clear1=1;
  if (arguments.length<4) howdo='TOGGLE';  
  zz=athis;
  while (1==1) {
     zz=zz.nextSibling ;
     if (zz==null) return 0     ;               // no next sibling, so do nothing
     if (zz.nodeType!==1) continue ;            // ignore comments, text, etc
     if (etype=='*') break;
     ztype=zz.nodeName.toUpperCase();
     if (etype==ztype) break ;
  }
  if (strip(howdo).toUpperCase()=='TOGGLE') {
    if (zz.style.display.toUpperCase()=='NONE') {
        howdo='block';
    } else {
        howdo='none';
    }
  }      
  zz.style.display=howdo;
  if (clear1==1) athis.style.display='none';
  return 0;
}



/* ==============================*/
// make a div visible, or invisible
// returns new state (none, block, or inline)
// Toggle is supported
// nomessage=1 means "don't write error message if adiv doesn't exist"
// 12/24/2010: todo0='STATUS' : returns 1 if  visible (0 if display:none)

function displayDiv(adiv,todo0,noMessage) {
var i1,i2,i3;
var dotog=0;
var todo='block';                           // default value (if todo is an unknown
var ttodo='';

if (arguments.length<2)  {
   dotog=1 ;
} else {
  ttodo=strip(todo0).toUpperCase(); 
  if (ttodo=='NO'     ||  ttodo=='NONE' ||  todo0==0) todo='none';
  if (ttodo=='YES'    || ttodo=='BLOCK' || ttodo=='DIV' || todo0==1) todo='block';
  if (ttodo=='TOGGLE' || todo0==2) dotog=1;
  if (ttodo=='INLINE' ) todo='inline';
}

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

i1=document.getElementById(adiv);  
if (!i1) {
   if (noMessage!=1) alert(' No such ID in displayDiv: ' + adiv);
    return 0;
}

if (ttodo=='STATUS') {
  i2=i1.style.display ;
  if (strip(i2).toUpperCase()=='NONE') return 0;
  return 1;
}

if (dotog==1)  {                         // toggle between block/inline and none

    nowd=strip(i1.style.display).toUpperCase() ;
    wasd=getAttributes(i1,'wasDisplay','');
//    alert('wasd '+wasd+','+nowd);
    if (wasd=='') {                             // first toggle, switch to default
       if (nowd=='NONE') {
//alert(' totobloc ');
          todo='inline';
       } else {
           todo='none';
//alert(' totonn ');
       }
       wasd=nowd ;
    } else {                    // toggle info exists
       todo=wasd;
       wasd=nowd ;
    }        
    i1.setAttribute('wasDisplay',wasd);
//alert(wasd+','+nowd+','+todo);
}

try {
  i1.style.display=todo ;
}
catch(err) {
  alert('Error in DisplayDiv, for adiv= '+adiv+' :: ' +err);
}

return todo ; 
}

 
// from:  http://www.mredkj.com/javascript/numberFormat.html
function addCommas(nStr)
{
	nStr += '';
	x = nStr.split('.');
	x1 = x[0];
	x2 = x.length > 1 ? '.' + x[1] : '';
	var rgx = /(\d+)(\d{3})/;
	while (rgx.test(x1)) {
		x1 = x1.replace(rgx, '$1' + ',' + '$2');
	}
	return x1 + x2;
}

// ==================================
// Return a string that is embedded within a start and stop HTML tag.
// This is mostly useful for embedding html markup in  SET
function htmlSurround(tagname,string)     {
   return '<'+tagname+'>'+string+'</'+tagname+'>';
}

// ==================================
//
//   -------  The next several E2L_ functions are copies of E2_ functions from svylibE2.js 
//   ------   If they are to be used seperately (not via calls to getXMLfile),
//   ------    you should use the E2_ versions in svyLibE2.js
//
// 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 E2L_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=E2L_xmlToDom(xnode) ;
        pnode.appendChild(cnode);
    } else {                     // then skip parent and get children 
        for (var i2=0 ; i2<xnode.childNodes.length ;i2++) {
           cnode=E2L_xmlToDom(xnode.childNodes[i2]) ;
           pnode.appendChild(cnode);
        }
    }                          // module
    return pnode ;
  } else {                             // atag  an object 
    if (xname!=skipTag)  {
        cnode=E2L_xmlToDom(xnode) ;
        atag.appendChild(cnode);
     } else {                     // skip parent (just get childred)
        for (var i2=0 ; i2<xnode.childNodes.length ;i2++) {
           cnode=E2L_xmlToDom(xnode.childNodes[i2]) ;
           atag.appendChild(cnode);
        }
     }                                  // module
     return 0 ;                         // append mode
  }                                     // atag an object 
}                                       // arguments.length

if (xtype==3 || xtype==4) {
     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
  if (atype==3 || atype==4) {                               // 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=E2L_xmlToDom(achild) ;
     pnode.appendChild(cnode);
  }                                             // else, skip the node   

}                       

return pnode;                   // return a new node xmlToDom

}

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

function E2L_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 || xtype==4) {
     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 || atype==4) {                               // 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=E2L_xmlToDomCmt(achild,1) ;
     pnode.appendChild(cnode);
  }                                             // else, skip the node   

}                       

return pnode;                   // return a new node xmlToD


}



//============ getAt
// extract name, and project, from a instrument descriptor file name
function extractProjectName(ainst) {  
var vv,tt,rr=[];

 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]).toUpperCase() ;
  }

 return rr;

}

//============
// create a string with name and project
function makeProjName(ainst) {
var uu,a1 ;
uu=extractProjectName(ainst);
a1=uu[0];
if (strip(uu[1])=='') return a1 ;
a1=a1+' (in project '+uu[1]+')';
return a1;
}


//=============
// alert with escate
function alertd(aline) {
var vv=confirm(aline);
if (!vv) abortJavascriptNOW_(4);
return 1 ;
}

//=============
// alert with escate
function alertD(aline) {
var vv=confirm(aline);
if (!vv) abortJavascriptNOW_(3);
return 1 ;
}

//=======================================================
// DEPRECATED
// caching version of get_elements

function get_elementsC(cname,chkElement,daclasses,namelist,cbase) {
alert('get_elementsC is DEPRECATED');
return 1 ;
/* ==========
  var ares;
  cname=strip(cname.toUpperCase());
  if (cname=='%RESET') {
         cacheElements=new Object() ;
         return 1;
  }

  if (arguments.length<2) chkElement='div span input select option ' ;     // avoid wierdness if less then 3 arguments
  if (arguments.length<3) daclasses='' ;
  if (arguments.length<4) namelist='' ;


  if (typeof(cacheElements)=='undefined')  cacheElements=new Object() ;

  if (cname=='') {                                      // no caching info, so just treat as call to get_elements
    if (arguments.length>4) {                           // use a cached list as chkElement?
       if (cbase) {
          if (typeof(cacheElements[cbase])!='undefined') chkElement=cacheElements[cbase];
       }
     }
//     alert(' using NO cache with '+ares.length);
     ares=get_elements(chkElement,daclasses,namelist);
     return ares ;
  }

  if (typeof(cacheElements[cname])!='undefined') {

     ares=cacheElements[cname];    // exists? use it and return
     return ares ;
   }

// read from, or write to, cache

  if (arguments.length>4) {                           // use a cached list as chkElement?
     if (cbase) {
        if (typeof(cacheElements[cbase])!='undefined') chkElement=cacheElements[cbase];
     }
  }

  var ares=get_elements(chkElement,daclasses,namelist);
  cacheElements[cname]=ares ;

  return ares ;
===== */
}

